我正在尝试将injection of my 64-bit DLL实现为64位进程。我的主机进程使用指向CreateRemoteThread
的线程子例程调用LoadLibrary
。 DLL稍后通过调用FreeLibraryAndExitThread
从内部卸载自己。
我的目标是知道注入的LoadLibrary
呼叫是否成功。遗憾的是,我无法在我的(主机)进程中使用GetExitCodeThread
,因为返回的64位HMODULE
句柄被远程线程截断为DWORD
。而且我不想使用Tool Help APIs,因为它们会引入竞争条件。
因此我想知道64位进程中HMODULE
返回的LoadLibrary
的低32位 - 我能否可靠地假设它的低32位不是0的有效的句柄?
PS。我不需要HMODULE
句柄本身,我需要知道LoadLibrary
是否成功。
编辑。来自我的主机进程的调用是这样完成的(以非常简洁的伪代码 - 没有错误检查):
CreateRemoteThread(hProcess, 0, 0,
GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"),
pVmAddressOfMyDllsPathWrittenWith_WriteProcessMemory, 0, 0);
答案 0 :(得分:3)
我能否可靠地假设它的低32位对于有效的句柄不会是0?
不,你不能。 HMODULE
在64位中与在32位中相同。它是加载模块的基址。因此,没有理由为有效的HMODULE
必须具有非零的低阶位。
您可以非常简单地确认这一点。创建一个64位DLL,IMAGEBASE
设置为0x0000000100000000
。加载该DLL,并检查返回的HMODULE
的值。
答案 1 :(得分:2)
而CreateRemoteThread
使用指向LoadLibraryW
的线程子例程,我们可以向远程进程注入微小的shell代码,首先调用LoadLibraryW
,如果失败,则GetLastError
- 结果远程线程返回错误代码(如果没有错误则为0) - 并且您将确切地知道 - LoadLibrary
是否正常,如果没有 - 有错误代码。 64位asm代码可以是:
CONST segment
SHELLDATA struct
LoadLibrary DQ ?
GetLastError DQ ?
SHELLDATA ends
public RemoteThreadProc_begin
public RemoteThreadProc_end
RemoteThreadProc_begin:
RemoteThreadProc proc
nop
nop
nop
call @@0
___ SHELLDATA <>
@@0:
xchg [rsp],rbp
sub rsp,20h
call SHELLDATA.LoadLibrary[rbp]
test rax,rax
jz @@1
xor eax,eax
@@2:
add rsp,20h
pop rbp
ret
@@1:
call SHELLDATA.GetLastError[rbp]
jmp @@2
RemoteThreadProc endp
RemoteThreadProc_end:
CONST ends
和c ++代码:
extern "C"
{
extern UCHAR RemoteThreadProc_begin[], RemoteThreadProc_end[];
}
enum INJECT_PHASE {
fOpenProcess, fVirtualAlloc, fWriteProcessMemory, fCreateRemoteThread, fMax
};
ULONG injectDll(ULONG dwprocessId, PCWSTR dllFilePath, INJECT_PHASE& phase)
{
ULONG err = 0;
struct SHELLDATA
{
__int64 code;
PVOID LoadLibrary, GetLastError;
};
if (HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, dwprocessId))
{
SIZE_T cbStr = (wcslen(dllFilePath) + 1) * sizeof(WCHAR);
SIZE_T cbCode = ((RemoteThreadProc_end - RemoteThreadProc_begin) + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
union {
PVOID RemoteAddress;
PBYTE pbRemote;
PTHREAD_START_ROUTINE lpStartAddress;
};
if (RemoteAddress = VirtualAllocEx(hProcess, 0, cbStr + cbCode, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
{
union {
PVOID pv;
PBYTE pb;
SHELLDATA* ps;
};
pv = alloca(cbStr + cbCode);
memcpy(pv, RemoteThreadProc_begin, cbCode);
memcpy(pb + cbCode, dllFilePath, cbStr);
HMODULE hmod = GetModuleHandle(L"kernel32");
ps->GetLastError = GetProcAddress(hmod, "GetLastError");
ps->LoadLibrary = GetProcAddress(hmod, "LoadLibraryW");
if (WriteProcessMemory(hProcess, RemoteAddress, pv, cbStr + cbCode, 0))
{
if (HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, lpStartAddress, pbRemote + cbCode, 0, 0))
{
phase = fMax;
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &err);
CloseHandle(hThread);
}
else
{
phase = fCreateRemoteThread;
err = GetLastError();
}
}
else
{
phase = fWriteProcessMemory;
err = GetLastError();
}
VirtualFreeEx(hProcess, RemoteAddress, 0, MEM_RELEASE);
}
else
{
phase = fVirtualAlloc;
err = GetLastError();
}
CloseHandle(hProcess);
}
else
{
phase = fOpenProcess;
err = GetLastError();
}
return err;
}