欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

破解DebugApiSpy v3.2.1.56

破解DebugApiSpy v3.2.1.56

破解DebugApiSpy v3.2.1.56 
上次trw2000兄的贴子里提到这个软件,我研究了一阵,现把结果呈给大家,请大家指正。我先扔一块石头,有玉的尽管朝我砸来。
原贴:http://bbs2.pediy.com/viewtopic.php?t=5531&highlight=%CB%AB%B2%E3%BF%C7
这是一个双层壳,比较简单。虽然可以一步一步跟,但trw2000兄的方法简洁实用,所以这儿用他的方法(谢谢trw2000兄)

【转】
一、脱壳
    一运行,要注册。很久没搞破解啦,就拿它开刀温习一下功课吧。 
    因为在od中找不到可用的中文字符串,所以考虑用w32dasm反汇编,但要求先脱壳。 
    用FI2.5查看,是用AsPack2.1加的壳,很久没有手工跟啦,手工跟一把吧。用od刚一载入,停在: 
00469001 PUSHAD 
    Ctrl-F查找popad指令,去掉“整个区段”选项,找到这里: 
004694F3  POPAD 
004694F4  JNZ SHORT 004694FE 
004694F6  MOV EAX,1 
004694FB  RETN 0C 
004694FE  PUSH 00464000 
00469503  RETN        
    让光标停在上面一段的最后一行,按F4一次,再F8一次,即可到达第一层壳的OEP。这时如果转存进程的话,用fi查看还有一层PeCompact的壳,并且不能运行(用工具自动脱也不能运行,不知怎样修改)。因此继续脱第二层壳,起始一段如下,有特征命令pushfd和pushad,是壳的开始: 
00464000  JMP SHORT 00464008 
00464002  PUSH 2E9E8     这就是程序的原始OEP的RVA地址  
00464007  RETN 
00464008  PUSHFD 
00464009  PUSHAD 
0046400A  CALL 00464011 
    跟到下面一段,有特征命令popad和popfd,是壳的结束: 
0046554E  POPAD 
0046554F  POPFD 
00465550  PUSH EAX 
00465551  PUSH 0042E9E8 
00465556  RETN 4 
    到达00465556一行,再F8一次,返回到真正入口点: 
0042E9E8  PUSH EBP 
0042E9E9  MOV EBP,ESP 
    光标停在入口点后转存该进程,再用fi查看无壳,是用Visual C++ 6.0编写的。但是用od直接转存的程序不能运行。重跟到入口点,用别的方法转存。重跟就没有必要细跟啦,只要在下面几个关键点设断即可: 
1. 停在入口点时,在00469503处设断,中断后单步一下,即到达第二层壳的入口点。 
2. 在第二层壳的入口点时,壳的结尾00465556处还没有代码,因此无法把断点设在这里,要分几步到才能到达这里。第一步可以断点可以设在0046407B,执行到这儿后,向结尾处写代码的代码才出现: 
00464077  REP MOVS DWORD PTR ES:[EDI],DWORD PTR [ESI] 
00464079  MOV EDI,EBX 
0046407B  RETN 
3. 第二步,在0046407B处中断后,断点可以设在004651A7,执行到这儿以后壳结尾代码才形成: 
004651A5  REP MOVS BYTE PTR ES:[EDI],BYTE PTR [ESI] 
004651A7  JMP SHORT 004651CF 
4. 第三步,在004651A7处中断后,在壳结尾代码00465556处设断,中断后单步走到真正的OEP。 
    用PEditor来dump进程,并修正入口点,测试,程序不能运行,用别的方法dump,也不能运行。

【结束】

当然在最后需要用ImportREC来修复输入表(未加密)。

下面我们来修复dump出来的程序。

二、修复
1.去掉ZwSetInformationThread
00409BD1   PUSH DebugApi.0044DD34                   ; ASCII "ZwSetInformationThread"
00409BD6   PUSH DebugApi.0044DD28                   ; ASCII "ntdll.dll"
00409BDB   CALL DWORD PTR DS:[4361D8]               ; kernel32.GetModuleHandleA
00409BE1   PUSH EAX
00409BE2   CALL DWORD PTR DS:[4361E8]               ; kernel32.GetProcAddress
00409BE8   MOV ESI, EAX
00409BEA   CMP ESI, EDI
00409BEC   JE SHORT DebugApi.00409BFB
00409BEE   PUSH EDI
00409BEF   PUSH EDI
00409BF0   PUSH 11
00409BF2   CALL DWORD PTR DS:[436150]               ; kernel32.GetCurrentThread
00409BF8   PUSH EAX                        //nop
00409BF9   CALL ESI                        //nop

    脱壳程序在00409BF9处调用ZwSetInformationThread函数来反调试,这个函数除了反调试以外没其他用途,因此可以把00409BF8和00409BF9处nop掉。

2.解决动态解码
运行程序到424d0f处出错,上一句为CALL 0042407C,进去看看,发现代码显然不对,这是程序动态自解码,脱壳后解码出错,因此运行也出错。
在OD中打开原程序在00409BF8处下一个硬件执行断点,运行停住,在00409BFB处new origin here。在0042407C处下硬件执行断点,运行停住,0042407C处已正确解码,0042407C~0042447B。可以直接用OD的Binary copy和Binary paste拷贝到脱壳程序中。但要注意,这样拷贝过去后,程序还是要对该段代码进行解码,因此要对解码函数处理。
下面寻找解码函数,运行到00409BFB后,在0042407C处下一硬件访问断点,再运行,中断:
0042CEA3     REP MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI]  //断下
这是把0042407C开始处的代码复制到一内存空间,准备解码。假设内存空间为0fc0570,则在0fc0570处再下一硬件访问断点,运行。
0040542D       XOR EAX, EAX
0040542F       CMP DWORD PTR SS:[EBP-8], EAX
00405432       JE SHORT DebugApi.00405449
00405434       PUSH DWORD PTR SS:[EBP+8]
00405437       MOV ECX, DWORD PTR SS:[EBP-4]
0040543A       PUSH ESI
0040543B       CALL DebugApi.00404E68            //解码函数
00405440       ADD ESI, 8
00405443       ADD DWORD PTR SS:[EBP+8], 8
00405447       JMP SHORT DebugApi.0040546E
00405449       MOV CL, BYTE PTR DS:[EAX+ESI]
0040544C       MOV BYTE PTR DS:[EAX+EDI], CL     //断在这
0040544F       INC EAX
00405450       CMP EAX, 8
00405453       JL SHORT DebugApi.00405449
00405455       PUSH DWORD PTR SS:[EBP+C]
00405458       MOV ECX, DWORD PTR SS:[EBP-4]
0040545B       PUSH EDI
0040545C       CALL DebugApi.00404E68            //解码函数
00405461       PUSH 8
00405463       POP EAX
00405464       ADD DWORD PTR SS:[EBP+8], EAX
00405467       ADD ESI, EAX
00405469       ADD EDI, EAX
0040546B       ADD DWORD PTR SS:[EBP+C], EAX
0040546E       DEC EBX
0040546F       JNZ SHORT DebugApi.0040542D

进入CALL DebugApi.00404E68看看,好长一段代码,没去研究解码算法。改成在00404E68直接返回,即改成:
00404E68  RETN 8
修改完成。我们回到调用0042CEA3复制语句的上一层函数看看:

00424CCC      PUSH ESI
00424CCD      PUSH DWORD PTR SS:[EBP+C]
00424CD0      PUSH EDI
00424CD1      CALL DebugApi.0042CE70               //复制
00424CD6      ADD ESP, 0C
00424CD9      MOV ECX, EBX
00424CDB      PUSH ESI
00424CDC      PUSH DWORD PTR SS:[EBP-10]
00424CDF      PUSH EDI
00424CE0      CALL DebugApi.004053F9               //解码
00424CE5      TEST EBX, EBX
00424CE7      JE SHORT DebugApi.00424CF7
00424CE9      MOV ECX, EBX
00424CEB      CALL DebugApi.00404AE1
00424CF0      PUSH EBX
00424CF1      CALL DebugApi.0042D1A5
00424CF6      POP ECX
00424CF7      PUSH ESI
00424CF8      PUSH DWORD PTR SS:[EBP-10]
00424CFB      PUSH DWORD PTR SS:[EBP+C]
00424CFE      CALL DebugApi.0042CE70              //把正确代码复制到42407c
00424D03      PUSH DWORD PTR SS:[EBP-10]
00424D06      PUSH EDI
00424D07      PUSH DWORD PTR SS:[EBP+10]
00424D0A      CALL DebugApi.0042407C              //运行42407c
00424D0F      PUSH ESI
00424D10      PUSH EDI
00424D11      PUSH DWORD PTR SS:[EBP+C]
00424D14      CALL DebugApi.0042CE70              //运行完后,把错误代码复制回42407c
00424D19      PUSH DWORD PTR SS:[EBP-10]

另外4144e2~4158e1也是类似的动态解码。程序中有两处解码函数:
 
0042429E    CALL dumped_6.004053F9
00424CE0    CALL dumped_6.004053F9
就是这两个地方的解码。也有可能还有其他地方是动态解码,我没有再找。

3.解决自效验
这个问题一开始我的方法是正面去找,即运行脱壳程序一处一处找,找到了一些地方,但太麻烦,后来看到程序中有这样的语句:
CALL DWORD PTR DS:[<&kernel32.ExitProces>; ExitProcess
这不就是退出函数吗,因此查找所有命令:CALL DWORD PTR DS:[4361F4],然后在每处都设断,运行,停住:
(1)
00414589    CMP EAX, DWORD PTR SS:[ESP+14]
0041458D    JE SHORT dumped_4.00414597      //JE改成JMP
0041458F    PUSH 0                                   ; /ExitCode = 0
00414591    CALL DWORD PTR DS:[<&kernel32.ExitProces>; ExitProcess    //停在这
00414589处就是一个自效验,把0041458D处的je改成jmp。好,其他的也类似修改:
(2)
004167E3    CMP EAX, DWORD PTR SS:[ESP+14]
004167E7    JE SHORT dumped_4.004167F1      //JE改成JMP
004167E9    PUSH 0                                   ; /ExitCode = 0
004167EB    CALL DWORD PTR DS:[<&kernel32.ExitProces>; ExitProcess

修改好这两处后,程序可以运行了,但运行一段时间后还会退出,因此还有自效验:
(3)
004168D3    CMP ECX, EDX
004168D5    MOV DWORD PTR SS:[EBP+8], ECX
004168D8    JE SHORT dumped_4.004168E2      //JE改成JMP
004168DA    PUSH 0                                   ; /ExitCode = 0
004168DC    CALL DWORD PTR DS:[<&kernel32.ExitProces>; ExitProcess
(4)
00416907    CMP EAX, DWORD PTR SS:[EBP-4]
0041690A    MOV DWORD PTR SS:[EBP+8], EAX
0041690D    JE SHORT dumped_4.0041691A      //JE改成JMP
0041690F    PUSH 0                                   ; /ExitCode = 0
00416911    CALL DWORD PTR DS:[<&kernel32.ExitProces>; ExitProcess
(5)
00416928    CMP EAX, DWORD PTR DS:[ECX+8]
0041692B    JE SHORT dumped_4.00416935      //JE改成JMP
0041692D    PUSH 0                                   ; /ExitCode = 0
0041692F    CALL DWORD PTR DS:[<&kernel32.ExitProces>; ExitProcess

修改好这些地方以后,程序正常运行。如果使用时还会退出,用同样的方法解决。

三、破解
(1)爆破:
从注册表中取假注册码:
0042497C     PUSH EAX                 //注册码字符长度保存地址
0042497D     PUSH EBX                 //注册码保存地址
0042497E     PUSH dumped_6.00452818                   ;  ASCII "RegInfoBin"
00424983     CALL dumped_6.00424A5E
........
假注册码计算:
004249B1      PUSH EAX                                 ; /Arg6
004249B2      PUSH 0                                   ; |Arg5 = 00000000
004249B4      PUSH 10                                  ; |Arg4 = 00000010
004249B6      PUSH DWORD PTR DS:[ESI+A4]               ; |Arg3
004249BC      PUSH 10                                  ; |Arg2 = 00000010
004249BE      PUSH EBX                                 ; |Arg1
004249BF      CALL dumped_6.0041EF76                   ; dumped_6.0041EF76

比较:
004249CE     E8 58000000   CALL dumped_6.00424A2B             //比较call
004249D3     85C0          TEST EAX, EAX                      //=0错,=1对  
004249D5     74 1B         JE SHORT dumped_6.004249F2

因此要爆破,只要把 004249D5处改成JMP SHORT dumped_6.004249E2即可。 这段代码中没出现真注册码的明码,是计算后的结果比较。

(1)寻找注册码:
这个软件注册算法很复杂,我没看明白,也不清楚找到的是不是真的注册码,但好像可以用,有兴趣的可以自己试试:
004244BE   PUSH EBX                                 ; /Arg6
004244BF   PUSH ECX                                 ; |Arg5
004244C0   OR DWORD PTR SS:[EBP-4], FFFFFFFF        ; |
004244C4   PUSH 10                                  ; |
004244C6   LEA ECX, DWORD PTR DS:[ESI+90]           ; |
004244CC   POP EDI                                  ; |
004244CD   LEA EAX, DWORD PTR DS:[ESI+24]           ; |
004244D0   PUSH EDI                                 ; |Arg4 => 00000010
004244D1   PUSH ECX                                 ; |Arg3
004244D2   PUSH 8                                   ; |Arg2 = 00000008
004244D4   PUSH EAX                                 ; |Arg1
004244D5   CALL dumped_6.0041F14C                   ; dumped_6.0041F14C

关键call:04244D5  CALL dumped_6.0041F14C,Arg5为保存保存注册码的地址。 

运行过这个call,得到注册码:AACBF24A6CE25E89AE6643DDC496502B
对应的注册ID:A7E4EB4B4A683C9E10ED6CF866F5188E   

pyzpyz
2004.3.31


注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功