SPQuery v4.2 build 4237
http://www.stbernard.com
如果你是WinNT/2K的系统管理员,这个工具是非常有用的。
用isDcc反编译setup.ins脚本,得到脚本源码。显然是调用sbssetup.dll来判断安装序列号的。关键的是下面这几个:
prototype SBSSETUP.VerifySN(string);
prototype SBSSETUP.GetModeCode(string);
prototype SBSSETUP.GetLicenseLevel(string);
判断序列号的部分如下(string7就是序列号):
label18: //Ref: 001428
00143F:00B4: SBSSETUP.VerifySN(string7);
//判断序列号
001447:0021: lNumber0 = LAST_RESULT;
00144F:0128: lNumber3 = lNumber0 < 0;
001461:0022: if (lNumber3 = 0) then
goto label19;
endif;
00146F:0112: StrLoadString("", "INVALID_SN", lString0);
001484:002A: MessageBox(lString0, -65535);
00148E:002C: goto label17;
label19: //Ref: 001461
001497:00B4: SBSSETUP.GetModeCode(string7);
//这里
00149F:0021: lNumber2 = LAST_RESULT;
0014A7:0128: lNumber3 = lNumber2 < 0;
0014B9:0022: if (lNumber3 = 0) then
goto label20;
endif;
0014C7:0112: StrLoadString("", "INVALID_SN", lString0);
0014DC:002A: MessageBox(lString0, -65535);
0014E6:002C: goto label17;
label20: //Ref: 0014B9
0014EF:00B4: SBSSETUP.GetLicenseLevel(string7);
//这里
0014F7:0021: lNumber1 = LAST_RESULT;
0014FF:0128: lNumber3 = lNumber1 < 0;
001511:0022: if (lNumber3 = 0) then
goto label21;
endif;
00151F:0112: StrLoadString("", "INVALID_SN", lString0);
001534:002A: MessageBox(lString0, -65535);
00153E:002C: goto label17;
label21: //Ref: 001511
001547:0128: lNumber3 = MODE = 0;
001559:0022: if (lNumber3 = 0) then
goto label26;
endif;
001567:0128: lNumber3 = lNumber2 > 1;
001579:0022: if (lNumber3 = 0) then
goto label24;
endif;
001587:0128: lNumber3 = lNumber1 = 0;
001599:0022: if (lNumber3 = 0) then
goto label22;
endif;
0015A7:0112: StrLoadString("", "LICENSE_EXPLANATION",
lString0);
0015C5:0112: StrLoadString("", "LIVE_TRIAL_UNLIMITED",
lString1);
0015E4:0104: SprintfBox(-65535, lString0, lString1);
0015F4:002C: goto label23;
label22: //Ref: 001599
0015FD:0112: StrLoadString("", "LICENSE_EXPLANATION",
lString0);
00161B:0112: StrLoadString("", "LIVE_TRIAL_LIMITED",
lString1);
001638:0104: SprintfBox(-65535, lString0, lString1,
lNumber1, lNumber1);
label23: //Ref: 0015F4
001652:002C: goto label26;
label24: //Ref: 001579
00165B:0128: lNumber3 = lNumber1 = 0;
00166D:0022: if (lNumber3 = 0) then
goto label25;
endif;
00167B:0112: StrLoadString("", "LICENSE_EXPLANATION",
lString0);
001699:0112: StrLoadString("", "MACHINE_UNLIMITED",
lString1);
0016B5:0104: SprintfBox(-65535, lString0, lString1);
0016C5:002C: goto label26;
label25: //Ref: 00166D
0016CE:0112: StrLoadString("", "LICENSE_EXPLANATION",
lString0);
0016EC:0112: StrLoadString("", "MACHINE_LIMITED",
lString1);
001706:0104: SprintfBox(-65535, lString0, lString1,
lNumber1, lNumber1);
察看文本文件value.shl,得到字符串宏定义如下:
INVALID_SN=Invalid Serial Number.
LIVE_TRIAL_LIMITED=You have installed a license allowing you to evaluate SPQuery
on %d machines for 15 days. Once %d machines have been queried, any
remaining machines will become inaccessible via SPQuery.
SERIAL_NUMBER=Serial Number:
MACHINE_UNLIMITED=You have installed a license allowing you to use SPQuery
at one physical site.
LIVE_TRIAL_UNLIMITED=You have installed a license allowing you to evaluate
SPQuery on any number of machines for 15 days.
MACHINE_LIMITED=You have installed a license allowing you to use SPQuery on
%d machines. Once %d machines have been queried, any remaining machines
will become inaccessible via SPQuery.
LICENSE_EXPLANATION=License Explanation
显然它有多种序列号,不同的序列号对应不同的license类型。最完美的当然是MACHINE_UNLIMITED,没有时间和机器数目的限制。
那就看看如何才能让程序流程走到MACHINE_UNLIMITED这里来。
lNumber0 = SBSSETUP.VerifySN(string7); //lNumber0
应大于等于0
lNumber2 = SBSSETUP.GetModeCode(string7); //lNumber2应大于等于0,且小于等于1
lNumber1 = SBSSETUP.GetLicenseLevel(string7); //lNumber1应等于0
得到上述条件之后启动SoftICE针对DLL中的函数设断点进行跟踪,使用其默认的序列号01-0184-4174-0909。
发现它是把注册码的后两部分4174和0909用同一个函数进行变换,分别得到0B26和5005,lNumber0就等于0B26的高两位即0B,
而lNumber2则等于0B26中的2,lNumber1则为5005的低三位即005。它还会取出0B26中的低位(即6),和5005的高位(即5)
凑成一个字节0x65,并将该字节与另外一个字节(此字节是根据注册码其它部分计算出来的)进行比较,比较的地方如下:
001B:01972307 CALL 01971FE0
001B:0197230C MOV DL,[ESP+32]
001B:01972310 MOV AL,[ESP+33]
001B:01972314 ADD ESP,20
001B:01972317 CMP DL,AL
//比较
001B:01972319 JNZ 01972368
再结合上面得出的lNumber0,lNumber1,lNumber2所要满足的条件,就可以知道变换后的两个数所要满足的条件。
现在的问题就是根据变换后的数如何反推出变换前的数(即注册码的后两部分)来,从而写出keymaker。看一下变换函数,
该函数只是对一个16-bit整数的16个bit进行调换位置的操作,从而得到一个新的16-bit数,这个换位变换显然是可逆的。
假定变换前的整数的16个bit依次为15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,则变换得到的新的整数16个bit依次为
15,11,7,3,14,10,6,2,13,9,5,1,12,8,4,0。即变换后的整数的第15 bit等于变换前的整数的第15 bit,变换后的整数的第14
bit
等于变换前的整数的第11 bit···依次类推。如下:
* Referenced by a CALL at Addresses:
|:10002200 , :1000220A
|
:10001D50 8B4C2404
mov ecx, dword ptr [esp+04]
:10001D54 83EC08
sub esp, 00000008
:10001D57 8D442400
lea eax, dword ptr [esp]
:10001D5B 53
push ebx
:10001D5C 55
push ebp
:10001D5D 56
push esi
:10001D5E 57
push edi
:10001D5F 50
push eax
:10001D60 51
push ecx
:10001D61 E84AFFFFFF call
10001CB0 //atol( )或sscanf(
)
:10001D66 8B442418
mov eax, dword ptr [esp+18] //变换前的16-bit整数
:10001D6A 8BC8
mov ecx, eax
:10001D6C 81E10F000080 and ecx, 8000000F
//ecx中存放该数的3~0 bit
:10001D72 7905
jns 10001D79
:10001D74 49
dec ecx
:10001D75 83C9F0
or ecx, FFFFFFF0
:10001D78 41
inc ecx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001D72(C)
|
:10001D79 99
cdq
:10001D7A 83E20F
and edx, 0000000F
:10001D7D 03C2
add eax, edx
:10001D7F C1F804
sar eax, 04
:10001D82 8BF0
mov esi, eax
:10001D84 81E60F000080 and esi, 8000000F
//esi中存放该数的7~4 bit
:10001D8A 7905
jns 10001D91
:10001D8C 4E
dec esi
:10001D8D 83CEF0
or esi, FFFFFFF0
:10001D90 46
inc esi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001D8A(C)
|
:10001D91 99
cdq
:10001D92 83E20F
and edx, 0000000F
:10001D95 03C2
add eax, edx
:10001D97 C1F804
sar eax, 04
:10001D9A 8BF8
mov edi, eax
:10001D9C 81E70F000080 and edi, 8000000F
//edi中存放该数的11~8 bit
:10001DA2 7905
jns 10001DA9
:10001DA4 4F
dec edi
:10001DA5 83CFF0
or edi, FFFFFFF0
:10001DA8 47
inc edi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001DA2(C)
|
:10001DA9 99
cdq
:10001DAA 83E20F
and edx, 0000000F
:10001DAD 03C2
add eax, edx
:10001DAF C1F804
sar eax, 04
:10001DB2 8BD8
mov ebx, eax
:10001DB4 81E30F000080 and ebx, 8000000F
//ebx中存放该数的15~12 bit
:10001DBA 7905
jns 10001DC1
:10001DBC 4B
dec ebx
:10001DBD 83CBF0
or ebx, FFFFFFF0
:10001DC0 43
inc ebx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001DBA(C)
|
:10001DC1 8BC3
mov eax, ebx
:10001DC3 99
cdq
:10001DC4 83E207
and edx, 00000007
:10001DC7 03C2
add eax, edx
:10001DC9 C1F803
sar eax, 03
:10001DCC 8BE8
mov ebp, eax
:10001DCE 81E501000080 and ebp, 80000001
//用掩码取出该数的第15 bit
:10001DD4 7905
jns 10001DDB
:10001DD6 4D
dec ebp
:10001DD7 83CDFE
or ebp, FFFFFFFE
:10001DDA 45
inc ebp
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001DD4(C)
|
:10001DDB 8BC7
mov eax, edi
:10001DDD 99
cdq
:10001DDE 83E207
and edx, 00000007
:10001DE1 03C2
add eax, edx
:10001DE3 C1F803
sar eax, 03
:10001DE6 2501000080 and eax,
80000001 //用掩码取出该数的第11 bit
:10001DEB 7905
jns 10001DF2
:10001DED 48
dec eax
:10001DEE 83C8FE
or eax, FFFFFFFE
:10001DF1 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001DEB(C)
|
:10001DF2 8D2C68
lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001DF5 8BC6
mov eax, esi
:10001DF7 99
cdq
:10001DF8 83E207
and edx, 00000007
:10001DFB 03C2
add eax, edx
:10001DFD C1F803
sar eax, 03
:10001E00 2501000080 and eax,
80000001 //用掩码取出该数的第7 bit
:10001E05 7905
jns 10001E0C
:10001E07 48
dec eax
:10001E08 83C8FE
or eax, FFFFFFFE
:10001E0B 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001E05(C)
|
:10001E0C 8D2C68
lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001E0F 8BC1
mov eax, ecx
:10001E11 99
cdq
:10001E12 83E207
and edx, 00000007
:10001E15 03C2
add eax, edx
:10001E17 C1F803
sar eax, 03
:10001E1A 2501000080 and eax,
80000001 //用掩码取出该数的第3 bit
:10001E1F 7905
jns 10001E26
:10001E21 48
dec eax
:10001E22 83C8FE
or eax, FFFFFFFE
:10001E25 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001E1F(C)
|
:10001E26 8D2C68
lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001E29 8BC3
mov eax, ebx
:10001E2B 99
cdq
:10001E2C 83E203
and edx, 00000003
:10001E2F 03C2
add eax, edx
:10001E31 C1F802
sar eax, 02
:10001E34 2501000080 and eax,
80000001 //用掩码取出该数的第14 bit
:10001E39 7905
jns 10001E40
:10001E3B 48
dec eax
:10001E3C 83C8FE
or eax, FFFFFFFE
:10001E3F 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001E39(C)
|
:10001E40 8D2C68
lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001E43 8BC7
mov eax, edi
:10001E45 99
cdq
:10001E46 83E203
and edx, 00000003
:10001E49 03C2
add eax, edx
:10001E4B C1F802
sar eax, 02
:10001E4E 2501000080 and eax,
80000001 //用掩码取出该数的第10 bit
:10001E53 7905
jns 10001E5A
:10001E55 48
dec eax
:10001E56 83C8FE
or eax, FFFFFFFE
:10001E59 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001E53(C)
|
:10001E5A 8D2C68
lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001E5D 8BC6
mov eax, esi
:10001E5F 99
cdq
:10001E60 83E203
and edx, 00000003
:10001E63 03C2
add eax, edx
:10001E65 C1F802
sar eax, 02
:10001E68 2501000080 and eax,
80000001 //用掩码取出该数的第6 bit
:10001E6D 7905
jns 10001E74
:10001E6F 48
dec eax
:10001E70 83C8FE
or eax, FFFFFFFE
:10001E73 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001E6D(C)
|
:10001E74 8D2C68
lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001E77 8BC1
mov eax, ecx
:10001E79 99
cdq
:10001E7A 83E203
and edx, 00000003
:10001E7D 03C2
add eax, edx
:10001E7F C1F802
sar eax, 02
:10001E82 2501000080 and eax,
80000001 //用掩码取出该数的第2 bit
:10001E87 7905
jns 10001E8E
:10001E89 48
dec eax
:10001E8A 83C8FE
or eax, FFFFFFFE
:10001E8D 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001E87(C)
|
:10001E8E 8D2C68
lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001E91 8BC3
mov eax, ebx
:10001E93 99
cdq
:10001E94 2BC2
sub eax, edx
:10001E96 D1F8
sar eax, 1
:10001E98 2501000080 and eax,
80000001 //用掩码取出该数的第13 bit
:10001E9D 7905
jns 10001EA4
:10001E9F 48
dec eax
:10001EA0 83C8FE
or eax, FFFFFFFE
:10001EA3 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001E9D(C)
|
:10001EA4 8D2C68
lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001EA7 8BC7
mov eax, edi
:10001EA9 99
cdq
:10001EAA 2BC2
sub eax, edx
:10001EAC D1F8
sar eax, 1
:10001EAE 2501000080 and eax,
80000001 //用掩码取出该数的第9 bit
:10001EB3 7905
jns 10001EBA
:10001EB5 48
dec eax
:10001EB6 83C8FE
or eax, FFFFFFFE
:10001EB9 40
inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001EB3(C)
|
:10001EBA 8D2C68 lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001EBD 8BC6 mov eax, esi
:10001EBF 99 cdq
:10001EC0 2BC2 sub eax, edx
:10001EC2 D1F8 sar eax, 1
:10001EC4 2501000080 and eax, 80000001 //用掩码取出该数的第5 bit
:10001EC9 7905 jns 10001ED0
:10001ECB 48 dec eax
:10001ECC 83C8FE or eax, FFFFFFFE
:10001ECF 40 inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001EC9(C)
|
:10001ED0 8D2C68 lea ebp, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001ED3 8BC1 mov eax, ecx
:10001ED5 99 cdq
:10001ED6 2BC2 sub eax, edx
:10001ED8 D1F8 sar eax, 1
:10001EDA 2501000080 and eax, 80000001 //用掩码取出该数的第1 bit
:10001EDF 7905 jns 10001EE6
:10001EE1 48 dec eax
:10001EE2 83C8FE or eax, FFFFFFFE
:10001EE5 40 inc eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001EDF(C)
|
:10001EE6 81E301000080 and ebx, 80000001 //用掩码取出该数的第12 bit
:10001EEC 8D1468 lea edx, dword ptr [eax+2*ebp] //乘以2(二进制)再加上新的bit
:10001EEF 7905 jns 10001EF6
:10001EF1 4B dec ebx
:10001EF2 83CBFE or ebx, FFFFFFFE
:10001EF5 43 inc ebx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001EEF(C)
|
:10001EF6 81E701000080 and edi, 80000001 //用掩码取出该数的第8 bit
:10001EFC 8D0453 lea eax, dword ptr [ebx+2*edx] //乘以2(二进制)再加上新的bit
:10001EFF 7905 jns 10001F06
:10001F01 4F dec edi
:10001F02 83CFFE or edi, FFFFFFFE
:10001F05 47 inc edi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001EFF(C)
|
:10001F06 81E601000080 and esi, 80000001 //用掩码取出该数的第4 bit
:10001F0C 8D1447 lea edx, dword ptr [edi+2*eax] //乘以2(二进制)再加上新的bit
:10001F0F 7905 jns 10001F16
:10001F11 4E dec esi
:10001F12 83CEFE or esi, FFFFFFFE
:10001F15 46 inc esi
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001F0F(C)
|
:10001F16 81E101000080 and ecx, 80000001 //用掩码取出该数的第0 bit
:10001F1C 8D0456 lea eax, dword ptr [esi+2*edx] //乘以2(二进制)再加上新的bit
:10001F1F 7905 jns 10001F26
:10001F21 49 dec ecx
:10001F22 83C9FE or ecx, FFFFFFFE
:10001F25 41 inc ecx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001F1F(C)
|
:10001F26 8B5C2424 mov ebx, dword ptr [esp+24]
:10001F2A 8D0441 lea eax, dword ptr [ecx+2*eax] //乘以2(二进制)再加上新的bit
:10001F2D 6A10 push 00000010
:10001F2F 53 push ebx //ebx中存放变换后的整数
:10001F30 50 push eax
:10001F31 89442424 mov dword ptr [esp+24], eax
:10001F35 E812060000 call 1000254C //sprintf( )
上面的变换看似复杂,实际上可以简化为一个循环,其逆运算就是把各个bit调换回去,如下:
int a = 0x0B26; //变换后的
int b = 0; //变换前的
int index[] = {15,11,7,3,14,10,6,2,13,9,5,1,12,8,4,0};
for(int k = 0; k < 16; k++)
{
b <<= 1;
b |= (a >> index[k]) & 1;
}
这样就可以写出keymaker来,一个注册码是01-0184-4056-8888。注意VerifySN( )函数实际上应该返回0x0B,这点在安装时
不判断,但是其主程序在运行时会判断,若不等于0x0B则无法运行,主要是因为它用这个返回值来区分该公司的不同软件。
* Possible StringData Ref from Data Obj ->"CSPQueryApp::InitInstance - About "
->"to validate SN"
|
:00498348 689C305200 push 0052309C
:0049834D E8FE08F7FF call 00408C50
:00498352 83C404 add esp, 00000004
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00498346(C)
|
:00498355 51 push ecx
:00498356 8BCC mov ecx, esp
:00498358 89642418 mov dword ptr [esp+18], esp
:0049835C 51 push ecx
:0049835D 8BCD mov ecx, ebp
:0049835F E88C270000 call 0049AAF0
:00498364 8BCD mov ecx, ebp
:00498366 E815280000 call 0049AB80
:0049836B 8BF0 mov esi, eax
:0049836D 3BF3 cmp esi, ebx
:0049836F 7423 je 00498394
:00498371 F6054078520002 test byte ptr [00527840], 02
:00498378 740D je 00498387
* Possible StringData Ref from Data Obj ->"CSPQueryApp::InitInstance - Invalid "
->"SN"
|
:0049837A 6874305200 push 00523074
:0049837F E8CC08F7FF call 00408C50
:00498384 83C404 add esp, 00000004
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00498378(C)
|
:00498387 56 push esi
:00498388 8BCD mov ecx, ebp
:0049838A E8312B0000 call 0049AEC0
:0049838F E939060000 jmp 004989CD
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0049836F(C)
|
:00498394 8B8504020000 mov eax, dword ptr [ebp+00000204]
:0049839A 83F80A cmp eax, 0000000A
:0049839D 7511 jne 004983B0
:0049839F 53 push ebx
:004983A0 53 push ebx
* Possible StringData Ref from Data Obj ->"Domain license is detected for "
->"this current version of SPQuery. "
->" Please contact St. Bernard Software "
->"for a new license."
|
:004983A1 68FC2F5200 push 00522FFC
* Reference To: MFC42.Ordinal:04B0, Ord:04B0h
|
:004983A6 E849950400 Call 004E18F4
:004983AB E91D060000 jmp 004989CD
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0049839D(C)
|
:004983B0 83F80B cmp eax, 0000000B //VerifySN( )的返回值
:004983B3 740C je 004983C1
:004983B5 8BCD mov ecx, ebp
:004983B7 E8D42B0000 call 0049AF90 //出错MessageBox
:004983BC E90C060000 jmp 004989CD
BF