c++ - 将线程重定向到另一个函数
问题描述
这是我开始的内容,但是我在无法在反汇编中查看的内存区域的某个随机地址处遇到执行违规(不是来自分配的页面内)
// 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;
- 分配的页面是可执行的;
- 该应用程序是32位的,因此汇编说明应该是正确的;
- 我希望调用的函数是 stdcall,因此推送应该是适当的;
- 我可以通过将 Eip 更改为函数的地址来重定向到另一个函数,因此这些调用也应该是正确的(我需要 shellcode 也能够将参数传递给它);
一定是一些我不知道的简单代码/思维错误
解决方案
OpCode0xE8
是x86指令的相对版本。您将要跳转到的回调函数的绝对内存地址传递给它,但是您需要给它一个相对于该函数的偏移量,其中该偏移量是相对于指令本身之后的指令的。在这种情况下,您需要获取( ) 指令的地址并从指向的地址中减去该地址,例如:CALL
CALL
RET
0xC3
ThreadCallback
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
...
推荐阅读
- android - Android Q 及更高版本的默认 SMS 设置
- google-analytics - 在过滤器(或段)中组合多个事件
- sql - 存储过程中的变量
- python - 创建一个包含 numpy nans 和 pandas NaTs 的系列默认全部为 pandas NaTs;这是故意的吗?
- java - 如何更新 Google Cloud Datastore 中的数组属性值
- python - 在 django 上修改模板时出现 err 500
- javascript - Javascript Observable -> 删除对象数组的项
- python-3.x - “NoneType”对象没有属性“boto_region_name”
- c - 找不到 emmake 和 emconfigure 命令 (osx)
- java - SMTP 与一封邮件