【文章标题】: vbsedit去除注册对话框
【文章作者】: MPL
【软件名称】: Vbsedit 5.2.4
【软件大小】: 8.5M
【下载地址】: http://www.vbsedit.com/tr_download.asp
【加壳方式】: 无壳
【保护方式】: 不懂
【编写语言】: Microsoft Visual Studio .NET 2005 -- 2008 -> Microsoft Corporation [Overlay]
【使用工具】: OD PEID SPY++
【操作平台】: Windows XP
【软件介绍】: 编写vbs脚本的IDE,具有语法高亮、代码自动提示等功能,可调试脚本代码。另外,内附大量的模板代码,可直接套用。
【作者声明】: 本人非专业逆向人员,只是兴趣所致,想把原有版本的限制去掉。连这开头的几个“字段”都是抄的别人的:P
--------------------------------------------------------------------------------
非注册版本有两个限制,一是软件启动的时候,会弹出要求注册的窗体A;
二是在点击Start按钮时,会弹出另外一个不同的要求注册的窗体B。
首先打开利器OD,加载vbsedit.exe。RUn之后,要两次Shift+F9跳过异常(我也不知道是软件设置的反调试导致的,菜阿。。。)。
ps:之前我没有检查软件加壳了没有,因为菜到极致的我,并不知道加没加壳对调试有什么影响。。。
1。寻找register按钮单击事件代码
我一开始想找到点击窗体A的Register按钮所执行的代码的地方,看能不能把关键的跳转改掉,进而随便输个注册码让注册成功。
(1) 对GetWindowTextA、GetWindowTextW、GetDlgItemTextA、GetDlgItemTextW、SendDlgItemMessageA和SendDlgItemMessagW下断点;
对SendMessageW下WM_GETTEXT的条件断点
实际发现原作者都使用了unicode版本的函数。结果是在注册窗体A输入注册码的时候,会断下来;而在点击register按钮的时候却
断不下来。我没仔细看代码,猜测是这样的:在输入的时候实时保存文本框的内容到全局字符串,然后点击register按钮的时候直接
取全局字符串。
(2) 对SendMessageW下WM_COMMAND的条件断点
我在OD的左下角命令行处输入bp SendMessageW,另外需对其设置条件,就是何时使这个断点激活。
当然是按Register按钮的时候,于是在ALT+B调出断点窗体后,右键编辑其条件:[ESP+8]==WM_COMMAND && [ESP+10]==01234567,
其中,01234567是用SPY++查看到的Register按钮的句柄。
整个条件的意思就是,SendMessageW的第二个参数为WM_COMMAND,并且第4个参数是Register按钮的句柄(其实严格的说还要第三个参数是
MAKEWPARAM(按钮id, BN_CLICKED))。
因为这个条件就表示当按钮Register被单击的时候,Regiser按钮向其父控件(即窗体A)发送WM_COMMAND消息。
当时我也不知道参数怎么表示,我看了OD的帮助,里面的表达式的例子中有类似的,我就拿来用了。后来想明白了:
当执行到SendMessageW内部的时候,[ESP]即栈顶存储着由调用它的函数的call压入的SendMessageW的下一条语句的EIP,
而[ESP+4]当然是SendMessageW的第一个参数(因为SendMessageW是stdcall调用约定,参数从右向左依次压入栈),
进而[ESP+8],[ESP+0C],[ESP+10]分别存储第2、3、4个参数。
后来果然在点击register按钮之后断了下来,接着我就在OD右下角的窗口(一直不知道叫什么窗口,汗...)点击鼠标右键,
选择“在汇编窗口跟随”,这样就来到了调用SendMessageW的函数所在的Context,居然不是vbsedit的环境,
而是系统的另一个dll环境COMCTL32。
我迷茫了,然后我又在OD提供的堆栈窗口中(第一次知道有这个窗口,瞎弄...),
发现了WM_LBUTTONUP常量,这不是鼠标左键弹起的消息吗?
也就是点击按钮之后一定会产生的消息!然后我又稀里糊涂从堆栈窗口跟随到汇编窗口,
当时好像是接着对DispatchMessageW下了条件断点,进入到了程序领空(其实后来发现在WM_COMMAND断下来后,
在堆栈窗口可以右键选择"Show call"就来到程序领空了),但是一步一步跟着跟着,我就无所适从了,还是不知道到底register按钮
的点击事件的代码在哪里。。。
(3) 对ShellExecuteW下断点
依然想找到register按钮的点击事件代码。
我在窗体A不输任何东西,直接点击注册按钮,会打开注册的网页。
我猜测作者是调用了ShellExecute,而由之前的SendMessageW推知应当还是调用的Unicode版本的ShellExecuteW。
果然不错,断了下来,但是我在OD的右下角窗口中右键跟随到汇编窗口的时候傻眼了,这一堆的db啊!按Ctrl+A再分析一下依然没变啊!
这样只能再次放弃了!(但是在整理这篇文档的时候,我又试了一次,发现又是正常的代码了,悲剧阿!是不是OD版本的原因阿?)
ps:其实后来我还以为软件是使用GetProcAddress动态加载ShellExecuteW的地址的。但是后来设置了条件断点,没有断到!!!
2. 寻找显示注册窗体A的时机
我一开始以为是ShowWindow,就简单的bp ShowWindow,但是殊不知很多控件如组合框、工具栏什么的都会使用ShowWindow。
而且不仅仅是在他们创建之后才ShowWindow,好像有个时钟或是在消息循环里调用ShowWindow,如果改掉ShowWindow的调用以隐藏
注册窗体A而不使其他控件受影响,应当会很麻烦。
3. 寻找创建注册窗体A的时机
对CreateWindowW(不知道OD为什么提示未知的标志符)、CreateWindowExW、CreateDialogIndirectParamW等下断点。
创建对话框的API比较多,我使用CreateDialogIndirectParamW成功断了下来,跟随到汇编窗口:
0047E22F > \53 push ebx ; /lParam
0047E230 . 68 D1D94700 push 0047D9D1 ; |pDlgProc = vbsedit.0047D9D1
0047E235 . 50 push eax ; |hOwner
0047E236 . 57 push edi ; |pTemplate
0047E237 . FF75 10 push dword ptr [ebp+10] ; |hInst
0047E23A . FF15 8CD96700 call dword ptr [<&USER32.CreateDialog>; \CreateDialogIndirectParamW
0047E240 . 8B4D E4 mov ecx, dword ptr [ebp-1C]
0047E243 . 83C1 F0 add ecx, -10
0047E246 . 8BF8 mov edi, eax
0047E248 . E8 3330F8FF call 00401280
0047E24D . 834D FC FF or dword ptr [ebp-4], FFFFFFFF
0047E251 . EB 24 jmp short 0047E277
0047E253 . 8B4D D4 mov ecx, dword ptr [ebp-2C]
0047E256 . 85C9 test ecx, ecx
0047E258 . 74 05 je short 0047E25F
0047E25A . E8 C4F3FFFF call 0047D623
0047E25F > 8B45 E0 mov eax, dword ptr [ebp-20]
0047E262 . 8348 60 FF or dword ptr [eax+60], FFFFFFFF
0047E266 . 834D FC FF or dword ptr [ebp-4], FFFFFFFF
0047E26A . B8 70E24700 mov eax, 0047E270
0047E26F . C3 retn
0047E270 . 8B75 E0 mov esi, dword ptr [ebp-20]
0047E273 . 33DB xor ebx, ebx
0047E275 . 8BFB mov edi, ebx
0047E277 > 8B4D D8 mov ecx, dword ptr [ebp-28]
0047E27A . 3BCB cmp ecx, ebx
0047E27C . 74 18 je short 0047E296
0047E27E . 3BFB cmp edi, ebx
0047E280 . 74 14 je short 0047E296
0047E282 . 8B01 mov eax, dword ptr [ecx]
0047E284 . 8D55 B8 lea edx, dword ptr [ebp-48]
0047E287 . 52 push edx
0047E288 . FF50 18 call dword ptr [eax+18]
0047E28B . 8B06 mov eax, dword ptr [esi]
0047E28D . 53 push ebx
0047E28E . 8BCE mov ecx, esi
0047E290 . FF90 58010000 call dword ptr [eax+158]
0047E296 > E8 97490000 call 00482C32
0047E29B . 85C0 test eax, eax
0047E29D . 75 0A jnz short 0047E2A9
0047E29F . 8B06 mov eax, dword ptr [esi]
0047E2A1 . 8BCE mov ecx, esi
0047E2A3 . FF90 20010000 call dword ptr [eax+120]
0047E2A9 > 3BFB cmp edi, ebx
0047E2AB . 74 0F je short 0047E2BC
0047E2AD . F646 58 10 test byte ptr [esi+58], 10
0047E2B1 . 75 09 jnz short 0047E2BC
0047E2B3 . 57 push edi ; /hWnd
0047E2B4 . FF15 A4D96700 call dword ptr [<&USER32.DestroyWindo>; \DestroyWindow
0047E2BA . 33FF xor edi, edi
0047E2BC > 395D EC cmp dword ptr [ebp-14], ebx
0047E2BF . 74 12 je short 0047E2D3
0047E2C1 . FF75 EC push dword ptr [ebp-14] ; /hMem
0047E2C4 . FF15 F0D36700 call dword ptr [<&KERNEL32.GlobalUnlo>; \GlobalUnlock
0047E2CA . FF75 EC push dword ptr [ebp-14] ; /hMem
0047E2CD . FF15 50D56700 call dword ptr [<&KERNEL32.GlobalFree>; \GlobalFree
0047E2D3 > 33C0 xor eax, eax
0047E2D5 . 3BFB cmp edi, ebx
0047E2D7 . 0F95C0 setne al
0047E2DA > E8 4E551A00 call 0062382D
0047E2DF . C2 0C00 retn 0C;返回到下面
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0047E3EA . 33FF xor edi, edi ; vbsedit.00400000
0047E3EC . 3BC7 cmp eax, edi
0047E3EE . 74 3A je short 0047E42A
0047E3F0 . F646 58 10 test byte ptr [esi+58], 10
0047E3F4 . 74 1E je short 0047E414
0047E3F6 . 6A 04 push 4
0047E3F8 . 5F pop edi
0047E3F9 . 8BCE mov ecx, esi
0047E3FB . E8 62910000 call 00487562
0047E400 . A9 00010000 test eax, 100
0047E405 . 74 03 je short 0047E40A
0047E407 . 6A 05 push 5
0047E409 . 5F pop edi
0047E40A > 57 push edi;push进的参数(nop掉!)
0047E40B . 8BCE mov ecx, esi
0047E40D . E8 38400000 call 0048244A;显示窗体的函数,跟进去发现,不断的在PeekMessage。(nop掉!)
0047E412 . 33FF xor edi, edi
0047E414 > \397E 20 cmp dword ptr [esi+20], edi
0047E417 . 74 11 je short 0047E42A
0047E419 . 68 97000000 push 97
0047E41E . 57 push edi
0047E41F . 57 push edi
0047E420 . 57 push edi
0047E421 . 57 push edi
0047E422 . 57 push edi
0047E423 . 8BCE mov ecx, esi
0047E425 . E8 E6950000 call 00487A10;上面的显示窗体的函数的返回值eax实际上在这个call里面没有用到,所以不用构造其返回值;实际上这个call里面是在释放资源前的隐藏窗体的函数
注意:nop掉显示窗体的函数的同时,要把压入的参数那里也nop掉,否则堆栈不平衡!
后来证明nop掉的显示窗体的函数不仅对注册窗体A和注册窗体B起作用,
对其他弹出的窗体,比如Tools菜单的 References... 和 Running Scripts...等也有作用。。。
所以因为被nop掉,这些窗体在创建之后都没显示,然后直接就被隐藏了!等有时间再完善吧。。。
终于写完了,要过年回家了!!!
(改的地方很少,就不上传改后的文件啦!)
~~~~~~~~~~~~~~~~~~~~~~以下是新修改的~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23:33 2012-01-27
【新增使用工具】: LordPE
上回说到在取消掉注册窗体的显示的同时,所有其他的弹出窗体也不能显示了,今天终于解决了这个问题!
我的思路是这样的:
判断窗体的标题是否以"Register"打头,是的话就不显示,不是的话就显示它!
上回修改的是这里:
0047E40A > 57 push edi;push进的参数(nop掉!)
0047E40B . 8BCE mov ecx, esi
0047E40D . E8 38400000 call 0048244A;显示窗体的函数,跟进去发现,不断的在PeekMessage。(nop掉!)
0047E412 . 33FF xor edi, edi
根据我的思路,必须找一个地方写代码,上面这小块儿地方显然不够!不如从这个地方跳到另一个自己写的代码的地方,然后跳回到0047E412!
来找区块间隙吧!(因为新增区块我不会:P)
用LordPE查看区块.text的voffset为1000,vsize为27bf0c,而RSize为27c000。
找到了,在这里:0067cf0c到0067cfff。
注意:因为取窗体标题的GetWindowTextA用到了缓冲buffer,所以我们写代码所在区块应当有可写的属性,用LordPE轻松改之!
改后的:
0047E40A /E9 11EB1F00 jmp 0067CF20
0047E40F |90 nop
0047E410 |90 nop
0047E411 |90 nop
0047E412 . |33FF xor edi, edi
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
下面是判断窗体标题并决定是否显示的代码:
0067CF0C 52 push edx ; db 'Register',0,0
0067CF0D 65:67:6973 74>imul esi, dword ptr gs:[bp+di+74], 72>
0067CF16 0000 add byte ptr [eax], al ; buffer, 10 bytes(0)
0067CF18 0000 add byte ptr [eax], al ; 2
0067CF1A 0000 add byte ptr [eax], al ; 4
0067CF1C 0000 add byte ptr [eax], al ; 6
0067CF1E 0000 add byte ptr [eax], al ; 8
0067CF20 6A 0A push 0A;前面是定义“常量”与缓冲buffer,而从这句开始才是真正的代码
0067CF22 68 16CF6700 push 0067CF16 ; Buffer 地址
0067CF27 FF76 20 push dword ptr [esi+20] ; 窗体句柄
0067CF2A E8 FC516B77 call USER32.GetWindowTextA
0067CF2F 53 push ebx;保存原来的ebx
0067CF30 BB 0CCF6700 mov ebx, 0067CF0C ; ASCII "Register"
0067CF35 66:B9 0800 mov cx, 8
0067CF39 8A03 mov al, byte ptr [ebx]
0067CF3B 3A43 0A cmp al, byte ptr [ebx+A]
0067CF3E 75 0A jnz short 0067CF4A ; 不相等则表示不是注册窗体,显示它
0067CF40 43 inc ebx
0067CF41 67:E2 F5 loopw short 0067CF39
0067CF44 5B pop ebx
0067CF45 ^ E9 C814E0FF jmp 0047E412 ; 是注册窗体!不显示它!
0067CF4A 5B pop ebx
0067CF4B 57 push edi
0067CF4C 8BCE mov ecx, esi
0067CF4E E8 F754E0FF call 0048244A;调用显示窗体的函数
0067CF53 ^ E9 BA14E0FF jmp 0047E412
全文完。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!