SmartCheck 6.03的InstallShield序列号破解。
Passion
2001.8.20
SmartCheck 6.03对于破解者来说不但是对付VB的利器,而且它自个儿也算是典型的InstallShield安装的破解范例。Numega的产品的检验过程似乎都类似。我以前不完全地破过SoftICE,因为不全,感觉总不对,这次拿SmartCheck重新来一次,希望过程还算完整。
先拿Windows instalshield decompiler也就是wisdec反setup.ins,反出来一大段。有过一点破Sice的经验,也不浪费时间查找字符串“The
Serial Number……”了,反正找不到。看看它导入了什么DLL文件,也就是看MISC菜单下的DLL import,有俩比较特别,是UTILITY.DLL和NMINST32.DLL,其中UTILITY.DLL有个导出的函数叫DigitCheck,一个参数还是STRING,似乎专门就是检验序列号的,这么容易?
在反编译后的文本中找字串UTILITY.DLL,很容易就找到一段:
StrLocal[0007] = SUPPORTDIR ^ "UTILITY.dll"
00004C96: 0128 IF (UseDLL (StrLocal[0007]) = 00000000) THEN
00004CB6: 00B4 NumLocal[0001] = UTILITY.DigitCheck
(StrLocal[0002])
00004CC6: 00B3 UnUseDLL (StrLocal[0007])
00004CC7: 0000 ENDIF
——这是典型的动态加载UTILITY.DLL,检验序列号再释放该DLL的过程。
动态加载好办,至少可以断LoadLibraryA。
好,现在开始动态跟踪。启动SmartCheck的setup.exe,下一步下一步,嗯?怎么序列号没填就通过了?——对了,SmartCheck安装的时候会检验注册表里是否有现存的NUmega的同种产品,有的话就自动读出序列号来填到序列号框里去,真是体贴人哇。——咱们这群人谁没装Numega的东西?^_^
算了算了,按上一步回到序列号填写的界面。Ctrl+D切入Sice,下断bpx loadlibrarya do "d esp->4"
回来按下一步,断了,正是加载utility.dll。
且慢,这是正确的序列号,倘若乱填的呢?——真的乱填一气,按下一步,糟!直接出来序列号错误的消息框了。
看来序列号有两步检验过程,第一步通过后才loadlibraryA来加载UTILITY.DLL来进行第二次检验。怎么办?
断messageboxa的话也有效,断后返回nminst32.dll的领空(在我的机子上call messageboxa的地址是2491cf9,mod
nmi命令可看见NMINST32.DLL的基址是2490000),只是只能跳过检验,不能帮我们弄出正确的序列号来。
看来是nminst32.dll在弄鬼,再静态的反反看,用Win32Dasm反一下nminst32.dll,10001cf9处果然是Call MessageBoxa,往上看,一大段REPNE
SCANSB加MOVSB的,也不知道在干什么。
往上面找个断点,既不能太远进不来,也不能太近(怕已经出错了)。——这段过程好像是用SendDlgItemmessagea来获取文本框内容并且进行第一步检验,对了就EndDialog。前后找找看就知道了。
选个断点1A70,也就是2491a70,是输出函数的开始:
:10001A70 8B442408 mov
eax, dword ptr [esp+08]
:10001A74 81EC64020000 sub esp, 00000264
:10001A7A 83E810
sub eax, 00000010
:10001A7D 53
push ebx
:10001A7E 55
push ebp
:10001A7F 56
push esi
:10001A80 57
push edi
:10001A81 0F8490050000 je 10002017
:10001A87 2D00010000 sub eax,
00000100
:10001A8C 0F841C040000 je 10001EAE
:10001A92 48
dec eax
:10001A93 0F858E050000 jne 10002027
:10001A99 8B842480020000 mov eax, dword ptr
[esp+00000280]
:10001AA0 25FFFF0000 and eax,
0000FFFF
:10001AA5 83F80C
cmp eax, 0000000C
:10001AA8 0F8F76030000 jg 10001E24
:10001AAE 0F8461030000 je 10001E15
:10001AB4 48
dec eax
:10001AB5 7416
je 10001ACD
:10001AB7 48
dec eax
:10001AB8 0F8569050000 jne 10002027
其实这个断点没啥效果,程序没事就进来(这段输出函数是对话框的过程,随便动点什么东西都会进来)。
不过跟了几次后觉得前面的是检查点击了什么按钮的,看看这儿1AB5处的跳
:10001AB5 7416
je 10001ACD
其他几个跳都很远(差不多就是直接退出对话框过程),而且这个跳指向的地方附近就有SendDlgItemMessagea函数引用。估计这里跳的话可能有文章,于是下断2491acd
(不知怎的,setup界面中直接CTRL+D切入再下断的话大多数不成功,不是没效果就是Invalid address,难道填序列号的时候nminsl32.dll还没装进来?不管它,填满后先断hmemcpy进来,回Nminst32领空再来下断bpx
2491acd,注意得清掉hmemcpy的断点。)
好,断了!F10往下走:
* Reference To: USER32.SendDlgItemMessageA, Ord:01D8h
|
:10001AD4 8B1D30230210 mov ebx, dword
ptr [10022330]
…………
:10001AEC FFD3
call ebx
…………
:10001B00 FFD3
call ebx
…………
:10001B11 FFD3
call ebx
连续三次Call USER32.SendDlgItemMessageA,目的八成就是获得三个序列号框中的内容。
:10001B1A 33C0
xor eax, eax
:10001B1C F2
repnz //这里看看EDI,就是输入的序列号的前四个字符。
:10001B1D AE
scasb
跟下来一大段REPNE MOVSB SCANSB之类的,不容易弄明白什么功能,直到下面这里:
:10001C52 8D442410 lea
eax, dword ptr [esp+10]
//这里EAX看看,是序列号第一部分的前三个字符,于是可以明白,前面是取三个字符。^_^
:10001C56 33F6
xor esi, esi
:10001C58 50
push eax
:10001C59 68608F0110 push 10018F60
:10001C5E E8DD860000 call 1000A340
//对这前三个字符进行检验。
10001C5E这里来个d *esp,看见什么了?一大堆数字:640 641 480 481 490 491 510 511 520 521
跟进去看看,原来:10001C5E处的这个Call是检验输入的序列号的前三位数字是不是这一堆中的,不是?不是当然就不行!
:10001C66 85C0
test eax, eax
:10001C68 7542
jne 10001CAC
//属于这一堆的话,返回那个符合的地址,否则返回0,不跳就完了。
稍微改改数据,接着跳:
:10001CAC 6820A60110 push 1001A620
:10001CB1 E85A810000 call 10009E10
//这里是第二步检验。
:10001CB6 83C404
add esp, 00000004
:10001CB9 8BF0
mov esi, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001CAA(C)
|
:10001CBB 85F6
test esi, esi
:10001CBD 7552
jne 10001D11 //这里不跳也完蛋。
现在,序列号判断的流程都清楚了。——如果从:10001CB1处的CALL进去,里面会来个Loadlibrarya,这才真正的装入utility.dll文件。接着GetProcAddress,传参数
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10009E75(C)
|
:10009E80 6890A20110 push 1001A290
//含utility.dll路径的字串
* Reference To: KERNEL32.LoadLibraryA, Ord:0190h
|
:10009E85 FF1518220210 Call dword ptr
[10022218] //装utility.dll
:10009E8B 8BF0
mov esi, eax
:10009E8D 85F6
test esi, esi //esi返回DLL的句柄。
:10009E8F 7539
jne 10009ECA //成功则跳。
接着GetProcAddress,传参数调用
* Possible StringData Ref from Data Obj ->"DigitCheck"
|
:10009ECA 68C0520110 push 100152C0
:10009ECF 56
push esi
* Reference To: KERNEL32.GetProcAddress, Ord:0116h
|
:10009ED0 FF151C220210 Call dword ptr
[1002221C] //取DigitCheck函数的地址
:10009ED6 85C0
test eax, eax
:10009ED8 740E
je 10009EE8
:10009EDA 8D4C240C lea
ecx, dword ptr [esp+0C]
//ECX指向我们输入的序列号,已经去掉了“-”号的,
:10009EDE 51
push ecx
:10009EDF FFD0
call eax //调用,
:10009EE1 83C404
add esp, 00000004
:10009EE4 8BD8
mov ebx, eax
:10009EE6 EB2D
jmp 10009F15
10009EDF处以刚刚推入堆栈的序列号的地址为参数调用utility.DigitCheck,是应该跟进去的时候了。
- 标 题:SmartCheck 6.03的InstallShield序列号破解(上)——好久没研究了。 (7千字)
- 作 者:Passion
- 时 间:2001-8-20 23:11:33
- 链 接:http://bbs.pediy.com