首页 > 解决方案 > 将线程重定向到另一个函数

问题描述

这是我开始的内容,但是我在无法在反汇编中查看的内存区域的某个随机地址处遇到执行违规(不是来自分配的页面内)

// ThreadCallbackParameter = void*
// ThreadCallback = void __stdcall (void*)

// suspend thread
SuspendThread(Thread->Handle);
// get the threads full context
CONTEXT c;
c.ContextFlags = CONTEXT_FULL;
GetThreadContext(Thread->Handle, &c);
// shellcode
// push ThreadCallbackParameter
// call ThreadCallback
// ret
unsigned char shell[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xC3 };
*(unsigned int*)(shell + 1) = ThreadCallbackParameter;
*(unsigned int*)(shell + 6) = ThreadCallback;
// allocate executable page for shellcode
void* mem = VirtualAlloc(0, sizeof(shell), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// copy shellcode to page
memcpy(mem, shell, sizeof(shell));
// redirect thread to shellcode
c.Eip = mem;
SetThreadContext(Thread->Handle, &c);
// resume thread
ResumeThread(Thread->Handle);
return 0;

一定是一些我不知道的简单代码/思维错误

标签: c++cwindowswinapiassembly

解决方案


OpCode0xE8是x86指令的相对版本。您将要跳转到的回调函数的绝对内存地址传递给它,但是您需要给它一个对于该函数的偏移量,其中该偏移量是相对于指令本身之后的指令的。在这种情况下,您需要获取( ) 指令的地址并从指向的地址中减去该地址,例如:CALLCALLRET0xC3ThreadCallback

PBYTE mem = (PBYTE) VirtualAlloc(0, sizeof(shell), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// copy shellcode to page
memcpy(mem, shell, sizeof(shell));
*(PDWORD)(mem + 1) = ThreadCallbackParameter;
*(PINT32)(mem + 6) = ((INT_PTR)ThreadCallback) - ((INT_PTR)(mem + 10));
// redirect thread to shellcode
...

话虽如此,您需要FlushInstructionCache()在执行之前调用分配的内存。您还应该从内存中删除READ/WRITE标志,以避免恶意代码劫持您的 shell 代码来做其他事情。

为了更好的可读性,我还建议struct在您的 shell 代码中使用 a 而不是原始字节。

#pragma pack(push, 1)
struct myByteCode
{
    BYTE push;
    DWORD pushValue;
    BYTE call;
    INT32 callOffset;
    BYTE ret;
};
#pragma pack(pop)

// allocate executable page for shellcode
struct myByteCode* mem = (struct myByteCode*) VirtualAlloc(0, sizeof(struct myByteCode), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!mem)
{
    // error handling...
}

// copy shellcode to page
mem->push = 0x68;
mem->pushValue = (DWORD) ThreadCallbackParameter;
mem->call = 0xE8;
mem->callOffset = ((INT_PTR)ThreadCallback) - ((INT_PTR)(&mem->ret));
mem->ret = 0xC3;

DWORD ignored;
if (!VirtualProtect(mem, sizeof(struct myByteCode), PAGE_EXECUTE, &ignored))
{
    // error handling...
}

FlushInstructionCache(GetCurrentProcess(), mem, sizeof(struct myByteCode));

// redirect thread to shellcode
...

推荐阅读