160 个 CrackMe 之 101 - Acid_Cool_178.4(VB6 Native)VB事件处理的分析和增删改!
本帖最后由 solly 于 2019-8-3 08:19 编辑160 个 CrackMe 之 101 -- Acid_Cool_178.4 是一个 VB6 编译的原生程序,破解相对简单,但破解不是本文重点,本文重点在于对 VB 表单及控件的事件进行分析,并对事件进行增加,删除或修改等。
第一部分 脱壳和破解
当然,我们还是把这个 CrackMe 破解了再説。先看看文件信息,如下所示:
有壳,先脱壳,用 OD 载入,如下图所示,可用 ESP 定律脱壳:
利用 ESP 定律,很快就可以来到 OEP,如下图所示,可以看到,这是一个 VB6 编译的程序:
这时候可以进行脱壳,用 OD 直接脱壳好象不能运行,我们使用 LordPE 1.6 脱壳,“用管理员身份”启动 LordPE 进行脱壳:
在 loadPE 中直接 Dump full... 即可,保存脱壳后的程序,然后运行脱壳后程序,其界面如下所示:
包括两个窗口,一个主界面窗口,一个背景窗口。
首先,对于 VB 程序,用 VB Decompiler 反编译看看,看看有哪些表单、控件,以及事件等信息。
上图是展开了全部事件的情况,Form4 有一个函数,没有事件。其它表单都有事件,没有函数。
先看看 CrackMe 的 Info,是一个破解説明,提示你要完成破解的两个任务:
1、使文本框可以输入字母通过 check;
2、去除 NAG。
关闭信息对话框,会重新返回主界面,这次点“Task1”,界面如下:
如果你在文本框中输入纯数字,点“Check”时,数字不会被清空,一直在文本框内。
但如果你的输入中包含非数字字母或标点等,点“Check”时,文本框就会被清空,CrackMe 的 Task1 就是要去除这个限制,输入任何内容都不会清空。
在 VB Decompiler 中,我们可以找到这个功能是在 Form1 中。在 Form1 的 Command1 按钮Click 事件中进行检查的,如下图所示:
如上图,我们直接来看看其事件处理函数,该函数的代码如下所示:
;==========去除输入非数字字符时,会清空输入内容的限制 ==================================================
; TASK1:
0042ED80 55 push ebp
0042ED81 8BEC mov ebp, esp
0042ED83 83EC 0C sub esp, 0C
0042ED86 68 36114000 push <jmp.&MSVBVM60.__vbaExceptHandler>
0042ED8B 64:A1 00000000 mov eax, dword ptr fs:
0042ED91 50 push eax
0042ED92 64:8925 00000000 mov dword ptr fs:, esp
0042ED99 83EC 30 sub esp, 30
0042ED9C 53 push ebx
0042ED9D 56 push esi
0042ED9E 57 push edi
0042ED9F 8965 F4 mov dword ptr , esp
0042EDA2 C745 F8 A0104000 mov dword ptr , 004010A0
0042EDA9 8B75 08 mov esi, dword ptr
0042EDAC 8BC6 mov eax, esi
0042EDAE 83E0 01 and eax, 1
0042EDB1 8945 FC mov dword ptr , eax
0042EDB4 83E6 FE and esi, FFFFFFFE
0042EDB7 56 push esi
0042EDB8 8975 08 mov dword ptr , esi
0042EDBB 8B0E mov ecx, dword ptr
0042EDBD FF51 04 call dword ptr
0042EDC0 8B16 mov edx, dword ptr
0042EDC2 33C0 xor eax, eax
0042EDC4 56 push esi
0042EDC5 8945 E8 mov dword ptr , eax
0042EDC8 8945 E4 mov dword ptr , eax
0042EDCB 8945 D4 mov dword ptr , eax
0042EDCE FF92 00030000 call dword ptr
0042EDD4 8B1D 28104000 mov ebx, dword ptr [<&MSVBVM60.__vbaObjS>; MSVBVM60.__vbaObjSet
0042EDDA 50 push eax
0042EDDB 8D45 E4 lea eax, dword ptr
0042EDDE 50 push eax
0042EDDF FFD3 call ebx
0042EDE1 8BF8 mov edi, eax
0042EDE3 8D55 E8 lea edx, dword ptr
0042EDE6 52 push edx
0042EDE7 57 push edi
0042EDE8 8B0F mov ecx, dword ptr
0042EDEA FF91 A0000000 call dword ptr ; GetDlgText()
0042EDF0 85C0 test eax, eax
0042EDF2 DBE2 fclex
0042EDF4 7D 12 jge short 0042EE08
0042EDF6 68 A0000000 push 0A0
0042EDFB 68 10BB4200 push 0042BB10
0042EE00 57 push edi
0042EE01 50 push eax
0042EE02 FF15 1C104000 call dword ptr [<&MSVBVM60.__vbaHresultCh>; MSVBVM60.__vbaHresultCheckObj
0042EE08 8B45 E8 mov eax, dword ptr
0042EE0B C745 E8 00000000 mov dword ptr , 0
0042EE12 8945 DC mov dword ptr , eax
0042EE15 8D45 D4 lea eax, dword ptr
0042EE18 50 push eax
0042EE19 C745 D4 08000000 mov dword ptr , 8
0042EE20 FF15 40104000 call dword ptr [<&MSVBVM60.#561>] ; 调用 MSVBVM60.rtcIsNumeric() 判断输入的字符串是否数字
0042EE26 66:8BF8 mov di, ax ; 标志
0042EE29 8D4D E4 lea ecx, dword ptr
0042EE2C F7D7 not edi ; 取反
0042EE2E FF15 94104000 call dword ptr [<&MSVBVM60.__vbaFreeObj>] ; MSVBVM60.__vbaFreeObj
0042EE34 8D4D D4 lea ecx, dword ptr
0042EE37 FF15 08104000 call dword ptr [<&MSVBVM60.__vbaFreeVar>] ; MSVBVM60.__vbaFreeVar
0042EE3D 66:85FF test di, di ; 检查标志(patch 这里为:xor di, di)
0042EE40 74 41 je short 0042EE83 ; 纯数字则跳转(也可以patch 这里为 jmp 0x0042EE83)
0042EE42 8B0E mov ecx, dword ptr
0042EE44 56 push esi
0042EE45 FF91 00030000 call dword ptr
0042EE4B 8D55 E4 lea edx, dword ptr
0042EE4E 50 push eax
0042EE4F 52 push edx
0042EE50 FFD3 call ebx
0042EE52 8BF0 mov esi, eax
0042EE54 68 24BB4200 push 0042BB24 ; 空串
0042EE59 56 push esi
0042EE5A 8B06 mov eax, dword ptr
0042EE5C FF90 A4000000 call dword ptr ; SetDlgText(""),当输入不是纯数字时清空文本框
0042EE62 85C0 test eax, eax
0042EE64 DBE2 fclex
0042EE66 7D 12 jge short 0042EE7A
0042EE68 68 A4000000 push 0A4
0042EE6D 68 10BB4200 push 0042BB10
0042EE72 56 push esi
0042EE73 50 push eax
0042EE74 FF15 1C104000 call dword ptr [<&MSVBVM60.__vbaHresultCh>; MSVBVM60.__vbaHresultCheckObj
0042EE7A 8D4D E4 lea ecx, dword ptr
0042EE7D FF15 94104000 call dword ptr [<&MSVBVM60.__vbaFreeObj>] ; MSVBVM60.__vbaFreeObj
0042EE83 C745 FC 00000000 mov dword ptr , 0
0042EE8A 68 AEEE4200 push 0042EEAE
0042EE8F EB 1C jmp short 0042EEAD
0042EE91 8D4D E8 lea ecx, dword ptr
0042EE94 FF15 98104000 call dword ptr [<&MSVBVM60.__vbaFreeStr>] ; MSVBVM60.__vbaFreeStr
0042EE9A 8D4D E4 lea ecx, dword ptr
0042EE9D FF15 94104000 call dword ptr [<&MSVBVM60.__vbaFreeObj>] ; MSVBVM60.__vbaFreeObj
0042EEA3 8D4D D4 lea ecx, dword ptr
0042EEA6 FF15 08104000 call dword ptr [<&MSVBVM60.__vbaFreeVar>] ; MSVBVM60.__vbaFreeVar
0042EEAC C3 retn
0042EEAD C3 retn
0042EEAE 8B45 08 mov eax, dword ptr
0042EEB1 50 push eax
0042EEB2 8B08 mov ecx, dword ptr
0042EEB4 FF51 08 call dword ptr
0042EEB7 8B45 FC mov eax, dword ptr
0042EEBA 8B4D EC mov ecx, dword ptr
0042EEBD 5F pop edi
0042EEBE 5E pop esi
0042EEBF 64:890D 00000000 mov dword ptr fs:, ecx
0042EEC6 5B pop ebx
0042EEC7 8BE5 mov esp, ebp
0042EEC9 5D pop ebp
0042EECA C2 0400 retn 4
关键代码是一个调用:MSVBVM60.rtcIsNumeric(),通过这个函数,判断输入的字符串是否是一个纯数字字符串,因此 Patch 也很简单,如下图所示:
直接将 0x0042EE3D 处的指令 testdi, di 改成 xordi, di 就可以了。再输入非数字字符,点“Check"也不会将文本框清空了。如下所示:
这样 patch 一下,第一个任务完成。
第 2 个任务是去除 NAG,在主界面上点"Task2",首先弹出一个 NAG 窗口,如下图所示:
点”Move On“后,会关闭 NAG 窗口,打开另一个窗口:
表示没有其它 NAG 了,就是前面一个 NAG 窗口需要移除。
再次来到 VB Decompiler,可以看到,在主界面显示 NAG 窗口 Form3,Form3 再显示 Form4,要去除 NAG,只要在主界面的事件中直接显示 Form4,跳过 Form3 即可。下图是主界面显示 Form3:
我们到 OD 中看看显示 Form3 的代码,如下图所示:
具体代码如下所示(关键部分):
0042F261|> \A1 4C004300 mov eax, dword ptr
0042F266|.85C0 test eax, eax
0042F268|.75 10 jnz short 0042F27A
0042F26A|.68 4C004300 push 0043004C
0042F26F|.68 74B04200 push 0042B074
0042F274|.FF15 68104000 call dword ptr [<&MSVBVM60.__vbaNew2>] ;MSVBVM60.__vbaNew2
0042F27A|>83EC 10 sub esp, 10
0042F27D|.B9 0A000000 mov ecx, 0A
0042F282|.8BDC mov ebx, esp
0042F284|.894D DC mov dword ptr , ecx
0042F287|.B8 04000280 mov eax, 80020004
0042F28C|.83EC 10 sub esp, 10
0042F28F|.890B mov dword ptr , ecx
0042F291|.8B4D D0 mov ecx, dword ptr
0042F294|.8BD0 mov edx, eax
0042F296|.8B35 4C004300 mov esi, dword ptr
再看看 Nag 窗口对 Form4 的显示:
在 OD 看看代码如下所示:
然后,我们将主界面上对 Form3 的引用和操作,全部改成 Form4 的即可,如下图所示:
具体改动后的代码如下,共 4 个位置有改动:
0042F261 A1 4C004300 mov eax, dword ptr ;改成对变量 的引用
0042F266 85C0 test eax, eax
0042F268 75 10 jnz short 0042F27A
0042F26A 68 4C004300 push 00430074 ;改成对变量 的引用
0042F26F 68 74B04200 push 0042A4E8 ;改成对 Form4 资源的引用
0042F274 FF15 68104000 call dword ptr [<&MSVBVM60.__vbaNew2>] ; MSVBVM60.__vbaNew2
0042F27A 83EC 10 sub esp, 10
0042F27D B9 0A000000 mov ecx, 0A
0042F282 8BDC mov ebx, esp
0042F284 894D DC mov dword ptr , ecx
0042F287 B8 04000280 mov eax, 80020004
0042F28C 83EC 10 sub esp, 10
0042F28F 890B mov dword ptr , ecx
0042F291 8B4D D0 mov ecx, dword ptr
0042F294 8BD0 mov edx, eax
0042F296 8B35 4C004300 mov esi, dword ptr ;改成对变量 的引用
如果简单一点,也可以只修改对表单资源的引用,改动一个即可:
0042F26F 68 74B04200 push 0042A4E8 ;改成对 Form4 资源的引用
这样,就可以去除 NAG 窗口的显示了,在主界面点击"Task2",就会显示 Form4 了:
这个时候,主界面隐藏了,但是当我们关闭这个 Form4 后,并不会象前面两个表单一样,会重新返回到主界面。
关闭 Form4 后,程序只剩下背景窗口,主界面出不来了。下一部分我们来解决这个问题。
下面进行第二个主题,VB 事件的探索。
第二部分 VB 事件处理探索
通过 VB Decompiler 可以看到 Form4 有一个函数,但并没有使用,如下所示:
在 OD 中,可以看到其代码如下所示:
所选部分,正是对主界面的引用,也就是显示主界面的代码,所以,这个函数可以显示主界面,但事件却丢失了,因此,我们需要将这个事件加上去。
我们首先要把处理事件的流程了解清楚,才有可能处理这个问题。
因此,我们先随便在另一个表单的一个事件中下一个断点。如下所示,在 Form1 的 Command1_Click() 事件下一断点:
然后,在 CrackMe 中打开 task1,输入几个字符,点”Check“,程序就会断下来,如下图所示:
然后,一路 F8 返回到 MSVBVM60 的地址空间,如下图所示:
我们在 call eax 前面下一个断点,然后 F9 ,再回到界面,点”Check“,然后又会断下来,如下所示:
我们在 call eax 处,按 F7 进入调用,来到下面:
可以看到,VB 先调用一个事件入口的 Stub,然后再跳转到事件处理代码中去的。
下面我们用 IDA 打开脱壳后的 CrackMe ,查看这些事件的引用关系,首先我们找到与上图类似的代码处,来查看其引用关系,如下图所示(用的是Form4):
可以看出,在一片内存区,有这些 Event_Stub 的地址引用,然后找其中一个,并查看其相关内存片,如下图所示:
推测,这些事件就是在这里填充 Event_stub 的地址,有很多空间为0,我在这里填上12个地址,如上图选择部分,保存以后,去反编译验证,如下图所示,是反编译结果:
可以看出,果然没有猜错,一下子多出了12个事件,到这里,大家就应该差不多明白了 VB 中的事件保存结构了。
于是我们数一下顺序,看看Unload事件在第几个位置并记好,先看看 Form4 那个函数,如下所示,选中函数第1条指令:
可以看到,有一个跳转指向这里,于是转到该跳转处,如下图:
正是一个与 Event_Stub 类似的 Func_Stub。记住其地址:0x0042A6B0,然后返回到前面我们改了12个地址的事件地址区,进行Unload事件的修正,如下图所示:
只剩下一个地址:0x0042A6B0。保存文件,再次反编译,如下图所示:
是不是函数变成事件了,哈哈!!!
还有,那个事件 Stub 代码中,有一个参数需要调整,这个参数是调整 Me 对象参数的。如下所示:
经过与基它函数对比和调校,确定为 0x38,上图含4C法调整Form显示顺序的修改。在文件中的位置如下:
这样修改后,就能正确执行事件过程了。当关闭 Form4 时,就会重新显示主界面了。
注意,应在数据窗口中修改 0x0000FFFF 为 0x00000038,因0x38小于0xFF,在指令窗口修改会改变数据格式。不符合 Stub 格式,可以正常运行,但反编译显示会不正确。
上面提到了4C法调整显示顺序的问题,但是主界面的 Load 事件会显示背景,如果要跳过背景的显示,还需要象去除 NAG 一样,修改主界面的Load事件的代码,
在 OD 中 Ctrl+G,输入上面函数地址:
来到函数,象修改去除 NAG 代码一样,修改即可去除背景的显示:
前面来了一段去背景窗口的小插曲,现在我们讨论一下给控件增加一个事件的方法,我们以 From4 的 Label1 控件为例作分析。
先在 IDA 中找一找 Label1的事件地址块:
如上图所示,找到 Label1 的事件地址块,上面红框下面的dd 12h dup(0) 就是 18 个 Label 事件地址块,目前没有一个事件。
我们按照事件代码格式,找一个空白区构建一个事件代码如下:
具体代码如下:
0042FFA0 816C24 04 34000000 sub dword ptr , 34
0042FFA8 E9 03000000 jmp 0042FFB0
0042FFAD 90 nop
0042FFAE 90 nop
0042FFAF 90 nop
0042FFB0 33C0 xor eax, eax
0042FFB2 90 nop
0042FFB3 C3 retn
上面那个 0x34 也是根据运行条件去调整。同时,返回指令(ret),可以根据事件函数的参数个数进行调整(参考其它事件),如下图所示:
然后,在事件地址块中填充这个事件的地址,如下图所示(数据区):
注意,最好在数据区填充代码,保证4字节的数据格式正确,并且 jmp 后要有偏移,不要直接跳转下一条指令(汇编码 E9 00000000),也是因为反编译不能正确显示,但可以正确执行。
下面修改文件,如下数据区:
填充事件地址:
然后再填充指令:
保存以后,看看反编译后的效果:
正确显示。
那个Me对象修正码,如下所示,修正堆栈中的地址:
如果不对,会报错,需要修正,如下图所示:
修改堆栈中的地址后,该地址指向 Me 对象,原则上这个地址与指令区间的地址接近,自己去判断,正确的话才能运行,当然我这个新增代码才一条指令,并没有引用 Me 对象,指向不对也不会报错 。
要检查是否正确,在该事件中的代码上下一个断点,然后在 Form4 中去点击一下 Label1,如果能断下来,表示这个事件就是正确调用了的。
最后,上面讲了修改和新增事件,最后如果要删除事件,最简单,将事件地址块中的相应事件地址清 0 即可解决(前面讲的去除背景窗口显示,可以将主界面的 Load() 事件删除即可,操作更简单)。
第三部分 p-code 的事件简单分析
前面讨论了 VB Native 代码的事件处理方法,如果是 p-code 代码的呢,是不是也一样,是的,差不多。
下面以 160 个 CrackMe 之 038 - CyberBlade.2 作分析説明。过程就简化了,除了指令,其它过程基本一样。
如上图,先找到事件的 Stub,与前面的一样,Stub 的代码还是 Native 代码,格式稍有不同,大体还是一样。
具体代码如下,6个事件 stub:
0040304C B8 5C000000 mov eax, 5C ; About_Click()
00403051 66:3D 33C0 cmp ax, 0C033
00403055 BA 54DD4000 mov edx, 0040DD54 ; 函数信息块地址,位于函数代码尾部
0040305A 68 42104000 push <jmp.&MSVBVM50.MethCallEngine>
0040305F C3 retn ; 跳转到 MSVBVM50导出函数 MethCallEngine()
00403060 B8 60000000 mov eax, 60 ; Command1_Click()
00403065 66:3D 33C0 cmp ax, 0C033
00403069 BA 80E64000 mov edx, 0040E680 ; 函数信息块地址,位于函数代码尾部
0040306E 68 42104000 push <jmp.&MSVBVM50.MethCallEngine>
00403073 C3 retn ; 跳转到 MSVBVM50导出函数 MethCallEngine()
00403074 B8 54000000 mov eax, 54 ; Command2_Click()
00403079 66:3D 33C0 cmp ax, 0C033
0040307D BA 00DD4000 mov edx, 0040DD00 ; 函数信息块地址,位于函数代码尾部
00403082 68 42104000 push <jmp.&MSVBVM50.MethCallEngine>
00403087 C3 retn ; 跳转到 MSVBVM50导出函数 MethCallEngine()
00403088 B8 58000000 mov eax, 58 ; Form_Initialize()
0040308D 66:3D 33C0 cmp ax, 0C033
00403091 BA 38DC4000 mov edx, 0040DC38 ; 函数信息块地址,位于函数代码尾部
00403096 68 42104000 push <jmp.&MSVBVM50.MethCallEngine>
0040309B C3 retn ; 跳转到 MSVBVM50导出函数 MethCallEngine()
0040309C B8 58000000 mov eax, 58 ; Form_Load()
004030A1 66:3D 33C0 cmp ax, 0C033
004030A5 BA B4E14000 mov edx, 0040E1B4 ; 函数信息块地址,位于函数代码尾部
004030AA 68 42104000 push <jmp.&MSVBVM50.MethCallEngine>
004030AF C3 retn ; 跳转到 MSVBVM50导出函数 MethCallEngine()
004030B0 B8 74000000 mov eax, 74 ; txtkey.KeyPress()
004030B5 66:3D 33C0 cmp ax, 0C033
004030B9 BA B0DD4000 mov edx, 0040DDB0 ; 函数信息块地址,位于函数代码尾部。 == 0x00402A74
004030BE 68 42104000 push <jmp.&MSVBVM50.MethCallEngine>
004030C3 C3 retn ; 跳转到 MSVBVM50导出函数 MethCallEngine()
因为是 p-code,最后不是 jmp 了,而是通过 ret 指令跳转到 MSVBVM60 中去执行事件的 P-code 代码了。
上在的 edx 参数,是一个指向 p-code 事件的信息块,这个与原生代码有区别,如下图所示一个信息块,并且,每个信息块紧接在事件代码的后面。
;; 事件信息块
0040E68074 2A 40 00 04 00 F4 00 14 04 3C 00 00 00 00 00t*@..?<.....
0040E69000 00 00 00 00 00 00 00 24 00 00 00 00 00 06 00........$......
信息块中包括了对象引用地址,局部变量空间大小,p-code 代码长度等数据。
同样,事件对应也有事件地址块,这个与原生代码的格式一样:
; 事件地址块
00402D0884 2B 40 00 74 2A 40 00 30 10 40 00 36 10 40 00?@.t*@.0@.6@.
00402D183C 10 40 00 74 30 40 00 00 00 00 00 00 00 00 00<@.t0@......... 0x00403074
00402D2800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402D3800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402D4800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402D5800 00 00 00 00 00 00 00 00 00 00 00 AC 2B 40 00............?@.
00402D6874 2A 40 00 30 10 40 00 36 10 40 00 3C 10 40 00t*@.0@.6@.<@.
00402D7800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402D8800 00 00 00 00 00 00 00 9C 30 40 00 00 00 00 00.........@..... 0x0040309C
00402D9800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402DA800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402DB800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402DC800 00 00 00 00 00 00 00 00 00 00 00 88 30 40 00............?@. 0x00403088
00402DD800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402DE800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402DF8D4 2B 40 00 74 2A 40 00 30 10 40 00 36 10 40 00?@.t*@.0@.6@.
00402E083C 10 40 00 4C 30 40 00 00 00 00 00 FC 2B 40 00<@.L0@.....?@. 0x0040304C,菜单只有两个可定制事件
00402E1874 2A 40 00 30 10 40 00 36 10 40 00 3C 10 40 00t*@.0@.6@.<@.
00402E2860 30 40 00 00 00 00 00 00 00 00 00 00 00 00 00`0@............. 0x00403060
00402E3800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402E4800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402E5800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402E6800 00 00 00 00 00 00 00 24 2C 40 00 74 2A 40 00........$,@.t*@.
00402E7830 10 40 00 36 10 40 00 3C 10 40 00 00 00 00 000@.6@.<@.....
00402E8800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402E9800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402EA800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402EB800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402EC800 00 00 00 00 00 00 00 4C 2C 40 00 74 2A 40 00........L,@.t*@.
00402ED830 10 40 00 36 10 40 00 3C 10 40 00 00 00 00 000@.6@.<@.....
00402EE800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402EF800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402F0800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402F1800 00 00 00 74 2C 40 00 74 2A 40 00 30 10 40 00....t,@.t*@.0@.
00402F2836 10 40 00 3C 10 40 00 00 00 00 00 00 00 00 006@.<@.........
00402F3800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402F4800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402F5800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402F689C 2C 40 00 74 2A 40 00 30 10 40 00 36 10 40 00?@.t*@.0@.6@.
00402F783C 10 40 00 00 00 00 00 00 00 00 00 00 00 00 00<@.............
00402F8800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402F9800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402FA800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402FB800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402FC800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
00402FD800 00 00 00 C4 2C 40 00 74 2A 40 00 30 10 40 00....?@.t*@.0@.
00402FE836 10 40 00 3C 10 40 00 00 00 00 00 00 00 00 006@.<@.........
00402FF800 00 00 00 00 00 00 00 00 00 00 00 B0 30 40 00............?@. 0x004030B0
0040300800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
0040301800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
0040302800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
0040303800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................
0040304800 00 00 00 ....
下面在 OD 中来看看这个事件 stub:
我们在注册码验证按钮的事件代码处,下一断点。
然后到 CrackMe 界面,按 ”Check“按钮,触发事件,断在我们下的断点处,按F8 跟踪,来到 MSVBVM60 的空间。如下图:
这里是不是与原生的 Event_Stub 类似??差不多吧!!!
;;;============MSVBVM50 事件调用入口 Stub ===============================================================
741C2FFC >294424 04 sub dword ptr , eax ; Me 对象指针修正
741C3000 B9 02E31B74 mov ecx, 741BE302
741C3005^ E9 39A2FFFF jmp 741BD243
修正 Me 指针后,指向应用的数据区。
继续,这里有是作准备的。
取得数据区对象地址。
生成 Me 对象。
开始准备 p-code 代码的指令指针了(相当于原生代码的 EIP)。
正式完成,这个时候,esi 指向事件函数的第1条指令,准备执行事件函数了。
函数p-code 代码如下(VB Explorer 反编译):
下面是,上面分析的代码(MSVBVM中的事件 Stub 代码):
;;;============MSVBVM50 事件入口代码 ====================================================================
741BD243 55 push ebp
741BD244 8BEC mov ebp, esp
741BD246 83EC 78 sub esp, 78
741BD249 53 push ebx
741BD24A 56 push esi
741BD24B 57 push edi
741BD24C 8BDA mov ebx, edx ; ebx == edx == 0x0040E680,传入的参数,指向函数信息块
741BD24E 895D B0 mov dword ptr , ebx
741BD251 894D 94 mov dword ptr , ecx
741BD254 8B15 64F01C74 mov edx, dword ptr
741BD25A 0BD2 or edx, edx
741BD25C 0F85 09630000 jnz 741C356B
741BD262 8B15 6CF01C74 mov edx, dword ptr
741BD268 8B3B mov edi, dword ptr ; ebx == edx,传入的参数, edi==>对象地址
741BD26A 8B77 34 mov esi, dword ptr
741BD26D 8975 AC mov dword ptr , esi
741BD270 8B77 04 mov esi, dword ptr
741BD273 8B76 14 mov esi, dword ptr
741BD276 8B76 0C mov esi, dword ptr
741BD279 8975 D4 mov dword ptr , esi
741BD27C 8955 BC mov dword ptr , edx
741BD27F C745 B8 00000000 mov dword ptr , 0
741BD286 81F9 02E31B74 cmp ecx, 741BE302
741BD28C 0F84 94000000 je 741BD326
741BD292 0FB74B 06 movzx ecx, word ptr ; 局部数据缓冲区大小,word == 0x00F4
741BD296 C745 C4 00000000 mov dword ptr , 0
741BD29D 8BFC mov edi, esp
741BD29F 8BC1 mov eax, ecx
741BD2A1 2BF8 sub edi, eax
741BD2A3 3B7A 70 cmp edi, dword ptr
741BD2A6 0F82 5D630000 jb 741C3609
741BD2AC 8BFC mov edi, esp
741BD2AE 3D 00100000 cmp eax, 1000
741BD2B3 0F83 3D630000 jnb 741C35F6
741BD2B9 2BF8 sub edi, eax
741BD2BB 830F 00 or dword ptr , 0
741BD2BE 2BE1 sub esp, ecx ; 生成局部变量空间
741BD2C0 8BFC mov edi, esp ; edi 为栈顶
741BD2C2 C1E9 02 shr ecx, 2 ; ecx /= 4,变为 DWORD 长度
741BD2C5 33C0 xor eax, eax
741BD2C7 F3:AB rep stos dword ptr es: ; 局部变量清 0
741BD2C9 8945 C0 mov dword ptr , eax ; 清 0
741BD2CC 8945 CC mov dword ptr , eax ; 清 0
741BD2CF 8BFA mov edi, edx
741BD2D1 66:837B 1C 00 cmp word ptr , 0 ; word == 0
741BD2D6 0F85 A0000000 jnz 741BD37C
741BD2DC 8B47 0C mov eax, dword ptr
741BD2DF 8945 A4 mov dword ptr , eax
741BD2E2 8D45 A4 lea eax, dword ptr
741BD2E5 8947 0C mov dword ptr , eax
741BD2E8 8B47 14 mov eax, dword ptr
741BD2EB 8945 F8 mov dword ptr , eax
741BD2EE 8D45 D8 lea eax, dword ptr
741BD2F1 8947 14 mov dword ptr , eax
741BD2F4 BE 01000000 mov esi, 1
741BD2F9 8D4D D8 lea ecx, dword ptr
741BD2FC C741 24 00000000 mov dword ptr , 0
741BD303 51 push ecx
741BD304 8B4D 94 mov ecx, dword ptr
741BD307 E8 5E2F0000 call 741C026A
741BD30C 0FB773 08 movzx esi, word ptr ; word,取函数代码的长度
741BD310 F7DE neg esi
741BD312 03F3 add esi, ebx ; 计算得到函数开始地址,esi指向函数第1条指令
741BD314 8975 A8 mov dword ptr , esi ; CyberBla.0040E26C
741BD317 8975 EC mov dword ptr , esi
741BD31A 33C0 xor eax, eax
741BD31C 8A06 mov al, byte ptr ; 取出第1条指令
741BD31E 46 inc esi
741BD31F FF2485 94ED1B74 jmp dword ptr ; 去执行指令
下面是函数信息数据,上面的 Stub 通过这个数据块来调用 p-code 代码:
;; 事件信息块
0040E68074 2A 40 00 04 00 F4 00 14 04 3C 00 00 00 00 00t*@..?<.....
0040E69000 00 00 00 00 00 00 00 24 00 00 00 00 00 06 00........$......
通过以上分析,可以看出,人为制作一个函数信息块,再写一个 p-code 代码的函数,也可以新加事件,只是难度比原生代码的高一些!!!
p-code例子就不做了。
分析完毕!!!
后面的图片是不需要的,没地方删除,请跳过!!!
多出的图怎么没地方删掉了呀? 感谢分享。。。。。。。。。。。。 谢谢分享,学习楼主的坚持 谢谢大佬,学习了 谢谢楼主的分享{:1_893:}{:1_893:} 谢谢楼主的分享 先回复,再学习 多图眼花缭乱的,相当精彩! 好详细的分析,谢谢啦
页:
[1]
2