找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 17197|回复: 5

HOOK NtCreateSection (另类阻止驱动加载)

 火... [复制链接]

8

主题

31

回帖

0

精华

铜牌会员

积分
129
发表于 2012-4-22 02:14:56 | 显示全部楼层 |阅读模式
原作者: czcqq ,我只是应用在VB上了。





作者原文:对于 在WINDOWS启动的时候加载 和 感染系统文件 我们暂时不讨论,玩么只讨论动态加载


一般的加载流程,是这样的:打开服务管理器->创建服务->启动服务->(系统加载驱动)
这个过程系统最终会调用NtLoadDriver来加载驱动(也可以用Ntdll.dll里面的NtSetSystemInformation来加载)


而NtLoadDriver 会向系统插入一个作业,然后等待另外一个系统线程来加载驱动,并等待驱动的加载完成(NtSetSystemInformation也是一样的),然后返回
这样我们就可以HOOK NtLoadDriver和NtSetSystemInformation来阻止驱动加载,但是这个方法已经用烂了,这里我HOOK NtCreateSection来阻止驱动加载
为什么HOOK NtCreateSection呢???
因为在另外一个线程取得消息加载驱动的时候会调用NtCreateSection来映射驱动到内核内存空间



(流程:大概是这样 IoCreateFile(打开驱动文件,将它的第二个参数设置为FILE_EXECUTE | SYNCHRONIZE) -> NtCreateSection(为驱动在内核内存空间创建一个节) ->NtMapViewOfSection(映射驱动到内核内存空间) -> 寻找驱动的DriverEntry,并调用 -> ZwClose(关闭文件句柄) ->然后通知NtLoadDriver(或者NtSetSystemInformation)驱动加载完成->NtLoadDriver(或者NtSetSystemInformation)返回用户层,并通知用户驱动加载完成)


在驱动加载流程中,我们可以看到我们有很多机会劫持驱动的加载
我们可以HOOK NtCreateSection 或者 NtMapViewOfSection 来阻止驱动加载
这里我采用HOOK NtCreateSection的办法阻止驱动加载

以下为驱动代码:



  1. #include <ntifs.h>

  2. //声明用到的头文件和结构 宏等
  3. #include "NtCreateSection.h"
  4. #if DBG
  5. #define DriversUnload(Address, p) \
  6. Address->DriverUnload=p;
  7. #else
  8. #define DriversUnload(Address, p) \
  9. Address->DriverUnload=NULL;
  10. #endif
  11. typedef int BOOL;
  12. typedef unsigned int UINT;
  13. typedef unsigned long DWORD;
  14. typedef unsigned short WORD;
  15. typedef void *LPVOID;
  16. typedef unsigned char BYTE;
  17. typedef DWORD *PDWORD;
  18. typedef BYTE *PBYTE;
  19. typedef WORD *PWORD;
  20. #define PAGE_NOACCESS 0x01
  21. #define PAGE_READONLY 0x02
  22. #define PAGE_READWRITE 0x04
  23. #define PAGE_WRITECOPY 0x08
  24. #define PAGE_EXECUTE 0x10
  25. #define PAGE_EXECUTE_READ 0x20
  26. #define PAGE_EXECUTE_READWRITE 0x40
  27. #define PAGE_EXECUTE_WRITECOPY 0x80
  28. #define PAGE_GUARD 0x100
  29. #define PAGE_NOCACHE 0x200
  30. #define PAGE_WRITECOMBINE 0x400
  31. #define MEM_COMMIT 0x1000
  32. #define MEM_RESERVE 0x2000
  33. #define MEM_DECOMMIT 0x4000
  34. #define MEM_RELEASE 0x8000
  35. #define MEM_FREE 0x10000
  36. #define MEM_PRIVATE 0x20000
  37. #define MEM_MAPPED 0x40000
  38. #define MEM_RESET 0x80000
  39. #define MEM_TOP_DOWN 0x100000
  40. #define MEM_4MB_PAGES 0x80000000
  41. #define SEC_FILE 0x800000
  42. #define SEC_IMAGE 0x1000000
  43. #define SEC_VLM 0x2000000
  44. #define SEC_RESERVE 0x4000000
  45. #define SEC_COMMIT 0x8000000
  46. #define SEC_NOCACHE 0x10000000
  47. #define MEM_IMAGE SEC_IMAGE
  48. PVOID WriteAddress=NULL;
  49. PMDL pMdl=NULL;
  50. //声明所需要的函数
  51. NTSYSAPI
  52. NTSTATUS
  53. NTAPI
  54. ZwYieldExecution(
  55. VOID
  56. );
  57. PVOID NTAPI GetJmpAddress(PVOID Fun,BOOL *Call_Code);
  58. NTSTATUS
  59. NTAPI
  60. CallBack_NtCreateSection (
  61. OUT PHANDLE SectionHandle,
  62. IN ACCESS_MASK DesiredAccess,
  63. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  64. IN PLARGE_INTEGER MaximumSize OPTIONAL,
  65. IN ULONG SectionPageProtection,
  66. IN ULONG AllocationAttributes,
  67. IN HANDLE FileHandle OPTIONAL
  68. );
  69. NTSTATUS
  70. NTAPI
  71. OldNtCreateSection (
  72. OUT PHANDLE SectionHandle,
  73. IN ACCESS_MASK DesiredAccess,
  74. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  75. IN PLARGE_INTEGER MaximumSize OPTIONAL,
  76. IN ULONG SectionPageProtection,
  77. IN ULONG AllocationAttributes,
  78. IN HANDLE FileHandle OPTIONAL
  79. );
  80. void makejmp(LPVOID Fun1,LPVOID Fun2,LPVOID jmp);
  81. #pragma alloc_text(PAGE,makejmp)
  82. #pragma alloc_text(PAGE,OldNtCreateSection)
  83. #pragma alloc_text(PAGE,CallBack_NtCreateSection)
  84. #pragma alloc_text(PAGE,GetJmpAddress)

  85. //所有声明结束


  86. //驱动入口

  87. NTSTATUS DriverEntry(
  88. IN PDRIVER_OBJECT DriverObject,
  89. IN PUNICODE_STRING RegistryPath
  90. )
  91. {
  92. NTSTATUS Status = 0;
  93. PDEVICE_OBJECT pDeviceObject = NULL;
  94. //创建设备,这个就不讲解了,大家明白就好,我重点讲解HOOK过程
  95. Status = IoCreateDevice(
  96. DriverObject,
  97. 0,
  98. NULL,
  99. FILE_DEVICE_UNKNOWN,
  100. 0,
  101. FALSE,
  102. &pDeviceObject
  103. );

  104. if ( NT_SUCCESS(Status) ) {
  105. KIRQL oldIrql;
  106. PVOID HookAddress = NULL;

  107. BOOL Hook=0;
  108. PVOID JmpData=ExAllocatePool(NonPagedPool,5);//申请内存,用来保存内容为Jmp CallBack_NtCreateSection的代码
  109. DriversUnload(DriverObject,Unload);//设置DriverObject->DriverUnload = Unload;这个宏只有在调试版本的时候才会设置
  110. //DriverObject->DriverUnload = Unload;如果不是调试版本,就会设置DriverObject->DriverUnload = NULL;
  111. if(JmpData==NULL)
  112. {
  113. DbgPrint("HOOK NtCreateSection失败! 内存申请失败\n");
  114. return Status;
  115. }
  116. memset(JmpData,0x90,5);//初始化JmpData内容为NOP
  117. //将NtCreateSection的头7个字节复制到OldNtCreateSection中来
  118. pMdl=IoCreateWriteMdlForAddress(OldNtCreateSection,&WriteAddress,7);
  119. if(pMdl==NULL)
  120. {
  121. DbgPrint("HOOK NtCreateSection失败! OldNtCreateSection 写入失败\n");
  122. ExFreePool(JmpData);
  123. JmpData=NULL;
  124. WriteAddress=NULL;
  125. pMdl=NULL;
  126. return Status;
  127. }
  128. memcpy(WriteAddress,NtCreateSection,7);
  129. IoFreeMdlForAddress(WriteAddress,pMdl);
  130. WriteAddress=NULL;
  131. //将NtCreateSection的头5字节变成可写
  132. pMdl=IoCreateWriteMdlForAddress(NtCreateSection,&WriteAddress,7);
  133. if(pMdl==NULL)
  134. {
  135. DbgPrint("HOOK NtCreateSection失败! NtCreateSection 写入失败\n");
  136. ExFreePool(JmpData);
  137. JmpData=NULL;
  138. WriteAddress=NULL;
  139. pMdl=NULL;
  140. return Status;
  141. }
  142. //检查是否已经被别人HOOK,如果已经被别人HOOK则我们退出HOOK,这里是可以改进的,但是我没有时间写,只能退出HOOK
  143. HookAddress=GetJmpAddress(NtCreateSection,&Hook);
  144. if(HookAddress!=NULL)
  145. {
  146. DbgPrint("HOOK NtCreateSection失败! 发现NtCreateSection已经被别人HOOK 所以本HOOK退出\n");
  147. ExFreePool(JmpData);
  148. JmpData=NULL;
  149. IoFreeMdlForAddress(WriteAddress,pMdl);
  150. WriteAddress=NULL;
  151. pMdl=NULL;
  152. return Status;
  153. }
  154. //HOOK NtCreateSection
  155. if(NT_SUCCESS(ZwYieldExecution()))//先向系统申请CPU时间
  156. {
  157. _asm cli//关闭中断
  158. oldIrql = KeRaiseIrqlToDpcLevel();//提升到DPC级别
  159. memset(WriteAddress,0x90,7);//修改NtCreateSection的前7个字节为NOP指令
  160. makejmp(NtCreateSection,CallBack_NtCreateSection,JmpData);//取得 Jmp CallBack_NtCreateSection的代码,代码保存在JmpData中
  161. memcpy(WriteAddress,JmpData,5);//修改NtCreateSection前5个字节为 Jmp CallBack_NtCreateSection
  162. KeLowerIrql(oldIrql);//还原到原来的IRQL级别
  163. _asm sti//开中断

  164. }else
  165. {
  166. DbgPrint("申请CPU时间失败,HOOK退出\n");
  167. }
  168. ExFreePool(JmpData);
  169. JmpData=NULL;

  170. }

  171. return Status;
  172. }

  173. //我们的NtCreateSection过滤函数
  174. NTSTATUS
  175. NTAPI
  176. CallBack_NtCreateSection (
  177. OUT PHANDLE SectionHandle,
  178. IN ACCESS_MASK DesiredAccess,
  179. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  180. IN PLARGE_INTEGER MaximumSize OPTIONAL,
  181. IN ULONG SectionPageProtection,
  182. IN ULONG AllocationAttributes,
  183. IN HANDLE FileHandle OPTIONAL
  184. )
  185. {
  186. NTSTATUS Status = 0;
  187. Status = OldNtCreateSection(
  188. SectionHandle,
  189. DesiredAccess,
  190. ObjectAttributes ,
  191. MaximumSize ,
  192. SectionPageProtection,
  193. AllocationAttributes,
  194. FileHandle);
  195. if ( NT_SUCCESS(Status) )
  196. {
  197. //进行行为判断,如果是要加载驱动,我们就直接返回错误,并关闭句柄,如果不是就返回原来的结果
  198. if(((DWORD)PsGetCurrentProcessId()==(DWORD)4)|((DWORD)PsGetCurrentProcessId()==(DWORD)8)|((DWORD)PsGetCurrentProcessId()==(DWORD)0))
  199. {

  200. if((FlagOn(DesiredAccess,SECTION_MAP_EXECUTE))||(FlagOn(DesiredAccess,PAGE_EXECUTE_READ)))
  201. if((PAGE_EXECUTE==SectionPageProtection)|(AllocationAttributes==SEC_IMAGE))
  202. {
  203. ZwClose(*SectionHandle);
  204. *SectionHandle=NULL;
  205. return STATUS_ACCESS_DENIED;
  206. }
  207. }
  208. }
  209. return Status;
  210. }
  211. //用来跳转到原函数的一个裸函数
  212. __declspec(naked)NTSTATUS
  213. NTAPI
  214. OldNtCreateSection (
  215. OUT PHANDLE SectionHandle,
  216. IN ACCESS_MASK DesiredAccess,
  217. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  218. IN PLARGE_INTEGER MaximumSize OPTIONAL,
  219. IN ULONG SectionPageProtection,
  220. IN ULONG AllocationAttributes,
  221. IN HANDLE FileHandle OPTIONAL
  222. )
  223. {
  224. _asm
  225. {
  226. nop
  227. nop
  228. nop
  229. nop
  230. nop
  231. nop
  232. nop
  233. nop
  234. nop
  235. nop
  236. nop
  237. nop
  238. nop
  239. nop
  240. nop
  241. nop
  242. nop
  243. nop
  244. mov eax,NtCreateSection //将原函数地址送入eax
  245. add eax,7 //eax加7,用来跳过我们的HOOK
  246. push eax //将eax压入
  247. ret //跳回原函数
  248. }
  249. }

  250. //用来生成跳转代码的函数
  251. void makejmp(LPVOID Fun1,LPVOID Fun2,LPVOID jmp)
  252. {
  253. BYTE *data=(BYTE *)jmp;
  254. long dFun1=(long)Fun1;
  255. long dFun2=(long)Fun2;
  256. DWORD H;
  257. data[0]=0xe9;


  258. _asm
  259. {

  260. mov eax,dFun1
  261. mov edx,dFun2
  262. sub edx,eax
  263. sub edx,5
  264. mov H,edx
  265. }

  266. memcpy(&data[1],(void *)&H,4);

  267. }
  268. VOID Unload(
  269. IN PDRIVER_OBJECT DriverObject
  270. )
  271. {
  272. KIRQL oldIrql;
  273. while(!NT_SUCCESS(ZwYieldExecution()))//取得CPU时间,如果取得失败,就一直获取,直到成功
  274. {
  275. }
  276. if(pMdl!=NULL)//检查我们是否已经进行过HOOK,//如果我们进行过HOOK 就还原
  277. {
  278. oldIrql = KeRaiseIrqlToDpcLevel();
  279. memcpy(WriteAddress,OldNtCreateSection,7);
  280. KeLowerIrql(oldIrql);
  281. IoFreeMdlForAddress(WriteAddress,pMdl);
  282. }
  283. IoDeleteDevice(DriverObject->DeviceObject);//删除设备

  284. pMdl=NULL;
  285. WriteAddress=NULL;
  286. }
  287. PVOID NTAPI GetJmpAddress(PVOID Fun,BOOL *Call_Code)
  288. {
  289. PVOID Return=NULL;
  290. BYTE *data=(BYTE *)Fun;
  291. DWORD Old=0;
  292. if(data[0]==0xe9)
  293. {
  294. *Call_Code=0;
  295. }else if (data[0]==0xe8)
  296. {
  297. *Call_Code=1;
  298. }else
  299. {
  300. *Call_Code=2;
  301. return NULL;
  302. }

  303. memcpy((void *)&Old,&data[1],4);
  304. _asm
  305. {
  306. mov eax,Old
  307. mov edx,Fun
  308. add eax,edx
  309. add eax,5
  310. mov Return,eax
  311. }
  312. return Return;
  313. }
复制代码



这个驱动只支持单核心CPU 多核心CPU请自行修改(将所有CPU都提升到DPC级别 以后再进行HOOK)驱动加载流程是看了WIN2K的代码来讲的,WIN2K的代码很长,所以就简单的讲了一下




NtCreateSection.rar

170.36 KB, 下载次数: 9927

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2012-4-22 17:27:34 | 显示全部楼层
LZ现在做的事跟我三年前做的事差不多,天天拿别人写的驱动玩。。。

不过也支持一下,毕竟我也是这么过来的。

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2012-4-23 20:34:23 | 显示全部楼层
sb666 发表于 2012-4-23 18:09
晕死……这不是修改了一个加载方式而已吗? 额……
我还能改成bat呢……调用debug就ok……


MmCheckSystemImage拦截更爽,能肯定得到驱动文件的路径。

可惜得到的PID一定是4。

最不爽的是,此函数在WIN7上返回失败会蓝。。。不知道怎么回事。。。

4

主题

183

回帖

3

精华

钻石会员

积分
4965
发表于 2012-4-24 10:57:36 | 显示全部楼层
本帖最后由 watchsky 于 2012-4-24 11:50 编辑

支持下,hook这个函数也可以监控进程的创建,不过说实话不算另类,老技术了。另外通过IoCreateDriver这种函数创建的无映像驱动也未必能拦截。

96

主题

158

回帖

4

精华

核心会员

积分
6513
发表于 2012-6-2 09:46:55 | 显示全部楼层

偶也來學習{:soso_e113:}

40

主题

324

回帖

0

精华

铂金会员

Eax=0

积分
1575
发表于 2012-6-8 14:56:29 | 显示全部楼层
Tesla.Angela 发表于 2012-4-23 20:34
MmCheckSystemImage拦截更爽,能肯定得到驱动文件的路径。

可惜得到的PID一定是4。

最不爽的是,此函数在WIN7上返回失败会蓝。。。不知道怎么回事。。。

在VISTA今后的操作系统,系统利用MmLoadSystemImage加载驱动之前,会挪用MmCheckSystemImage函数来检查镜像准确性,在VISTA及今后的操作系统中,MmCheckSystemImage发生了一个有意思的转变.
  原本MmCheckSystemImage(vista以前的系统上),会利用SEC_IMAGE作为AllocationAttributes来挪用ZwCreateSection为驱动文件建立Section,可是VISTA今后的系统上,该参数被换成了一个未公开的值: 0x100000(注重,SEC_IMAGE是0x1000000,6个0)。

这大概就是蓝的原因吧
Do my best.
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表