64 位注入洞






4.80/5 (8投票s)
适用于 64 位进程的代码注入洞
引言
我正在开发的软件使用了 Darawk 编写的优秀的注入洞代码,来源是:http://www.gamerztools.net/foros/showthread.php?1080-Dll-Injection-Using-Code-Caves-by-Darawk。
这对于 32 位来说很棒,但我需要它也能在 64 位上运行。由于该解决方案使用了 Visual Studio 在 64 位中不支持的内联汇编,我不得不寻找另一种方法。在四处寻找 64 位注入洞之后,我最终自己编写了它。
64 位的编译代码
在上述 Darawk 的代码中,要注入的代码是用内联汇编编写的。然后,该函数的名称被用作从运行时复制编译代码的指针。
问题是,64 位的 Visual Studio 不支持内联汇编。因此,Darawk 的代码不能按原样使用。我选择的解决方案是生成 64 位机器码,并将其包含在代码中的硬编码数组中。
为了实现这一点,我将 Darawk 的汇编代码用 ml64 编译。
正如预期的那样,它不能按原样编译,所以我将代码移植到 MASM64。
这里需要合并几个差异
- MASM64 使用
fastcall
,因此函数的参数必须通过寄存器传递,而不是通过堆栈传递。 - 必须考虑地址的长度 - 32 位与 64 位。
- MASM64 没有将所有寄存器压入堆栈的指令(例如 32 位中的
pushad
),因此必须通过显式地压入所有寄存器来完成此操作。
一旦 64 位汇编使用 ml64 成功编译,我就将生成的机器码放入一个数组中,并将该数组本身注入到目标进程中。
Using the Code
以下是注入函数以及它注入的机器码数组。
请注意,Darawk 的 32 位代码使用了 VirtualProtect
来保护注入的代码,因为该代码位于代码段中。在我们的例子中,注入的代码位于堆上。您应该考虑在锁下运行注入函数,以防止在同一时间从多个线程运行该函数时发生冲突。
unsigned char codeToInject[] =
{
// Placeholder for the return address
0x68, 0xAA, 0xAA, 0xAA, 0xAA, // push 0AAAAAAAAh
// Save the flags
0x9c, // pushfq
// Save the registers
0x50, // push rax
0x51, // push rcx
0x52, // push rdx
0x53, // push rbx
0x55, // push rbp
0x56, // push rsi
0x57, // push rdi
0x41, 0x50, // push r8
0x41, 0x51, // push r9
0x41, 0x52, // push r10
0x41, 0x53, // push r11
0x41, 0x54, // push r12
0x41, 0x55, // push r13
0x41, 0x56, // push r14
0x41, 0x57, // push r15
// Placeholder for the string address and LoadLibrary
0x48, 0xB9, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, // mov rcx, 0BBBBBBBBBBBBBBBBh
0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, // mov rax, 0CCCCCCCCCCCCCCCCh
// Call LoadLibrary with the string parameter
0xFF, 0xD0, // call rax
// Restore the registers
0x41, 0x5F, // pop r15
0x41, 0x5E, // pop r14
0x41, 0x5D, // pop r13
0x41, 0x5C, // pop r12
0x41, 0x5B, // pop r11
0x41, 0x5A, // pop r10
0x41, 0x59, // pop r9
0x41, 0x58, // pop r8
0x5F, // pop rdi
0x5E, // pop rsi
0x5D, // pop rbp
0x5B, // pop rbx
0x5A, // pop rdx
0x59, // pop rcx
0x58, // pop rax
// Restore the flags
0x9D, // popfq
0xC3 // ret
};
int WINAPI inject_lib_cave( HANDLE hProcess, HANDLE hThread, const char* lib_name )
{
void* dllString;
void* stub;
DWORD64 stubLen, loadLibAddr;
DWORD oldIP;
CONTEXT ctx;
BOOL result = FALSE;
DWORD suspend_result = -1;
stubLen = sizeof( codeToInject );
loadLibAddr = (DWORD64)GetProcAddress( GetModuleHandleA("Kernel32"),
"LoadLibraryA" );
dllString = VirtualAllocEx(hProcess, NULL, (strlen(lib_name) + 1),
MEM_COMMIT, PAGE_READWRITE);
stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if( dllString == NULL || stub == NULL )
{
if(dllString != NULL) free( dllString );
if(stub != NULL) free( stub );
MessageBoxA( NULL, "Virtual Alloc failed.", "My Msg", MB_OK );
goto clean_exit;
}
result = WriteProcessMemory(hProcess, dllString, lib_name, strlen(lib_name), NULL);
if ( !result )
{
MessageBoxA( NULL, "Could not write process memory for dllString.",
"My Msg", MB_OK );
goto clean_exit;
}
suspend_result = SuspendThread( hThread );
if ( suspend_result == -1 )
{
MessageBoxA( NULL, "Could not suspend thread.",
"My Msg", MB_OK );
goto clean_exit;
}
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = (DWORD)ctx.Rip;
ctx.Rip = (DWORD)stub;
ctx.ContextFlags = CONTEXT_CONTROL;
/*
* Insert the addresses into the local copy of the codeToInject before copying it to
* the remote process
*/
memcpy( codeToInject + 1, &oldIP, sizeof( oldIP ) );
memcpy( codeToInject + 31, &dllString, sizeof( dllString ) );
memcpy( codeToInject + 41, &loadLibAddr, sizeof( loadLibAddr ) );
result = WriteProcessMemory(hProcess, stub, codeToInject, stubLen, NULL);
if ( !result )
{
MessageBoxA( NULL, "Could not write process memory.",
"My Msg", MB_OK );
goto clean_exit;
}
result = SetThreadContext(hThread, &ctx);
if ( !result )
{
MessageBoxA( NULL, "Could not set thread context.",
"My Msg", MB_OK );
goto clean_exit;
}
clean_exit:
if ( suspend_result > -1 )
{
suspend_result = ResumeThread( hThread );
if ( suspend_result == -1 )
{
MessageBoxA( NULL, "Could not resume thread.",
"My Msg", MB_OK );
}
}
return result;
}