高级远程线程注入NtCreateThreadEx
高级远程线程注入NtCreateThreadEx
一丶简介
在Windows下NtCreateThreadEx
是CreateRemoteThread
的底层函数。RtlCreateUserThread
也是对 NtCreateThreadEx的一层包装
所以着重一下研究NtCreateThreadEx
函数
二丶原型
2.1 函数原型
NtCreateThreadEx
在32位下和64位下函数原型不一致。
结构如下:
#ifdef _AMD64_ typedef DWORD(WINAPI* PfnZwCreateThreadEx)( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, ULONG CreateThreadFlags, SIZE_T ZeroBits, SIZE_T StackSize, SIZE_T MaximunStackSize, LPVOID pUnkown); #else typedef DWORD(WINAPI *PfnZwCreateThreadEx)( PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, BOOL CreateThreadFlags, DWORD ZeroBits, DWORD StackSize, DWORD MaximumStackSize, LPVOID pUnkown); #endif // DEBUG
如果要想使用 NtCreateThreadEx
函数。那么就需要从NtDll
中以动态的方式导出使用。
2.2 远程线程注入代码
远程线程代码注入分为如下几个步骤
- OpenProcess 打开要注入的进程
- VirtualAllocEx 在被注入的进程中申请读写内存
- WriteProcessMemory 写入DLL路径到申请的内存中
- VirtualProtectEx 修改内存保护属性,这一步可以不需要使用。
- CreateRemoteThread 创建远程线程,高级远程线程注入可以 将此函数 替换为
NtCreateThreadEx
- WaitForSingleObject 等待过程完成
完整伪代码如下:
BOOLEAN RemoteInject(DWORD pid, LPWSTR wszInjectDllPathName,ULONG uDllPathSize) { HANDLE hProc = NULL; LPVOID lpBuffer = NULL; SIZE_T dwWriteBytes = 0; DWORD dwRetErrorCode = 0; HANDLE hThreadHandle = NULL;; PVOID pfnLoadLibraryW = NULL; HMODULE ntdll = NULL; HMODULE k32 = NULL; bool bIsOk = FALSE; do { ntdll = LoadLibrary(TEXT("ntdll.dll")); if (ntdll == NULL) { break; } k32 = LoadLibrary(TEXT("kernel32.dll")); if (k32 == NULL) { break; } m_ZwCreateThreadEx = reinterpret_cast<PfnZwCreateThreadEx>(GetProcAddress(ntdll, "ZwCreateThreadEx")); if (NULL == m_ZwCreateThreadEx) { break; } pfnLoadLibraryW = reinterpret_cast<PVOID>(::GetProcAddress(k32, "LoadLibraryW")); if (pfnLoadLibraryW == NULL) { break; } hProc = OpenProcess(PROCESS_ALL_ACCESS, false, pid); if (hProc == NULL) { break; } lpBuffer = VirtualAllocEx(hProc, 0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (NULL == lpBuffer) { break; } dwRetErrorCode = WriteProcessMemory(hProc, lpBuffer, wszInjectDllPathName, uDllPathSize, &dwWriteBytes); if (0 == dwRetErrorCode) { break; } m_ZwCreateThreadEx(&hThreadHandle, PROCESS_ALL_ACCESS, NULL, hProc, (LPTHREAD_START_ROUTINE)pfnLoadLibraryW, lpBuffer, 0, 0, 0, 0, NULL); WaitForSingleObject(hProc, 2000); if (NULL == hThreadHandle) { break; } bIsOk = TRUE; } while (FALSE); if (NULL != lpBuffer) { VirtualFreeEx(hProc, lpBuffer, 0, MEM_RELEASE); lpBuffer = NULL; } if (NULL != hProc) { CloseHandle(hProc); hProc = NULL; } if (NULL != hThreadHandle) { CloseHandle(hThreadHandle); hThreadHandle = NULL; } if (k32 != NULL) { FreeLibrary(k32); k32 = NULL; } if (ntdll != NULL) { FreeLibrary(ntdll); ntdll = NULL; } return bIsOk; }
注意: uDllPathSize 是DLL全路径的空间长度。 如果是宽字符一定要 wcslen(str) * 2
才可以。
代码经过验证 32位程序可以注入DLL到32位的进程。 64位进程可以注入dll到64位进程。
32位进程不可注入DLL到64位进程。需要特殊方式。
作者:IBinary
坚持两字,简单,轻便,但是真正的执行起来确实需要很长很长时间.当你把坚持两字当做你要走的路,那么你总会成功. 想学习,有问题请加群.群号:725864912(收费)群名称: 逆向学习小分队 群里有大量学习资源. 以及定期直播答疑.有一个良好的学习氛围. 涉及到外挂反外挂病毒 司法取证加解密 驱动过保护 VT 等技术,期待你的进入。
详情请点击链接查看置顶博客 https://www.cnblogs.com/iBinary/p/7572603.html
本文来自博客园,作者:iBinary,未经允许禁止转载 转载前可联系本人.对于爬虫人员来说如果发现保留起诉权力.https://www.cnblogs.com/iBinary/p/16026217.html
欢迎大家关注我的微信公众号.不定期的更新文章.更新技术. 关注公众号后请大家养成 不白嫖的习惯.欢迎大家赞赏. 也希望在看完公众号文章之后 不忘 点击 收藏 转发 以及点击在看功能.

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决