• 标 题:Blaze Media Pro5.05脱壳+基本修复CC(int3)+破解
  • 作 者:pyzpyz
  • 时 间:2004年4月22日 11:08
  • 链 接:http://bbs.pediy.com

Blaze Media Pro5.05脱壳(armadillo)+基本修复CC(int3)+破解(一)


Blaze Media Pro 是一款造型新颖,功能齐全的多媒体工具。5.05是它的最新版。它的脱壳不算太难。我搞过它的4.6版、5.03直到5.05版,但cc一直没法搞定。到现在也不能说是完全修复了。我觉得现在的armadillo壳的cc应该没有什么办法可以完美修复。当然这是我个人的看法,请大侠高手们指正。我修复cc的方法完全没有技术性,高手们莫笑啊。

下载地址:google或百度找

工具:ollydbg、ultraedit、winhex、lordpe、ImportREC1.6f等。

平台:winxp


一、脱壳

这个软件是vb编写的,IAT从401000开始。因此不好用mysqladm大侠的方法,但可以使用Ricardo Narvaja或tDasm的方法。Ricardo Narvaja的方法是经典方法,但太麻烦且有限制。这儿我用tDasm的方法(参见文章Armadillo 3_6主程序脱壳)。谢谢tDasm大侠。

先找oep,下he WaitForDebugEvent和he WriteProcessMemory能很快找到oep=41a528。

在OD中重开程序,下硬件断点:he WaitForDebugEvent,运行停住。回到壳空间,查找常数FFFFFFF8,得到结果:

009EAE36   OR EAX, FFFFFFF8
009EAE51   OR EDX, FFFFFFF8
009EAE7A   OR ECX, FFFFFFF8
009EB350   OR EDX, FFFFFFF8
009EB36B   OR ECX, FFFFFFF8
009EB393   OR EAX, FFFFFFF8

在009EAE36上双击,来到这代码处,朝上几行看:


009EADEA    CMP DWORD PTR SS:[EBP-A30], 0     //这就是tDasm大侠文中提到的关键代码。
009EADF1    JL BMP.009EB0A0
009EADF7    MOV ECXDWORD PTR SS:[EBP-A30]
009EADFD    CMP ECXDWORD PTR DS:[A177BC]
009EAE03    JGE BMP.009EB0A0
009EAE09    MOV EDXDWORD PTR SS:[EBP-9BC]
009EAE0F    AND EDX, 0FF
009EAE15    TEST EDXEDX
009EAE17    JE BMP.009EAECA
009EAE1D    PUSH 0
009EAE1F    MOV ESIDWORD PTR SS:[EBP-A30]
009EAE25    SHL ESI, 4
009EAE28    MOV EAXDWORD PTR SS:[EBP-A30]
009EAE2E    AND EAX, 80000007
009EAE33    JNS SHORT BMP.009EAE3A
009EAE35    DEC EAX
009EAE36    OR EAX, FFFFFFF8
009EAE39    INC EAX
009EAE3A    XOR ECXECX

.....

009EAEA4    MOV EDXDWORD PTR DS:[A177AC]
009EAEAA    LEA EAXDWORD PTR DS:[EDX+ESI*4]
009EAEAD    PUSH EAX
009EAEAE    MOV ECXDWORD PTR SS:[EBP-A30]
009EAEB4    PUSH ECX
009EAEB5    CALL BMP.009ECFCA
009EAEBA    ADD ESP, 0C
009EAEBD    AND EAX, 0FF
009EAEC2    TEST EAXEAX


在009EADEA处下一硬件执行断点,运行停住。 按照tDasm的方法,修改代码为:

009EAEBD    INC DWORD PTR DS:[12EB40]
009EAEC3    MOV DWORD PTR DS:[A177C0], 1
009EAECD    JMP BMP.009EADEA
009EAED2    NOP
            

把12EB40处置0,去掉所有硬件断点,并在9eb0a0处下断,运行,停住。好,所有代码都强制解压完成。


如果你是xp系统,那么你可以用DebugActiveProcessStop把子进程和父进程脱开。如果你是2000系统,你就直接dump吧。我这儿脱离子进程:

009EB0A0    PUSH 0D44
009EB0A5    CALL kernel32.DebugActiveProcessStop
009EB0AA    NOP


这时系统会出现错误提示框,你可以选调试(当然事先要把ollydbg设置为just-in-time debuger),或者不理提示,直接打开另一个OD来attach子进程。附加上后程序后,会出错,到不了程序空间。没关系,你要记住代码已经完全解压。ctrl+g,输入41a528,来到oep处。

接下来我们有三件事要做:修复IAT、dump主程序、dump动态解压代码。查一下即知,IAT在401000~40150c。打开ImportREC1.6f,选上子进程看看,只有一个错误指针:13cd485(401064处)。回到OD,ctrl+g来到13cd485处:

013CD485    PUSH EBP
013CD486    MOV EBPESP
013CD488    PUSH -1
013CD48A    PUSH 13EB680
013CD48F    PUSH 13EA7F0                             ; JMP to msvcrt._except_handler3
013CD494    MOV EAXDWORD PTR FS:[0]
013CD49A    PUSH EAX
013CD49B    MOV DWORD PTR FS:[0], ESP
013CD4A2    SUB ESP, 10
013CD4A5    PUSH EBX
013CD4A6    PUSH ESI
013CD4A7    PUSH EDI
013CD4A8    MOV DWORD PTR SS:[EBP-18], ESP
013CD4AB    XOR ESIESI
013CD4AD    PUSH 13F0B48                             ; ASCII "MSVBVM60.DLL"
013CD4B2    CALL DWORD PTR DS:[13EB0C8]              ; kernel32.GetModuleHandleA
013CD4B8    TEST EAXEAX
013CD4BA    JE SHORT 013CD4CA
013CD4BC    PUSH 13F0B3C                             ; ASCII "__vbaEnd"
013CD4C1    PUSH EAX
013CD4C2    CALL DWORD PTR DS:[13EB0CC]              ; kernel32.GetProcAddress
013CD4C8    MOV ESIEAX
013CD4CA    AND DWORD PTR SS:[EBP-4], 0
013CD4CE    TEST ESIESI
013CD4D0    JE SHORT 013CD4E8
013CD4D2    CALL ESI
013CD4D4    JMP SHORT 013CD4E8
013CD4D6    PUSH 1
013CD4D8    POP EAX
013CD4D9    RETN

很显然这是函数__vbaEnd,OK,IAT可以修复了。


下面用lordpe把主程序dump出来吧,但别急着把od关掉。好,再回到OD,alt+m打开内存窗口,找到用户空间的最高段,我这儿是20c0000,大小20000。cltr+g来到这:

020C0000    XCHG ECXESI
020C0002    XCHG EBXECX
020C0004    JPE SHORT 020C0008
020C0006    JPE SHORT 020C001F
020C0008    XCHG EBXECX
020C000A    JA SHORT 020C000E
020C000C    JA SHORT 020C0020
020C000E    XCHG ECXESI
020C0010    PUSH 419D96                              ; JMP to MSVBVM60.__vbaExceptHandler
020C0015    JMP BMP.005FE66B
020C001A    NOT ECX
020C001C    JGE SHORT 020C001E
020C001E    XCHG EAXECX
020C001F    JNB SHORT 020C0021
020C0021    BSWAP EDX
020C0023    JBE SHORT 020C0027
020C0025    JBE SHORT 020C005D
020C0027    NOT EDX
020C0029    XCHG AXCX
020C002B    XCHG SISI
020C002E    XCHG AXCX
020C0030    MOV ECXECX
020C0032    NOT EDX


看看,armadillo把程序中的一部分代码加上垃圾代码移到一动态空间,dump出来的主程序没有这些代码是不可能运行的。因此把这些代码也dump出来吧。

现在的任务就要把这些重组起来。用lordpe在主程序中加一个section,VOffset设置为020C0000,大小设置为10000。用winhex把dump出来的020C0000处代码放回主程序。这样可以保证其中的跳转地址不会改变。具体操作我就不说了,请参考有关的资料。


现在程序脱壳工作已经结束,接下来就是最麻烦的cc修复了。

(二)cc修复

下面我尝试着来修复CC。cc实际上就是int3指令,armadillo把程序中的一些跳转指令改成int3。子进程运行到int3时发生异常,父进程可以捕捉到,然后计算出子进程该不该跳转,如果跳转,跳转量是多少,如果不跳转,下一条指令应从哪里开始。通过getthreadcontext和setthreadcontext函数来干预子进程的运行。因此程序脱壳后,里面的int3指令不修复成原本的跳转指令,程序是不可能运行起来的。

但问题是:脱壳程序中哪些cc是int3指令,哪些cc是数据呢?原先版本的armardillo可以完全区分开来,但现在的版本好像不能够区分,至少我没有找到方法,不知高手们是采用什么办法的。从技术角度来讲,armadillo可以不用区分。我们试想一下:armardillo可以把原程序中所有跳转指令都改成int3,然后连同程序中的cc数据一起进行计算得到一张总表。在加壳时却只随机选一些跳转指令改成int3,但使用的还是那张总表。程序完全可以运行。但我们怎么才能知道总表中哪些是跳转指令呢?我觉得不能,因此也就很难完美修复。

我想到修复的方法有两种,一是在OD中运行加壳程序,设置条件记录断点,然后把程序所有的功能都运行一遍,得到子进程发生int3的地址。二是设计一代码分析器,分析脱壳程序中哪些是int3指令,哪些不是。这两种方法都不能算是完美修复。我的方法是借用OD来找到int3。


我们的目标是得到四个表:int3地址表、跳转类型表、跳转量表及跳转指令长度表。有了这四个表,我们就可以修复cc了。


我们先看第一张int3地址表。在od中打开脱壳程序,从401000~98cfff都是程序的内容,包括代码和资源。armadillo把它们放在同一节中。查找二进制55 8b ec(PUSH EBP  MOV EBPESP)找到代码开始的部分在5fe660。把5fe660~98cfff选上然后复制到文件中,用ultraedit打开文件,选上“列出包含字符串的行”,查找文本int3。ok,找到如下形式的int3:

0060063E    CC              INT3
0060063F    CC              INT3
0060D481    CC              INT3
0060D482    CC              INT3
0060D483    CC              INT3
.....

使用ultraedit的列编辑功能编辑成:

3E 06 60 00 
3F 06 60 00 
81 D4 60 00 
82 D4 60 00 
83 D4 60 00 
84 D4 60 00 
.....

当然这里面有很多都是不符合条件的,是int3原始表。先保存好,下面要用。


在OD中重新打开BMP.exe。下he GetThreadContext,运行,第二次停住时,看堆栈窗:

0012DA78   009EBC88  /CALL to GetThreadContext from BMP.009EBC82
0012DA7C   00000050  |hThread = 00000050 (window)
0012DA80   0012E10C  pContext = 0012E10C

在follow in dump 来到0012E10C。按alt+f9回到用户空间。


0012E1AC  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0012E1BC  00 00 00 00 64 EE 12 00 DC 37 79 00 1B 00 00 00  ....d?.?y....
0012E1CC  46 02 00 00 24 EE 12 00 23 00 00 00 00 00 00 00  F..$?.#.......

12e1c4处的7937dc就是子进程发生的第一个int3地址+1,我们可以用OD把脱壳程序打开看看,运行出的第一个错也是那。 0012E1CC处的246是子进程的Flag寄存器内容。


009EBC82    CALL DWORD PTR DS:[<&KERNEL32.GetThreadC>; 
009EBC88    PUSH EAX                                  //停在这,这条指令到009EBCCA都是垃圾指令
009EBC89    NOT EAX
009EBC8B    BSWAP EAX
009EBC8D    POP EAX
009EBC8E    JNB SHORT BMP.009EBC90
009EBC90    PUSHFD
009EBC91    PUSHAD


009EBCC1    MOV EAX, C80F9D61
009EBCC6    NOT ECX
009EBCC8    BSWAP EAX
009EBCCA    NOT ECX
009EBCCC    MOV DWORD PTR SS:[EBP-1468], 0
009EBCD6    PUSH -1
009EBCD8    PUSH 4
009EBCDA    LEA EDXDWORD PTR SS:[EBP-13AC]         ; [12e1c4]=7937dc,子进程发生int3的地址+1
009EBCE0    PUSH EDX
009EBCE1    CALL BMP.009D4F90                        ; 对int3地址运算
009EBCE6    ADD ESP, 0C
009EBCE9    MOV DWORD PTR SS:[EBP-1194], EAX         ; 运算结果
009EBCEF    MOV EAXDWORD PTR SS:[EBP-1194]
009EBCF5    XOR EDXEDX
009EBCF7    MOV ECX, 10
009EBCFC    DIV ECX                                  ; 运算结果除以10
009EBCFE    MOV DWORD PTR SS:[EBP-1198], EDX         ; 取余数
009EBD04    MOV EDXDWORD PTR SS:[EBP-13AC]         ; int3地址+1
009EBD0A    PUSH EDX
009EBD0B    MOV EAXDWORD PTR SS:[EBP-1198]         ; 前面得到的余数
009EBD11    CALL DWORD PTR DS:[EAX*4+A15838]         ; 再次运算。
009EBD18    ADD ESP, 4
009EBD1B    MOV DWORD PTR SS:[EBP-1468], EAX         ; 运算结果,将用于在table1(int3地址计算结果表)中查找
009EBD21   >MOV DWORD PTR SS:[EBP-146C], 0
009EBD2B    MOV ECXDWORD PTR SS:[EBP-1198]
009EBD31    MOV EDXDWORD PTR DS:[ECX*4+A176D4]
009EBD38    MOV DWORD PTR SS:[EBP-118C], EDX
009EBD3E    MOV EAXDWORD PTR SS:[EBP-146C]
009EBD44    CMP EAXDWORD PTR SS:[EBP-118C]
009EBD4A    JGE SHORT BMP.009EBDA8
009EBD4C    MOV EAXDWORD PTR SS:[EBP-118C]
009EBD52    SUB EAXDWORD PTR SS:[EBP-146C]
009EBD58    CDQ
009EBD59    SUB EAXEDX
009EBD5B    SAR EAX, 1
009EBD5D    MOV ECXDWORD PTR SS:[EBP-146C]
009EBD63    ADD ECXEAX
009EBD65    MOV DWORD PTR SS:[EBP-1470], ECX
009EBD6B    MOV EDXDWORD PTR SS:[EBP-1198]         ; 前面得到的余数
009EBD71    MOV EAXDWORD PTR DS:[EDX*4+A1768C]     ; [A1768C]开始的是table1地址表,根据前面得到的余数找到table1的地址
009EBD78    MOV ECXDWORD PTR SS:[EBP-1470]
009EBD7E    MOV EDXDWORD PTR SS:[EBP-1468]
009EBD84    CMP EDXDWORD PTR DS:[EAX+ECX*4]
009EBD87    JBE SHORT BMP.009EBD9A
009EBD89    MOV EAXDWORD PTR SS:[EBP-1470]
009EBD8F    ADD EAX, 1
009EBD92    MOV DWORD PTR SS:[EBP-146C], EAX
009EBD98    JMP SHORT BMP.009EBDA6
009EBD9A    MOV ECXDWORD PTR SS:[EBP-1470]
009EBDA0    MOV DWORD PTR SS:[EBP-118C], ECX
009EBDA6    JMP SHORT BMP.009EBD3E
009EBDA8    PUSHAD                                   ; eax=查表结果(前面运算结果在table1中的序号)
009EBDA9    NOP                                                              
     
.......                                              //nop掉垃圾指令
                                                         
009EBDCB    NOP                                                              
009EBDCC    NOP                                                              
009EBDCD    POPAD                                                           
009EBDCE    MOV EDXDWORD PTR SS:[EBP-1198]          前面的余数                            
009EBDD4    MOV EAXDWORD PTR DS:[EDX*4+A1768C]     ; table1地址            
009EBDDB    MOV ECXDWORD PTR SS:[EBP-146C]                                 
009EBDE1    MOV EDXDWORD PTR DS:[EAX+ECX*4]                                
009EBDE4    CMP EDXDWORD PTR SS:[EBP-1468]         ; 再比较一下,看是否相等
009EBDEA    JNZ BMP.009EC102                                                 
  
........                                              // 垃圾指令     

 
009EBE47    MOV EAXDWORD PTR SS:[EBP-1198]          前面的余数 
009EBE4D    MOV ECXDWORD PTR DS:[EAX*4+A17714]     ; table2(跳转类型代号表)
009EBE54    MOV EDXDWORD PTR SS:[EBP-146C]
009EBE5A    XOR EAXEAX
009EBE5C    MOV ALBYTE PTR DS:[ECX+EDX]            ; 得到跳转类型代号
009EBE5F    MOV DWORD PTR SS:[EBP-1488], EAX
009EBE65    MOV EAXDWORD PTR SS:[EBP-1488]
009EBE6B    CDQ
009EBE6C    AND EDX, 0F
009EBE6F    ADD EAXEDX
009EBE71    SAR EAX, 4
009EBE74    MOV DWORD PTR SS:[EBP-1480], EAX
009EBE7A    MOV ECXDWORD PTR SS:[EBP-1488]
009EBE80    AND ECX, 8000000F
009EBE86    JNS SHORT BMP.009EBE8D
009EBE88    DEC ECX
009EBE89    OR ECX, FFFFFFF0
009EBE8C    INC ECX
009EBE8D    MOV DWORD PTR SS:[EBP-1484], ECX
009EBE93    MOV EDXDWORD PTR SS:[EBP-1480]
009EBE99    CMP EDXDWORD PTR SS:[EBP-1484]
009EBE9F    JNZ SHORT BMP.009EBEBC
009EBEA1    MOV EAXDWORD PTR SS:[EBP-1484]
009EBEA7    ADD EAX, 1
009EBEAA    AND EAX, 8000000F
009EBEAF    JNS SHORT BMP.009EBEB6
009EBEB1    DEC EAX
009EBEB2    OR EAX, FFFFFFF0
009EBEB5    INC EAX
009EBEB6    MOV DWORD PTR SS:[EBP-1484], EAX
009EBEBC    MOV ECXDWORD PTR SS:[EBP-1488]
009EBEC2    MOV EDXDWORD PTR SS:[EBP-1480]
009EBEC8    MOV EAXDWORD PTR DS:[ECX*4+A16ED0]
009EBECF    XOR EAXDWORD PTR DS:[EDX*4+A1125C]
009EBED6    MOV ECXDWORD PTR SS:[EBP-1484]
009EBEDC    XOR EAXDWORD PTR DS:[ECX*4+A1125C]
009EBEE3    MOV DWORD PTR SS:[EBP-1478], EAX
009EBEE9    MOV EDXDWORD PTR SS:[EBP-13A4]         ; 子进程context的flag寄存器内容
009EBEEF    AND EDX, 0FD7
009EBEF5    PUSH EDX
009EBEF6    MOV EAXDWORD PTR SS:[EBP-1488]         ; 跳转类型代号
009EBEFC    MOVSX ECXBYTE PTR DS:[EAX+A15730]
009EBF03    CALL DWORD PTR DS:[ECX*4+A15838]
009EBF0A    ADD ESP, 4
009EBF0D    MOV DWORD PTR SS:[EBP-1474], EAX
009EBF13    MOV EDXDWORD PTR SS:[EBP-13B8]          子进程context的ecx内容        
009EBF19    PUSH EDX
009EBF1A    MOV EAXDWORD PTR SS:[EBP-1474]
009EBF20    PUSH EAX
009EBF21    CALL DWORD PTR SS:[EBP-1478]
009EBF27    ADD ESP, 8
009EBF2A    PUSH EAX
009EBF2B    MOV ECXDWORD PTR SS:[EBP-1488]
009EBF31    MOVSX EDXBYTE PTR DS:[ECX+A15730]
009EBF38    CALL DWORD PTR DS:[EDX*4+A15878]           
009EBF3F    ADD ESP, 4
009EBF42    MOV DWORD PTR SS:[EBP-147C], EAX
009EBF48    MOV EAXDWORD PTR SS:[EBP-147C]
009EBF4E    AND EAX, 1
009EBF51    TEST EAXEAX                            //经过若干次复杂计算最后得到子进程在7937dc处是跳呢(eax=1),还是不跳(eax=0)
009EBF53    JE BMP.009EC007
009EBF59    PUSHAD


009EBF7E    POPAD                     
009EBF7F    MOV ECXDWORD PTR SS:[EBP-1198]           //如果eax=1,到这
009EBF85    MOV ECXDWORD PTR DS:[ECX*4+A1764C]
009EBF8C    MOV EAXDWORD PTR SS:[EBP-146C]
009EBF92    XOR EDXEDX
009EBF94    MOV ESI, 10
009EBF99    DIV ESI
009EBF9B    MOV EAXDWORD PTR SS:[EBP-146C]
009EBFA1    MOV ECXDWORD PTR DS:[ECX+EAX*4]
009EBFA4    XOR ECXDWORD PTR SS:[EBP+EDX*4-1170]    //得到跳转量
009EBFAB    MOV EDXDWORD PTR SS:[EBP-13AC]           
009EBFB1    ADD EDXECX
009EBFB3    MOV DWORD PTR SS:[EBP-13AC], EDX          //重新设置context



009EC012    MOV EAXDWORD PTR SS:[EBP-1198]          //如果eax=0,到这
009EC018    MOV ECXDWORD PTR DS:[EAX*4+A17758]
009EC01F    MOV EDXDWORD PTR SS:[EBP-146C]
009EC025    XOR EAXEAX
009EC027    MOV ALBYTE PTR DS:[ECX+EDX]             //得到下一条指令的距离
009EC02A    MOV ECXDWORD PTR SS:[EBP-13AC]
009EC030    ADD ECXEAX
009EC032    MOV DWORD PTR SS:[EBP-13AC], ECX         //重新设置context


好,知道这些后,我们要对上段代码进行大修改。
 
下面是修改好的代码:

××××××
009EBC88    PUSH ESP                                   //下面代码修改401000开始的空间读写属性,使得可写。  
009EBC89    PUSH 4
009EBC8B    PUSH BMP.00578000
009EBC90    PUSH BMP.00401000
009EBC95    CALL DWORD PTR DS:[<&KERNEL32.VirtualPro>; kernel32.VirtualProtect
009EBC9B    NOP
            
009EBC9F    NOP
009EBCA0    MOV EAXDWORD PTR DS:[500000]              //[500000]中是原始int3表计数器
009EBCA5    MOV EAXDWORD PTR DS:[EAX*4+401000]        //401000开始放置int3原始表
009EBCAD    TEST EAXEAX            
009EBCAF    JE BMP.009EC045                             //int3原始表到最后?是则结束。
009EBCB5    LEA EDXDWORD PTR SS:[EBP-13AC]
009EBCBB    INC EAX
009EBCBC    MOV DWORD PTR DS:[EDX], EAX
009EBCBE    INC DWORD PTR DS:[500000]
009EBCC4    NOP
××××××


009EBCCB    NOP
009EBCCC    MOV DWORD PTR SS:[EBP-1468], 0
009EBCD6    PUSH -1
009EBCD8    PUSH 4
009EBCDA    LEA EDXDWORD PTR SS:[EBP-13AC]         ;
009EBCE0    PUSH EDX
009EBCE1    CALL BMP.009D4F90                        ;
009EBCE6    ADD ESP, 0C
009EBCE9    MOV DWORD PTR SS:[EBP-1194], EAX         ; 
009EBCEF    MOV EAXDWORD PTR SS:[EBP-1194]
009EBCF5    XOR EDXEDX
009EBCF7    MOV ECX, 10
009EBCFC    DIV ECX                                  ; 
009EBCFE    MOV DWORD PTR SS:[EBP-1198], EDX         ;
009EBD04    MOV EDXDWORD PTR SS:[EBP-13AC]         ;
009EBD0A    PUSH EDX
009EBD0B    MOV EAXDWORD PTR SS:[EBP-1198]         ; 
009EBD11    CALL DWORD PTR DS:[EAX*4+A15838]         ; 
009EBD18    ADD ESP, 4
009EBD1B    MOV DWORD PTR SS:[EBP-1468], EAX         ;
009EBD21    MOV DWORD PTR SS:[EBP-146C], 0
009EBD2B    MOV ECXDWORD PTR SS:[EBP-1198]
009EBD31    MOV EDXDWORD PTR DS:[ECX*4+A176D4]
009EBD38    MOV DWORD PTR SS:[EBP-118C], EDX
009EBD3E    MOV EAXDWORD PTR SS:[EBP-146C]
009EBD44    CMP EAXDWORD PTR SS:[EBP-118C]
009EBD4A    JGE SHORT BMP.009EBDA8
009EBD4C    MOV EAXDWORD PTR SS:[EBP-118C]
009EBD52    SUB EAXDWORD PTR SS:[EBP-146C]
009EBD58    CDQ
009EBD59    SUB EAXEDX
009EBD5B    SAR EAX, 1
009EBD5D    MOV ECXDWORD PTR SS:[EBP-146C]
009EBD63    ADD ECXEAX
009EBD65    MOV DWORD PTR SS:[EBP-1470], ECX
009EBD6B    MOV EDXDWORD PTR SS:[EBP-1198]         ;
009EBD71    MOV EAXDWORD PTR DS:[EDX*4+A1768C]     ;
009EBD78    MOV ECXDWORD PTR SS:[EBP-1470]
009EBD7E    MOV EDXDWORD PTR SS:[EBP-1468]
009EBD84    CMP EDXDWORD PTR DS:[EAX+ECX*4]
009EBD87    JBE SHORT BMP.009EBD9A
009EBD89    MOV EAXDWORD PTR SS:[EBP-1470]
009EBD8F    ADD EAX, 1
009EBD92    MOV DWORD PTR SS:[EBP-146C], EAX
009EBD98    JMP SHORT BMP.009EBDA6
009EBD9A    MOV ECXDWORD PTR SS:[EBP-1470]
009EBDA0    MOV DWORD PTR SS:[EBP-118C], ECX
009EBDA6    JMP SHORT BMP.009EBD3E
009EBDA8    NOP                                      ; 
009EBDA9    NOP
009EBDAA    MOV EDXDWORD PTR SS:[EBP-1198]
009EBDB0    MOV EAXDWORD PTR DS:[EDX*4+A1768C]
009EBDB7    MOV ECXDWORD PTR SS:[EBP-146C]               
009EBDBD    MOV EDXDWORD PTR DS:[EAX+ECX*4]
009EBDC0    CMP EDXDWORD PTR SS:[EBP-1468]
009EBDC6    JNZ BMP.009EBCA0                          //这段代码我把它的位置朝前挪了,修改了跳转量
009EBDCC    NOP
009EBDCD    NOP


××××××
009EBDCE    MOV EAXDWORD PTR DS:[500004]            //符合条件的int3计数器
009EBDD3    LEA EDXDWORD PTR SS:[EBP-13AC]
009EBDD9    MOV EDXDWORD PTR DS:[EDX]
009EBDDB    MOV DWORD PTR DS:[EAX*4+405F00], EDX      //符合条件的int3地址从405F00开始放
009EBDE3    NOP

                                                      //下面这段代码是为了得到跳转类型而增加的,目的是得到009EBF75处我自编函数需要的东西
009EBDEA    NOP                                      
009EBDEB    MOV EAX, BMP.0050000C                    //50000C中是计数器        
009EBDF0    XOR ECXECX
009EBDF2    MOV DWORD PTR DS:[EAX], ECX              //计数器置0              
009EBDF4    MOV DWORD PTR DS:[EAX+4], ECX            //context的ecx=0
009EBDF7    MOV DWORD PTR DS:[EAX+C], ECX             //context的flag=0
009EBDFA    INC ECX
009EBDFB    MOV DWORD PTR DS:[EAX+8], ECX            //context的ecx=1        
009EBDFE    MOV DWORD PTR DS:[EAX+10], ECX           //flag的cf=1
009EBE01    MOV DWORD PTR DS:[EAX+14], 4             //pf=1
009EBE08    MOV DWORD PTR DS:[EAX+18], 40            //zf=1
009EBE0F    MOV DWORD PTR DS:[EAX+1C], 80            //sf=1
009EBE16    MOV DWORD PTR DS:[EAX+20], 800           //of=1
009EBE1D    LEA EAXDWORD PTR SS:[EBP-1464]
009EBE23    MOV ECXDWORD PTR DS:[50000C]             
009EBE29    MOV EDXDWORD PTR DS:[ECX*4+500010]
009EBE31    CMP ECX, 1
009EBE34    JG SHORT BMP.009EBE3E
009EBE36    MOV DWORD PTR DS:[EAX+AC], EDX
009EBE3C    JMP SHORT BMP.009EBE44
009EBE3E    MOV DWORD PTR DS:[EAX+C0], EDX
009EBE44    NOP
××××××

009EBE46    NOP
009EBE47    MOV EAXDWORD PTR SS:[EBP-1198]
009EBE4D    MOV ECXDWORD PTR DS:[EAX*4+A17714]     
009EBE54    MOV EDXDWORD PTR SS:[EBP-146C]
009EBE5A    XOR EAXEAX
009EBE5C    MOV ALBYTE PTR DS:[ECX+EDX]            ; 
009EBE5F    MOV DWORD PTR SS:[EBP-1488], EAX
009EBE65    MOV EAXDWORD PTR SS:[EBP-1488]
009EBE6B    CDQ
009EBE6C    AND EDX, 0F
009EBE6F    ADD EAXEDX
009EBE71    SAR EAX, 4
009EBE74    MOV DWORD PTR SS:[EBP-1480], EAX
009EBE7A    MOV ECXDWORD PTR SS:[EBP-1488]
009EBE80    AND ECX, 8000000F
009EBE86    JNS SHORT BMP.009EBE8D
009EBE88    DEC ECX
009EBE89    OR ECX, FFFFFFF0
009EBE8C    INC ECX
009EBE8D    MOV DWORD PTR SS:[EBP-1484], ECX
009EBE93    MOV EDXDWORD PTR SS:[EBP-1480]
009EBE99    CMP EDXDWORD PTR SS:[EBP-1484]
009EBE9F    JNZ SHORT BMP.009EBEBC
009EBEA1    MOV EAXDWORD PTR SS:[EBP-1484]
009EBEA7    ADD EAX, 1
009EBEAA    AND EAX, 8000000F
009EBEAF    JNS SHORT BMP.009EBEB6
009EBEB1    DEC EAX
009EBEB2    OR EAX, FFFFFFF0
009EBEB5    INC EAX
009EBEB6    MOV DWORD PTR SS:[EBP-1484], EAX
009EBEBC    MOV ECXDWORD PTR SS:[EBP-1488]
009EBEC2    MOV EDXDWORD PTR SS:[EBP-1480]
009EBEC8    MOV EAXDWORD PTR DS:[ECX*4+A16ED0]
009EBECF    XOR EAXDWORD PTR DS:[EDX*4+A1125C]
009EBED6    MOV ECXDWORD PTR SS:[EBP-1484]
009EBEDC    XOR EAXDWORD PTR DS:[ECX*4+A1125C]
009EBEE3    MOV DWORD PTR SS:[EBP-1478], EAX
009EBEE9    MOV EDXDWORD PTR SS:[EBP-13A4]         ;
009EBEEF    AND EDX, 0FD7
009EBEF5    PUSH EDX
009EBEF6    MOV EAXDWORD PTR SS:[EBP-1488]         ;
009EBEFC    MOVSX ECXBYTE PTR DS:[EAX+A15730]
009EBF03    CALL DWORD PTR DS:[ECX*4+A15838]
009EBF0A    ADD ESP, 4
009EBF0D    MOV DWORD PTR SS:[EBP-1474], EAX
009EBF13    MOV EDXDWORD PTR SS:[EBP-13B8]
009EBF19    PUSH EDX
009EBF1A    MOV EAXDWORD PTR SS:[EBP-1474]
009EBF20    PUSH EAX
009EBF21    CALL DWORD PTR SS:[EBP-1478]
009EBF27    ADD ESP, 8
009EBF2A    PUSH EAX
009EBF2B    MOV ECXDWORD PTR SS:[EBP-1488]
009EBF31    MOVSX EDXBYTE PTR DS:[ECX+A15730]
009EBF38    CALL DWORD PTR DS:[EDX*4+A15878]
009EBF3F    ADD ESP, 4
009EBF42    MOV DWORD PTR SS:[EBP-147C], EAX
009EBF48    MOV EAXDWORD PTR SS:[EBP-147C]
009EBF4E    AND EAX, 1
009EBF51    NOP
009EBF52    NOP

×××××××
009EBF53    MOV ECXDWORD PTR DS:[50000C]
009EBF59    MOV DWORD PTR DS:[ECX*4+500010], EAX   //得到的eax从500010开始放。
009EBF61    INC ECX
009EBF62    MOV DWORD PTR DS:[50000C], ECX         //计数器+1
009EBF68    CMP ECX, 7
009EBF6B    JLE BMP.009EBE1D                      //循环8次
009EBF71    NOP
009EBF72    NOP
009EBF73    PUSHAD
009EBF74    PUSHFD
009EBF75    CALL BMP.009EC050                      //我编的判断跳转类型的函数,后面有说明
009EBF7A    POPFD
009EBF7B    POPAD
009EBF7C    NOP
××××××

009EBF7E    NOP
009EBF7F    MOV ECXDWORD PTR SS:[EBP-1198]        
009EBF85    MOV ECXDWORD PTR DS:[ECX*4+A1764C]
009EBF8C    MOV EAXDWORD PTR SS:[EBP-146C]
009EBF92    XOR EDXEDX
009EBF94    MOV ESI, 10
009EBF99    DIV ESI
009EBF9B    MOV EAXDWORD PTR SS:[EBP-146C]
009EBFA1    MOV ECXDWORD PTR DS:[ECX+EAX*4]
009EBFA4    XOR ECXDWORD PTR SS:[EBP+EDX*4-1170]
009EBFAB    NOP
009EBFAC    NOP
009EBFAD    MOV EAXDWORD PTR DS:[500004]        
009EBFB2    MOV DWORD PTR DS:[EAX*4+40FD00], ECX       ;跳转量从40FD00开始放
009EBFBA    NOP
......      
            
009EC011    NOP
009EC012    MOV EAXDWORD PTR SS:[EBP-1198]          
009EC018    MOV ECXDWORD PTR DS:[EAX*4+A17758]
009EC01F    MOV EDXDWORD PTR SS:[EBP-146C]
009EC025    XOR EAXEAX
009EC027    MOV ALBYTE PTR DS:[ECX+EDX]
009EC02A    NOP
009EC02B    NOP
009EC02C    MOV ECXDWORD PTR DS:[500004]
009EC032    MOV BYTE PTR DS:[ECX+414C00], AL            ;不跳,下条指令偏移量从414C00开始放     
009EC038    NOP
009EC039    NOP
009EC03A    INC DWORD PTR DS:[500004]
009EC040    JMP BMP.009EBCA0
009EC045    NOP


说明:

×××××××之间的代码是我添加上去的。

其中call 009EC050是我自己编的判断跳转类型代码,需要8个输入量:yecx0,yecx1,yflag0,ycf1,ypf1,yzf1,ysf1,yof1。
yecx0是context中ecx=0,armadillo计算出的值(1或0,分别表示跳或不跳),yecx1是ecx=1对应的值,其它类似。


代码流程:

if(yecx0 XOR yecx1)  -> JECXZ
else if(ypf0 XOR ypf1)
{
  if(ypf0)    ->JNP
  else        ->JP 
}
else if(yzf0 XOR yzf1)
{
  if(ycf0 XOR ycf1)
    {
    if(yzf0)  ->JNBE
    else      ->JBE
    }
  else if(ysf0 XOR ysf1)
    {
    if(yzf0)  ->JNLE
    else      ->JLE
    }
  else
    {
    if(yzf0)  ->JNE
    else      ->JE
    }
}
else if(ysf0 XOR ysf1)
{
  if(yof0 XOR yof1)
    {
    if(yof0)  ->JNL
    else      ->JL
    }
  else 
    {
    if(ysf0)  ->JNS
    else      ->JS
    }  
}
else if(yof0 XOR yof1)
{
  if(yof0)    ->JNO
  else        ->JO
}
else if(ycf0 XOR ycf1)
{
  if(ycf0)    ->JNB
  else        ->JB
}
else if(yzf0) ->JMP
else          ->NOP

其中yzf0、ysf0、yof0...等于yflag0。


具体代码(中间的nop是预留的,以便增加代码):
 
009EC050    MOV EDIDWORD PTR DS:[500004]         //有效int3的计数器
009EC056    ADD EDI, BMP.0040AE00                 //跳转类型从40AE00开始放
009EC05C    MOV EDX, BMP.0050000C
009EC061    MOV EAXDWORD PTR DS:[EDX+4]
009EC064    MOV EBXDWORD PTR DS:[EDX+8]
009EC067    XOR EBXEAX
009EC069    JE SHORT BMP.009EC07A
009EC06B    NOP
009EC06C    NOP
009EC06D    MOV BYTE PTR DS:[EDI], 0E3            
009EC070    JMP BMP.009EC195
009EC075    NOP
009EC076    NOP
009EC077    NOP
009EC078    NOP
009EC079    NOP
009EC07A    MOV EAXDWORD PTR DS:[EDX+C]
009EC07D    MOV EBXDWORD PTR DS:[EDX+14]
009EC080    XOR EBXEAX
009EC082    JE SHORT BMP.009EC0A1
009EC084    TEST EAXEAX
009EC086    JE SHORT BMP.009EC094
009EC088    NOP
009EC089    NOP
009EC08A    MOV BYTE PTR DS:[EDI], 7B
009EC08D    JMP BMP.009EC195
009EC092    NOP
009EC093    NOP
009EC094    MOV BYTE PTR DS:[EDI], 7A
009EC097    JMP BMP.009EC195
009EC09C    NOP
009EC09D    NOP
009EC09E    NOP
009EC09F    NOP
009EC0A0    NOP
009EC0A1    MOV EBXDWORD PTR DS:[EDX+18]
009EC0A4    XOR EBXEAX
009EC0A6    JE SHORT BMP.009EC109
009EC0A8    NOP
009EC0A9    NOP
009EC0AA    MOV EBXDWORD PTR DS:[EDX+10]
009EC0AD    XOR EBXEAX
009EC0AF    JE SHORT BMP.009EC0CB
009EC0B1    TEST EAXEAX
009EC0B3    JE SHORT BMP.009EC0C1
009EC0B5    NOP
009EC0B6    NOP
009EC0B7    MOV BYTE PTR DS:[EDI], 77
009EC0BA    JMP BMP.009EC195
009EC0BF    NOP
009EC0C0    NOP
009EC0C1    MOV BYTE PTR DS:[EDI], 76
009EC0C4    JMP BMP.009EC195
009EC0C9    NOP
009EC0CA    NOP
009EC0CB    MOV EBXDWORD PTR DS:[EDX+1C]
009EC0CE    XOR EBXEAX
009EC0D0    JE SHORT BMP.009EC0EC
009EC0D2    TEST EAXEAX
009EC0D4    JE SHORT BMP.009EC0E2
009EC0D6    NOP
009EC0D7    NOP
009EC0D8    MOV BYTE PTR DS:[EDI], 7F
009EC0DB    JMP BMP.009EC195
009EC0E0    NOP
009EC0E1    NOP
009EC0E2    MOV BYTE PTR DS:[EDI], 7E
009EC0E5    JMP BMP.009EC195
009EC0EA    NOP
009EC0EB    NOP
009EC0EC    TEST EAXEAX
009EC0EE    JE SHORT BMP.009EC0FC
009EC0F0    NOP
009EC0F1    NOP
009EC0F2    MOV BYTE PTR DS:[EDI], 75
009EC0F5    JMP BMP.009EC195
009EC0FA    NOP
009EC0FB    NOP
009EC0FC    MOV BYTE PTR DS:[EDI], 74
009EC0FF    JMP BMP.009EC195
009EC104    NOP
009EC105    NOP
009EC106    NOP
009EC107    NOP
009EC108    NOP
009EC109    MOV EBXDWORD PTR DS:[EDX+1C]
009EC10C    XOR EBXEAX
009EC10E    JE SHORT BMP.009EC144
009EC110    NOP
009EC111    NOP
009EC112    MOV EBXDWORD PTR DS:[EDX+20]
009EC115    XOR EBXEAX
009EC117    JE SHORT BMP.009EC12D
009EC119    TEST EAXEAX
009EC11B    JE SHORT BMP.009EC126
009EC11D    NOP
009EC11E    NOP
009EC11F    MOV BYTE PTR DS:[EDI], 7D
009EC122    JMP SHORT BMP.009EC195
009EC124    NOP
009EC125    NOP
009EC126    MOV BYTE PTR DS:[EDI], 7C
009EC129    JMP SHORT BMP.009EC195
009EC12B    NOP
009EC12C    NOP
009EC12D    TEST EAXEAX
009EC12F    JE SHORT BMP.009EC13A
009EC131    NOP
009EC132    NOP
009EC133    MOV BYTE PTR DS:[EDI], 79
009EC136    JMP SHORT BMP.009EC195
009EC138    NOP
009EC139    NOP
009EC13A    MOV BYTE PTR DS:[EDI], 78
009EC13D    JMP SHORT BMP.009EC195
009EC13F    NOP
009EC140    NOP
009EC141    NOP
009EC142    NOP
009EC143    NOP
009EC144    MOV EBXDWORD PTR DS:[EDX+20]
009EC147    XOR EBXEAX
009EC149    JE SHORT BMP.009EC162
009EC14B    TEST EAXEAX
009EC14D    JE SHORT BMP.009EC158
009EC14F    NOP
009EC150    NOP
009EC151    MOV BYTE PTR DS:[EDI], 71
009EC154    JMP SHORT BMP.009EC195
009EC156    NOP
009EC157    NOP
009EC158    MOV BYTE PTR DS:[EDI], 70
009EC15B    JMP SHORT BMP.009EC195
009EC15D    NOP
009EC15E    NOP
009EC15F    NOP
009EC160    NOP
009EC161    NOP
009EC162    MOV EBXDWORD PTR DS:[EDX+10]
009EC165    XOR EBXEAX
009EC167    JE SHORT BMP.009EC180
009EC169    TEST EAXEAX
009EC16B    JE SHORT BMP.009EC176
009EC16D    NOP
009EC16E    NOP
009EC16F    MOV BYTE PTR DS:[EDI], 73
009EC172    JMP SHORT BMP.009EC195
009EC174    NOP
009EC175    NOP
009EC176    MOV BYTE PTR DS:[EDI], 72
009EC179    JMP SHORT BMP.009EC195
009EC17B    NOP
009EC17C    NOP
009EC17D    NOP
009EC17E    NOP
009EC17F    NOP
009EC180    TEST EAXEAX
009EC182    JE SHORT BMP.009EC190
009EC184    NOP
009EC185    NOP
009EC186    MOV BYTE PTR DS:[EDI], 0EB
009EC189    JMP SHORT BMP.009EC195
009EC18B    NOP
009EC18C    NOP
009EC18D    NOP
009EC18E    NOP
009EC18F    NOP
009EC190    MOV BYTE PTR DS:[EDI], 90
009EC193    NOP
009EC194    NOP
009EC195    RETN

 
在009EC045处下断,运行之前,记得把int3原始表拷贝到401000开始处。运行停住。从405f00到419b00有四个表:

405f00~40ae00  int3地址表
40ae00~40fd00  跳转类型表
40fd00~414c00  跳转量表
414c00~419b00  跳转命令长度表

把405f00~419b00拷贝下来保存好。接下来要用。

Blaze Media Pro5.05脱壳(armadillo)+基本修复CC(int3)+破解(三)


继续修复cc。

在(二)中我们得到了四张表 :

int3地址表 (实际地址+1)   
跳转类型表      
跳转量表        
跳转命令长度表 (实际长度-1)


在OD中打开已脱壳程序,现在壳已经是垃圾了,我们就用用它的空间吧。把前面保存的连续的四个表拷贝到壳开始的空间,我这儿是9d1000。得到:
9d1000~9d5f00  int3地址表
9d5f00~9dae00  跳转类型表
9dae00~9dfd00  跳转量表
9dfd00~9e4c00  跳转命令长度表


随便找个地方写入下列代码:

009E4C04    XOR ECXECX
009E4C06    MOV EAXDWORD PTR DS:[ECX*4+9D1000]         //取出int3地址
009E4C0E    CMP EAX, 0
009E4C11    JE SHORT dumped_.009E4C80
009E4C13    MOVZX EDXBYTE PTR DS:[ECX+9D5F00]          //跳转类型
009E4C1A    MOV EBXDWORD PTR DS:[ECX*4+9DAE00]         //跳转量
009E4C22    MOVZX EDIBYTE PTR DS:[ECX+9DFD00]          //跳转命令长度
009E4C29    DEC EAX
009E4C2A    INC ECX
009E4C2B    CMP DWORD PTR DS:[EAX], EC8B55CC             //进一步排除无效的int3
009E4C31    JE SHORT dumped_.009E4C06
009E4C33    CMP BYTE PTR DS:[EAX-1], 0CC
009E4C37    JE SHORT dumped_.009E4C06
009E4C39    CMP BYTE PTR DS:[EAX+1], 0CC
009E4C3D    JE SHORT dumped_.009E4C06
009E4C3F    NOP
009E4C40    CMP EDI, 1
009E4C43    JNZ SHORT dumped_.009E4C4E
009E4C45    MOV BYTE PTR DS:[EAX], DL                             //短跳转
009E4C47    DEC BL
009E4C49    MOV BYTE PTR DS:[EAX+1], BL
009E4C4C    NOP
009E4C4D    NOP
009E4C4E    CMP EDI, 5
009E4C51    JNZ SHORT dumped_.009E4C64
009E4C53    MOV BYTE PTR DS:[EAX], 0F                             //条件长跳转
009E4C56    ADD DL, 10
009E4C59    MOV BYTE PTR DS:[EAX+1], DL
009E4C5C    SUB EBX, 5
009E4C5F    MOV DWORD PTR DS:[EAX+2], EBX
009E4C62    NOP
009E4C63    NOP
009E4C64    CMP EDI, 4
009E4C67    JNZ SHORT dumped_.009E4C79
009E4C69    CMP DL, 0EB
009E4C6C    JNZ SHORT dumped_.009E4C79
009E4C6E    MOV BYTE PTR DS:[EAX], 0E9                           //绝对长跳转
009E4C71    SUB EBX, 4
009E4C74    MOV DWORD PTR DS:[EAX+1], EBX
009E4C77    NOP
009E4C78    NOP
009E4C79    JMP dumped_.009E4BFA
009E4C7E    NOP
009E4C7F    NOP
009E4C80    NOP
               
在009E4C04处New origin here,在009E4C80下断,运行停住。修复了大部分int3。把修复好的程序另存为一文件。

现在工作结束了吗?答案是没有。你运行修复的文件看看,还出错。如下代码:


006539B4    85C9            TEST ECXECX
006539B6    CC              INT3
006539B7    7A C7           JPE SHORT dumped_.00653980
006539B9    45              INC EBP
006539BA    FC              CLD
006539BB    2E:0000         ADD BYTE PTR CS:[EAX], AL
006539BE    00CC            ADD AHCL                        //这里的cc也是int3
006539C0    B7 8A           MOV BH, 8A
006539C2    71 0A           JNO SHORT dumped_.006539CE


把006539B6处的int3修复好以后,变成如下代码:

006539B4    85C9               TEST ECXECX
006539B6    75 12              JNZ SHORT dumped_1.006539CA
006539B8    C745 FC 2E000000   MOV DWORD PTR SS:[EBP-4], 2E
006539BF    CC                 INT3
006539C0    B7 8A              MOV BH, 8A
006539C2    71 0A              JNO SHORT dumped_1.006539CE

这时在006539BF处的在OD才显示正确的int3。

怎么办?你得把修复的文件按照(二)(三)中的步骤再来一遍。麻烦吧。经过两次修复后,程序终于可以正常运行了,但有些功能不能用,还没破解。


(三)破解

 破解我就不详细说了。vb程序,挺麻烦的。

 1、功能破解:
                                                                                                                                                                                         
   从401000开始查找unicode码“DAYSLEFT”,在4876b0。在4876c8处有一unicode码“20",改成0即可。                                                                                        
                                                                                                                 
 2、about菜单显示: 
                                                                                            
   从401000开始查找unicode码“Registered to”,在49e904。然后查找命令“push 49e904”可以定位about菜单的代码。     
                                                                                                                 
  00842120    PUSH dumped_c.0049E904                   ; UNICODE "Registered To:  "              
  00842125    PUSH EDX                                                                           
  00842126    MOV EBXDWORD PTR DS:[ESI]                                                        
  00842128    CALL DWORD PTR DS:[<&msvbvm60.__vbaStrCa>; msvbvm60.__vbaStrCat                    
                                                                                                 
  修改:                                                                                         
  00841F4F    JE dumped_c.0084216F        JE->JNE                                                
                                                                                                 
  00841FF2    JE BMP_crac.008420AE        JE->JNE                                               
   
   
   
 pyzpyz
 2004.4.22