Blaze Media Pro5.05脱壳(armadillo)+基本修复CC(int3)+破解(一)
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 ECX, DWORD PTR SS:[EBP-A30]
009EADFD CMP ECX, DWORD PTR DS:[A177BC]
009EAE03 JGE BMP.009EB0A0
009EAE09 MOV EDX, DWORD PTR SS:[EBP-9BC]
009EAE0F AND EDX, 0FF
009EAE15 TEST EDX, EDX
009EAE17 JE BMP.009EAECA
009EAE1D PUSH 0
009EAE1F MOV ESI, DWORD PTR SS:[EBP-A30]
009EAE25 SHL ESI, 4
009EAE28 MOV EAX, DWORD 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 ECX, ECX
.....
009EAEA4 MOV EDX, DWORD PTR DS:[A177AC]
009EAEAA LEA EAX, DWORD PTR DS:[EDX+ESI*4]
009EAEAD PUSH EAX
009EAEAE MOV ECX, DWORD PTR SS:[EBP-A30]
009EAEB4 PUSH ECX
009EAEB5 CALL BMP.009ECFCA
009EAEBA ADD ESP, 0C
009EAEBD AND EAX, 0FF
009EAEC2 TEST EAX, EAX
在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 EBP, ESP
013CD488 PUSH -1
013CD48A PUSH 13EB680
013CD48F PUSH 13EA7F0 ; JMP to msvcrt._except_handler3
013CD494 MOV EAX, DWORD 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 ESI, ESI
013CD4AD PUSH 13F0B48 ; ASCII "MSVBVM60.DLL"
013CD4B2 CALL DWORD PTR DS:[13EB0C8] ; kernel32.GetModuleHandleA
013CD4B8 TEST EAX, EAX
013CD4BA JE SHORT 013CD4CA
013CD4BC PUSH 13F0B3C ; ASCII "__vbaEnd"
013CD4C1 PUSH EAX
013CD4C2 CALL DWORD PTR DS:[13EB0CC] ; kernel32.GetProcAddress
013CD4C8 MOV ESI, EAX
013CD4CA AND DWORD PTR SS:[EBP-4], 0
013CD4CE TEST ESI, ESI
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 ECX, ESI
020C0002 XCHG EBX, ECX
020C0004 JPE SHORT 020C0008
020C0006 JPE SHORT 020C001F
020C0008 XCHG EBX, ECX
020C000A JA SHORT 020C000E
020C000C JA SHORT 020C0020
020C000E XCHG ECX, ESI
020C0010 PUSH 419D96 ; JMP to MSVBVM60.__vbaExceptHandler
020C0015 JMP BMP.005FE66B
020C001A NOT ECX
020C001C JGE SHORT 020C001E
020C001E XCHG EAX, ECX
020C001F JNB SHORT 020C0021
020C0021 BSWAP EDX
020C0023 JBE SHORT 020C0027
020C0025 JBE SHORT 020C005D
020C0027 NOT EDX
020C0029 XCHG AX, CX
020C002B XCHG SI, SI
020C002E XCHG AX, CX
020C0030 MOV ECX, ECX
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 EBP, ESP)找到代码开始的部分在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 EDX, DWORD 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 EAX, DWORD PTR SS:[EBP-1194]
009EBCF5 XOR EDX, EDX
009EBCF7 MOV ECX, 10
009EBCFC DIV ECX ; 运算结果除以10
009EBCFE MOV DWORD PTR SS:[EBP-1198], EDX ; 取余数
009EBD04 MOV EDX, DWORD PTR SS:[EBP-13AC] ; int3地址+1
009EBD0A PUSH EDX
009EBD0B MOV EAX, DWORD 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 ECX, DWORD PTR SS:[EBP-1198]
009EBD31 MOV EDX, DWORD PTR DS:[ECX*4+A176D4]
009EBD38 MOV DWORD PTR SS:[EBP-118C], EDX
009EBD3E MOV EAX, DWORD PTR SS:[EBP-146C]
009EBD44 CMP EAX, DWORD PTR SS:[EBP-118C]
009EBD4A JGE SHORT BMP.009EBDA8
009EBD4C MOV EAX, DWORD PTR SS:[EBP-118C]
009EBD52 SUB EAX, DWORD PTR SS:[EBP-146C]
009EBD58 CDQ
009EBD59 SUB EAX, EDX
009EBD5B SAR EAX, 1
009EBD5D MOV ECX, DWORD PTR SS:[EBP-146C]
009EBD63 ADD ECX, EAX
009EBD65 MOV DWORD PTR SS:[EBP-1470], ECX
009EBD6B MOV EDX, DWORD PTR SS:[EBP-1198] ; 前面得到的余数
009EBD71 MOV EAX, DWORD PTR DS:[EDX*4+A1768C] ; [A1768C]开始的是table1地址表,根据前面得到的余数找到table1的地址
009EBD78 MOV ECX, DWORD PTR SS:[EBP-1470]
009EBD7E MOV EDX, DWORD PTR SS:[EBP-1468]
009EBD84 CMP EDX, DWORD PTR DS:[EAX+ECX*4]
009EBD87 JBE SHORT BMP.009EBD9A
009EBD89 MOV EAX, DWORD PTR SS:[EBP-1470]
009EBD8F ADD EAX, 1
009EBD92 MOV DWORD PTR SS:[EBP-146C], EAX
009EBD98 JMP SHORT BMP.009EBDA6
009EBD9A MOV ECX, DWORD 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 EDX, DWORD PTR SS:[EBP-1198] 前面的余数
009EBDD4 MOV EAX, DWORD PTR DS:[EDX*4+A1768C] ; table1地址
009EBDDB MOV ECX, DWORD PTR SS:[EBP-146C]
009EBDE1 MOV EDX, DWORD PTR DS:[EAX+ECX*4]
009EBDE4 CMP EDX, DWORD PTR SS:[EBP-1468] ; 再比较一下,看是否相等
009EBDEA JNZ BMP.009EC102
........ // 垃圾指令
009EBE47 MOV EAX, DWORD PTR SS:[EBP-1198] 前面的余数
009EBE4D MOV ECX, DWORD PTR DS:[EAX*4+A17714] ; table2(跳转类型代号表)
009EBE54 MOV EDX, DWORD PTR SS:[EBP-146C]
009EBE5A XOR EAX, EAX
009EBE5C MOV AL, BYTE PTR DS:[ECX+EDX] ; 得到跳转类型代号
009EBE5F MOV DWORD PTR SS:[EBP-1488], EAX
009EBE65 MOV EAX, DWORD PTR SS:[EBP-1488]
009EBE6B CDQ
009EBE6C AND EDX, 0F
009EBE6F ADD EAX, EDX
009EBE71 SAR EAX, 4
009EBE74 MOV DWORD PTR SS:[EBP-1480], EAX
009EBE7A MOV ECX, DWORD 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 EDX, DWORD PTR SS:[EBP-1480]
009EBE99 CMP EDX, DWORD PTR SS:[EBP-1484]
009EBE9F JNZ SHORT BMP.009EBEBC
009EBEA1 MOV EAX, DWORD 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 ECX, DWORD PTR SS:[EBP-1488]
009EBEC2 MOV EDX, DWORD PTR SS:[EBP-1480]
009EBEC8 MOV EAX, DWORD PTR DS:[ECX*4+A16ED0]
009EBECF XOR EAX, DWORD PTR DS:[EDX*4+A1125C]
009EBED6 MOV ECX, DWORD PTR SS:[EBP-1484]
009EBEDC XOR EAX, DWORD PTR DS:[ECX*4+A1125C]
009EBEE3 MOV DWORD PTR SS:[EBP-1478], EAX
009EBEE9 MOV EDX, DWORD PTR SS:[EBP-13A4] ; 子进程context的flag寄存器内容
009EBEEF AND EDX, 0FD7
009EBEF5 PUSH EDX
009EBEF6 MOV EAX, DWORD PTR SS:[EBP-1488] ; 跳转类型代号
009EBEFC MOVSX ECX, BYTE 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 EDX, DWORD PTR SS:[EBP-13B8] 子进程context的ecx内容
009EBF19 PUSH EDX
009EBF1A MOV EAX, DWORD PTR SS:[EBP-1474]
009EBF20 PUSH EAX
009EBF21 CALL DWORD PTR SS:[EBP-1478]
009EBF27 ADD ESP, 8
009EBF2A PUSH EAX
009EBF2B MOV ECX, DWORD PTR SS:[EBP-1488]
009EBF31 MOVSX EDX, BYTE 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 EAX, DWORD PTR SS:[EBP-147C]
009EBF4E AND EAX, 1
009EBF51 TEST EAX, EAX //经过若干次复杂计算最后得到子进程在7937dc处是跳呢(eax=1),还是不跳(eax=0)
009EBF53 JE BMP.009EC007
009EBF59 PUSHAD
009EBF7E POPAD
009EBF7F MOV ECX, DWORD PTR SS:[EBP-1198] //如果eax=1,到这
009EBF85 MOV ECX, DWORD PTR DS:[ECX*4+A1764C]
009EBF8C MOV EAX, DWORD PTR SS:[EBP-146C]
009EBF92 XOR EDX, EDX
009EBF94 MOV ESI, 10
009EBF99 DIV ESI
009EBF9B MOV EAX, DWORD PTR SS:[EBP-146C]
009EBFA1 MOV ECX, DWORD PTR DS:[ECX+EAX*4]
009EBFA4 XOR ECX, DWORD PTR SS:[EBP+EDX*4-1170] //得到跳转量
009EBFAB MOV EDX, DWORD PTR SS:[EBP-13AC]
009EBFB1 ADD EDX, ECX
009EBFB3 MOV DWORD PTR SS:[EBP-13AC], EDX //重新设置context
009EC012 MOV EAX, DWORD PTR SS:[EBP-1198] //如果eax=0,到这
009EC018 MOV ECX, DWORD PTR DS:[EAX*4+A17758]
009EC01F MOV EDX, DWORD PTR SS:[EBP-146C]
009EC025 XOR EAX, EAX
009EC027 MOV AL, BYTE PTR DS:[ECX+EDX] //得到下一条指令的距离
009EC02A MOV ECX, DWORD PTR SS:[EBP-13AC]
009EC030 ADD ECX, EAX
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 EAX, DWORD PTR DS:[500000] //[500000]中是原始int3表计数器
009EBCA5 MOV EAX, DWORD PTR DS:[EAX*4+401000] //401000开始放置int3原始表
009EBCAD TEST EAX, EAX
009EBCAF JE BMP.009EC045 //int3原始表到最后?是则结束。
009EBCB5 LEA EDX, DWORD 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 EDX, DWORD 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 EAX, DWORD PTR SS:[EBP-1194]
009EBCF5 XOR EDX, EDX
009EBCF7 MOV ECX, 10
009EBCFC DIV ECX ;
009EBCFE MOV DWORD PTR SS:[EBP-1198], EDX ;
009EBD04 MOV EDX, DWORD PTR SS:[EBP-13AC] ;
009EBD0A PUSH EDX
009EBD0B MOV EAX, DWORD 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 ECX, DWORD PTR SS:[EBP-1198]
009EBD31 MOV EDX, DWORD PTR DS:[ECX*4+A176D4]
009EBD38 MOV DWORD PTR SS:[EBP-118C], EDX
009EBD3E MOV EAX, DWORD PTR SS:[EBP-146C]
009EBD44 CMP EAX, DWORD PTR SS:[EBP-118C]
009EBD4A JGE SHORT BMP.009EBDA8
009EBD4C MOV EAX, DWORD PTR SS:[EBP-118C]
009EBD52 SUB EAX, DWORD PTR SS:[EBP-146C]
009EBD58 CDQ
009EBD59 SUB EAX, EDX
009EBD5B SAR EAX, 1
009EBD5D MOV ECX, DWORD PTR SS:[EBP-146C]
009EBD63 ADD ECX, EAX
009EBD65 MOV DWORD PTR SS:[EBP-1470], ECX
009EBD6B MOV EDX, DWORD PTR SS:[EBP-1198] ;
009EBD71 MOV EAX, DWORD PTR DS:[EDX*4+A1768C] ;
009EBD78 MOV ECX, DWORD PTR SS:[EBP-1470]
009EBD7E MOV EDX, DWORD PTR SS:[EBP-1468]
009EBD84 CMP EDX, DWORD PTR DS:[EAX+ECX*4]
009EBD87 JBE SHORT BMP.009EBD9A
009EBD89 MOV EAX, DWORD PTR SS:[EBP-1470]
009EBD8F ADD EAX, 1
009EBD92 MOV DWORD PTR SS:[EBP-146C], EAX
009EBD98 JMP SHORT BMP.009EBDA6
009EBD9A MOV ECX, DWORD PTR SS:[EBP-1470]
009EBDA0 MOV DWORD PTR SS:[EBP-118C], ECX
009EBDA6 JMP SHORT BMP.009EBD3E
009EBDA8 NOP ;
009EBDA9 NOP
009EBDAA MOV EDX, DWORD PTR SS:[EBP-1198]
009EBDB0 MOV EAX, DWORD PTR DS:[EDX*4+A1768C]
009EBDB7 MOV ECX, DWORD PTR SS:[EBP-146C]
009EBDBD MOV EDX, DWORD PTR DS:[EAX+ECX*4]
009EBDC0 CMP EDX, DWORD PTR SS:[EBP-1468]
009EBDC6 JNZ BMP.009EBCA0 //这段代码我把它的位置朝前挪了,修改了跳转量
009EBDCC NOP
009EBDCD NOP
××××××
009EBDCE MOV EAX, DWORD PTR DS:[500004] //符合条件的int3计数器
009EBDD3 LEA EDX, DWORD PTR SS:[EBP-13AC]
009EBDD9 MOV EDX, DWORD 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 ECX, ECX
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 EAX, DWORD PTR SS:[EBP-1464]
009EBE23 MOV ECX, DWORD PTR DS:[50000C]
009EBE29 MOV EDX, DWORD 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 EAX, DWORD PTR SS:[EBP-1198]
009EBE4D MOV ECX, DWORD PTR DS:[EAX*4+A17714]
009EBE54 MOV EDX, DWORD PTR SS:[EBP-146C]
009EBE5A XOR EAX, EAX
009EBE5C MOV AL, BYTE PTR DS:[ECX+EDX] ;
009EBE5F MOV DWORD PTR SS:[EBP-1488], EAX
009EBE65 MOV EAX, DWORD PTR SS:[EBP-1488]
009EBE6B CDQ
009EBE6C AND EDX, 0F
009EBE6F ADD EAX, EDX
009EBE71 SAR EAX, 4
009EBE74 MOV DWORD PTR SS:[EBP-1480], EAX
009EBE7A MOV ECX, DWORD 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 EDX, DWORD PTR SS:[EBP-1480]
009EBE99 CMP EDX, DWORD PTR SS:[EBP-1484]
009EBE9F JNZ SHORT BMP.009EBEBC
009EBEA1 MOV EAX, DWORD 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 ECX, DWORD PTR SS:[EBP-1488]
009EBEC2 MOV EDX, DWORD PTR SS:[EBP-1480]
009EBEC8 MOV EAX, DWORD PTR DS:[ECX*4+A16ED0]
009EBECF XOR EAX, DWORD PTR DS:[EDX*4+A1125C]
009EBED6 MOV ECX, DWORD PTR SS:[EBP-1484]
009EBEDC XOR EAX, DWORD PTR DS:[ECX*4+A1125C]
009EBEE3 MOV DWORD PTR SS:[EBP-1478], EAX
009EBEE9 MOV EDX, DWORD PTR SS:[EBP-13A4] ;
009EBEEF AND EDX, 0FD7
009EBEF5 PUSH EDX
009EBEF6 MOV EAX, DWORD PTR SS:[EBP-1488] ;
009EBEFC MOVSX ECX, BYTE 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 EDX, DWORD PTR SS:[EBP-13B8]
009EBF19 PUSH EDX
009EBF1A MOV EAX, DWORD PTR SS:[EBP-1474]
009EBF20 PUSH EAX
009EBF21 CALL DWORD PTR SS:[EBP-1478]
009EBF27 ADD ESP, 8
009EBF2A PUSH EAX
009EBF2B MOV ECX, DWORD PTR SS:[EBP-1488]
009EBF31 MOVSX EDX, BYTE 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 EAX, DWORD PTR SS:[EBP-147C]
009EBF4E AND EAX, 1
009EBF51 NOP
009EBF52 NOP
×××××××
009EBF53 MOV ECX, DWORD 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 ECX, DWORD PTR SS:[EBP-1198]
009EBF85 MOV ECX, DWORD PTR DS:[ECX*4+A1764C]
009EBF8C MOV EAX, DWORD PTR SS:[EBP-146C]
009EBF92 XOR EDX, EDX
009EBF94 MOV ESI, 10
009EBF99 DIV ESI
009EBF9B MOV EAX, DWORD PTR SS:[EBP-146C]
009EBFA1 MOV ECX, DWORD PTR DS:[ECX+EAX*4]
009EBFA4 XOR ECX, DWORD PTR SS:[EBP+EDX*4-1170]
009EBFAB NOP
009EBFAC NOP
009EBFAD MOV EAX, DWORD PTR DS:[500004]
009EBFB2 MOV DWORD PTR DS:[EAX*4+40FD00], ECX ;跳转量从40FD00开始放
009EBFBA NOP
......
009EC011 NOP
009EC012 MOV EAX, DWORD PTR SS:[EBP-1198]
009EC018 MOV ECX, DWORD PTR DS:[EAX*4+A17758]
009EC01F MOV EDX, DWORD PTR SS:[EBP-146C]
009EC025 XOR EAX, EAX
009EC027 MOV AL, BYTE PTR DS:[ECX+EDX]
009EC02A NOP
009EC02B NOP
009EC02C MOV ECX, DWORD 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 EDI, DWORD PTR DS:[500004] //有效int3的计数器
009EC056 ADD EDI, BMP.0040AE00 //跳转类型从40AE00开始放
009EC05C MOV EDX, BMP.0050000C
009EC061 MOV EAX, DWORD PTR DS:[EDX+4]
009EC064 MOV EBX, DWORD PTR DS:[EDX+8]
009EC067 XOR EBX, EAX
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 EAX, DWORD PTR DS:[EDX+C]
009EC07D MOV EBX, DWORD PTR DS:[EDX+14]
009EC080 XOR EBX, EAX
009EC082 JE SHORT BMP.009EC0A1
009EC084 TEST EAX, EAX
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 EBX, DWORD PTR DS:[EDX+18]
009EC0A4 XOR EBX, EAX
009EC0A6 JE SHORT BMP.009EC109
009EC0A8 NOP
009EC0A9 NOP
009EC0AA MOV EBX, DWORD PTR DS:[EDX+10]
009EC0AD XOR EBX, EAX
009EC0AF JE SHORT BMP.009EC0CB
009EC0B1 TEST EAX, EAX
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 EBX, DWORD PTR DS:[EDX+1C]
009EC0CE XOR EBX, EAX
009EC0D0 JE SHORT BMP.009EC0EC
009EC0D2 TEST EAX, EAX
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 EAX, EAX
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 EBX, DWORD PTR DS:[EDX+1C]
009EC10C XOR EBX, EAX
009EC10E JE SHORT BMP.009EC144
009EC110 NOP
009EC111 NOP
009EC112 MOV EBX, DWORD PTR DS:[EDX+20]
009EC115 XOR EBX, EAX
009EC117 JE SHORT BMP.009EC12D
009EC119 TEST EAX, EAX
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 EAX, EAX
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 EBX, DWORD PTR DS:[EDX+20]
009EC147 XOR EBX, EAX
009EC149 JE SHORT BMP.009EC162
009EC14B TEST EAX, EAX
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 EBX, DWORD PTR DS:[EDX+10]
009EC165 XOR EBX, EAX
009EC167 JE SHORT BMP.009EC180
009EC169 TEST EAX, EAX
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 EAX, EAX
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拷贝下来保存好。接下来要用。
继续修复cc。
在(二)中我们得到了四张表 :
int3地址表 (实际地址+1)
跳转类型表
跳转量表
跳转命令长度表 (实际长度-1)
在OD中打开已脱壳程序,现在壳已经是垃圾了,我们就用用它的空间吧。把前面保存的连续的四个表拷贝到壳开始的空间,我这儿是9d1000。得到:
9d1000~9d5f00 int3地址表
9d5f00~9dae00 跳转类型表
9dae00~9dfd00 跳转量表
9dfd00~9e4c00 跳转命令长度表
随便找个地方写入下列代码:
009E4C04 XOR ECX, ECX
009E4C06 MOV EAX, DWORD PTR DS:[ECX*4+9D1000] //取出int3地址
009E4C0E CMP EAX, 0
009E4C11 JE SHORT dumped_.009E4C80
009E4C13 MOVZX EDX, BYTE PTR DS:[ECX+9D5F00] //跳转类型
009E4C1A MOV EBX, DWORD PTR DS:[ECX*4+9DAE00] //跳转量
009E4C22 MOVZX EDI, BYTE 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 ECX, ECX
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 AH, CL //这里的cc也是int3
006539C0 B7 8A MOV BH, 8A
006539C2 71 0A JNO SHORT dumped_.006539CE
把006539B6处的int3修复好以后,变成如下代码:
006539B4 85C9 TEST ECX, ECX
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 EBX, DWORD 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