[原创]浅析****安全卫士hook"框架"
昨日闲着无聊 随手下了个****安全卫士, 想简单看看其功能大概什么样, 随后就发现了些有趣的东西.
本篇就写下其最有毒的 hook”框架”,
软件主程序版本: 1.6.0.8746 ==> 官网最新版
****port.sys: 1.6.0.547
****cport.sys 1.6.0.547
nt!KiFastCallEntry+0xb8: 8053e618 33db xor ebx,ebx 8053e61a 0b99700f0000 or ebx,dword ptr [ecx+0F70h] 8053e620 740a je nt!KiFastCallEntry+0xcc (8053e62c) 8053e622 52 push edx 8053e623 50 push eax 8053e624 ff1564405580 call dword ptr [nt!KeGdiFlushUserBatch (80554064)] 8053e62a 58 pop eax //> service number 8053e62b 5a pop edx //> argument address 8053e62c e857acd605 call 862a9288 //> ****hook point 8053e631 e88bf28b5f call dfdfd8c1 8053e636 cd0e int 0Eh 8053e638 c9 leave 8053e639 8a0c18 mov cl,byte ptr [eax+ebx] 8053e63c 8b3f mov edi,dword ptr [edi] 8053e63e 8b1c87 mov ebx,dword ptr [edi+eax*4] 8053e641 e9524fe705 jmp 863b3598 //>360 hook point 8053e646 8bfc mov edi,esp 8053e648 3b35549a5580 cmp esi,dword ptr [nt!MmUserProbeAddress (80559a54)] 8053e64e 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (8053e7fc) 8053e654 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] 8053e656 ffd3 call ebx 8053e658 8be5 mov esp,ebp 8053e65a 8b0d24f1dfff mov ecx,dword ptr ds:[0FFDFF124h] 8053e660 8b553c mov edx,dword ptr [ebp+3Ch] 8053e663 899134010000 mov dword ptr [ecx+134h],edx !chkimg nt -d 8053e62c-8053e631 6 bytes - nt!KiFastCallEntry+cc (+0x3b634) [ ff 05 38 f6 df ff:e8 57 ac d6 05 e8 ] 8053e636-8053e637 2 bytes - nt!KiFastCallEntry+d6 (+0x0a) [ 0c 33:cd 0e ]
通过上面可以看到在****的挂钩点在常规杀软的前面(360 Q管 金山 百度等), 在该点上其寄存器eax ebx保存的系统服务号 ecx保存表的索引 edx保存的是参数地址 edi保存系统服务表地址.
框架实现在 ****port.sys和****Cport.sys中,这两个在功能上类似360的hookport和360selfprotect 即前者实现框架后者注册过滤函数.
当我满怀兴奋的心情祭出IDA打开****port.sys和****Cport.sys时, 发现我伟大的F5居然不能用. 直接看反汇编 然后瞬间爆炸,满眼的花指令 连shllcode派发函数都是花指令 乱序长度不一 本想写个idc脚本去了 但是实在太多变形就放弃了, 但是不影响我们分析.基本花指令格式如下:
cmp reg, 77584BBh jnz reloc_handle //>跳到重定位处理流程 ...junk code reloc_handle push eax //> 这两个指令 随机可有可无 call $+5 mov eax, true_handle //>真实地址 mov [esp+2Ch+var_2C], eax //>修改返回地址 mov eax, edx retn
//> 看下其shellcode
kd> dt nt!_pool_header 862a9288-8
+0x000 PreviousSize : 0y000000110 (0x6)
+0x000 PoolIndex : 0y0000000 (0)
+0x002 BlockSize : 0y000100111 (0x27)
+0x002 PoolType : 0y0000101 (0x5)
+0x000 Ulong1 : 0xa270006
+0x004 ProcessBilled : 0x73747562 _EPROCESS
+0x004 PoolTag : 0x73747562
+0x004 AllocatorBackTraceIndex : 0x7562
+0x006 PoolTagHash : 0x7374
kd> .formats 0x73747562
Evaluate expression:
Hex: 73747562
Decimal: 1937012066
Octal: 16335072542
Binary: 01110011 01110100 01110101 01100010
Chars: stub
Time: Tue May 20 10:54:26 2031
Float: low 1.9368e+031 high 0
Double: 9.57011e-315
//>其kifastcall挂钩点代理函数如下
kd> uf 862a9288 862a9288 50 push eax 862a9289 52 push edx 862a928a 51 push ecx 862a928b 8bd4 mov edx,esp 862a928d b8a06442f7 mov eax,offset ****Port+0x4a0 (f74264a0) //> 跳转地址 862a9292 91 xchg eax,ecx 862a9293 81f9bb847507 cmp ecx,77584BBh 862a9299 0f85ec000000 jne 862a938b 862a929f b923000000 mov ecx,23h 862a92a4 6a30 push 30h 862a92a6 0fa1 pop fs 862a92a8 668ed9 mov ds,cx 862a92ab 668ec1 mov es,cx 862a92ae 648b0d40000000 mov ecx,dword ptr fs:[40h] 862a92b5 8b6104 mov esp,dword ptr [ecx+4] 862a92b8 6a23 push 23h 862a92ba 52 push edx 862a92bb 9c pushfd 862a92bc 6a02 push 2 862a92be 83c208 add edx,8 862a92c1 9d popfd 862a92c2 804c240102 or byte ptr [esp+1],2 862a92c7 6a1b push 1Bh 862a92c9 3eff350403dfff push dword ptr ds:[0FFDF0304h] 862a92d0 6a00 push 0 862a92d2 55 push ebp 862a92d3 53 push ebx 862a92d4 56 push esi 862a92d5 57 push edi 862a92d6 648b1d1c000000 mov ebx,dword ptr fs:[1Ch] 862a92dd 6a3b push 3Bh 862a92df 8bb324010000 mov esi,dword ptr [ebx+124h] 862a92e5 ff33 push dword ptr [ebx] 862a92e7 c703ffffffff mov dword ptr [ebx],0FFFFFFFFh 862a92ed 8b6e18 mov ebp,dword ptr [esi+18h] 862a92f0 6a01 push 1 862a92f2 83ec48 sub esp,48h 862a92f5 81ed9c020000 sub ebp,29Ch 862a92fb c6864001000001 mov byte ptr [esi+140h],1 862a9302 3bec cmp ebp,esp 862a9304 83652c00 and dword ptr [ebp+2Ch],0 862a9308 f6462cff test byte ptr [esi+2Ch],0FFh 862a930c 89ae34010000 mov dword ptr [esi+134h],ebp 862a9312 8b5d60 mov ebx,dword ptr [ebp+60h] 862a9315 8b7d68 mov edi,dword ptr [ebp+68h] 862a9318 89550c mov dword ptr [ebp+0Ch],edx 862a931b c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h 862a9322 895d00 mov dword ptr [ebp],ebx 862a9325 897d04 mov dword ptr [ebp+4],edi 862a9328 fb sti 862a9329 8bf8 mov edi,eax 862a932b c1ef08 shr edi,8 862a932e 83e730 and edi,30h 862a9331 8bcf mov ecx,edi 862a9333 03bee0000000 add edi,dword ptr [esi+0E0h] 862a9339 8bd8 mov ebx,eax 862a933b 25ff0f0000 and eax,0FFFh 862a9340 3b4708 cmp eax,dword ptr [edi+8] 862a9343 83f910 cmp ecx,10h 862a9346 648b0d18000000 mov ecx,dword ptr fs:[18h] 862a934d 33db xor ebx,ebx 862a934f 0b99700f0000 or ebx,dword ptr [ecx+0F70h] 862a9355 52 push edx 862a9356 50 push eax 862a9357 58 pop eax 862a9358 5a pop edx 862a9359 64ff0538060000 inc dword ptr fs:[638h] 862a9360 8bf2 mov esi,edx 862a9362 8b5f0c mov ebx,dword ptr [edi+0Ch] 862a9365 33c9 xor ecx,ecx 862a9367 8a0c18 mov cl,byte ptr [eax+ebx] 862a936a 8b3f mov edi,dword ptr [edi] 862a936c 8b1c87 mov ebx,dword ptr [edi+eax*4] 862a936f 2be1 sub esp,ecx 862a9371 c1e902 shr ecx,2 862a9374 8bfc mov edi,esp 862a9376 8be5 mov esp,ebp 862a9378 648b0d24010000 mov ecx,dword ptr fs:[124h] 862a937f 8b553c mov edx,dword ptr [ebp+3Ch] 862a9382 899134010000 mov dword ptr [ecx+134h],edx 862a9388 5e pop esi 862a9389 5f pop edi 862a938a 5b pop ebx 862a938b 894a0c mov dword ptr [edx+0Ch],ecx //>修改返回地址配合ret 862a938e 8bc1 mov eax,ecx 862a9390 8bd3 mov edx,ebx 862a9392 59 pop ecx 862a9393 5a pop edx 862a9394 58 pop eax 862a9395 c3 ret
该函数去掉花指令其实就是实现了一个jmp指令 jmp ****Port+0x4a0 (f74264a0)
****port的挂钩点寻找是通过rdmsr指令读取SYSENTER_EIP_MSR(0x176)寄存器的值 来找到kifastcallentry的地址进而匹配特征码进程挂钩如下图:



下面贴出 最关键的处理简化流程



简单来讲流程如下: 在驱动初始化时会通过解析PE 来获取两份纯净的服务函数表(ssdt 和 shadow ssdt),过滤函数表没有任何数据结构只是一个函数指针数组, 与服务号对应 如果该服务号有过滤函数则数组元素非空, 如果没有过滤函数则数组元素值填0, 派发例程通过判断改值是否为0 判断有无过滤函数. 如果有过滤函数则调用过滤函数, 如果没有过滤函数则调用纯净的服务函数。如下图:
系统调用-->kifastcallentry-->****dispatch-->判断服务表是ssdt还是shadowssdt-->根据服务号和对应表 找到相应的过滤函数以及对应的纯净NT函数-->进行派发调用如果过滤函数非空则调用过滤函数否则调用纯净Nt服务
至此 “框架”就到此结束。
其中该驱动对
84h NtPlugPlayControl
3f NewNtDeleteKey
41 NewNtDeleteValueKey
f7 NewNtSetValueKey
c0 NewNtRenameKey
b1 NewNtQueryValueKey
这6个调用是单独处理 但是代码逻辑还是跟框架一样,所以应该是后期做优化没去掉该处代码.
那么问题来了 为何是有毒的hook”框架”呢,
细看一下派发流程:
1.不管过不过滤 最终都会调用 纯净服务函数 穿透ssdt hook.
2.如果其他软件是通过ssdt hook 返回地址来找挂钩点的话 装了**** 直接导致找不到挂钩点,因为调用不会走到代理函数里面去(可以通过rdsmr 或者idt 0x2e去寻找).
3.接管nt派发调用 即真正的调用服务函数不会在nt 的原始派发代码里 而是****port.sys写死在自己的代码里.(即跳过nt 本身的call ebx 在自己的代码里call ebx(高版本系统是call edx)) ,而360 Q管金山百度等 大致钩子位置相近或者一致但是都是在系统原有派发前面挂钩(即call ebx之前挂钩) 他们的挂钩属于寄存器hook, 即修改ebx(服务函数)的值, 最终让nt 服务派发器去调用. 恰巧****在接管派发流程时 不会重走nt的服务派发流程(这里的派发是指调用服务函数 并不是全部的派发代码), 直接在自己的代码里派发 这样 就造成了除****之外的所有的杀软 需要钩子的功能全部失效.
所以这套服务派发逻辑 毒就毒在没有考虑兼容性 比如多杀软共存(感觉像是故意的~)
以xp为例 其过滤函数表如下:
SSDT:
服务号 服务名称
==================================================
2 fake_NtAccessCheckAndAuditAlarm
11 fake_NtAdjustPrivilegesToken
17 fake_NtAllocateVirtualMemory
19 fake_NewNtAssignProcessToJobObject
25 fake_NtClose
31 fake_NtConnectPort
37 fake_NtCreateFile
41 fake_NewNtCreateKey
43 fake_NtCreateMutant
45 fake_NtCreatePagingFile
48 fake_NtCreateProcessEx
50 fake_NtCreateSection
52 fake_NtCreateSymbolicLinkObject
53 fake_NtCreateThread
57 fake_NtDebugActiveProcess
62 fake_NtDeleteFile
63 fake_NtDeleteKey
65 fake_NtDeleteValueKey
66 fake_NtDeviceIoControlFile
67 fake_ZwDisplayString
68 fake_NtDuplicateObject
71 fake_NtEnumerateKey
73 fake_NtEnumerateValueKey
83 fake_ZwFreeVirtualMemory
84 fake_NtFsControlFile
93 fake_NtInitiatePowerAction
97 fake_NtLoadDriver
105 fake_NtMakeTemporaryObject
116 fake_NtOpenFile
119 fake_NtOpenKey
122 fake_NtOpenProcess
125 fake_NtOpenSection
127 fake_NtOpenSymbolicLinkObject
128 fake_NtOpenThread
132 fake_NtPlugPlayControl
137 fake_NtProtectVirtualMemory
160 fake_NtQueryKey
177 fake_NtQueryValueKey
178 fake_NtQueryVirtualMemory
180 fake_NtQueueApcThread
182 fake_NewNtRaiseHardError
192 fake_NtRenameKey
193 fake_NtReplaceKey
200 fake_NtRequestWaitReplyPort
204 fake_NtRestoreKey
210 fake_NtSecureConnectPort
213 fake_NtSetContextThread
224 fake_NtSetInformationFile
228 fake_NtSetInformationProcess
237 fake_NtSetSecurityObject
240 fake_NtSetSystemInformation
241 fake_NtSetSystemPowerState
242 fake_NtSetSystemTime
244 fake_NtSetTimer
247 fake_NtSetValueKey
249 fake_NtShutdownSystem
253 fake_NtSuspendProcess
254 fake_NtSuspendThread
255 fake_NtSystemDebugControl
256 fake_NtTerminateJobObject
257 fake_NtTerminateProcess
258 fake_NtTerminateThread
259 fake_NtTestAlert
262 fake_NtUnloadDriver
267 fake_NtUnmapViewOfSection
274 fake_NtWriteFile
277 fake_NtWriteVirtualMemory
ShadowSSDT
服务号 服务名称
=========================================================
310 fake_NtUserBlockInput
319 fake_NtUserCallHwndParamLock
330 fake_NtUserClipCursor
355 fake_NtUserDestroyWindow
383 fake_NtUserGetAsyncKeyState
414 fake_NtUserGetKeyboardState
416 fake_NtUserGetKeyState
427 fake_NtUserGetRawInputBuffer
428 fake_NtUserGetRawInputData
460 fake_NtUserMessageCall
465 fake_NtUserMoveWindow
475 fake_NtUserPostMessage
476 fake_NtUserPostThreadMessage
502 fake_NtUserSendInput
517 fake_NtUserSetImeInfoEx
529 fake_NtUserSetParent
544 fake_NtUserSetWindowLong
545 fake_NtUserSetWindowPlacement
546 fake_NtUserSetWindowPos
547 fake_NtUserSetWindowRgn
549 fake_NtUserSetWindowsHookEx
552 fake_NtUserSetWinEventHook
555 fake_NtUserShowWindow
556 fake_NtUserShowWindowAsync
559 fake_NtUserSystemParametersInfo
581 fake_NtUserSetLayeredWindowAttributes
写的比较匆忙 如有问题欢迎指正~
图如果看不清, 请下载文档查看 或者点击图片放大
****hook分析.doc
驱动文件
****driver.rar
