| 查看: 502 | 回复: 0 | |||
| 当前主题已经存档。 | |||
sdlj8051金虫 (著名写手)
|
[交流]
[转贴]对Rav 2005中HOOK的初步分析
|
||
|
从出错信息入手,可以找到下面的代码(注释是我加的): .text:01001603 loc_1001603: .text:01001603 call sub_1001D1B .text:01001608 mov eax, dword_12D3180 ; EAX里应该是PID .text:0100160D test eax, eax .text:0100160F jz short loc_100163D .text:01001611 push eax .text:01001612 call sub_1001F2C ; 清理内存 .text:01001617 test eax, eax .text:01001619 jnz short loc_1001636 .text:0100161B push dword_12D3180 .text:01001621 push offset aCouldNotEmptyW ; "could not empty working set for process"... .text:01001626 call ds:printf .text:0100162C pop ecx OK,到sub_1001F2C去看看: .text:01001F2C push ebp .text:01001F2D mov ebp, esp .text:01001F2F push ecx .text:01001F30 push esi .text:01001F31 push edi .text:01001F32 push [ebp+MaximumWorkingSetSize] ; dwProcessId .text:01001F35 xor edi, edi .text:01001F37 push edi ; bInheritHandle .text:01001F38 push 1F0FFFh ; dwDesiredAccess .text:01001F3D call ds:OpenProcess .text:01001F43 mov esi, eax .text:01001F45 cmp esi, edi .text:01001F47 jnz short loc_1001F4D .text:01001F49 xor eax, eax .text:01001F4B jmp short loc_1001F77 首先是以PROCESS_ALL_ACCESS权限调用OpenProcess。但就是在这里,esi=edi,跳到出口loc_1001F77。 好,于是写段调用OpenProcess的程序。结果发现,对ravmond的操作结果是返回ERROR_INVALID_PARAMETER??!!但是我的参数没有写错啊!然后开始怀疑bInheritHandle参数,但改了还是一样。那么,换PID。换了SMSS的PID,说没有权限,很正常。换delphi32的PID,可以正常打开。那么,就是说,参数绝对是正确的,只是RAV玩了个花样。那样,按照系统给的PID去找就找不到了。 既然这样,那就拿RAV开刀。先翻了一下RAV的目录,有几个驱动文件引起了我的注意: Hooksys.sys hookbase.sys HOOKREG.sys HookCont.sys HookApi.sys 难道是OpenProcess被HOOK了?于是先在HookApi里查import,没有可疑的API。hookbase?Hooksys?HookCont?都没有。 还是写程序看看……GetProcAddress却报告说没有异常。 没办法,查找ravmond吧……HOOKREG里居然有ravmond的字样!改之,重新启动RAV的服务,bingo!在任务管理器里k进程时显示没有权限!那么很明显是被HOOK了。 以前玩过rootkit(只是玩而已,写不来),本来是应该想到的…… 那么反汇编HOOKREG,查找ravmond的xref……在00011BEF有一个push,向上找到函数入口,得到整个函数: .text:00011B74 sub_11B74 proc near .text:00011B74 .text:00011B74 var_2C = dword ptr -2Ch .text:00011B74 var_28 = byte ptr -28h .text:00011B74 var_9 = byte ptr -9 .text:00011B74 var_8 = dword ptr -8 .text:00011B74 var_4 = dword ptr -4 .text:00011B74 arg_0 = dword ptr 8 .text:00011B74 .text:00011B74 push ebp .text:00011B75 mov ebp, esp .text:00011B77 sub esp, 2Ch .text:00011B7A mov [ebp+var_2C], 0 .text:00011B81 mov [ebp+var_28], 0 .text:00011B85 call ds:IoGetCurrentProcess .text:00011B8B mov [ebp+var_8], eax //指向当前进程开头的指针 .text:00011B8E mov eax, [ebp+var_8] .text:00011B91 add eax, dword_12F48 //dword_12F48的真实偏移 .text:00011B97 mov [ebp+var_4], eax .text:00011B9A mov ecx, [ebp+var_4] .text:00011B9D push ecx .text:00011B9E lea edx, [ebp+var_28] //缓冲的长度是$1F .text:00011BA1 push edx .text:00011BA2 call strcpy .text:00011BA7 add esp, 8 //复制 .text:00011BAA mov [ebp+var_9], 0 .text:00011BAE lea eax, [ebp+var_28] .text:00011BB1 push eax ; char * .text:00011BB2 call ds:_strupr .text:00011BB8 add esp, 4 //大写 .text:00011BBB cmp [ebp+arg_0], 0 .text:00011BBF jz short loc_11BD1 //若参数是0就走 .text:00011BC1 lea ecx, [ebp+var_28] //dword_12F48的复件 .text:00011BC4 push ecx .text:00011BC5 mov edx, [ebp+arg_0] .text:00011BC8 push edx .text:00011BC9 call strcpy .text:00011BCE add esp, 8 //这样看,参数应该是PChar //参数非0就给个dword_12F48的复件 .text:00011BD1 loc_11BD1: .text:00011BD1 push offset dword_11B50 .text:00011BD6 lea eax, [ebp+var_28] .text:00011BD9 push eax .text:00011BDA call strcmp .text:00011BDF add esp, 8 .text:00011BE2 test eax, eax .text:00011BE4 jnz short loc_11BEF //和dword_11B50比较(RAV.EXE),若不等就继续,否则返回2 .text:00011BE6 mov [ebp+var_2C], 2 .text:00011BED jmp short loc_11C41 .text:00011BEF loc_11BEF: .text:00011BEF push offset dword_11B58 .text:00011BF4 lea ecx, [ebp+var_28] .text:00011BF7 push ecx .text:00011BF8 call strcmp .text:00011BFD add esp, 8 .text:00011C00 test eax, eax .text:00011C02 jz short loc_11C19 //和dword_11B58比较(RAVMOND.EXE),若相等就返回3,否则继续 .text:00011C04 push offset dword_11B64 .text:00011C09 lea edx, [ebp+var_28] .text:00011C0C push edx .text:00011C0D call strcmp .text:00011C12 add esp, 8 .text:00011C15 test eax, eax .text:00011C17 jnz short loc_11C22 //和dword_11B64比较(RAVMON.EXE),若相等就返回3,否则继续 .text:00011C19 loc_11C19: .text:00011C19 mov [ebp+var_2C], 3 .text:00011C20 jmp short loc_11C41 .text:00011C22 loc_11C22: .text:00011C22 push 3 ; size_t .text:00011C24 push offset aRav ; char * .text:00011C29 lea eax, [ebp+var_28] .text:00011C2C push eax ; char * .text:00011C2D call ds:strncmp .text:00011C33 add esp, 0Ch .text:00011C36 test eax, eax .text:00011C38 jnz short loc_11C41 //检查var_28的头3个字符是否RAV,是就返回4,不是就直接返回 .text:00011C3A mov [ebp+var_2C], 4 .text:00011C41 loc_11C41: .text:00011C41 mov eax, [ebp+var_2C] .text:00011C44 mov esp, ebp .text:00011C46 pop ebp .text:00011C47 retn 4 .text:00011C47 sub_11B74 endp 我们可以看到,这个东西有点象call/pop的手法。好处就是可以不要数据段(反正特征字符串是只读的)。 那么,这只是一个判断。判断dword_12F48是否含有特定的字符串,若是RAV的核心就返回3,主程序返回2,外围程序返回4,其他返回0。 那么来看看sub_11B74的xref,有三处:11D27、119E6、115E2,对应的sub分别是sub_11D00、sub_119D0、sub_115BC。 sub_115BC有4个xref,全部是code引用,sub_119D0只有1个data引用的xref,而11D00,有3个xref,data引用。 先看11D00,xref全在start里: .text:00010453 8B 45 08 mov eax, [ebp+DriverObject] .text:00010456 C7 40 38 00 1D 01+ mov dword ptr [eax+38h], offset sub_11D00 .text:0001045D 8B 4D 08 mov ecx, [ebp+DriverObject] .text:00010460 C7 41 40 00 1D 01+ mov dword ptr [ecx+40h], offset sub_11D00 .text:00010467 8B 55 08 mov edx, [ebp+DriverObject] .text:0001046A C7 82 80 00 00 00+ mov dword ptr [edx+80h], offset sub_11D00 下面就dump一下和DriverObject有关的代码(eax,ecx,edx都是临时使用的): .text:00010308 ; int __stdcall start(PDRIVER_OBJECT DriverObject) .text:00010308 public start .text:00010308 start proc near .text:00010308 .text:00010308 var_64 = dword ptr -64h .text:00010308 var_60 = dword ptr -60h .text:00010308 SymbolicLinkName= UNICODE_STRING ptr -5Ch .text:00010308 DeviceObject = dword ptr -54h .text:00010308 DeviceName = UNICODE_STRING ptr -50h .text:00010308 SourceString = word ptr -48h .text:00010308 var_28 = dword ptr -28h .text:00010308 DriverObject = dword ptr 8 .text:00010308 .text:00010308 55 push ebp .text:00010309 8B EC mov ebp, esp .text:0001030B 83 EC 64 sub esp, 64h .text:0001030E 56 push esi .text:0001030F 57 push edi .text:00010310 C7 45 AC 00 00 00+ mov [ebp+DeviceObject], 0 ..... .text:0001036A 8D 55 AC lea edx, [ebp+DeviceObject] .text:0001036D 52 push edx ; DeviceObject .text:0001036E 6A 00 push 0 ; Exclusive .text:00010370 6A 00 push 0 ; DeviceCharacteristics .text:00010372 68 00 84 00 00 push 8400h ; DeviceType .text:00010377 8D 45 B0 lea eax, [ebp+DeviceName] .text:0001037A 50 push eax ; DeviceName .text:0001037B 6A 00 push 0 ; DeviceExtensionSize .text:0001037D 8B 4D 08 mov ecx, [ebp+DriverObject] .text:00010380 51 push ecx ; DriverObject .text:00010381 FF 15 DC 26 01 00 call ds:IoCreateDevice ..... .text:000103BD 8B 45 08 mov eax, [ebp+DriverObject] .text:000103C0 8B 48 04 mov ecx, [eax+4] .text:000103C3 51 push ecx ; DeviceObject .text:000103C4 FF 15 D4 26 01 00 call ds:IoDeleteDevice .text:000103CA 8B 45 9C mov eax, [ebp+var_64] ..... .text:00010453 8B 45 08 mov eax, [ebp+DriverObject] .text:00010456 C7 40 38 00 1D 01+ mov dword ptr [eax+38h], offset sub_11D00 .text:0001045D 8B 4D 08 mov ecx, [ebp+DriverObject] .text:00010460 C7 41 40 00 1D 01+ mov dword ptr [ecx+40h], offset sub_11D00 .text:00010467 8B 55 08 mov edx, [ebp+DriverObject] .text:0001046A C7 82 80 00 00 00+ mov dword ptr [edx+80h], offset sub_11D00 .text:00010474 8B 45 08 mov eax, [ebp+DriverObject] .text:00010477 C7 40 70 BF 1D 01+ mov dword ptr [eax+70h], offset sub_11DBF .text:0001047E 8B 4D 08 mov ecx, [ebp+DriverObject] .text:00010481 C7 41 34 68 05 01+ mov dword ptr [ecx+34h], offset sub_10568 就是填充PDRIVER_OBJECT,其他没有什么。这里的大概意思是创建一个内核Device,然后定义几个Function。问题是,这个驱动的Type是自定义的,而我又不懂Driver…… 不过还好,119D0的xref有点意思: .text:00010CBA mov eax, ds:ZwSetValueKey .text:00010CBF mov ecx, [eax+1] .text:00010CC2 mov edx, ds:KeServiceDescriptorTable .text:00010CC8 mov eax, [edx] .text:00010CCA mov dword ptr [eax+ecx*4], offset sub_119D0 那么,这里是修改ServiceDescriptorTable里ZwSetValueKey的入口。联想一下,应该是不允许修改RAVMOND服务的Key。 最后看看115BC,xref对应的sub有111A0,112F0,11360和119D0。而它们都是只有一个data的xref,应该是function了: .text:00010CD1 mov ecx, ds:ZwCreateKey .text:00010CD7 mov edx, [ecx+1] .text:00010CDA mov eax, ds:KeServiceDescriptorTable .text:00010CDF mov ecx, [eax] .text:00010CE1 mov dword ptr [ecx+edx*4], offset sub_111A0 .text:00010CE8 mov edx, ds:ZwDeleteValueKey .text:00010CEE mov eax, [edx+1] .text:00010CF1 mov ecx, ds:KeServiceDescriptorTable .text:00010CF7 mov edx, [ecx] .text:00010CF9 mov dword ptr [edx+eax*4], offset sub_11360 .text:00010D00 mov eax, ds:ZwDeleteKey .text:00010D05 mov ecx, [eax+1] .text:00010D08 mov edx, ds:KeServiceDescriptorTable .text:00010D0E mov eax, [edx] .text:00010D10 mov dword ptr [eax+ecx*4], offset sub_112F0 没有什么,都是常规的Reg读写。失望ing…… 回头再找,居然在Hooksys里看见了ravmond!看来下次要用Hex editer了……用BIEW虽然方便,但很容易看漏的。而且,还犯了轻信IDA的错误…… OK,再看Hooksys!有了刚才的经验,这次应该很简单了。 很快发现字符串'RAV.EXE'在11D70处。判断子程序是sub_11ED4。但是居然没有使用KeServiceDescriptorTable!而且驱动的Type是8300h,自定义。 下面就没有什么进展了。在网上搜了搜,发现有人问过类似的问题。不过他要知道的是如何完美地对文件系统Hook。 不过可以肯定的是,RAV没有使用常规的方法来Hook。有可能是通过FileSystem或自己直接计算内存地址来实现Hook的。 PS:在小四的站看了篇Hume的文章,讲通过SEH获取Ker32基址的。在IDA里搜了搜,发现有 .text:00012CD9 mov eax, large fs:4 .text:00012CDF mov [ebp+VirtualAddress], eax 很可能就是这个了……暴力搜索,然后改cr0,直接修改物理地址,完美Hook……猜测而已…… TMD简直跟rootkit没什么区别了。隐蔽得一塌糊涂,拿来做rootkit连import也不要,想k的话就乖乖地从头做逆向工程吧……不过做一遍也有好处,现在起码对驱动有点了解了。以前?觉得象天书…… [ Last edited by sdlj8051 on 2006-10-6 at 12:37 ] |
» 猜你喜欢
拟解决的关键科学问题还要不要写
已经有4人回复
基金委咋了?2026年的指南还没有出来?
已经有9人回复
基金申报
已经有5人回复
国自然申请面上模板最新2026版出了吗?
已经有17人回复
纳米粒子粒径的测量
已经有8人回复
疑惑?
已经有5人回复
计算机、0854电子信息(085401-058412)调剂
已经有5人回复
Materials Today Chemistry审稿周期
已经有5人回复
溴的反应液脱色
已经有7人回复
推荐一本书
已经有12人回复











回复此楼