System power belongs to the cnblogs.

qing_feng1903

青青子衿, 悠悠我心。但为君故, 沉吟至今。

导航

【转载自CSDN-henzox】论如何保护进程.

Posted on 2018-08-07 17:13  qing_feng1903  阅读(95)  评论(0)    收藏  举报

  关于这篇文章的题目,思索良久,其实一些技术术语一直是我的软肋。高大上标题,别人会认为你言过其实,低调隐晦的标题,又根本提不起别人打开这篇博文的兴趣。许久之后,就下定决心,那么就起一个朴实无华的名字算了,所以就想到了“进程保护”,但仔细想想,其实这也是一个非常大的技术专题,包括众多的技术细节。所以就此声明,其实这只是一篇利用了一个简单的小技术,在一定程度上达到防止你的程序被结束的技术而已。通过读这篇文章,你可能会了解,什么叫 inline hook ?如何利用 inline hook 来保护进程的。

Hook 有很多种,那些多如牛毛的术语,如 IAT HOOK, Inline Hook, SSDT Hook, Message Hook 等,要想知道这些名词,搜索引擎会帮助你,而为了保护进程,也有很多 Hook 方法来完成,这里我选用了inline hook。

简单地介绍下 inline hook 。所谓 inline hook 就是,在所要被拦截的函数的里,通过指令跳转,来达到跳转到目的函数的手段,当跳转到目标函数以后,就可以在堆栈中得到调用被拦截函数的参数,当然,此时你就可以做一些自己的逻辑,比如记录一些信息,然后放行,或者直接返回到调用者,以达到欺骗调用者的目的,让它误以为调用该函数失败。

那么本文用的到原理也就显而易见,大致原理就是,利用 inline hook 技术,拦截 NtOpenProcess API 调用,当检测到正在打开我们想要保护的进程的时候,就直接返回失败,让调用失败。因为想要结束一个进程,往往会先打开该进程,然后得到句柄,如果打开进程都失败了,那么自然就不能结束掉我们的进程了。

代码如下:

  1 #define DBG 1
  2  
  3 #include <ntifs.h>
  4 #include <ntddk.h>
  5 #include <ntstrsafe.h>
  6  
  7 VOID PPUnload(PDRIVER_OBJECT driverObject);
  8  
  9  
 10 #define HAPI    unsigned int
 11 #define PFUNC   void *
 12  
 13  
 14 #define SHELLCODE_SHADOW_OFFSET          0xD + 1
 15 #define TARTGET_HEADE                    0x28
 16 #define SHELLCODE_TARGET_OFFSET          0x2D + 1
 17 #define HOOKAPI                          _cdecl
 18 #define HOOK_PARAMETERS                  ULONG henzox_hookIsBlock, ULONG henzox_hookCount, ULONG henzox_hookRet,
 19 #define HookBlock(block, count)           *&henzox_hookCount = 4*(count);  *&henzox_hookIsBlock = block;                             
 20                                                                              
 21                        
 22 void __declspec(naked) GhostTemplate()
 23 {
 24     _asm {
 25         push    0                                   ; 压入 block 参数
 26         push    0                                   ; 压入 count 参数
 27         call    _SAVE_EIP
 28 _SAVE_EIP:
 29         add     dword ptr[esp], 9
 30         ; 跳转到影子函数处执行
 31         _emit   0xE9
 32         _emit   0x00
 33         _emit   0x00
 34         _emit   0x00
 35         _emit   0x00
 36 _BACK:
 37         ; 判断是否放行
 38         cmp     dword ptr[esp], 0
 39         jz      _PASS                               ; 放行
 40         ; 被阻止,返回到调用者
 41         mov     edx, dword ptr 8[esp]               ; 保存返回地址
 42         add     esp, dword ptr 4[esp]
 43         add     esp, 0xC                            ; 略去压入的我们的两个参数和原返回地址
 44         push    edx
 45         ret
 46 _PASS:
 47         add     esp, 8
 48         ; 目标函数的头五个字节
 49         _emit   0x00
 50         _emit   0x00
 51         _emit   0x00
 52         _emit   0x00
 53         _emit   0x00 
 54 _JMP_2_TAR:                                         ; 跳转到目标函数处执行
 55         _emit   0xE9
 56         _emit   0x00
 57         _emit   0x00
 58         _emit   0x00
 59         _emit   0x00
 60     }
 61 }
 62  
 63  
 64  
 65  
 66 HAPI HookApi(PFUNC target, PFUNC shadow)
 67 {
 68     unsigned char shellCode[] = {0xE9,0x00,0x00,0x00,0x00};
 69     DWORD dwBytes = 0;
 70     int nOffset;
 71     unsigned char *tmpCode = NULL;
 72     void * addrGhost;
 73     int count = 64;
 74  
 75  
 76     /* 申请一段可执行的内存作为跳转代码并调整里面的跳转 */
 77     tmpCode = (unsigned char *)ExAllocatePool(NonPagedPool, 0x1000);
 78     RtlZeroMemory(tmpCode, 0x1000);
 79     // 写入目标函数被修改的地址
 80     *(ULONG *)((ULONG)tmpCode + 0x1000 - 4) = (ULONG)target;
 81     // 拷贝模板代码
 82     // DEBUG addrGhost = (ULONG)GhostTmplate + *(ULONG *)((PUCHAR)GhostTmplate + 1) + 5;
 83     addrGhost = (ULONG)GhostTemplate;
 84     RtlMoveMemory(tmpCode, addrGhost, 512);
 85     // 修改跳转到 Shadow 函数的地址
 86     *(ULONG *)&tmpCode[SHELLCODE_SHADOW_OFFSET] = (ULONG)shadow - (ULONG)&tmpCode[SHELLCODE_SHADOW_OFFSET] - 4;
 87     // 修改跳转到目标函数的地址
 88     *(ULONG *)&tmpCode[SHELLCODE_TARGET_OFFSET] = (ULONG)target + 5 - (ULONG)&tmpCode[SHELLCODE_TARGET_OFFSET] - 4;
 89     
 90     // 保存原来的五个字节
 91     memcpy(&tmpCode[TARTGET_HEADE], (ULONG)target,5);
 92     /* 写入跳转地址 */
 93     nOffset = (ULONG)tmpCode - (ULONG)target - 5;
 94     *(ULONG *)&shellCode[1] = nOffset;
 95     memcpy(target, shellCode, sizeof(shellCode));
 96  
 97     return (HAPI)tmpCode;
 98 }
 99  
100 NTSTATUS UnHookApi(HAPI handle)
101 {
102     DWORD dwBytes = 0;
103     int i = 10000;
104     unsigned char *tmpCode = (unsigned char *)handle;
105     void *target = *(ULONG *)((ULONG)tmpCode + 0x1000 - 4);
106  
107     memcpy(target, &tmpCode[TARTGET_HEADE], 5);
108     while (i-- > 0) {
109         i = i;
110     }
111     ExFreePool((void *)handle);
112  
113     return STATUS_SUCCESS;
114 }
115  
116 NTSTATUS
117 HOOKAPI
118 MyNtOpenProcess (
119     HOOK_PARAMETERS
120     __out PHANDLE ProcessHandle,
121     __in ACCESS_MASK DesiredAccess,
122     __in POBJECT_ATTRIBUTES ObjectAttributes,
123     __in_opt PCLIENT_ID ClientId
124     )
125 {
126     PEPROCESS process;
127     char *imageName;
128     //KdPrint(("MyNtOpenProcess.\n"));
129  
130     if (!ClientId) {
131         goto _NONBLOCK;
132     }
133  
134     PsLookupProcessByProcessId(ClientId->UniqueProcess, &process);
135     if (!process) {
136         goto _NONBLOCK;
137     }
138  
139     imageName = (char *)((PUCHAR)process + 0x164);
140     if (!strcmp(imageName, "Locator.exe")) {
141         HookBlock(TRUE, 4);
142         KdPrint(("Pid: %d, Image: %s is blocked!\n", ClientId->UniqueProcess, imageName));
143  
144         return STATUS_INVALID_PARAMETER_MIX;
145     }
146     
147 _NONBLOCK:
148     HookBlock(FALSE, 4);
149     return STATUS_SUCCESS;
150 }
151  
152 static HAPI s_hNtOpenProcess;
153  
154 NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject,IN PUNICODE_STRING serviceRegPath)
155 {
156     KdPrint(("DriverEntry.\n"));
157  
158     driverObject->DriverUnload = PPUnload;
159  
160     s_hNtOpenProcess = HookApi(NtOpenProcess, MyNtOpenProcess);
161     
162  
163     return STATUS_SUCCESS;
164 }
165  
166 VOID PPUnload(PDRIVER_OBJECT driverObject)
167 {
168     KdPrint(("PPUnload.\n"));
169  
170     UnHookApi(s_hNtOpenProcess);
171 }

   我一直认为,所以的细节都体现在源码中,代码和原理都很简单。以上代码可以编译为一个驱动程序,它会 Hook 掉 NtOpenProcess ,在我们自己的函数中,保护了 Locator.exe 进程。

写文章真是一件值得的事情,也许很多年后,我都忘了怎么写程序的时候,翻一翻现在的文章,也可以感叹下此时的时光!