📄 反病毒引擎设计之实时监控篇.txt
字号:
0001171A repne scasb ;扫描串结束符号位置
0001171C not ecx ;取反后得到串长度
0001171E sub edi, ecx ;恢复串首地址指针
最后一点是必须要有坚忍的毅力和清晰的头脑。逆向工程本身是件痛苦的工作:高级语言源代码中使用的变量和函数名字在这里仅是一个地址,需要反复调试琢磨才能确定其含义;另外编译器优化更为我们理解代码增加了不少障碍,如上例中那句压栈指令是将后面函数调用时参数入栈提前放置。所以毅力和头脑二者缺一不可。
以下进入hooksys.vxd代码剖析,由于代码过于庞大,我只选择有代表性且精彩的部分进行介绍。代码中的变量和函数及标签名是我分析后自己添加的,可能会与原作者的意图有些出入。
3.3.3.1钩子函数入口代码
C00012E0 push ebp
C00012E1 mov ebp, esp
C00012E3 sub esp, 11Ch
C00012E9 push ebx
C00012EA push esi
C00012EB push edi
C00012EC mov eax, [ebp+arg_4] ; 被执行的函数的代号
C00012EF mov [ebp+var_11C], eax
C00012F5 cmp [ebp+var_11C], 1 ; IFSFN_WRITE
C00012FC jz writefile
C0001302 cmp [ebp+var_11C], 0Bh ; IFSFN_CLOSE
C0001309 jz closefile
C000130F cmp [ebp+var_11C], 24h ; IFSFN_OPEN
C0001316 jz short openfile
C0001318 jmp irqpassdown
钩子函数入口处,堆栈参数分布如下:
ebp+00h -> 保存的EBP值.
ebp+04h -> 返回地址.
ebp+08h -> 提供这个API要调用的FSD函数的的地址
ebp+0Ch -> 提供被执行的函数的代号
ebp+10h -> 提供了操作在其上执行的以1为基准的驱动器代号(如果UNC为-1)
ebp+14h -> 提供了操作在其上执行的资源的种类。
ebp+18h -> 提供了用户串传递其上的代码页
ebp+1Ch -> 提供IOREQ结构的指针。
钩子函数利用[ebp+0Ch]中保存的被执行的函数的代号来判断该请求的类型。同时它利用[ebp+0Ch]中保存的IOREQ结构的指针从该结构中偏移0ch处path_t ir_ppath域取得完整的文件路径名称。
3.3.3.2取得当前进程名称代码
C0000870 push ebx
C0000871 push esi
C0000872 push edi
C0000873 call VWIN32_GetCurrentProcessHandle ;在eax中返回ring0 PDB(进程数据库)
C0000878 mov eax, [eax+38h] ;HTASK W16TDB
;偏移38h处是Win16任务数据库选择子
C000087B push 0 ;DWORD Flags
C000087D or al,
C000087F push eax ;DWORD Selector
C0000880 call Get_Sys_VM_Handle@0
C0000885 push eax ;取得系统VM的句柄 VMHANDLE hVM
C0000886 call _SelectorMapFlat ;将选择子基址映射为平坦模式的线形地址
C000088B add esp, 0Ch
C000088E cmp eax, 0FFFFFFFFh ;映射错误
C0000891 jnz short loc_C0000899
......
C0000899 lea edi, [eax+0F2h] ;从偏移0F2h取得模块名称
;char TDB_ModName[8]
3.3.3.3通信部分代码
hooksys.vxd中代码:
C00011BC push ecx ;客户程序的ring0线程句柄
C00011BD push ebx ;传入APC的参数
C00011BE push edx ;ring3级APC函数的平坦模式地址
C00011BF call _VWIN32_QueueUserApc ;排队APC
C00011C4 mov eax, [ebp+0Ch] ;事件对象的ring0句柄
C00011C7 push eax
C00011C8 call _VWIN32_ResetWin32Event;设置事件对象为无信号态
......
C00011E7 mov eax, [ebp+0Ch]
C00011EA push 3E8h ;超时设置
C00011EF push eax ;事件对象的ring0句柄
C00011F0 call _VWIN32_WaitSingleObject ;等待ring3查毒的完成
guidll.dll中代码:
APC函数入口:
10001AD1 mov eax, hDevice ;取得设备句柄
10001AD6 lea ecx, [esp+4]
10001ADA push 0
10001ADC push ecx ;返回字节数
10001ADD lea edx, [esp+8]
10001AE1 push 4 ;输出缓冲区大小
10001AE3 push edx ;输出缓冲区指针
10001AE4 push 0 ;输入缓冲区大小
10001AE6 push 0 ;输入缓冲区指针
10001AE8 push 83003C07h ;IO控制代码
10001AED push eax ;设备句柄
10001AEE call ds:DeviceIoControl
10001AF4 test eax, eax
10001AF6 jz short loc_10001B05
10001AF8 mov ecx, [esp+0] ;得到打开文件链表头元素
10001AFC push ecx
10001AFD call ScanOpenFile ;调用查毒函数
ScanOpenFile函数中:
1000185D call ds:fnScanOneFile ;调用真正查毒库导出函数
10001863 mov edx, hMutex
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -