• 标 题:Armadillo v3.01标准加壳方式的脱壳--Konvertor V3.30
  • 作 者:FTBirthday
  • 时 间:2004-1-13 周二, 下午11:00
  • 链 接:http://bbs.pediy.com

FTBirthday的Armadillo全程教程--第一章.标准加壳方式

第一章.标准加壳方式

 

[实例解析三] Armadillo v3.01标准加壳方式的脱壳--Konvertor V3.30 

 

※软件简介※: Konvertor V3.30是一个图片、音乐、文字及影音格式文件的转换程序,它总共可以转换135种文件格式,包含25种音乐格式、4种影音格式、105种图片格式及1种文字格式。

软件大小:6439 KB

软件语言:英文

软件类别:国外软件 / 共享版 / 图像转换

运行环境:Win98/NT/2000/XP/

软件添加:乱马

下载次数:1356

开 发 商:http://www.logipole.com/download_konv_us.htm

下载页面:http://www.downxp.com/soft/2638.htm

 
※软件限制※:The shareware version of this software can be freely used for 30 days.

You will have to register next.


 
※破解工具※:Ollydbg1.09、FI 3.01、DriverSuite2.7中的softice4.2.7 

 
※※※※※※※※※※※※※※※※开始吧※※※※※※※※※※※※※※※※※※

FI 3.01侦测知Armadillo v3.01加壳


 
记得jwh51在Armadillo标准加壳的程序的脱壳和引入表修复方案中说:"用过ARMADILLO的人都知道,用它加壳有两种方式,一是使用COPYMEMII,一是标准加壳.用COPYMEMII的一般可用DILLODUMP脱(当然也有时脱不了),而用标准加壳用DILLODUMP是脱不了的."

 

Konvertor V3.30采用了Armadillo标准加壳。有30天试用期。并且在程序退出时出现提示框。所以,如果脱了壳,上述现象都将没有了.现在开始脱壳历程.!! 

 
如何DUMP(转储)Konvertor v3.30

 
第一步,扫除障碍

 

[障碍一]挫败anti-debug代码, 

用OLLYDBG载入程序.在调试选项中忽略所有异常,这样可以少按SHIFT+F9.

[方法一]

用IsDebug 1.4插件去掉Ollydbg的调试器标志。

[方法二] 重新设置检测IsDebuggerPresent API的那个字节!

Bp IsDebuggerPresent



现在按F9运行程序,当遇到异常,一直按SHIFT+F7或者F8,直到中断于



在这张图中我们可以看到OllyDBG中断在API IsDebuggerPresent(红色), 然后按F7步进到第三行(白色) 77E52749 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2]

一旦我到达那儿,看一下disassembly,在那儿我们可以看到的内容如下图:



这儿我们可以看到在我的机器中偏移是7ffdf002,包含了值01.这个地址在其它机器中可能会不同. 值01意味着调试器被检测到了,所以写下这个地址,在任何时候我们在ollydbg中运行程序,都必须改变它为00,从而避免被packer检测到.记住改变此值为00在任何时候在ollydbg中运行或重运行程序. 记下这个地址,以后经常会用到的。

我们将以重启ollydbg (ctrl+F2)来结束第一步,到转储窗口(DUMP)单击右键选择"前往 表达" 7ffdf002或者其它任何先前你记下的地址,然后改变它的值从01变为00.

[障碍二]击败检测系统时间的代码

如果系统时间在安装SoundEdit Pro后修改过,程序会检测到,并警告修改系统时间而退出程序. 在我安装完Konvertor V3.30后,我改了一下系统时间,在启动时Konvertor V3.30就提示发现时间不对,需要从作者那儿得到帮助.


如下方法可挫败它的这个保护。打开softice4.2.7,ctrl+D调出softice

bpx getlocaltime

g回来点击ok按键,中断两次后,先别忙g退出.

经过测试内存地址00CB4677处的test al,al是关键,所以bpx 00CB4677再g.

(((( 

00CB4672   E8 08060000      CALL 00CB4C7F 

00CB4677   84C0             TEST AL,AL      ====>走到这里将AL改为00000000即可  

00CB4679   74 1C            JE SHORT 00CB4697 

00CB467B   E8 56050000      CALL 00CB4BD6   ====>这个call警告修改系统时间

))))

中断后,R EAX 00000000修改寄存器EAX的值为0,然后BC *清除所有断点.

先别忙退出,继续BPX VirtualProtect.至此击败它了.

 

第二步: BP WaitForDebugEvent寻找API report

这一步并非必要,但却是一个好的选择,当它停止时在dump区看到API report。

首先我们需要在命令行输入BP WaitForDebugEvent,现在运行它,当它停下时我们可以在Stack 窗口看到关于这个API的所有参数信息。 

 

0012DAC4   00984B44  /CALL to WaitForDebugEvent

0012DAC8   0012EB74  |pDebugEvent = 0012EB74

0012DACC   000003E8  \Timeout = 1000. ms

 

看一下第二行。那儿我们可以看到它将在哪儿显示report,所以到dump窗口, 右键选择 "前往 表达"= 12EB74。注意这个值在一些机器上可能会不同,所以前往你的机器显示的值。

 

0012EB74  9C EB 12 00 C0 EB 12 00  滊.离.12

0012EB7C  00 00 00 00 90 FE 12 00  ....慆.0

0012EB84  9C 00 00 00 89 46 99 00  ?..塅? 00

0012EB8C  00 00 00 00 D8 EC 12 00  ....仂.0

0012EB94  F7 C6 E5 77 D0 EC 12 00  髌鍂徐. E5

0012EB9C  00 00 00 00 00 00 00 00  ........

 

我们在上面的图中看到的是我们将要称之为"API report"的东西。父进程通过那里得知子进程发生了什么。现在我们可以很容易地通过在命令行输入BC WaitForDebugEvent来删除这个断点。所有的操作都是为了在dump窗口看到report,在这个report中我们可以看到入口点OEP。 

 

第三步: 寻找子进程入口点

[方法一],BP WRITEPROCESSMEMORY(使用OLLYDBG)

Bp WriteProcessMemory停下时在STACK窗口看到:

0012D964   0098867F  /CALL to WriteProcessMemory from Konverto.00988679

0012D968   00000050  |hProcess = 00000050

0012D96C   004BA000  |Address = 4BA000

0012D970   003B51D0  |Buffer = 003B51D0

0012D974   00001000  |BytesToWrite = 1000 (4096.)

0012D978   0012DA80  \pBytesWritten = 0012DA80

这些信息被保存在父进程的一个缓冲区从3B51D0开始,然后它会复制给子进程一个从4BA000开始的 1000 bytes的块,所以如果我们到了这一步,我们可以很容易理解子进程的第一个section是完全空的,所以当它试图执行到OEP时,它报告一个错误因为那儿没有任何东西,所以 父进程得到了通知正如我们可以在父进程的report中看到的,所以它停止了运行,复制必要的数据块,然后继续运行直到下一个错误。被复制的数据块的大小是1000 bytes,所以当程序试图执行任何超过这个大小的块外的指令时, 另一个错误将会发生,然后这个错误会被通知给父进程, 父进程会复制另外1000 bytes的块然后继续。 

顺便说一下,我们可以假设第一个错误发生是因为子进程call了它的入口点OEP,它的值应该就在API report上。显然OEP的值必定在第一个块,父进程复制过去来解决子进程报告的错误。

这个块从4BA000开始直到4BAFFF。OEP值必定在这些值中。 让我们看一下API report。看dump窗口我们先前已经知道了指向report的指针12EB74。

0012EB74  01 00 00 00 98 03 00 00  ...?..0

0012EB7C  D4 05 00 00 01 00 00 80  ?....0

0012EB84  00 00 00 00 00 00 00 00  ........

0012EB8C  97 A6 4B 00 02 00 00 00  棪K.[1]...B

0012EB94  00 00 00 00 97 A6 4B 00  ....棪K.0

0012EB9C  97 A6 4B 00 00 00 00 00  棪K.....B

0012EBA4  01 85 54 E1 10 01 00 00  匱?..54

太好了!在那儿我们至少看到了三次这个值: 4BA697。数学课告诉我4BA697比4BA000大,比4BAFFF小 (那些是父进程试图拷贝给子进程的那个块的起止值)所以我可以确信4BA697就是子进程的OEP。

 [方法二],bpx SetProcessWorkingSetSize(使用DriverSuite2.7中的softice4.2.7)

标准的流程,下bpx SetProcessWorkingSetSize去找OEP 一旦softice中断了,检查softice是否在Get Right的领空,如果不在则按F5直到softice在Get Right 的领空中断。然后按F12辅之以F10跟踪过去一些指令,直到你看到一个"call edi"指令,停在那儿,然后写下edi的值。那就是OEP。

按三下F12 返回

……

001B:00981739  PUSH      EAX

001B:0098173A  CALL      [009B1EA8]     ;这个CALL进入

001B:00981740  MOV       EAX,[EBP-1C]

……

……

001B:0109EEE2  XOR       ECX,[EAX+6C]

001B:0109EEE5  XOR       ECX,[EAX]

001B:0109EEE7  SUB       EDI,ECX

001B:0109EEE9  CALL      EDI             ;到了这里,EDI的值就是OEP=004BA697

001B:0109EEEB  MOV       EBX,EAX

001B:0109EEED  POP       EDI

001B:0109EEEE  MOV       EAX,EBX

001B:0109EEF0  POP       ESI

001B:0109EEF1  POP       EBX

001B:0109EEF2  RET

注意:copy-mem II加壳方式找OEP有三种方法,标准加壳只有两种,标准加壳不能用CreateProcessA方法。因为只有copy-mem II加壳方式的父进程通过CreateProcessA产生另外一个进程即子进程。

第四步,DUMP出程序

标准的流程如下, 下bpx VirtualProtect去找OEP一旦softice中断了,检查softice是否在

Konvertor的领空,如果不在则按F5直到softice在Konvertor的领空中断.然后按F12辅之以F10跟踪过去一些指令,直到你看到一个"call EDI"指令,停在那儿,然后写下EDI的值.那就是OEP.

具体如下:

运行softice4.2.7, ctrl+D调出softice, BPX VirtualProtect.到中断124次时程序运行了,重新来一遍,当在123次出现中断在VirtualProtect时停下(好累啊,也好晕啊),BC *清除所有断点,然后按F10单步返回到主程序. 再耐心地用F10单步走,因为有一堆的JMP,JNZ,JO等,用不了多久的就可来到这:

001B:009815EA  C705B01E9B0006000000MOV       DWORD PTR [009B1EB0],00000006

001B:009815F4  FF1568C19A00        CALL      [009AC168]    ,这个CALL用F8跟进

在009815F4这个CALL用F8跟进,然后继续F10,几次后就来到这:

001B:0109EEDF  8B487C              MOV       ECX,[EAX+7C]

001B:0109EEE2  33486C              XOR       ECX,[EAX+6C]

001B:0109EEE5  3308                XOR       ECX,[EAX]

001B:0109EEE7  2BF9                SUB       EDI,ECX

001B:0109EEE9  FFD7                CALL      EDI  =====>EDI=004BA697

dump取内存中己脱壳的文件

0109EEE9  FFD7                CALL      EDI

现在这一行,键入以下命令: 

a eip (然后按回车)

jmp eip (然后按回车) 

按下F5 

这样将改变001B:0109EEE9行的代码. 你会注意到在键入"jmp eip"并按下回车后, 0109EEE9的指令现在是一个jmp.这将有效地使程序"暂停"(有点类似TRW2000的suspend命令). 按下F5使你回到window XP。运行LordPE,在进程列表中选择" Konvertor.exe"然后点击鼠标

右键选中"Dump (Full)",给脱壳的程序起名dump存盘.

知道了OEP那就bpm 004BA697 

001B:0098737D  6A00                PUSH      00

001B:0098737F  8B4D0C              MOV       ECX,[EBP+0C]

001B:00987382  51                  PUSH      ECX

001B:00987383  8B5508              MOV       EDX,[EBP+08]

001B:00987386  52                  PUSH      EDX

001B:00987387  E847030000          CALL      009876D3

001B:0098738C  83C40C              ADD       ESP,0C

001B:0098738F  25FF000000          AND       EAX,000000FF

001B:00987394  85C0                TEST      EAX,EAX

001B:00987396  7507                JNZ       0098739F

第五步, 修复输入表

一般步骤如下:

(1)找被脱壳的入口点(OEP);

(2)完全Dump目标文件;

(3)运行Import REConstructor和需要脱壳的应用程序;

(4)在Import REConstructor下拉列表框中选择应用程序进程; 

(5)在左下角填上应用程序的真正入口点偏移(OEP);

(6)按"IAT AutoSearch"按钮,让其自动检测IAT位置,出现"Found address which may be in the Original IAT.Try 'Get Import'"对话框,这表示输入的OEP发挥作用了。

(7)按"Get Import"按钮,让其分析IAT结构得到基本信息;

(8)如发现某个DLL显示"valid :NO" ,按"Show Invalids"按钮将分析所有的无效信息,在Imported Function Found栏中点击鼠标右键,选择"Trace Level1 (Disasm)",再按"Show Invalids"按钮。如果成功,可以看到所有的DLL都为"valid:YES"字样; 

(9)再次刷新"Show Invalids"按钮查看结果,如仍有无效的地址,继续手动用右键的Level 2或3修复;

(10)如还是出错,可以利用"Invalidate function(s)"、"Delete thunk(s)"、编辑Import表(双击函数)等功能手动修复。

(11)开始修复已脱壳的程序。选择Add new section (缺省是选上的) 来为Dump出来的文件加一个Section(虽然文件比较大,但避免了许多不必要的麻烦) 。

(12)按"Fix Dump"按钮,并选择刚在(2)步Dump出来的文件,在此不必要备份。如修复的文件名是"Dump.exe",它将创建一个"Dump_.exe",此外OEP也被修正。

(13)生成的文件可以跨平台运行。

在Import REConstructor v1.4.2+ 的 Attach to an Active Process 窗口中选取加壳程序的进程,有2个进程选上面的一个,然后在下方的oep处填入000BA697,点IAI AutoSearch,再点Get Imports,然后点 Auto Trace,然后点看还有多少地址是NO,剩下的事就是手动找这些函数了.  

hying大哥说过  CreateEventW   GetStringTypeA  如果发现这两个函数连续在一起的话,上面一个该改为GetStringTypeW  手工修复修入表后,程序应能运行了,好像也就不用注册了,因为注册部分在壳中,壳脱了注册也就不用了.这程序的输入表我是手工找到一部分,然后参照hying大哥给我的Konvertor 3.12A的输入表修复的.先用importREC试试,输入我们找到的正确的OEP: 004BA697,注意输入004BA697-00400000=000BA697有很多指针无效。

这里现不要bpx GetModuleHandleA,否则会被发现的,我想可能在unpack前程序会检测,所以要是能在程序开始unpack后再设断多好,怎么做呢,这样,先bpx SetProcessWorkingSetSize

断下来之后再bpx GetModuleHandleA按F12没几次就到了如下

001B:01085B86  FF15AC800A01        CALL      [KERNEL32!GetModuleHandleA]

001B:01085B8C  394508              CMP       [EBP+08],EAX

001B:01085B8F  7507                JNZ       01085B98

001B:01085B91  B968B40A01          MOV       ECX,010AB468

001B:01085B96  EB52                JMP       01085BEA

001B:01085B98  393D68BA0A01        CMP       [010ABA68],EDI

001B:01085B9E  B968BA0A01          MOV       ECX,010ABA68

001B:01085BA3  0F8491000000        JZ        01085C3A  ======>magic jump!

001B:01085BA9  8B35581C0B01        MOV       ESI,[010B1C58]

001B:01085BAF  A1085D0B01          MOV       EAX,[010B5D08]

001B:01085BB4  F6410801            TEST      BYTE PTR [ECX+08],01

001B:01085BB8  740E                JZ        01085BC8

001B:01085BBA  8B507C              MOV       EDX,[EAX+7C]

001B:01085BBD  335070              XOR       EDX,[EAX+70]

001B:01085BC0  33501C              XOR       EDX,[EAX+1C]

001B:01085BC3  F6C280              TEST      DL,80

001B:01085BC6  7513                JNZ       01085BDB

001B:01085BC8  8B507C              MOV       EDX,[EAX+7C]

001B:01085BCB  335078              XOR       EDX,[EAX+78]

001B:01085BCE  335068              XOR       EDX,[EAX+68]

001B:01085BD1  335004              XOR       EDX,[EAX+04]

001B:01085BD4  3316                XOR       EDX,[ESI]

001B:01085BD6  395508              CMP       [EBP+08],EDX

001B:01085BD9  740C                JZ        01085BE7

001B:01085BDB  83C10C              ADD       ECX,0C

001B:01085BDE  83C604              ADD       ESI,04

001B:01085BE1  3939                CMP       [ECX],EDI

001B:01085BE3  75CF                JNZ       01085BB4

这里面有几个跳转,其中最后一个01085BB4是往上跳的.我们看一个就可发现:   

001B:01085BA3  0F8491000000  JZ 01085C3A,这个跳正好可跳出这个循环.只要改这个跳,就不会破坏引入表了. 再来, 注意刚回到那段代码时,就下a 01085BA3 将JZ 01085C3A改成JMP  01085C3A,清除所有断点,按F5运行,程序运行后打开importREC,选中程序(注意选择上面那个进程),入口填入OEP: 004BA697 ,-->RVA005AC000 SIZE00000214-->获得输入信息"。

如果还有无效的大可放心的cut,因为它们本来就不是有用指针了.然后修复脱壳后的文件.OK,大功告成.脱壳后的程序,运行正常,圆满成功.