闲来无事胡写些东西留给自己以后看,没有技术含量,想笑的人劳驾,飘过吧!
周末在家宅了2天很是无聊,下午把以前玩过的一个网游拿出来调试,用OD挂上游戏,不一会弹出来一个MessageBox说,什么网警检测到非法调试,弄的还挺吓人的,因为之前开着抓包工具,看了一下没有往发发送什么可疑数据。看来真的是吓人的,呵呵!
以前调试的时候都很顺利没遇到过什么情况,所以怀疑这公司反外挂技术获过奖是涂有虚名,真的勾起我的好奇了。因为咱这技术也不太好,小菜一个,所以还是怀疑自己的能力啊,姑且试试吧......
用OD重加载游戏运行,在MessageBoxA上下断点,程序运行在断点停下,确实是那条赫人的信息
0C71A4FD /. 55 push ebp
0C71A4FE |. 8BEC mov ebp, esp
0C71A500 |. 51 push ecx
0C71A501 |. C745 FC 8C227>mov dword ptr ss:[ebp-4], 0>
0C71A508 >|. 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
0C71A50A |. 68 BC22750C push 0C7522BC ; |Title = "网警:****
0C71A50F |. 8B45 FC mov eax, dword ptr ss:[ebp-4] ; |
0C71A512 |. 50 push eax ; |Text = "程序检到***********如有疑问请联**"?
0C71A513 |. 6A 00 push 0 ; |hOwner = NULL
0C71A515 |. FF15 7CC1740C call near dword ptr ds:[<&USER32.Mess>; /MessageBoxA
0C71A51B |. 8BE5 mov esp, ebp
0C71A51D |. 5D pop ebp
0C71A51E /. C3 retn
看了一下调用堆栈是空的,堆栈里的数据也都是假的,汗了,有点摸不到头绪了。看来宅在家里能让人情绪紧张。
分析一下:起初以为这里做了什么高深的处理,后来看到调用堆栈和栈里的数据都做了处理,也没什么可利用的。很迷糊中...
总还是有希望的,因为想到调用这个函数无非就是用jmp或者call指令完成,所以一定会在程序中留下痕迹的,在程序中搜索了一下jmp0C71A4FD未果,call 0C71A4FD 未果。一定还有痕迹留下的,最终找到一处
mov eax,0C71A4FD.呵呵就是这里了。
0C73B156 /$ 55 push ebp
0C73B157 |. 8BEC mov ebp, esp
0C73B159 |. B8 FDA4710C mov eax, 0C71A4FD
0C73B15E |. 35 AAAAAAAA xor eax, AAAAAAAA '还做了以下xor迷惑人的
0C73B163 |. A3 98C3750C mov dword ptr ds:[C75C398], eax '应该是存到全局变量里了吧
0C73B168 |. 5D pop ebp
0C73B169 /. C3 retn
找到这里就有希望了,用OD重新运行程序,这次在执行完0C73B163处指令后,在C75C398的位置下内存访问断点。继续运行程序,在0C73B1DD断下,看了一下调用堆栈,知道这是一个Timer的过程入口,这里有几处判断,多次调用了0C7399F9函数,跟进看一下。
0C73B1C2 /. 55 push ebp ; check debug timer proc
0C73B1C3 |. 8BEC mov ebp, esp
0C73B1C5 |. 83EC 14 sub esp, 14
0C73B1C8 |. C745 EC 00000>mov dword ptr ss:[ebp-14], 0
0C73B1CF |. E8 0FE9FFFF call 0C739AE3 ;不贴这个函数过程了就是通过ZwQueryInformationProcess检查是否被调试,总之返回eax=1就完蛋了,几处检测类似只贴主要函数了(下同)
0C73B1D4 |. 8945 F4 mov dword ptr ss:[ebp-C], eax
0C73B1D7 |. 837D F4 00 cmp dword ptr ss:[ebp-C], 0
0C73B1DB |. 74 15 je short 0C73B1F2
0C73B1DD |. A1 98C3750C mov eax, dword ptr ds:[C75C398]
0C73B1E2 |. 35 AAAAAAAA xor eax, AAAAAAAA
0C73B1E7 |. 50 push eax
0C73B1E8 |. E8 0CE8FFFF call 0C7399F9
0C73B1ED |. 83C4 04 add esp, 4
0C73B1F0 |. EB 56 jmp short 0C73B248
0C73B1F2 |> FF15 68C0740C call near dword ptr ds:[<&KERNEL32.Ge>; [GetCurrentProcessId
0C73B1F8 |. 8945 F0 mov dword ptr ss:[ebp-10], eax
0C73B1FB |. 8B4D F0 mov ecx, dword ptr ss:[ebp-10]
0C73B1FE |. 51 push ecx
0C73B1FF |. E8 3DEAFFFF call 0C739C41 ;CheckRemoteDebuggerPresent
0C73B204 |. 83C4 04 add esp, 4
0C73B207 |. 8945 F8 mov dword ptr ss:[ebp-8], eax
0C73B20A |. 837D F8 00 cmp dword ptr ss:[ebp-8], 0
0C73B20E 74 17 je short 0C73B227
0C73B210 |. 8B15 98C3750C mov edx, dword ptr ds:[C75C398]
0C73B216 |. 81F2 AAAAAAAA xor edx, AAAAAAAA
0C73B21C |. 52 push edx
0C73B21D |. E8 D7E7FFFF call 0C7399F9
0C73B222 |. 83C4 04 add esp, 4
0C73B225 |. EB 21 jmp short 0C73B248
0C73B227 |> E8 8EE8FFFF call 0C739ABA ; IsDebuggerPresent
0C73B22C |. 8945 FC mov dword ptr ss:[ebp-4], eax
0C73B22F |. 837D FC 00 cmp dword ptr ss:[ebp-4], 0
0C73B233 74 13 je short 0C73B248
0C73B235 |. A1 98C3750C mov eax, dword ptr ds:[C75C398]
0C73B23A |. 35 AAAAAAAA xor eax, AAAAAAAA
0C73B23F |. 50 push eax
0C73B240 |. E8 B4E7FFFF call 0C7399F9
0C73B245 |. 83C4 04 add esp, 4
0C73B248 |> 8BE5 mov esp, ebp
0C73B24A |. 5D pop ebp
0C73B24B /. C2 1000 retn 10
看一下0C7399F9函数,哇!豁然开朗了!想明白的东西终于明白了,这个函数还是很简单的,就是把堆栈中的数据摸去,然后修改返回地址为0C71A4FD(其实返回地址后边还有几个连续的0C71A4FD可能是为了ret的时候安全调用吧),这样修改完0x200个堆栈空间后(真下功夫的),直接ret就飞向0C71A4FD了,就是开始那个调用MessageBox的函数了,不细说了。
仔细看一下这一大堆代码,呵呵还有传说中的花指令吧,不过真不太高明啊!
0C7399F9 $ 55 push ebp
0C7399FA . 8BEC mov ebp, esp
0C7399FC . 6A FF push -1
0C7399FE . 68 20B1740C push 0C74B120 ;
0C739A03 . 64:A1 0000000>mov eax, dword ptr fs:[0]
0C739A09 . 50 push eax
0C739A0A . 64:8925 00000>mov dword ptr fs:[0], esp
0C739A11 . 51 push ecx
0C739A12 . 83EC 10 sub esp, 10
0C739A15 . 53 push ebx
0C739A16 . 56 push esi
0C739A17 . 57 push edi
0C739A18 . 8965 F0 mov dword ptr ss:[ebp-10], esp
0C739A1B . C745 EC 00000>mov dword ptr ss:[ebp-14], 0
0C739A22 . 8B45 08 mov eax, dword ptr ss:[ebp+8]
0C739A25 . 8945 E0 mov dword ptr ss:[ebp-20], eax
0C739A28 . 837D 08 00 cmp dword ptr ss:[ebp+8], 0
0C739A2C . 75 08 jnz short 0C739A36
0C739A2E . E8 25490000 call 0C73E358
0C739A33 . 8945 E0 mov dword ptr ss:[ebp-20], eax
0C739A36 > 8D4D EC lea ecx, dword ptr ss:[ebp-14]
0C739A39 . 894D E4 mov dword ptr ss:[ebp-1C], ecx
0C739A3C . C745 E8 00000>mov dword ptr ss:[ebp-18], 0
0C739A43 . C745 E8 00000>mov dword ptr ss:[ebp-18], 0
0C739A4A . EB 09 jmp short 0C739A55
0C739A4C > 8B55 E8 mov edx, dword ptr ss:[ebp-18]
0C739A4F . 83C2 01 add edx, 1
0C739A52 . 8955 E8 mov dword ptr ss:[ebp-18], edx
0C739A55 > 837D E8 0A cmp dword ptr ss:[ebp-18], 0A
0C739A59 . 7D 0E jge short 0C739A69
0C739A5B . 8B45 E8 mov eax, dword ptr ss:[ebp-18]
0C739A5E . 8B4D E4 mov ecx, dword ptr ss:[ebp-1C]
0C739A61 . 8B55 E0 mov edx, dword ptr ss:[ebp-20]
0C739A64 . 891481 mov dword ptr ds:[ecx+eax*4], edx
0C739A67 .^ EB E3 jmp short 0C739A4C
0C739A69 > E8 EA480000 call 0C73E358
0C739A6E . 8945 E0 mov dword ptr ss:[ebp-20], eax
0C739A71 . EB 09 jmp short 0C739A7C
0C739A73 > 8B45 E8 mov eax, dword ptr ss:[ebp-18]
0C739A76 . 83C0 01 add eax, 1
0C739A79 . 8945 E8 mov dword ptr ss:[ebp-18], eax
0C739A7C > 817D E8 00020>cmp dword ptr ss:[ebp-18], 200
0C739A83 . 7D 24 jge short 0C739AA9
0C739A85 . C745 FC 00000>mov dword ptr ss:[ebp-4], 0
0C739A8C . 8B4D E8 mov ecx, dword ptr ss:[ebp-18]
0C739A8F . 8B55 E4 mov edx, dword ptr ss:[ebp-1C]
0C739A92 . 8B45 E0 mov eax, dword ptr ss:[ebp-20]
0C739A95 . 89048A mov dword ptr ds:[edx+ecx*4], eax
0C739A98 . EB 06 jmp short 0C739AA0
0C739A9A . B8 A09A730C mov eax, 0C739AA0
0C739A9F . C3 retn
0C739AA0 > C745 FC FFFFF>mov dword ptr ss:[ebp-4], -1
0C739AA7 .^ EB CA jmp short 0C739A73
0C739AA9 > 8B4D F4 mov ecx, dword ptr ss:[ebp-C]
0C739AAC . 64:890D 00000>mov dword ptr fs:[0], ecx
0C739AB3 . 5F pop edi
0C739AB4 . 5E pop esi
0C739AB5 . 5B pop ebx
0C739AB6 . 8BE5 mov esp, ebp
0C739AB8 . 5D pop ebp
0C739AB9 . C3 retn
总结一下,其实感觉我是舍近求远了,因为无聊啊,可以直接从ZwQueryInformationProcess,CheckRemoteDebuggerPresent ,IsDebuggerPresent函数入手,这种检测调试的方法就是《加密解密》上介绍的,地球人都知道了。直接干掉那个timer就可以了,应该是这样的!
补充一下:上次干掉了那个Timer,更狠的东西来了,没多一会OD都结束了,呵呵!再跟踪了一下发现有可疑线程,它检查是否程序被调试,如果发现被调试就调用C:/WINDOWS/System32/ntsd.exe结束掉这个调试进程,具体代码就不贴了,调用太多,不过原理就是这样的,呵呵!ntsd.exe让我想起了有的病毒是通过它结束杀毒软件的,挺有意思,真是先礼后兵啊,先提示你一下,最后直接kill了!希望游戏程序员再接再厉,我会继续跟进...