破解NetScanTools Pro 2000及其InstallShield脚本破解(不完整)
Passion
我几个星期前曾受被人尊称为“皮大爷”的peterchen老兄的语无伦次的鞭策,于是也好高骛远地想研究研究InstallShield的脚本破解,正巧不久前见了洋白菜兄的InstallShield脚本反编译教程,觉得比一个字节一个字节地研究INS文件的编译后代码要方便多了,因而也就偷了许多懒。——NetScanTools
Pro 2000是一套功能非常全面的网络扫描监控工具,Northwest Performance公司开发,网址是http://www.nwpsw.com/,不过此处没完整版下载。
NetScanTools Pro 2000安装时需要输入序列号,直接破据说非常麻烦,一个比较好的法子是从INS文件入手。我在洋白菜兄的主页crackbest.com上下了一个DIS(DeInstallShield),用它反编译setup.ins文件感觉还可以。
NetScanTools Pro 2000安装程序会询问姓名公司序列号,填完按NEXT后会出现一个框要你确认填的是否正确,按“Yes”后才进行序列号检测,错则弹出对话框说“Invalid
Serial Number。”没的说,用DIS反编译其SETUP.INS,在结果中找“Invalid Serial Number”的MSGREF消息字串引用,很快就找到了下面的一段:
<LABEL_0038> REF: 00000F72
|
00002044: 00B6 START OF FUNCTION (2*StrLocals + 3*NumLocals)
00002054: 0013 StrVar[001C] = ""
0000205C: 0013 StrVar[001D] = ""
00002064: 0013 StrLocal[0001] = ""
0000206C: 0013 StrLocal[0002] = ""
00002074: 0002 Disable (00000032)
<LABEL_0039> REF: 00002147
|
0000207F: 0021 NumLocal[0002] = 00000000
0000208D: 0129 WHILE (NumLocal[0002] = 00000000)
000020AF: 00B5 NumLocal[0001] = SdRegisterUserEx_[LABEL_00B0]
(StrLocal[0001],StrLocal[0002],StrVar[001C],StrVar[001D],StrVar[001E])
000020CE: 00B5 NumLocal[0002] = SdConfirmRegistration_[LABEL_00E5]
(StrLocal[0001],StrVar[001C],StrVar[001D],StrVar[001E],00000000)
000020EF: 0000 ENDWHILE
//以上这个WHILE就是让你输入序列号并确认的。
00002108: 0128 IF (Call Function_006F_[LABEL_004D] != 00000001) THEN
~~~~这里是不等于号
00002128: 002A MessageBox ("Invalid Serial Number",SEVERE)
//在此处引用MSG字符串。
00002147: 002C Goto (LABEL_0039)
00002148: 0000 ENDIF
//然后调用LABEL_004D处的Function_006F来验证序列号,如果返回值不是1就表示出错,出现出错对话框。
00002150: 012F Return (NumLocal[0001])
00002157: 00B8 END OF FUNCTION ()
因此这里最简单的想法是把00002108处的不等于改成等于,正巧DIS有这个功能,右键点击它选Change to,改成等于就行了。退出DIS的时候会提示是否重新校验INS文件,因为SETUP在运行时会首先检测INS文件的CRC校验和,因此这里修改后也要重新校验,选“是”后新的INS文件就产生了。
再运行NetScanTools Pro 2000的安装程序,序列号乱填一气,安装通过。
按理说通常的安装软件,破到这个程度也就差不多了,但NetScanTools Pro 2000多做了一点小手脚。本来我还挺高兴地运行NSTPRO.EXE想看看自己的成果,NSTPRO.EXE却忽地弹出个窗口说是“Invalid
Installation……”并且要求重新安。?哇!看来NSTPRO.EXE启动时还有一步序列号的判断过程。序列号信息存放在什么地方呢?我连REGMON和FILEMON都懒得用了,直接打开注册表寻寻觅觅就找到了这一处:HKEY_LOCAL_MACHINE\Software\Northwest
Performance Software, Inc.\NetScanTools Pro\2000\NETSCANTOOLSPRO,下面是输入的用户名和序列号等。
首先就觉得似乎从NSTPRO.EXE中分析序列号算法还不如从INS文件中分析来得简单,既然脚本中判断序列号是否正确的子程序在LABEL_004D处,就把它的内容列出来看看啦:
<LABEL_004D> REF: 00002108
|
00002A92: 00B6 START OF FUNCTION (3*StrLocals + 10*NumLocals)
00002AA4: 0021 NumLocal[0005] = 00000081
//一个固定值
00002ABB: 0128 IF (StrLength (StrVar[001E]) < 00000018) THEN
00002ADB: 012F Return (00000000)
00002ADC: 0000 ENDIF
//如果序列号长度小于18H则出错
00002AE8: 0128 IF (NumLocal[0006] > 00000019) THEN
00002B08: 012F Return (00000000)
00002B09: 0000 ENDIF
//长度大于19H也出错,因此序列号只能是18H位或19H位。
00002B15: 0128 IF (NumLocal[0006] = 00000018) THEN
//如果长度是18H,则……
00002B35: 0021 NumLocal[0003] = 00000000
//N3是SL3的字串位置指针
00002B3F: 0021 NumLocal[0002] = 00000013
//N2是序列号的字串位置指针
<LABEL_0050> REF: 00002B9D
|
00002B4D: 0128 IF (NumLocal[0002] <= 00000017)
THEN
00002B6D: 007A NumLocal[0009] = GetByte
(StrVar[001E],NumLocal[0002])
//SV1E是用户输入的序列号
00002B78: 007B SetByte (StrLocal[0003],NumLocal[0003],NumLocal[0009])
00002B83: 0119 NumLocal[0003] = NumLocal[0003]
+ 00000001
00002B90: 0119 NumLocal[0002] = NumLocal[0002]
+ 00000001
00002B9D: 002C Goto (LABEL_0050)
00002B9E: 0000 ENDIF
//将SL3的值赋成序列号中的第13H位到17H位子串,该子串是数字。
00002BA6: 0021 NumLocal[0006] = 00000013
//并且N6记录了该数字字串在序列号中出现的位置
00002BA7: 0000 ENDIF
//如果长度是19,则……
00002BB4: 0128 IF (NumLocal[0006] = 00000019) THEN
00002BD4: 0021 NumLocal[0003] = 00000000
00002BDE: 0021 NumLocal[0002] = 00000014
<LABEL_0053> REF: 00002C3C
|
00002BEC: 0128 IF (NumLocal[0002] <= 00000018)
THEN
00002C0C: 007A NumLocal[0009] = GetByte
(StrVar[001E],NumLocal[0002])
00002C17: 007B SetByte (StrLocal[0003],NumLocal[0003],NumLocal[0009])
00002C22: 0119 NumLocal[0003] = NumLocal[0003]
+ 00000001
00002C2F: 0119 NumLocal[0002] = NumLocal[0002]
+ 00000001
00002C3C: 002C Goto (LABEL_0053)
00002C3D: 0000 ENDIF
00002C45: 0021 NumLocal[0006] = 00000014
00002C46: 0000 ENDIF
00002C53: 0021 NumLocal[0002] = 00000000
//如果长度是19H,则取14H到18H位到SL3中。
<LABEL_0056> REF: 00002D5D
|
//到这里为止,N2是下一步即将进行的处理中的字串指针
//下一步是个大循环。
00002C61: 007A NumLocal[0009] = GetByte (StrVar[001E],NumLocal[0002])
//N9是输入序列号的某个字符
00002C6C: 011D NumLocal[0007] = 000000FF & NumLocal[0009]
//N7=N9 AND 0xFF,个人感觉N7实际上等于N9
00002C79: 0119 NumLocal[0002] = NumLocal[0002] + 00000001
00002C86: 0021 NumLocal[0003] = 00000000
//N3是循环变量,此处初始化
<LABEL_0057> REF: 00002D35
|
//以下是个小循环,处理序列号中的一个字符
00002C94: 0128 IF (NumLocal[0003] <= 00000007) THEN
00002CB4: 011D NumLocal[0009] = NumLocal[0005]
& 00000001
00002CC1: 011D NumLocal[000A] = NumLocal[0007]
& 00000001
00002CD9: 0022 IF (NumLocal[0009] ^ NumLocal[000A]
!= 00000000) THEN
00002CE7: 0122 NumLocal[0009] = NumLocal[0005]
>> 00000001
00002CF4: 011F NumLocal[0005] = NumLocal[0009]
^ 00008408
00002D01: 0000 ELSE
00002D0A: 0122 NumLocal[0005] = NumLocal[0005]
>> 00000001
00002D0B: 0000 ENDIF
00002D1B: 0122 NumLocal[0007] = NumLocal[0007]
>> 00000001
00002D28: 0119 NumLocal[0003] = NumLocal[0003]
+ 00000001
00002D35: 002C Goto (LABEL_0057)
00002D36: 0000 ENDIF
//小循环结束
00002D5D: 0022 IF (NumLocal[0006] - = 00000000) THEN GOTO LABEL_0056
//减一后等于0就跳回去继续循环?不等呢就结束循环?这是疑点之一。
//大循环结束后开始验证
00002D6B: 0120 NumLocal[0007] = NumLocal[0005] ~ NumLocal[0005]
00002D7E: 0121 NumLocal[0009] = NumLocal[0005] << 00000008
00002D8B: 0122 NumLocal[000A] = NumLocal[0007] >> 00000008
00002D98: 011D NumLocal[000A] = NumLocal[000A] & 000000FF
00002DA5: 011E NumLocal[0005] = NumLocal[0009] | NumLocal[000A]
00002DB0: 011D NumLocal[0005] = NumLocal[0005] & 0000FFFF
//最后的结果是N5,与SL3的数字值比较,等则表示输入的序列号合法。
00002DCD: 0128 IF (StrToNum (NumLocal[0004],StrLocal[0003]) < 00000000)
THEN
00002DED: 012F Return (FFFFFFFF)
00002DEE: 0000 ENDIF
00002DFA: 0128 IF (NumLocal[0005] != NumLocal[0004]) THEN
00002E18: 012F Return (FFFFFFFF)
00002E21: 0000 ELSE
00002E2A: 012F Return (00000001)
00002E2B: 0000 ENDIF
00002E37: 00B8 END OF FUNCTION ()
上边我能看懂的地方加了一些注释,名为STRVAL的都是字符串型全局变量,名里有local的都是局部变量。StrVar[001E]是我们输入的序列号。这个程序首先判断序列号是否是18H或19H长,然后取出序列号的最后五个数字。程序末尾把运算的结果与这个五位数字值比较,不等则出错。整个运算过程虽不长,却有点不符合常规。——我手头没有详细介绍INSTALLshield脚本语法的资料,上次皮特陈兄虽做了一个,却不敢看(老死机),只有猜测着来。与或非左右移等符号和C中差不多,IFWHILEENDIF等和VB又差不多。我按照我的理解编了一段C代码来模仿这段运算过程。先输入19个字符(0到0x13),再把这些字符运算得到五位数字(0x13到0x17),但拼凑起来的序列号根本通不过。我一直以为是我的脚本算法理解错误,山穷水尽了好几天也没什么结果(对自己的水平没有自信啦)。
我也打算去找一个正确的序列号来验证自己的想法,可这种软件的这个版本的序列号在什么啊嘶嗒啦唯嘶嗒上是找不到的。再后来,“我本善良”兄给了我一个能用的序列号9351324-005376-001-32602,确实后五位是数字,前19位应该是输入的东西,只是前19位看起来有了许多限制,比如哪几位是数字,哪一位是“-”等,这在脚本里却没找到。
现在只有从NSTPRO.EXE入手分析读注册表中序列号的一段了。老法子,弹出出错框时切入TRW查输入的序列号再下Bpm内存断点,偏偏TRW不稳定,内存断点又断不了,我气得扔下它不干了。过了几天,该忙的似乎应付了一点后,弄了个SOFTICE来,这下子稳定多了。——由于这段时间忙,搞点破解只能挤出时间来,经常是研究几个小时又停几天,这就叫“三天破解,两天晒网”,这种不良的风气值得批斗。
后来通过几个BPM断点来到了这一段:
* Reference To: KERNEL32.lstrlenA, Ord:02A1h
|
:00438D10 FF15C0D24900 Call dword
ptr [0049D2C0]
:00438D16 83F818
cmp eax, 00000018
:00438D19 0F858D000000 jne 00438DAC
:00438D1F 8D8C2494000000 lea ecx, dword
ptr [esp+00000094]
* Possible Reference to String Resource ID=00019: "Edit the list of IP addresses
and Hostnames."
|
:00438D26 6A13
push 00000013
:00438D28 51
push ecx
:00438D29 E8C2210000 call
0043AEF0
:00438D2E 83C408
add esp, 00000008
:00438D31 8D942494000000 lea edx, dword
ptr [esp+00000094]
:00438D38 8D4C2418
lea ecx, dword ptr [esp+18]
:00438D3C 8BF0
mov esi, eax
:00438D3E 52
push edx
:00438D3F E848AB0400 call
0048388C
:00438D44 8D44241C
lea eax, dword ptr [esp+1C]
* Possible Reference to String Resource ID=00005: "Error getting host address:
%s"
|
:00438D48 6A05
push 00000005
:00438D4A 50
push eax
:00438D4B 8D4C2420
lea ecx, dword ptr [esp+20]
:00438D4F C684245C63000001 mov byte ptr [esp+0000635C],
01
:00438D57 E8E3440400 call
0047D23F //取序列号后五位子串
:00438D5C 50
push eax
:00438D5D 8D4C241C
lea ecx, dword ptr [esp+1C]
:00438D61 C684245863000002 mov byte ptr [esp+00006358],
02
:00438D69 E8A9AB0400 call
00483917
:00438D6E 8D4C241C
lea ecx, dword ptr [esp+1C]
:00438D72 C684245463000001 mov byte ptr [esp+00006354],
01
:00438D7A E89FAA0400 call
0048381E
:00438D7F 8B4C2418
mov ecx, dword ptr [esp+18]
:00438D83 51
push ecx
:00438D84 E8572F0300 call
0046BCE0
:00438D89 81E6FFFF0000 and esi, 0000FFFF
:00438D8F 83C404
add esp, 00000004
:00438D92 3BF0
cmp esi, eax
//此处EAX和ESI,一个是根据前多少位计算出来的校验值,一个是序列号中后五位转换成的数字值,所以这里是一步比较关键的跳转。
:00438D94 7502
jne 00438D98
:00438D96 33FF
xor edi, edi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00438D94(C)
|
:00438D98 8D4C2418
lea ecx, dword ptr [esp+18]
:00438D9C C684245463000000 mov byte ptr [esp+00006354],
00
:00438DA4 E875AA0400 call
0048381E
:00438DA9 83CEFF
or esi, FFFFFFFF
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00438D19(C)
|
:00438DAC 8D942494000000 lea edx, dword
ptr [esp+00000094]
:00438DB3 52
push edx
* Reference To: KERNEL32.lstrlenA, Ord:02A1h
|
:00438DB4 FF15C0D24900 Call dword
ptr [0049D2C0]
:00438DBA 83F819
cmp eax, 00000019
:00438DBD 0F858D000000 jne 00438E50
:00438DC3 8D842494000000 lea eax, dword
ptr [esp+00000094]
* Possible Reference to String Resource ID=00020: "If checked, get latest
news from our website when first view"
|
:00438DCA 6A14
push 00000014
:00438DCC 50
push eax
:00438DCD E81E210000 call
0043AEF0
:00438DD2 83C408
add esp, 00000008
:00438DD5 8D8C2494000000 lea ecx, dword
ptr [esp+00000094]
:00438DDC 8BF0
mov esi, eax
:00438DDE 51
push ecx
:00438DDF 8D4C241C
lea ecx, dword ptr [esp+1C]
:00438DE3 E8A4AA0400 call
0048388C
:00438DE8 8D54241C
lea edx, dword ptr [esp+1C]
* Possible Reference to String Resource ID=00005: "Error getting host address:
%s"
|
:00438DEC 6A05
push 00000005
:00438DEE 52
push edx
:00438DEF 8D4C2420
lea ecx, dword ptr [esp+20]
:00438DF3 C684245C63000003 mov byte ptr [esp+0000635C],
03
:00438DFB E83F440400 call
0047D23F
:00438E00 50
push eax
:00438E01 8D4C241C
lea ecx, dword ptr [esp+1C]
:00438E05 C684245863000004 mov byte ptr [esp+00006358],
04
:00438E0D E805AB0400 call
00483917
:00438E12 8D4C241C
lea ecx, dword ptr [esp+1C]
:00438E16 C684245463000003 mov byte ptr [esp+00006354],
03
:00438E1E E8FBA90400 call
0048381E
:00438E23 8B442418
mov eax, dword ptr [esp+18]
:00438E27 50
push eax
:00438E28 E8B32E0300 call
0046BCE0
:00438E2D 81E6FFFF0000 and esi, 0000FFFF
:00438E33 83C404
add esp, 00000004
:00438E36 3BF0
cmp esi, eax
//这里与上面的是一样的,所不同的应该就是一个处理0X18位,一个处理0X19位。
:00438E38 7502
jne 00438E3C
:00438E3A 33FF
xor edi, edi
如果要找注册码运算的地方,可从前面跟进去到下面的这个地方(如果是0X18位序列号的话):
|
:00445DF7 6A13
push 00000013
:00445DF9 50
push eax
:00445DFA E8F150FFFF call
0043AEF0 //从这里再跟进去。
:00445DFF 83C408
add esp, 00000008
:00445E02 8D4C241C
lea ecx, dword ptr [esp+1C]
:00445E06 8BF8
mov edi, eax
:00445E08 51
push ecx
:00445E09 8D4C2414
lea ecx, dword ptr [esp+14]
:00445E0D E87ADA0300 call
0048388C
:00445E12 8D542414
lea edx, dword ptr [esp+14]
从00445DFA处跟进CALL中,代码如下:
:0043AEF0 55
push ebp
:0043AEF1 8B6C240C
mov ebp, dword ptr [esp+0C]
//BP循环控制,目前是13,似乎对应着00002BA6: 0021 的NumLocal[0006] = 00000013
:0043AEF5 6685ED
test bp, bp
* Possible Reference to Dialog: DialogID_0081
|
:0043AEF8 B881000000 mov eax,
00000081
//这个0X81的常数是否有些眼熟?——就是INSTALLSHIELD反编译脚本中的
00002AA4: 0021 NumLocal[0005] = 00000081 哇!
:0043AEFD 7506
jne 0043AF05
:0043AEFF 66B87EFF
mov ax, FF7E
:0043AF03 5D
pop ebp
:0043AF04 C3
ret
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0043AEFD(C)
|
:0043AF05 57
push edi
:0043AF06 8B7C240C
mov edi, dword ptr [esp+0C]
:0043AF0A 56
push esi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0043AF37(C)
|
:0043AF0B 8A0F
mov cl, byte ptr [edi] //读一个字符
* Possible Reference to String Resource ID=00008: "Error connecting to host:
%s"
|
:0043AF0D BE08000000 mov esi,
00000008 //对每一个字符要进行八次循环。
//
:0043AF12 81E1FF000000 and ecx, 000000FF
//对应着
:00
- 标 题:破解NetScanTools Pro 2000及其InstallShield脚本破解(其实脚本没破成) (18千字)
- 作 者:Passion
- 时 间:2001-3-30 23:50:41
- 链 接:http://bbs.pediy.com