- UID
- 2198
注册时间2005-6-29
阅读权限255
最后登录1970-1-1
副坛主
该用户从未签到
|
——
本课的分析目标为:IP-Tools 2.54,程序非明码,无壳,有自效检。我们通过这个个例的分析来了解非码文比较的程序的验证过程,以及处理程序的效检的基本思路。我们OD载入程序,运行后随意输入注册信息,下万能断点,中断后返回到程序凌空,我们在这里下断:
0050F174 |. E8 9B6FF2FF CALL Ip_tools.00436114
0050F179 |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8] ; 下万能断点 返回到这里
0050F17C |. 8D55 FC LEA EDX,DWORD PTR SS:[EBP-4]
0050F17F |. E8 40A3EFFF CALL Ip_tools.004094C4
……
……
0050F1C0 |. E8 4F6FF2FF CALL Ip_tools.00436114
0050F1C5 |. 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14]
0050F1C8 |. E8 47A1FCFF CALL Ip_tools.004D9314 ; 比较用户名是否在黑名单
0050F1CD |. 84C0 TEST AL,AL
0050F1CF |. 74 3C JE SHORT Ip_tools.0050F20D
……
……
0050F218 |. E8 F76EF2FF CALL Ip_tools.00436114
0050F21D |. 837D E0 00 CMP DWORD PTR SS:[EBP-20],0 ; 比较用户名是否为空
0050F221 |. 0F84 CB010000 JE Ip_tools.0050F3F2
0050F227 |. 8D55 DC LEA EDX,DWORD PTR SS:[EBP-24]
0050F22A |. 8B06 MOV EAX,DWORD PTR DS:[ESI]
0050F22C |. 8B80 E8020000 MOV EAX,DWORD PTR DS:[EAX+2E8]
0050F232 |. E8 DD6EF2FF CALL Ip_tools.00436114
0050F237 |. 837D DC 00 CMP DWORD PTR SS:[EBP-24],0
0050F23B |. 0F84 B1010000 JE Ip_tools.0050F3F2 ; 比较注册码是否为空
0050F241 |. 8D55 D8 LEA EDX,DWORD PTR SS:[EBP-28]
0050F244 |. 8B06 MOV EAX,DWORD PTR DS:[ESI]
0050F246 |. 8B80 E4020000 MOV EAX,DWORD PTR DS:[EAX+2E4]
0050F24C |. E8 C36EF2FF CALL Ip_tools.00436114
0050F251 |. 8B45 D8 MOV EAX,DWORD PTR SS:[EBP-28] ; 用户名送EAX
0050F254 |. E8 13BFFEFF CALL Ip_tools.004FB16C ; 对用户名做加密运算 设为 f(name)
0050F259 |. 8BF8 MOV EDI,EAX
0050F25B |. 8D55 D4 LEA EDX,DWORD PTR SS:[EBP-2C]
0050F25E |. 8B06 MOV EAX,DWORD PTR DS:[ESI]
0050F260 |. 8B80 E8020000 MOV EAX,DWORD PTR DS:[EAX+2E8]
0050F266 |. E8 A96EF2FF CALL Ip_tools.00436114
0050F26B |. 8B45 D4 MOV EAX,DWORD PTR SS:[EBP-2C] ; 注册码送EAX
0050F26E |. E8 95BFFEFF CALL Ip_tools.004FB208 ; 对注册码做加密运算 设为 g(key)
0050F273 |. 66:3BF8 CMP DI,AX ; 比较加密后的数据长度是否都为50H
0050F276 |. 0F85 76010000 JNZ Ip_tools.0050F3F2
0050F27C |. A1 C82F5500 MOV EAX,DWORD PTR DS:[552FC8] ; f(name)结果送EAX
0050F281 |. BA FF010000 MOV EDX,1FF
0050F286 |. E8 C5BEFEFF CALL Ip_tools.004FB150
0050F28B |. 8BF8 MOV EDI,EAX
0050F28D |. A1 442E5500 MOV EAX,DWORD PTR DS:[552E44] ; f(key)结果送EAX
0050F292 |. BA FF010000 MOV EDX,1FF
0050F297 |. E8 B4BEFEFF CALL Ip_tools.004FB150 ; 比较函数
0050F29C |. 3BF8 CMP EDI,EAX
0050F29E |. 0F85 4E010000 JNZ Ip_tools.0050F3F2
0050F2A4 |. A1 C82F5500 MOV EAX,DWORD PTR DS:[552FC8] ; f(name)结果送EAX
0050F2A9 |. 83C0 07 ADD EAX,7
0050F2AC |. 8B00 MOV EAX,DWORD PTR DS:[EAX]
0050F2AE |. 8B15 442E5500 MOV EDX,DWORD PTR DS:[552E44] ; f(key)结果送EAX
0050F2B4 |. 83C2 07 ADD EDX,7
0050F2B7 |. 3B02 CMP EAX,DWORD PTR DS:[EDX]
0050F2B9 |. 0F85 33010000 JNZ Ip_tools.0050F3F2 ; 继续比较 若f(name)==g(key) 下面代码将保存注册信息
……
综上分析,我们修改跳转,先将注册信息保存。作者在这里设置了一个小陷阱,将注册信息保存在注册表的两个位置,程序启动时验证的其实是第二处保存的数据。
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\KS-Soft\IP-Tools]
"UserName"="rE3YHz^g?"
"UserSNum"="=E8x?9"
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Devices\00102]
"DATA5"="NCiUsDyF[XPFYNGX]H"
"DATA6"="2C5U9D7F7X5F8N"
我们猜测程序启动时还会调用相同的算法CALL来对KEY进行验证。我们查看一下对KEY做计算的函数:CALL 004FB208,发现有两处调用:局部调用来自 0050F26E, 00547F99 我们来到地址00547F99处,在上方的地址处下断即可。当然我们也可以查看用户名是否属于黑名单的CALL的调用来定位启动时的验证地址,这种快速定位的小技巧将省去我们下API函数断点的麻烦。
00547F51 |. E8 BE13F9FF CALL Ip_tools.004D9314 ; 检测用户名是否在黑名单
00547F56 |. 84C0 TEST AL,AL
00547F58 |. 74 34 JE SHORT Ip_tools.00547F8E
00547F5A |. 68 84835400 PUSH Ip_tools.00548384 ; Sorry, your registration name (
00547F5F |. FF75 EC PUSH DWORD PTR SS:[EBP-14]
00547F62 |. 68 AC835400 PUSH Ip_tools.005483AC ; ) is found on the "Black List".\r\n\r\n
00547F67 |. 68 D8835400 PUSH Ip_tools.005483D8 ; If you have any questions, please, contact KS-Soft: [email protected]; [email protected]
00547F6C |. 8D45 D4 LEA EAX,DWORD PTR SS:[EBP-2C]
00547F6F |. BA 04000000 MOV EDX,4
00547F74 |. E8 2BC3EBFF CALL Ip_tools.004042A4
00547F79 |. 8B45 D4 MOV EAX,DWORD PTR SS:[EBP-2C]
00547F7C |. E8 236AF1FF CALL Ip_tools.0045E9A4
00547F81 |. A1 202E5500 MOV EAX,DWORD PTR DS:[552E20]
00547F86 |. C600 01 MOV BYTE PTR DS:[EAX],1
00547F89 |. E9 89000000 JMP Ip_tools.00548017
00547F8E 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14] ; 用户名送EAX
00547F91 |. E8 D631FBFF CALL Ip_tools.004FB16C ; f(name)
00547F96 |. 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18] ; 注册码送EAX
00547F99 |. E8 6A32FBFF CALL Ip_tools.004FB208 ; g(key)
00547F9E |. A1 C82F5500 MOV EAX,DWORD PTR DS:[552FC8]
00547FA3 |. BA FF010000 MOV EDX,1FF
00547FA8 E8 A331FBFF CALL Ip_tools.004FB150
00547FAD |. 8BF0 MOV ESI,EAX
00547FAF |. A1 442E5500 MOV EAX,DWORD PTR DS:[552E44]
00547FB4 |. BA FF010000 MOV EDX,1FF
00547FB9 |. E8 9231FBFF CALL Ip_tools.004FB150 ; 比较CALL
00547FBE |. 3BF0 CMP ESI,EAX
00547FC0 |. 75 33 JNZ SHORT Ip_tools.00547FF5 ; 第一处比较
00547FC2 |. A1 C82F5500 MOV EAX,DWORD PTR DS:[552FC8]
00547FC7 |. 83C0 07 ADD EAX,7
00547FCA |. 8B00 MOV EAX,DWORD PTR DS:[EAX]
00547FCC |. 8B15 442E5500 MOV EDX,DWORD PTR DS:[552E44] ; Ip_tools.00555BF8
00547FD2 |. 83C2 07 ADD EDX,7
00547FD5 |. 3B02 CMP EAX,DWORD PTR DS:[EDX]
00547FD7 |. 75 1C JNZ SHORT Ip_tools.00547FF5 ; 再次比较
00547FD9 |. A1 F8315500 MOV EAX,DWORD PTR DS:[5531F8]
分析出程序的验证流程,我们来考虑下如何爆破:
00547F9E |. A1 C82F5500 MOV EAX,DWORD PTR DS:[552FC8] ; [552FC8]中保存的地址送EAX
00547FA3 |. BA FF010000 MOV EDX,1FF
00547FA8 E8 A331FBFF CALL Ip_tools.004FB150
00547FAD |. 8BF0 MOV ESI,EAX
00547FAF |. A1 442E5500 MOV EAX,DWORD PTR DS:[552E44] ; [552E44]中保存的地址送EAX
既然是对加密后的两组数据进行比较,我们何不使其比较同一字符串,做如下修改:
00547FAF |. A1 442E5500 MOV EAX,DWORD PTR DS:[552E44] ; MOV EAX,DWORD PTR DS:[552FC8]
比较同一字符串,结果肯定是相同的 ^_^ 第二处比较也做相同的修改
思考:程序启动时为何也调用检测用户名是在黑名单呢?对,若不检查这里,我们只需将被黑名单中用户的注册表信息导入即可实现注册。
保存程序后运行,已显示为注册版,但程序的一些功能却出现了问题,比如我们选择Ping Scanner的功能时,出现以下提示,而运行原程序却没有问题。
我们来分析一下原因:程序一直都在OD中,所以一定不是自身的效检问题,我们只对程序启动时验证注册码的真假做了修改,那么问题一定出在了这里。莫非程序有对注册信息做了验证?带着这种猜测,我们OD再次载入,并在[552FC8]该地址下硬件访问断点。程序过了前两道验证后,后然再次中断:
00535505 . 8B1D C82F5500 MOV EBX,DWORD PTR DS:[552FC8] ; Ip_tools.005559F8
0053550B . 8B35 442E5500 MOV ESI,DWORD PTR DS:[552E44] ; Ip_tools.00555BF8
00535511 . 33C0 XOR EAX,EAX
老方法,我们还是将MOV ESI,DWORD PTR DS:[552E44]修改为[552FC8],让程序去比较同一字符串好了。
由于程序比较非明文,处于好奇,我们想对程序对加密后数据的比较探个究竟,在地址 00547F9E (次时程序已经执行完f(name)函数) 下断点,查看[00552FC8]地址所保存的数据。
DS:[00552FC8]=005559F8
DS:[00552E44]=00555BF8
005559F8 56 D6 59 09 75 F9 24 05 FA AD 10 C8 2C 71 11 82 V諽.u???q
00555A08 8B F7 19 D6 C7 77 83 8E 9A E5 7B 88 FC E5 3C C1 嬿智w儙氬{堻?
00555A18 7F 33 38 00 A2 58 F8 F5 94 68 EB 52 1E 06 CA 42 38.??攈隦蔅
00555A28 87 4B EF 3E 40 C1 40 69 FD EA E7 46 E4 20 43 3A 嘖?@罖i?鏔?C:
00555A38 D2 BB 0E 48 12 52 EE 94 05 CD 58 42 12 70 97 6E 一HR顢蚗Bp梟
00555BF8 63 E6 08 EE 40 98 75 C3 76 9F 72 FE E2 EE 48 12 c?頏榰胿焤?頗
00555C08 30 06 C7 3A C7 9A 92 08 A0 33 C7 6B B2 95 30 AA 0?菤??莐矔0
00555C18 EC 3C 53 17 EB A2 38 53 B8 D7 E1 E1 0C C0 8D FB ?S擘8S缸後.缻
00555C28 7E 0E CE FF 47 CA AD 9A 66 D4 43 D1 B2 75 18 24 ~?G虱歠訡巡u$
00555C38 2E 97 12 2C E5 8B 68 72 90 28 C8 B8 E4 2F 90 23 .?,鍕hr?雀??
正好是50H个字节的比较,既然我们得知程序是比较NAME和KEY经过计算后的数据,我们何不写一段代码将f(name)的结果COPY到g(key)中呢 o(∩_∩)o... 有想法我们就要付诸实践,我们开工:
00547FB9 |. E8 9231FBFF CALL Ip_tools.004FB150 ; 将这里修改为 CALL 005498AB
Patch代码如下:
005498AB /$ 56 PUSH ESI
005498AC |. 57 PUSH EDI
005498AD |. 51 PUSH ECX
005498AE |. 8B35 C82F5500 MOV ESI,DWORD PTR DS:[552FC8] ; 源地址送ESI
005498B4 |. 8B3D 442E5500 MOV EDI,DWORD PTR DS:[552E44] ; 目标地址送EDI
005498BA |. B9 50000000 MOV ECX,50 ; 长度为50H
005498BF |. FC CLD
005498C0 |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
005498C2 |. 59 POP ECX
005498C3 |. 5F POP EDI
005498C4 |. 5E POP ESI
005498C5 |. E8 8618FBFF CALL Ip_tools.004FB150
005498CA \. C3 RETN
我们写这样一个功能函数来实现f(name)的结果对g(key)结果的替换,这样程序再多几道验证也就不怕了。我们保存文件后发现程序启动时出现提示:
我们F8单步几下就可以找到程序的效检地址:
005490C3 . E8 0805F9FF CALL Ip_tools.004D95D0 ; 程序的自效检
005490C8 . 8B15 842D5500 MOV EDX,DWORD PTR DS:[552D84] ; Ip_tools.00555810
005490CE . 3B82 B4000000 CMP EAX,DWORD PTR DS:[EDX+B4] ; 自效检的比较
005490D4 74 0F JE SHORT Ip_tools.005490E5 ; 不等则提示程序出错
005490D6 . B8 CC965400 MOV EAX,Ip_tools.005496CC ; Program was corrupted !
005490DB . E8 C458F1FF CALL Ip_tools.0045E9A4
005490E0 . E9 2E050000 JMP Ip_tools.00549613
005490E5 > 68 8C965400 PUSH Ip_tools.0054968C ; [
我们将JE 修改为 JMP 后,运行程序发现部分功能仍旧无法使用。:-) 这下就很好分析了,问题肯定出在了自效检上了。
原程序的自效检值为:77B8FADC,而修改后的程序的效检变为了:9E62EC0F,如果程序在执行中又对效检值做了验证,就会出问题。呵呵,这个提示程序出错的NAG,看来作者是聪明反被聪明误了。我们跟进跳转上方的CALL 004D95D0,跟踪一下是哪句指令对EAX进行了赋值。
004D9737 |. E8 50CEF2FF CALL Ip_tools.0040658C ; 我们在这里做手脚
004D973C |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; 在这里对EAX赋予了程序的效检值
004D973F |. A3 94FF5400 MOV DWORD PTR DS:[54FF94],EAX
004D9744 |> 33C0 XOR EAX,EAX
004D9746 |. 5A POP EDX
004D9747 |. 59 POP ECX
004D9748 |. 59 POP ECX
004D9749 |. 64:8910 MOV DWORD PTR FS:[EAX],EDX
004D974C |. 68 64974D00 PUSH Ip_tools.004D9764
004D9751 |> 8D85 A4BEFFFF LEA EAX,DWORD PTR SS:[EBP+FFFFBEA4]
004D9757 |. E8 08A8F2FF CALL Ip_tools.00403F64
004D975C \. C3 RETN
为了更好的迷惑大家,使其不容易发现我们的修改痕迹,这里我们不使用JMP指令来Patch代码,而修改上方的CALL指令。
004D9737 |. E8 50CEF2FF CALL Ip_tools.0040658C ; 修改为 CALL 005498CC
Patch代码:
005498CC /$ E8 BBCCEBFF CALL Ip_tools.0040658C ; 还原覆盖的代码
005498D1 |. C745 FC DCFAB877 MOV DWORD PTR SS:[EBP-4],77B8FADC ;自身的效检值
005498D8 \. C3 RETN
再次保存程序,:-) 这下就OK了。在爆破上修改跳转是下策,更优的方法就是在比较前使其数据相等,当然,为追求快速,我们更常用的还是修改跳转。
由于程序的对name和key计算后的结果地址放在两个指针变量中,我们通过查看程序的区段,发现指针变量[00552FC8]和[00552E44]位于数据段,所以我们可以得知这两个变量为全局变量(全局变量保存在数据段中)。如图:
我们OD载入程序后,先不运行,输入 d 00552FC8 发现[00552FC8]中已保存了数据,通过几次的调试我们发现该地址为固定值:
DS:[00552FC8]=005559F8
DS:[00552E44]=00555BF8
通过对PE各区段地址的了解,我们得知 地址005559F8 和 地址00555BF8 位于数据段下方区段名为BBS的的区段,在调试中我们可以发现该区段保存程序执行时的一些数据,所以我们推测该区段为附加的数据段。由于[00552FC8]和[00552E44]为定值,那我们可直接将这两个指针变量保存相同的地址,即将[00552E44]中的地址00555BF8 修改为地址005559F8 ,为避免程序的自效检,我们使用Loader来实现,这样只需要修改一个字节即可实现程序的爆破,若注册表信息也保存在Loader中,便可无需输入注册信息即可实现程序的注册。
我们调试一款程序,不要刻意去追求结果,而要通过发现的一个个的线索,来洞察程序的加密体系。当我们掌握了程序的加密体系,破解自然水到渠成。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?加入我们
x
|