高级远程线程注入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
欢迎大家关注我的微信公众号.不定期的更新文章.更新技术. 关注公众号后请大家养成 不白嫖的习惯.欢迎大家赞赏. 也希望在看完公众号文章之后 不忘 点击 收藏 转发 以及点击在看功能. QQ群: