149 lines
4.6 KiB
C++
149 lines
4.6 KiB
C++
#include "LoaderError.h"
|
|
#include "IdentifyEXE.h"
|
|
#include "common/IFileStream.h"
|
|
|
|
// remote thread creation
|
|
|
|
static bool DoInjectDLLThread(PROCESS_INFORMATION * info, const char * dllPath, bool sync, bool noTimeout);
|
|
|
|
bool InjectDLLThread(PROCESS_INFORMATION * info, const char * dllPath, bool sync, bool noTimeout)
|
|
{
|
|
bool result = false;
|
|
|
|
// wrap DLL injection in SEH, if it crashes print a message
|
|
__try {
|
|
result = DoInjectDLLThread(info, dllPath, sync, noTimeout);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
PrintLoaderError("DLL injection failed. In most cases, this is caused by an overly paranoid software firewall or antivirus package. Disabling either of these may solve the problem.");
|
|
result = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
48:83EC 28 | sub rsp, 28 |
|
|
48:8BD9 | mov rbx,rcx | save to non-volatile register
|
|
48:8D4B 10 | lea rcx,qword ptr ds:[rbx+10] | offsetof(InjectDLLThreadData, dllPath)
|
|
FF13 | call qword ptr ds:[rbx] | offsetof(InjectDLLThreadData, loadLibraryA)
|
|
48:8BC8 | mov rcx,rax |
|
|
BA 01000000 | mov edx,1 |
|
|
FF53 08 | call qword ptr ds:[rbx+8] | offsetof(InjectDLLThreadData, getProcAddress)
|
|
FFD0 | call rax |
|
|
48:83C4 28 | add rsp, 28 |
|
|
C3 | ret |
|
|
*/
|
|
|
|
struct InjectDLLThreadData
|
|
{
|
|
InjectDLLThreadData(uintptr_t _loadLibraryA, uintptr_t _getProcAddress, const char * _dllPath)
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
loadLibraryA = _loadLibraryA;
|
|
getProcAddress = _getProcAddress;
|
|
strcpy_s(dllPath, sizeof(dllPath), _dllPath);
|
|
|
|
static const UInt8 kCode[] =
|
|
{
|
|
0x48, 0x83, 0xEC, 0x28,
|
|
0x48, 0x8B, 0xD9,
|
|
0x48, 0x8D, 0x4B, 0x10,
|
|
0xFF, 0x13,
|
|
0x48, 0x8B, 0xC8,
|
|
0xBA, 0x01, 0x00, 0x00, 0x00,
|
|
0xFF, 0x53, 0x08,
|
|
0xFF, 0xD0,
|
|
0x48, 0x83, 0xC4, 0x28,
|
|
0xC3,
|
|
};
|
|
|
|
memcpy(code, kCode, sizeof(kCode));
|
|
}
|
|
|
|
uintptr_t loadLibraryA; // 00
|
|
uintptr_t getProcAddress; // 08
|
|
char dllPath[2048]; // 10
|
|
UInt8 code[128]; // 810
|
|
};
|
|
|
|
static bool DoInjectDLLThread(PROCESS_INFORMATION * info, const char * dllPath, bool sync, bool noTimeout)
|
|
{
|
|
bool result = false;
|
|
|
|
// make sure the dll exists
|
|
IFileStream fileCheck;
|
|
if(!fileCheck.Open(dllPath))
|
|
{
|
|
PrintLoaderError("Couldn't find %s.", dllPath);
|
|
return false;
|
|
}
|
|
|
|
fileCheck.Close();
|
|
|
|
HANDLE process = OpenProcess(
|
|
PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, info->dwProcessId);
|
|
if(process)
|
|
{
|
|
uintptr_t hookBase = (uintptr_t)VirtualAllocEx(process, NULL, 8192, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
if(hookBase)
|
|
{
|
|
// safe because kernel32 is loaded at the same address in all processes
|
|
// (can change across restarts)
|
|
uintptr_t loadLibraryAAddr = (uintptr_t)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
|
|
uintptr_t getProcAddressAddr = (uintptr_t)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetProcAddress");
|
|
|
|
_MESSAGE("hookBase = %016I64X", hookBase);
|
|
_MESSAGE("loadLibraryAAddr = %016I64X", loadLibraryAAddr);
|
|
_MESSAGE("getProcAddressAddr = %016I64X", getProcAddressAddr);
|
|
|
|
InjectDLLThreadData data(loadLibraryAAddr, getProcAddressAddr, dllPath);
|
|
|
|
size_t bytesWritten;
|
|
WriteProcessMemory(process, (LPVOID)hookBase, (void *)&data, sizeof(data), &bytesWritten);
|
|
|
|
auto * remoteData = (InjectDLLThreadData *)hookBase;
|
|
|
|
HANDLE thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)(&remoteData->code), (void *)remoteData, 0, NULL);
|
|
if(thread)
|
|
{
|
|
if(sync)
|
|
{
|
|
switch(WaitForSingleObject(thread, noTimeout ? INFINITE : 1000 * 60)) // timeout = one minute
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
_MESSAGE("hook thread complete");
|
|
result = true;
|
|
break;
|
|
|
|
case WAIT_ABANDONED:
|
|
_ERROR("Process::InstallHook: waiting for thread = WAIT_ABANDONED");
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
_ERROR("Process::InstallHook: waiting for thread = WAIT_TIMEOUT");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
result = true;
|
|
|
|
CloseHandle(thread);
|
|
}
|
|
else
|
|
_ERROR("CreateRemoteThread failed (%d)", GetLastError());
|
|
|
|
VirtualFreeEx(process, (LPVOID)hookBase, 0, MEM_RELEASE);
|
|
}
|
|
else
|
|
_ERROR("Process::InstallHook: couldn't allocate memory in target process");
|
|
|
|
CloseHandle(process);
|
|
}
|
|
else
|
|
_ERROR("Process::InstallHook: couldn't get process handle");
|
|
|
|
return result;
|
|
}
|