![]() |
[原创]初识逆向技术 适合读者:逆向爱好者、程序员 前置知识:基本汇编代码阅读能力 Icefire:通常所谓的软件逆向工程是指:跟踪复原(或仿制)软件的编程过程、修改软件的部分代码、添加或者删除软件的部分功能等等。然而,要想达到自如地对软件跟踪与修改,既需要过 |
适合读者:逆向爱好者、程序员 前置知识:基本汇编代码阅读能力 Icefire:通常所谓的软件逆向工程是指:跟踪复原(或仿制)软件的编程过程、修改软件的部分代码、添加或者删除软件的部分功能等等。然而,要想达到自如地对软件跟踪与修改,既需要过硬的跟踪与识别技术,更需要对软件的基本结构做出较为透彻了解。尤其是软件的PE结构更是逆向技术中需要掌握的。因为你需要达到的某种目的,可能条件并不具备,你不得不在软件中做出适当补充与完善。即使是条件具备,没有恰当地使用好,可能目的达不到,还会引起软件崩溃。从本期开始,我们将和大家一起,逐步系统地了解逆向技术,看看它的神秘究竟在那里! 初识逆向技术 文/图 laoxuetong 逆向是很让人陶醉的一种技术,相信很多朋友都和我一样,喜欢研究它。当然,这就需要有几件上手的工具,以方便对软件进行跟踪与察看、修改与编辑。虽然各类工具非常多,但我推荐一下组合: OllyDbg—Windows下优秀的跟踪调试软件。即可用于跟踪,也可以轻松地修改软件。 PEiD—性能不错的侦察软件。即可以用来查看软件编辑平台和侦查外壳,准备足够的插件还可以侦查软件的加密算法。 LordPE—PE文件查看与修改工具。条件不具备时你少不了它的帮助。 WinHex或UltraEdit—文本编辑工具。可任选一种或其它的,主要用于编辑一些文本类资源。 好,下面我们选定一个软件《WinPatrol v8.1.2.0》,看看我们能作些什么?
软件简单介绍 WinPatrol是网络安全工具,可以探测出蠕虫、间谍程序、木马等恶意的程序。界面如图1所示:
图1 软件除了可以查看各种可能出现的项目及其相关信息外,你也可以设置对某一个项目的监视,用以跟踪监视可疑的病毒与木马的运行情况。软件启动后在任务栏会出现一只黑色的小狗,时不时掉转头来,煞是可爱。 软件运行有三种状态。它们分别是:未注册状态、注册于PLUS状态和注册于Professional状态。其中注册于PLUS状态和注册于Professional状态的界面略有不同,如图2、3所示:
图2 注册于PLUS状态
图3 注册于Professional状态 关于PLUS的注册方式,网上有现成的注册机,这里就不多说了。现在我想注册于Professional状态,那么我们能作些什么呢?
问题分析 通过对软件的跟踪发现,软件的注册验证并不复杂。有关代码如下: 读取名称: 00408CF1 PUSH 40 ; /Count = 40 (64.) 00408CF3 PUSH WinPatro.004276E0 ; |Buffer = WinPatro.004276E0 00408CF8 PUSH 432 ; |ControlID = 432 (1074.) 00408CFD PUSH ESI ; |hWnd 00408CFE CALL EDI ; "GetDlgItemTextA 读取注册码: 00408D00 PUSH 20 ; /Count = 20 (32.) 00408D02 PUSH WinPatro.00427720 ; |Buffer = WinPatro.00427720 00408D07 PUSH 430 ; |ControlID = 430 (1072.) 00408D0C PUSH ESI ; |hWnd 00408D0D MOV EBX,EAX ; |转移名称长度 00408D0F CALL EDI ; "GetDlgItemTextA 判断: 00408D11 LEA EAX,DWORD PTR DS:[EBX-1] ; 名称长度-1 00408D14 TEST EAX,EAX 00408D16 JLE SHORT WinPatro.00408D33 00408D18 JMP SHORT WinPatro.00408D20 00408D1A LEA EBX,DWORD PTR DS:[EBX] 00408D20 CMP BYTE PTR DS:[EAX+4276E0],20 ; 名称最后一位是空格么? 00408D27 JNZ SHORT WinPatro.00408D30 00408D29 DEC EAX 00408D2A TEST EAX,EAX 00408D2C JG SHORT WinPatro.00408D20 00408D2E JMP SHORT WinPatro.00408D33 00408D30 LEA EBX,DWORD PTR DS:[EAX+1] ; 还原名称长度 00408D33 MOVSX EAX,BYTE PTR DS:[427721] ; 取出注册码第二位 00408D3A ADD BL,40 ; 名称长度+0x40=注册码第二位 00408D3D MOVZX EDX,BL 00408D40 CMP EAX,EDX ; 比较 00408D42 JE SHORT WinPatro.00408D9B ; 相等则跳 00408D44 PUSH 200 00408D49 LEA ECX,DWORD PTR SS:[ESP+D0] 00408D50 PUSH ECX 00408D51 PUSH 26C 00408D56 CALL WinPatro.0041A290 ; 读取注册不成功消息 00408D5B XOR EDX,EDX 00408D5D MOV DX,WORD PTR DS:[42C100] 00408D64 ADD ESP,0C 00408D67 LEA EAX,DWORD PTR SS:[ESP+CC] 注册不成功消息: 00408D6E PUSH EDX ; /LanguageID 00408D6F PUSH 40040 ; |Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL|40000 00408D74 PUSH WinPatro.00427DC0 ; |Title = "WinPatrol Professional" 00408D79 PUSH EAX ; |Text 00408D7A PUSH ESI ; |hOwner 00408D7B CALL DWORD PTR DS:[<&USER32.MessageBoxExA>] ; "MessageBoxExA 00408D81 POP EDI 00408D82 POP ESI 00408D83 XOR EAX,EAX 00408D85 POP EBX 00408D86 MOV ECX,DWORD PTR SS:[ESP+2C0] 00408D8D CALL WinPatro.0041B575 00408D92 ADD ESP,2C4 00408D98 RETN 10 00408D9B CALL WinPatro.0041B060 ; 相等跳到这里--读写注册表 00408DA0 TEST EAX,EAX 00408DA2 JE WinPatro.00408F6F 00408DA8 PUSH 200 00408DAD LEA ECX,DWORD PTR SS:[ESP+D0] 00408DB4 PUSH ECX 00408DB5 PUSH 26D 00408DBA CALL WinPatro.0041A290 ; 读取注册有效的信息 00408DBF XOR EDX,EDX 00408DC1 MOV DX,WORD PTR DS:[42C100] 00408DC8 ADD ESP,0C 00408DCB LEA EAX,DWORD PTR SS:[ESP+CC] ; 注册成功消息: 00408DD2 PUSH EDX ; /LanguageID 00408DD3 PUSH 40040 ; |Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL|40000 00408DD8 PUSH WinPatro.00427DC0 ; |Title = "WinPatrol Professional" 00408DDD PUSH EAX ; |Text 00408DDE PUSH ESI ; |hOwner 00408DDF CALL DWORD PTR DS:[<&USER32.MessageBoxExA>] ; "MessageBoxExA 从上可以看出,注册码的第二位应该是“名称长度+0x40”。如果是,则可以注册成PLUS版。如果不是,则不能注册。通过仔细跟踪看到,注册码并没有由注册名计算而来,所以也就是非明码比较范畴。这类软件一般不宜做内存注册机。 那么,这种情况下能不能让软件自动显示正确的注册码呢?经过思索和试验,发现也完全可做到。
准备工作 要显示注册码,需要一个消息盒,这东西通常需要调用API。请出LordPE来看一看,看软件为我们实现目标准备了相应条件没有。启动LordPE,如图4所示: 图4 选PE编辑器,打开需要查看的文件,如图5所示: 图5 单击 打开,出现第一个对话框,如图6所示: 图6 选择目录,出现第二个对话框,如图7所示: 图7 点击导入表右侧的第一个按钮出现第三个对话框,如图8所示: 图8 在这个对话框的上面查找USER32.DLL,则在下面出现这个文件中所有被使用的函数名称及其调用方法。如图9所示: 图9 从图中可以看到,软件包含了对函数MessageBox的调用。这为我们制作自显示注册码方案提供极大方便了,不需要作过多的操劳了。 调用对话框函数MessageBox通常需要4个参数,其中两个默认状态下为0。另两个一个是对话框的标题一个是对话框要显示的内容。另外,在调用时还必须遵守PE格式文件的规则。否则,轻则不能跨平台使用,重则软件不能启动。请注意,这个软件调用的不是MessageBoxA,而是MessageBoxExA。主要区别在于增加了语系识别。这些问题在进行软件逆向时必须进行学习与研究,逐步掌握并融会贯通。这里我们暂时不讲了。
实施手术 调用MessageBox的反汇编代码的一般形式形如: PUSH 0 ; /Style = MB_OK|MB_APPLMODAL PUSH Address1 ; |Title = "<消息盒标题>" PUSH Address2 ; |Text = "<消息盒内容>" PUSH 0 ; |hOwner = NULL CALL <JMP.&USER32.MessageBoxA> ; "MessageBoxA JMP Address3 JMP DWORD PTR DS:[<&USER32.MessageBoxA>] ; USER32.MessageBoxA 其中Address1对应着你的标题资源在内存中的位置,一般情况下地址是固定的。Address2对应着需要现实的内容在内存中的位置,大多数情况下地址是动态的,要根据情况加以利用。Address3是显示完毕后,应该返回到软件相应位置的地址,是固定的。值得注意的是,最后的两个跳转的顺序不能颠倒,否则软件不能正确地工作。 在添加这些代码时,上述三个地址可以先随意输入,等将代码输入完成、标题地址设置好、跳转地址找好再集中处理。而第二个跳转的地址可将软件已使用的地址复制过来(见未注册提示框位置)。当然,也可以根据PeiD中显示的地址计算。 好,现在选择合适的跳转点。因为软件需要用到名称长度,所以应该选择在恢复名称长度的位置跳转,即: 00408D30 LEA EBX,DWORD PTR DS:[EAX+1] ; 还原名称长度 00408D33 MOVSX EAX,BYTE PTR DS:[427721] ; 取出注册码第二位 00408D3A ADD BL,40 ; 名称长度+0x40=注册码第二位 因为这一行语句后面用到,所以必须在添加的代码里加上占用的代码部分。在程序后面的空余位置添加好代码,并将00408D33这一行改为: JMP < 添加代码入口> 并且让: Address2=<消息盒标题> Address3=<消息盒内容> 而消息盒标题紧放在添加代码的后面。经过这样设计,我的代码及存放位置如图10所示: 图10 紧随其后是标题数据。当你注册时,点击Apple后会出现如下图11所示的信息: 图11 怎么样?注册码出来了吧。而且还已经真的替你注册了,是不是很爽?! 容易么?看来很容易。但又不容易!如果软件本身不带MessageBox函数,实现起来就有些麻烦。能办到么?当然能。甚至可以直接使用,但不能互相交流及跨平台使用。 我不止想做到这些,还想做一些其它的事情;我的软件加壳了,不脱壳能否实现一些附加功能;能添加菜单项么?能添加或删除图像么?没位置存放我所添加的内容了,等等,等等。只要你能跟着我们学习,都是可以实现的。不过要记住,这里研究的是逆向技术,非软件开发。所以你如果想在试用版上处理成正式版,那倒不如自己开发了。 逆向方法小结 l 检查或者添加MessageBox函数 l 准备好MessageBox函数的反汇编代码 l 准备好消息盒中显示的数据地址 l 准备好合适的跳转点 l 在选定的合适位置输入代码和数据 l 检验、调试所作的工作 l 收集相关API函数,已备不时之用 |