星外飞客

突破《up英语通》层层防护(脱壳+父进程+CRC32+去NAG窗口+注册检测)

 

【详细过程】
并不是跟这个软件过不去要这么做,而是太喜欢这个软件了。首先它提供丰富的教程内容,最令我欣赏的是朗读过程一句一句,清清楚楚,标准真人发音,对于学习英语口语和听力的同学来说,这个软件确实是不可多得的。惜没有注册的只能用很少一部分教材,因此,便尝试解开它的算法。但是还没有开始就碰了一脸灰:程序在启动过程中有父进程检测、主程序的CRC32校验、Dll文件的完整性检测加上一个现在还未弄懂的算法注册检测。
算法就暂时不去研究那么多,反而对如何突破它的各种检测很感兴趣。于是就有了下文:

第一步:脱壳
PEid查得:ASPack 2.12 -> Alexey Solodovnikov,压缩壳,很容易就脱掉,这里略过。========================================================================================

第二步:去父进程检测
脱壳后用汉化版OD加载运行,只见OD一闪,就不见了,明显是进行了父进程的检测。以前有过经验,可以用“野猪OD”注入Explorer运行就可以了;但今天偏要用非野猪版本OD弄它。
几种方法可以达到程序检测父进程的过程。

重新OD载入,停在入口处:
005904A4 > $ 55            PUSH EBP                                 ; 加载后OD停在这里
005904A5   . 8BEC          MOV EBP,ESP
005904A7   . 83C4 F0       ADD ESP,-10
005904AA   . 53            PUSH EBX
005904AB   . 56            PUSH ESI
005904AC   . B8 2CFD5800   MOV EAX,p51877_.0058FD2C
005904B1   . E8 D266E7FF   CALL p51877_.00406B88
005904B6   . 8B35 08685A00 MOV ESI,DWORD PTR DS:[5A6808]            ; p51877_.005A7C1C
005904BC   . E8 03FEF1FF   CALL p51877_.004B02C4                    ; 单步到这里,F7进入,否则OD被关闭。
005904C1   . E8 EA00F2FF   CALL p51877_.004B05B0
005904C6   . 84C0          TEST AL,AL
005904C8   . 74 02         JE SHORT p51877_.005904CC
005904CA   >- EB FE         JMP SHORT p51877_.005904CA
005904CC   > 33C9          XOR ECX,ECX

=======================================

004B02C4 /$ 55            PUSH EBP                                 ; 父进程检测过程
004B02C5 |. 8BEC          MOV EBP,ESP                              ; 向下F8单步
004B02C7 |. 81C4 84F8FFFF ADD ESP,-77C
004B02CD |. 53            PUSH EBX

 

……以下省略N代码……

 

004B0347 |. 8D45 F0       LEA EAX,DWORD PTR SS:[EBP-10]
004B034A |. B9 94054B00   MOV ECX,p51877_.004B0594                 ; \explorer.exe
004B034F |. E8 4044F5FF   CALL p51877_.00404794                    ; 获得exoplorer的绝对路径

……以下省略N代码……

 

004B04DF |. E8 B043F5FF   |CALL p51877_.00404894
004B04E4 |. 75 09         |JNZ SHORT p51877_.004B04EF
004B04E6 |. 8B85 CCFEFFFF |MOV EAX,DWORD PTR SS:[EBP-134]
004B04EC |. 8945 F8       |MOV DWORD PTR SS:[EBP-8],EAX            ; 循环读取本程序的进程ID及以Explorer的进程ID
004B04EF |> 8D85 E8FEFFFF |LEA EAX,DWORD PTR SS:[EBP-118]
004B04F5 |. 33C9          |XOR ECX,ECX
004B04F7 |. BA 04010000   |MOV EDX,104
004B04FC |. E8 A72AF5FF   |CALL p51877_.00402FA8
004B0501 |. 8D95 C4FEFFFF |LEA EDX,DWORD PTR SS:[EBP-13C]
004B0507 |. 8BC6          |MOV EAX,ESI
004B0509 |. E8 D6ECFFFF   |CALL p51877_.004AF1E4
004B050E |. 83F8 01       |CMP EAX,1
004B0511 |. 1BDB          |SBB EBX,EBX
004B0513 |. 43            |INC EBX
004B0514 |> 84DB           TEST BL,BL
004B0516 |.^ 0F85 9FFEFFFF \JNZ p51877_.004B03BB
004B051C |. 85F6          TEST ESI,ESI
004B051E |. 76 06         JBE SHORT p51877_.004B0526
004B0520 |. 56            PUSH ESI                                 ; /hObject
004B0521 |. E8 C268F5FF   CALL <JMP.&kernel32.CloseHandle>         ; \CloseHandle
004B0526 |> 3B7D F8       CMP EDI,DWORD PTR SS:[EBP-8]         ; EDI=Explorer进程ID,[EBP-8]=本程序进程ID,在这里进行进程的ID比较
004B0529      74 17         JE SHORT p51877_.004B0542              ; 关键跳转,修改JE为JMP跳过TerminateProcess函数
004B052B |. 6A 00         PUSH 0                                   ; /ExitCode = 0
004B052D |. 8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]             ; |
004B0530 |. 50            PUSH EAX                                 ; |hProcess (父进程ID)
004B0531 |. E8 526CF5FF   CALL <JMP.&kernel32.TerminateProcess>    ; \TerminateProcess
……以下省略N代码……

 

004B057C \. C3            RETN

原理十分简单,循环读取当前所有进程的ID,把Exporer.exe和自身进程ID进行比较,如果相等则通过,否则把父进程关闭,同时把自己关闭。

用Delphi还原即以下:

    {   注意加载TlHelp32.pas单元   }   
    procedure   CheckParentProc;  
    var   //检查自己的进程的父进程  
        Pn:   TProcesseNtry32;  
        sHandle:   THandle;  
        H,   ExplProc,   ParentProc:   Hwnd;  
        Found:   Boolean;  
        Buffer:   array[0..1023]   of   Char;  
        Path:   string;  
        begin  
            H   :=   0;  
            ExplProc   :=   0;  
            ParentProc   :=   0;  
            //得到Windows的目录
            SetString(Path,Buffer,GetWindowsDirectory(Buffer,   Sizeof(Buffer)   -   1));
            Path   :=   UpperCase(Path)   +   ‘\Explorer\.exe’;   //得到Explorer的路径
            sHandle   :=   CreateToolHelp32SnapShot(TH32CS_SNAPALL,   0); //得到所有进程的列表快照    
            Found   :=   Process32First(sHandle,   Pn);   //查找进程  
            while   Found   do   //遍历所有进程  
            begin  
                if   Pn.szExeFile   =   ParamStr(0)   then   //自己的进程  
                begin  
                    ParentProc   :=   Pn.th32ParentProcessID;   //得到父进程的进程ID  
                    H   :=   OpenProcess(PROCESS_ALL_ACCESS,   True,   Pn.th32ParentProcessID); //父进程的句柄    
                end  
                else   if   UpperCase(Pn.szExeFile)   =   Path   then  
                    ExplProc   :=   Pn.th32ProcessID;             //Explorer的PID  
                Found   :=   Process32Next(sHandle,   Pn);   //查找下一个  
            end;  
            //父进程不是Explorer,是调试器……  
            if   ParentProc   <>   ExplProc   then  
            begin  
                TerminateProcess(H,   0);   //杀之!    
                Close; //好在作者没有在这里继续加入病毒代码。
            end;  
        end;

这种伎俩在很多软件自我保护中已经在应用,早已被N多Cracker们研究透,基本上已经失去保护能力了。
========================================================================================

第三步:突破文件大小对比
突破父进程后,重新OD载入,却出现一个大大的红叉叉,如图:

看来这是作者友善的提示,看到它第一反应便猜到它对文件大小或者属性等进行了检测。

于是OD重新加载,在命令行里输入 bp CreateFileA,回车进行内存下断,尝试捕获它读取文件的动作,按F9马上被中断,
总共连续按F9七次,就会出现错误对话框,于是重新载入,bp CreateFileA后按六次F9,停下。然后按Alt+F9回到程序领空。

再按一次 Alt + F10,跳出到以下过程:

0049CE24 /$ 53            PUSH EBX                                 ; 文件大小校验过程
0049CE25 |. 56            PUSH ESI

……以下省略N代码……

0049CF19 |. 8B46 78       MOV EAX,DWORD PTR DS:[ESI+78]
0049CF1C |. E8 1FE9FFFF   CALL p51877_1.0049B840                   ; 对备份文件进行(文件名.dat)大小进行检测
0049CF21 |. 84C0          TEST AL,AL
0049CF23 |. 75 04         JNZ SHORT p51877_1.0049CF29
0049CF25 |> 33C0          XOR EAX,EAX
0049CF27 |. EB 02         JMP SHORT p51877_1.0049CF2B
0049CF29 |> B0 01         MOV AL,1
0049CF2B |> 8846 70       MOV BYTE PTR DS:[ESI+70],AL
0049CF2E |. 807E 38 00    CMP BYTE PTR DS:[ESI+38],0
0049CF32 |. 74 5E         JE SHORT p51877_1.0049CF92               ; 爆破点之一,改为JMP直接跳过错误对话框
0049CF34 |. 807E 3B 00    CMP BYTE PTR DS:[ESI+3B],0
0049CF38 |. 74 58         JE SHORT p51877_1.0049CF92               ; 此处也可以爆
0049CF3A |. 807E 70 00    CMP BYTE PTR DS:[ESI+70],0

……以下省略N代码……

0049CF8A |. 8B00          MOV EAX,DWORD PTR DS:[EAX]
0049CF8C |. 59            POP ECX
0049CF8D |. E8 4AD3FFFF   CALL p51877_1.0049A2DC                   ; 这里弹出错误对话框:“文件被非法修改……”
0049CF92 |> 66:837E 52 00 CMP WORD PTR DS:[ESI+52],0
……以下省略N代码……
0049CFA8 \. C3            RETN

很明显,0049CF32和0049CF38处,只要把JE指令改成JMP即可跳过出错提示,搞定这一关。

========================================================================================

第四步:突破CRC32校验
紧接着继续运行,却发现又弹出一个错误对话框:

看来作者在保护自己软件上真是花了不少心机。

重新加载,运行到上述第三步过程最后, 0049CFA8 处继续跳出该过程,即可来到:
005904F3   . E8 2CC9F0FF   CALL p51877_1.0049CE24                   ; 第三步的文件大小校验过程
005904F8   . 8BC3          MOV EAX,EBX                              ; 继续单步向下。
005904FA   . E8 3931E7FF   CALL p51877_1.00403638
……以下省略N代码……

 

00590517   >- EB FE         JMP SHORT p51877_1.00590517
00590519   > E8 7EFAF1FF   CALL p51877_1.004AFF9C                   ; F8单步过会弹出CRC32校验错误提示,F7进入分析
0059051E   . 84C0          TEST AL,AL
00590520   . 0F84 C2000000 JE p51877_1.005905E8
00590526   . B2 01         MOV DL,1
00590528   . A1 D4AA5700   MOV EAX,DWORD PTR DS:[57AAD4]
0059052D   . E8 2EA6FEFF   CALL p51877_1.0057AB60

F7进入CALL 004AFF9C 处看看,好戏在里面:

004AFF9C /$ 55            PUSH EBP                                 ; 系列文件校验过程
004AFF9D |. 8BEC          MOV EBP,ESP
004AFF9F |. B9 07000000   MOV ECX,7

……以下省略N代码……

004B00B9 |. E8 8A48F5FF   CALL p51877_1.00404948
004B00BE |. 50            PUSH EAX
004B00BF |. E8 10EBFFFF   CALL <JMP.&makelib.FileVerionCheck>      ; 文件版本检查?
004B00C4 |. 59            POP ECX
004B00C5 |. 66:8945 FE    MOV WORD PTR SS:[EBP-2],AX
004B00C9 |> 66:817D FE A0>CMP WORD PTR SS:[EBP-2],4FA0
004B00CF |. 74 5E         JE SHORT p51877_1.004B012F
004B00D1 |. 8D45 D4       LEA EAX,DWORD PTR SS:[EBP-2C]
004B00D4 |. 50            PUSH EAX
004B00D5 |. 8D45 D0       LEA EAX,DWORD PTR SS:[EBP-30]
004B00D8 |. 50            PUSH EAX
004B00D9 |. 68 40024B00   PUSH p51877_1.004B0240                   ; ASCII "anfei.com"
004B00DE |. A1 C04B5A00   MOV EAX,DWORD PTR DS:[5A4BC0]
004B00E3 |. E8 6048F5FF   CALL p51877_1.00404948
004B00E8 |. 50            PUSH EAX
004B00E9 |. E8 06EBFFFF   CALL <JMP.&ToolLIB.ECKeyCode>
004B00EE |. 83C4 08       ADD ESP,8
004B00F1 |. 8945 E0       MOV DWORD PTR SS:[EBP-20],EAX            ; ||
004B00F4 |. C645 E4 06    MOV BYTE PTR SS:[EBP-1C],6               ; ||
004B00F8 |. 8D55 E0       LEA EDX,DWORD PTR SS:[EBP-20]            ; ||
004B00FB |. 33C9          XOR ECX,ECX                              ; ||
004B00FD |. B8 54024B00   MOV EAX,p51877_1.004B0254                ; ||ASCII "%s"
004B0102 |. E8 81A8F5FF   CALL p51877_1.0040A988                   ; |\p51877_1.0040A988
004B0107 |. 8B45 D0       MOV EAX,DWORD PTR SS:[EBP-30]            ; |
004B010A |. 0FB755 FE     MOVZX EDX,WORD PTR SS:[EBP-2]            ; |
004B010E |. 8955 E0       MOV DWORD PTR SS:[EBP-20],EDX            ; |
004B0111 |. C645 E4 00    MOV BYTE PTR SS:[EBP-1C],0               ; |
004B0115 |. 8D55 E0       LEA EDX,DWORD PTR SS:[EBP-20]            ; |
004B0118 |. 33C9          XOR ECX,ECX                              ; |
004B011A |. E8 69A8F5FF   CALL p51877_1.0040A988                   ; \p51877_1.0040A988
004B011F |. 8B55 D4       MOV EDX,DWORD PTR SS:[EBP-2C]
……以下省略N代码……

 

004B01B6 |. B9 80024B00   MOV ECX,p51877_1.004B0280
004B01BB |. E8 D445F5FF   CALL p51877_1.00404794
004B01C0 |> 837D F4 00    CMP DWORD PTR SS:[EBP-C],0
004B01C4 |. 74 2B         JE SHORT p51877_1.004B01F1         ; 关键跳转,改为JMP,跳过下面错误提示
004B01C6 |. 6A 00         PUSH 0
004B01C8 |. 8B45 F4       MOV EAX,DWORD PTR SS:[EBP-C]
004B01CB |. E8 7847F5FF   CALL p51877_1.00404948
004B01D0 |. 8BD0          MOV EDX,EAX
004B01D2 |. B9 88024B00   MOV ECX,p51877_1.004B0288          ; ASCII "Error" //错误对话框出现
004B01D7 |. A1 08685A00   MOV EAX,DWORD PTR DS:[5A6808]
……以下省略N代码……

004B0215 |. E8 9242F5FF   CALL p51877_1.004044AC
004B021A \. C3            RETN

原来只需要把004B01C4处的JE改成JMP跳过错误提示即可突破这一层防线。OK,这时候可以把主程序保存为一个新文件了,暂时命名为p51877_1.exe吧。
试一下直接运行,没问题,没有出现错误对话框了。
========================================================================================

第五步:突破NAG注册窗口提示
虽然没有了错误提示,真正的好戏还在后头,出现了注册窗口,这一关看怎么过?如图:

我的想法并非搞它的算法,而是把这个窗口当NAG窗口来去掉。我们继续在完成上一步后,跳出 CALL 004AFF9C(系列文件校验过程),

来到以下代码我们继续F8前进,看有没有什么新发现:
00590519   > \E8 7EFAF1FF   CALL p51877_1.004AFF9C                  ; F8跳过会弹出CRC32校验错误提示,F7进入分析
0059051E   . 84C0          TEST AL,AL
00590520   . 0F84 C2000000 JE p51877_1.005905E8
……以下省略N代码……

 

00590591   . E8 369BF0FF   CALL p51877_1.0049A0CC
00590596   . 8B0D CC685A00 MOV ECX,DWORD PTR DS:[5A68CC]            ; p51877_1.005A8A14
0059059C   . 8B06          MOV EAX,DWORD PTR DS:[ESI]
0059059E   . 8B15 A40B5800 MOV EDX,DWORD PTR DS:[580BA4]            ; p51877_1.00580BF0
005905A4   . E8 239BF0FF   CALL p51877_1.0049A0CC                   ; F8单步至此,将弹出注册窗口,必须F7进入
005905A9   . 8B0D E0635A00 MOV ECX,DWORD PTR DS:[5A63E0]            ; p51877_1.005A8A1C
005905AF   . 8B06          MOV EAX,DWORD PTR DS:[ESI]

看提示,F8单步至偏移 005905A4 处,将弹出注册窗口。那就F7进入吧,看看怎么弹出窗口:但令人抓狂的是,这个Call 是个巨型CALL,单步F8无数次都未能达到关键处,看来这种靠单步的方法效率很低,必须得想别的办法了。

由于OD在加载程序的时候会提示几个.dll已经被压缩,再加上在主程序里查找ASCII没有查到任何关于注册的信息,因此判断注册函数可能藏在dll文件里,于是目光转移到一个叫toollib.dll的文件中,先把它的壳子脱掉,用 "DLL导出函数查看器”一查,如图

呵呵,别说你不懂英文啊,第6个导出函数“StartForm”是什么意思?当然其它几个函数明显就是注册码加密和解密过程了。 现在只对“StartForm”感兴趣,知道了导出函数名就容易办了。

回到OD,右键菜单“查看”-“查看模块间的调用”,即可查得StartForm函数在主程序中被调用处的偏移。如图

 

有两个,都下断吧。重新载入,一路运行直到下断处:005820CE,纵观这个过程如下:

005820B4 /$ 53            PUSH EBX                                ; NAG窗口弹出过程
005820B5 |. 56            PUSH ESI
005820B6 |. 8BF0          MOV ESI,EAX
005820B8 |. B3 01         MOV BL,1
005820BA |. E8 65D6F2FF   CALL p51877_1.004AF724                   ; 主算法过程,略过
005820BF |. 84C0          TEST AL,AL
005820C1      74 09         JE SHORT p51877_1.005820CC             ; 关键跳转,直跳弹出窗口过程;把它NOP掉或改为JNE
005820C3 |. E8 3CCBF2FF   CALL <JMP.&ToolLIB.CheKeyCode>
005820C8 |. 84C0          TEST AL,AL
005820CA      75 49         JNZ SHORT p51877_1.00582115            ; 关键跳转,改为JMP,直接跳过StartForm过程
005820CC |> 33DB          XOR EBX,EBX
005820CE |. E8 19CBF2FF   CALL <JMP.&ToolLIB.StartForm>
005820D3 |. 83E8 01       SUB EAX,1                                ; Switch (cases 0..2)
005820D6 |. 72 07         JB SHORT p51877_1.005820DF
……以下省略N代码……

00582118 |. 5B            POP EBX
00582119 \. C3            RETN

看来搞定这个NAG也比较轻松,只需修改两个跳转指令:
第一处:005820C1 处的JE 把它NOP掉或改为JNE; 第二处:005820CA 处JNZ 改为JMP,直接跳过(上述两并非标志位),保存文件,重新运行一下保存后的文件,程序一路直达主界面,没有任何提示了,而且标题栏处也没有了“未注册”字样。

========================================================================================

第六步:彻底爆破注册验证过程
虽然标题栏没有了“未注册”字样,但并不代表已经成功注册了,试一下下载一个需要注册才能用的教程来看看,在播放时仍然后提示“请注册软件”等字样。

看来这已经是最后一道防线了。
既然已经出现了文字提示,那就顺藤摸瓜,用文字来查找关键代码处。即可查得以下信息:
 超级字串参考+ , 条目 566 地址=004B30A3 反汇编=MOV EAX,p51877_1.004B336C  文本字串="%s" 为注册用户专用课件或收费课件,%s请您注册软件!
下断在004B30A3 处,前后查看,即可迅速定位关键跳转

……以上省略N行代码……
004B3030   . 50            PUSH EAX
004B3031   . 68 07010001   PUSH 1000107
004B3036   . 68 00020000   PUSH 200
004B303B   . E8 74BBFFFF   CALL <JMP.&makelib.CheckFCH>
004B3040   . 83C4 0C       ADD ESP,0C
004B3043   . 66:85C0       TEST AX,AX
004B3046      76 72         JBE SHORT p51877_1.004B30BA            ; 完美爆破点,改JBE为JMP,跳过CheKeyCode过程
004B3048   . E8 B7BBFFFF   CALL <JMP.&ToolLIB.CheKeyCode>
004B304D   . 84C0          TEST AL,AL

……以下省略N代码……

004B3080   . E8 DF6FF5FF   CALL p51877_1.0040A064
004B3085   . 8B45 B4       MOV EAX,DWORD PTR SS:[EBP-4C]            ; |
004B3088   . 8945 B8       MOV DWORD PTR SS:[EBP-48],EAX            ; |
004B308B   . C645 BC 0B    MOV BYTE PTR SS:[EBP-44],0B              ; |
004B308F   . B8 5C334B00   MOV EAX,p51877_1.004B335C                ; |\n\n\n\n
004B3094   . 8945 C0       MOV DWORD PTR SS:[EBP-40],EAX            ; |
004B3097   . C645 C4 0B    MOV BYTE PTR SS:[EBP-3C],0B              ; |
004B309B   . 8D55 B8       LEA EDX,DWORD PTR SS:[EBP-48]            ; |
004B309E   . B9 01000000   MOV ECX,1                                ; |
004B30A3   . B8 6C334B00   MOV EAX,p51877_1.004B336C                ; |"%s" 为注册用户专用课件或收费课件,%s请您注册软件!
004B30A8   . E8 DB78F5FF   CALL p51877_1.0040A988                   ; \p51877_1.0040A988
004B30AD   . 8B45 C8       MOV EAX,DWORD PTR SS:[EBP-38]
004B30B0   . E8 A7BDFFFF   CALL p51877_1.004AEE5C
004B30B5   . E9 E2010000   JMP p51877_1.004B329C
004B30BA   > 8B45 F8       MOV EAX,DWORD PTR SS:[EBP-8]             ; 004B3046处修改后,程序跳至此,直达成功彼岸
004B30BD   . 83C0 3C       ADD EAX,3C
004B30C0   . 8BD3          MOV EDX,EBX
004B30C2   . E8 1514F5FF   CALL p51877_1.004044DC
004B30C7   . 8BC3          MOV EAX,EBX

最后一道防线也在004B3046处被修改为JMP后成功告破。保存为新文件“完美爆破.exe”,运行,没有任何错误,而且已经是完美注册版了。

来个总结吧:程序脱壳后修改以下几个地方即可完美告破:
1、004B0529 处 JE SHORT p51877_.004B0542   ; 关键跳转,修改JE为JMP跳过TerminateProcess函数;
2、0049CF32 处 JE SHORT p51877_1.0049CF92 ; 爆破点之一,改为JMP直接跳过错误对话框
3、004B01C4 处 JE SHORT p51877_1.004B01F1 ; 关键跳转,改为JMP,跳过下面错误提示。
4、005820C1 处 JE SHORT p51877_1.005820CC ; 关键跳转,直跳弹出窗口过程;把它NOP掉或改为JNE。
   005820CA 处 JNZ SHORT p51877_1.00582115 ; 关键跳转,改为JMP,直接跳过StartForm过程
5、004B3046 处 JBE SHORT p51877_1.004B30BA ; 完美爆破点,改JBE为JMP,跳过CheKeyCode过程

到此,可以做一个文件型补丁,或者内存补丁了,留给大家去做。还有它的算法,大侠们帮忙分析吧。

版权所有,转载请注明出处。
转载自 <a href="http://www.yanghengfei.com/archives/158/" title="突破《UP英语通》层层防护" rel="bookmark">突破《UP英语通》层层防护 | 星外飞客 </a>

我简单说几句

随机推荐

最新评论

无觅相关文章插件,快速提升流量