WinIMP软件是和WinRAR、WinZIP等类似的一款压缩打包软件,而其独有的.imp格式的压缩率远高于ZIP格式,和RAR也是各有千秋,而它的自解压格式更是我的至爱,时至今日仍然不比其它同类软件逊色。
七年前,小楼大侠曾经写过一篇与它相关的算法文章,可能是受当时的工具所限,却不理想。而dr0大侠倒是丢了个注册机外(感谢你的注册机),从此再无与 WinIMP 注册算法相关的信息了。
这两天无聊,再次把这个软件拖入了OD中,呵呵,机缘巧合,居然给看懂了(也许是受到刚分析ReadBook1.51plus的影响,呵呵),写此文章,留作纪念!也纪念这个优秀的、却被人淡忘的、不再继续开发的软件!
好,我们开始分析,通过错误提示信息“the keys
do not match the names...”,由字符串参考方式,我们轻松的来到了这里:
004260DA |. 68 28CC4400
push winimp32.0044CC28
顺着它,往上查找,来到了这个call的开始处,F2键下断后,F9键运行软件,然后打开注册窗口,输入一组实验码:
Name: aCaFeeL
Key1: 1234567
Key2: 7654321
然后点击‘OK’按钮,便在OD中断了下来,来到如下位置:
》》》》》》》》
00426013 /$ 53
push ebx ; 被断在了这里
00426014 |. 51
push ecx
00426015 |. 52
push edx
00426016 |. 56
push esi
00426017 |. 57
push edi
00426018 |. C8 240000
enter 24, 0
0042601C |. 89C6
mov esi ,
eax
0042601E |. 68 00010000
push 100 ; /Count = 100 (256.)
00426023 |. 68 603C4500
push winimp32.00453C60 ; |Buffer = winimp32.00453C60
00426028 |. 6A 65
push 65 ; |ControlID = 65 (101.)
0042602A |. 50
push eax ; |
hWnd
0042602B |. 31DB
xor ebx ,
ebx ; |
0042602D |. 2E:FF15 A0D74>
call dword ptr
cs :[<&USER32.GetDlgIte>; \得到注册名
00426034 |. C745 FC 00000>
mov dword ptr [
ebp -4], 0
0042603B |. B8 603C4500
mov eax , winimp32.00453C60 ; 注册名 ->
eax
00426040 |. EB 04
jmp short winimp32.00426046
00426042 |> 83E3 03 /
and ebx , 3 ;
ebx =
ebx and $3
00426045 |. 40 |
inc eax ; 取注册名的下一个字符
00426046 |> 8038 00
cmp byte ptr [
eax ], 0 ; 结果是否为空?
00426049 |. 74 1C |
je short winimp32.00426067 ; 结束检查才跳
0042604B |. 8038 20 |
cmp byte ptr [
eax ], 20 ; 是否为空格
0042604E |.^ 74 F2 |
je short winimp32.00426042 ; 如若是
00426050 |. 8038 2E |
cmp byte ptr [
eax ], 2E ; 是否为符号.
00426053 |.^ 74 ED |
je short winimp32.00426042 ; 如若是
00426055 |. 0FB638 |
movzx edi ,
byte ptr [
eax ] ; 依次取注册名字符码 ->
edi
00426058 |. 89DA |
mov edx ,
ebx
0042605A 8A8F 10114500
mov cl ,
byte ptr [
edi +451110] ;
cl := [
edi + 451110]所指码数
//从451110开始的一张表
00426060 |. 43 |
inc ebx ;
ebx =
ebx + 1
00426061 |. 004C2A FC |
add byte ptr [
edx +
ebp -4],
cl ; tempA := tempA +
cl ;
//edx由ebx赋值,注意and 3后的结果
00426065 |.^ EB DB \jmp
short winimp32.00426042 ; 上面这个结果tempA将和后面的结果tempB比较,判断是否成功
00426067 |> 6A 0C
push 0C ; /Count = C (12.)
00426069 |. 8D45 DC
lea eax ,
dword ptr [
ebp -24] ; |
0042606C |. 50
push eax ; |Buffer
0042606D |. 6A 66
push 66 ; |ControlID = 66 (102.)
0042606F |. 56
push esi ; |
hWnd
00426070 |. BB 10000000
mov ebx , 10 ; |
00426075 |. 2E:FF15 A0D74>
call dword ptr
cs :[<&USER32.GetDlgIte>; \得到Key1
0042607C |. 8D45 DC
lea eax ,
dword ptr [
ebp -24] ; Key1
0042607F |. 31D2
xor edx ,
edx
00426081 |. E8 CE130100
call winimp32.00437454 ; key1 ->
eax
00426086 |. 6A 0C
push 0C ; /Count = C (12.)
00426088 |. 8945 F4
mov dword ptr [
ebp -C],
eax ; |
0042608B |. 8D45 DC
lea eax ,
dword ptr [
ebp -24] ; |
0042608E |. 50
push eax ; |Buffer
0042608F |. 6A 67
push 67 ; |ControlID = 67 (103.)
00426091 |. 56
push esi ; |
hWnd
00426092 |. C745 F8 00000>
mov dword ptr [
ebp -8], 0 ; |
00426099 |. BB 10000000
mov ebx , 10 ; |
0042609E |. 2E:FF15 A0D74>
call dword ptr
cs :[<&USER32.GetDlgIte>; \得到Key2
004260A5 |. 8D45 DC
lea eax ,
dword ptr [
ebp -24]
004260A8 |. 31D2
xor edx ,
edx
004260AA |. E8 A5130100
call winimp32.00437454 ; key2 ->
eax
004260AF |. 8B55 F4
mov edx ,
dword ptr [
ebp -C] ; key1 ->
edx
004260B2 |. 8945 F8
mov dword ptr [
ebp -8],
eax
004260B5 |. 81FA 00000001
cmp edx , 1000000 ;
edx = key1,不能小于1000000
004260BB |. 72 16
jb short winimp32.004260D3
004260BD |. 3D 00000001
cmp eax , 1000000 ;
eax = key2,不能小于1000000
004260C2 |. 72 0F
jb short winimp32.004260D3
004260C4 |. 89D0
mov eax ,
edx ; key1 ->
eax (key1/key2互换)
004260C6 |. 8B55 F8
mov edx ,
dword ptr [
ebp -8] ; key2 ->
edx (key1/key2互换)
004260C9 |. E8 D9010000
call winimp32.004262A7 ; ×××算法Call×××::F7进入×××
004260CE |. 3B45 FC
cmp eax ,
dword ptr [
ebp -4] ; eax结果(tempB) = 上面的循环结果(tempA) ?
004260D1 |. 74 18
je short winimp32.004260EB ; 相等便成功,之后保存注册相关的信息
004260D3 |> 6A 30
push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004260D5 |. 68 30D24400
push winimp32.0044D230 ; |Title = "WinImp"
004260DA |. 68 28CC4400
push winimp32.0044CC28 ; |Text = "The keys
do not match ..."
004260DF |. 56
push esi ; |hOwner
004260E0 |. 2E:FF15 0CD84>
call dword ptr
cs :[<&USER32.MessageBo>; \注册错误对话框
004260E7 |. 31C0
xor eax ,
eax
004260E9 |. EB 68
jmp short winimp32.00426153
004260EB |> BB 603C4500
mov ebx , winimp32.00453C60 ; ASCII "aCaFeeL"
004260F0 |. BA 98DA4400
mov edx , winimp32.0044DA98 ; ASCII "
Register "
004260F5 |. B8 D8DA4400
mov eax , winimp32.0044DAD8 ; ASCII "Options"
004260FA |. E8 D868FFFF
call winimp32.0041C9D7
004260FF |. 31F6
xor esi ,
esi
00426101 |. 31C0
xor eax ,
eax
00426103 |> 8D78 01 /
lea edi ,
dword ptr [
eax +1]
00426106 |. 57 |
push edi
00426107 |. 68 A8DA4400 |
push winimp32.0044DAA8 ; ASCII "Key%d"
0042610C |. 8D45 E8 |
lea eax ,
dword ptr [
ebp -18]
0042610F |. 50 |
push eax
00426110 |. E8 1B090100 |
call winimp32.00436A30
00426115 |. 83C4 0C |
add esp , 0C
00426118 |. FF742E F4 |
push dword ptr [
esi +
ebp -C]
0042611C |. 68 A8E64400 |
push winimp32.0044E6A8 ; ASCII "%X"
00426121 |. 8D45 DC |
lea eax ,
dword ptr [
ebp -24]
00426124 |. 50 |
push eax
00426125 |. 8D5D DC |
lea ebx ,
dword ptr [
ebp -24]
00426128 |. 8D55 E8 |
lea edx ,
dword ptr [
ebp -18]
0042612B |. E8 00090100 |
call winimp32.00436A30
00426130 |. 83C4 0C |
add esp , 0C
00426133 |. B8 D8DA4400 |
mov eax , winimp32.0044DAD8 ; ASCII "Options"
00426138 |. 83C6 04 |
add esi , 4
0042613B |. E8 9768FFFF |
call winimp32.0041C9D7
00426140 |. 89F8 |
mov eax ,
edi
00426142 |. 83FF 02 |
cmp edi , 2
00426145 |.^ 7C BC \jl
short winimp32.00426103
00426147 |. C605 52134500>
mov byte ptr [451352], 1
0042614E |. B8 01000000
mov eax , 1
00426153 |> C9
leave
00426154 |. 5F
pop edi
00426155 |. 5E
pop esi
00426156 |. 5A
pop edx
00426157 |. 59
pop ecx
00426158 |. 5B
pop ebx
00426159 \. C3
retn
》》》》》》》》
可能大家也都注意到了:
0042605A 8A8F 10114500
mov cl ,
byte ptr [
edi +451110]
这里的byte ptr [
edi +451110],我们顺着来到 00451110 后,会发现这是一张字符码对应表格,长度为:(4x4)x16 = 256,格式如下:
00451110 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ...
..
00451120 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
00451130 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F !"#$%&
'()*+,-./
00451140 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?
00451150 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F @abcdefghijklmno
00451160 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F pqrstuvwxyz[\]^_
00451170 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F `abcdefghijklmno
00451180 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F pqrstuvwxyz
{|} ~
00451190 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F €亗儎厗噲墛媽崕
004511A0 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F 悜挀敃枟槞殯湞灍
004511B0 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF 牎ⅲぅΗī
004511C0 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF 氨渤吹斗腹夯冀究
004511D0 C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF 懒旅呐魄壬仕掏蜗
004511E0 D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF 醒矣哉肿刭谯茌捱
004511F0 E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF 噌忏溴骁栝觌祉铒
00451200 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF 瘃蝮趱鲼?
通过分析上面的这张表格,我们会发现,这张表格的主要作用便是:不管你输入的注册名字符是否为大写字母,他都通过这张表格将注册名全部转换为小写字母。
而 00426042~00426065 处的循环算法我用 delphi+kol/mck 源码表示,则为如下形式:
》》》》》》》》
for i:=0
to 3
do sum[i] := $00;
//初始化变量sum
Tebx := 0;
for i:=1
to length (RegName)
do
begin
if (ord(RegName[i])=$20)
or (ord(RegName[i])=$2E)
then Tebx := (Tebx
and $3)
else begin
sum[Tebx] := sum[Tebx] + key[ord(RegName[i])
and $FF];
Tebx := Tebx + 1;
Tebx := (Tebx
and $3);
end ;
end ;
sumAll := int2hex(sum[3],2)+int2hex(sum[2],2)+int2hex(sum[1],2)+int2hex(sum[0],2);
tempA := Hex2Int(
'$' + sumAll);
//得到的前部分的结果(RegName -> TempA)
》》》》》》》》
上面的算法举列来说就是:
比如我输入的注册名为:aCaFeeL,则查找到上面我给出来的‘字符码对应表格’中相应的ASCII码就是:61 63 61 66 65 65 6C;sum[0]=61,sum[1]=63,sum[2]=61,sum[3]=66;然后又开始从sum[0]开始累加,即:sum[0]=61+65=C6,sum[1]=63+65=C8,sum[2]=61+6C=CD,sum[3]=66;则结果在内存窗口中为:sum[0]=C6 sum[1]=C8 sum[2]=CD sum[3]=66,故实际为十六进制的:$66CDC8C6 数字,暂且命名为tempA吧!
走过上面的循环运算后,我们继续F8键向下分析,来到这里后:
》》》》》》》》
004260AA |. E8 A5130100
call winimp32.00437454 ; key2 ->
eax
004260AF |. 8B55 F4
mov edx ,
dword ptr [
ebp -C] ; key1 ->
edx
004260B2 |. 8945 F8
mov dword ptr [
ebp -8],
eax
004260B5 |. 81FA 00000001
cmp edx , 1000000 ;
edx = hex(key1),不能小于1000000
004260BB |. 72 16
jb short winimp32.004260D3
004260BD |. 3D 00000001
cmp eax , 1000000 ;
eax = hex(key2),不能小于1000000
004260C2 |. 72 0F
jb short winimp32.004260D3
004260C4 |. 89D0
mov eax ,
edx ; key1 ->
eax (key1/key2互换)
004260C6 |. 8B55 F8
mov edx ,
dword ptr [
ebp -8] ; key2 ->
edx (key1/key2互换)
004260C9 |. E8 D9010000
call winimp32.004262A7 ; ×××算法Call×××::F7进入×××
004260CE |. 3B45 FC
cmp eax ,
dword ptr [
ebp -4] ; eax结果(tempB) = 上面的循环结果(tempA) ?
004260D1 |. 74 18
je short winimp32.004260EB ; 成功后保存注册相关的信息
004260D3 |> 6A 30
push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
》》》》》》》》
我们知道了,Key1、Key2的数值都必须大于$1000000才行,而满足上述条件后,我们便来到了后面部分的算法相关的call子程序了,这便是:
004260C9 |. E8 D9010000
call winimp32.004262A7
我们需要进入到这个子程序中一探究竟,按F7键进入后,来到了这里:
》》》》》》》》
004262A7 /$ 53
push ebx
004262A8 |. 51
push ecx
004262A9 |. 56
push esi
004262AA |. 89C1
mov ecx ,
eax ; key1 ->
ecx
004262AC |. 89D3
mov ebx ,
edx ; key2 ->
ebx
004262AE |. 8B15 64A74400
mov edx ,
dword ptr [44A764] ; $E8B8D413 ->
edx
004262B4 |. E8 74FFFFFF
call winimp32.0042622D ; ::F7进入::(注意:只要eax的结果)
004262B9 |. 89C6
mov esi ,
eax ; (运算结果eax)TempB -> (esi下面要用)
004262BB |. 89DA
mov edx ,
ebx
004262BD |. BB 20000000
mov ebx , 20
004262C2 |. 89C8
mov eax ,
ecx ; key1 ->
eax
004262C4 |. 31C9
xor ecx ,
ecx
004262C6 |. E8 B3080100
call winimp32.00436B7E ; key2 ->
eax
004262CB |. 31F0
xor eax ,
esi ; tempB = hex(key2)
xor TempB(esi上面算法中得到的值)
004262CD |. 5E
pop esi ; 如要注册成功,则必须: TempA = TempB
004262CE |. 59
pop ecx ; 即推出:Key2 = TempA
xor TempB;
004262CF |. 5B
pop ebx
004262D0 \. C3
retn
》》》》》》》》
通过上面的代码,我们看到后半部分的关键算法便在:
004262B4 |. E8 74FFFFFF
call winimp32.0042622D
的这个子call中,所以走到这里后,F7键进入,来到了如下的地方:
》》》》》》》》
0042622D /$ 53
push ebx
0042622E |. 51
push ecx
0042622F |. 56
push esi
00426230 |. 57
push edi
00426231 |. C8 040000
enter 4, 0
00426235 |. 52
push edx
00426236 |. F645 F8 01
test byte ptr [
ebp -8], 1
0042623A |. 75 07
jnz short winimp32.00426243
0042623C |. B9 01000000
mov ecx , 1
00426241 |. EB 02
jmp short winimp32.00426245
00426243 |> 89C1
mov ecx ,
eax ;
ecx =
eax = key1
00426245 |> C745 FC 02000>
mov dword ptr [
ebp -4], 2 ; $2 -> [
ebp -4]
0042624C |. 89C7
mov edi ,
eax ;
edi =
eax = key1
0042624E |. EB 09
jmp short winimp32.00426259
00426250 |> D165 FC /
shl dword ptr [
ebp -4], 1 ; [
ebp -4] = [
ebp -4]
shl 1
00426253 |. 837D FC 00 |
cmp dword ptr [
ebp -4], 0 ; ? = 0
00426257 |. 74 46 |
je short winimp32.0042629F
00426259 |> 8B35 60A74400
mov esi ,
dword ptr [44A760] ; $F527789F ->
esi
0042625F |. 89F8 |
mov eax ,
edi
00426261 |. 89FA |
mov edx ,
edi ; 下面是大数运算
00426263 |. F7E2 |
mul edx ;
edx <- (
edi *
edi ) 无符号乘法,结果送eax/
edx
00426265 |. 39D6 |
cmp esi ,
edx ; $F527789F 与
edx 结果比较
00426267 |. 77 0A |
ja short winimp32.00426273 ; $F527789F >
edx 结果,便跳转
00426269 |. 89C3 |
mov ebx ,
eax
0042626B |. 89D0 |
mov eax ,
edx
0042626D |. 31D2 |
xor edx ,
edx
0042626F |. F7F6 |
div esi
00426271 |. 89D8 |
mov eax ,
ebx
00426273 |> F7F6 |
div esi ; 上面的乘积
div $F527789F 无符号除法
00426275 |. 8B75 F8 |
mov esi ,
dword ptr [
ebp -8] ; $E8B8D413 ->
esi
00426278 |. 89D0 |
mov eax ,
edx ; 除法余数 ->
eax
0042627A |. 89D7 |
mov edi ,
edx ; ->
edi
0042627C |. 8575 FC |
test dword ptr [
ebp -4],
esi ; [
ebp -4]
and $E8B8D413 = 0 ??
0042627F |.^ 74 CF |
je short winimp32.00426250 ; =0,跳
00426281 |. 8B35 60A74400 |
mov esi ,
dword ptr [44A760] ; $F527789F ->
esi
00426287 |. 89CA |
mov edx ,
ecx ; key1 ->
edx
00426289 |. F7E2 |
mul edx ;
eax *
edx
0042628B |. 39D6 |
cmp esi ,
edx ; $F527789F 与
edx 结果比较
0042628D |. 77 0A |
ja short winimp32.00426299 ; $F527789F >
edx 结果,便跳转
0042628F |. 89C3 |
mov ebx ,
eax
00426291 |. 89D0 |
mov eax ,
edx
00426293 |. 31D2 |
xor edx ,
edx
00426295 |. F7F6 |
div esi
00426297 |. 89D8 |
mov eax ,
ebx
00426299 |> F7F6 |
div esi ; 无符号
eax div $F527789F
0042629B |. 89D1 |
mov ecx ,
edx ;
edx ->
ecx 最终结果
0042629D |.^ EB B1 \jmp
short winimp32.00426250
0042629F |> 89C8
mov eax ,
ecx ; 最终结果ecx ->
eax
004262A1 |. C9
leave
004262A2 |. 5F
pop edi
004262A3 |. 5E
pop esi
004262A4 |. 59
pop ecx
004262A5 |. 5B
pop ebx
004262A6 \. C3
retn
004262A7 /$ 53
push ebx
004262A8 |. 51
push ecx
004262A9 |. 56
push esi
004262AA |. 89C1
mov ecx ,
eax ; key1 ->
ecx
004262AC |. 89D3
mov ebx ,
edx ; key2 ->
ebx
004262AE |. 8B15 64A74400
mov edx ,
dword ptr [44A764] ; $E8B8D413 ->
edx
004262B4 |. E8 74FFFFFF
call winimp32.0042622D ; ::F7进入::(注意:只要eax的结果)
004262B9 |. 89C6
mov esi ,
eax ; (运算结果eax)TempB -> (esi下面要用)
004262BB |. 89DA
mov edx ,
ebx
004262BD |. BB 20000000
mov ebx , 20
004262C2 |. 89C8
mov eax ,
ecx ; key1 ->
eax
004262C4 |. 31C9
xor ecx ,
ecx
004262C6 |. E8 B3080100
call winimp32.00436B7E ; key2 ->
eax
004262CB |. 31F0
xor eax ,
esi ; tempA = tempB = hex(key2)
xor TempB(esi上面算法中得到的值)
004262CD |. 5E
pop esi ; 即是:Key2 = TempA
xor TempB;
004262CE |. 59
pop ecx
004262CF |. 5B
pop ebx
004262D0 \. C3
retn
》》》》》》》》
由上面的代码,我们知道了它的算法形式如下:
》》》》》》》》
Key1 := hex2int(
'$' + KeyCode1);
Tecx := Key1;
Tebp := $2;
Tedi := Key1;
goto cz59;
cz50:
Tebp := Tebp
shl $1;
if (Tebp - 0) = 0
then goto cz9F;
cz59:
Tesi := $F527789F;
Teax := Tedi;
Tedx := Tedi;
// Tedx_eax := Teax * Tedx;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
MUL EDX
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
//showmessage('cz59: '+int2hex(Tedx,8));
if Tesi > Tedx
then goto cz73;
Tebx := Teax;
Teax := Tedx;
Tedx := Tedx
xor Tedx;
//Tedx := Tedx_eax mod Tesi;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
DIV ESI
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
//showmessage('cz73: '+int2hex(Tedx,8));
Teax := Tebx;
cz73:
//Tedx := Tedx_eax mod Tesi;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
DIV ESI
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
//showmessage('cz73: '+int2hex(Tedx,8));
Tesi := $E8B8D413;
Teax := Tedx;
Tedi := Tedx;
if (Tebp
and Tesi)=0
then goto cz50;
Tesi := $F527789F;
Tedx := Tecx;
//Tedx_eax := Teax * Tedx;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
MUL EDX
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
//showmessage('cz73: '+int2hex(Tedx,8));
if Tesi > Tedx
then goto cz99;
Tebx := Teax;
Teax := Tedx;
Tedx := Tedx
xor Tedx;
//Tedx := Tedx_eax mod Tesi;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
DIV ESI
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
//showmessage('cz73: '+int2hex(Tedx,8));
Teax := Tebx;
cz99:
//Tedx := Tedx_eax mod Tesi;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
DIV ESI
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
//showmessage('cz73: '+int2hex(Tedx,8));
Tecx := Tedx;
goto cz50;
cz9F:
TempB := Tecx;
//得到的后部分的结果(KeyCode1 ->TempB)
》》》》》》》》
在分析上面的这个算法前,我们已知道:
》》》》》》》》
004262C2 |. 89C8
mov eax ,
ecx ; key1 ->
eax
004262C4 |. 31C9
xor ecx ,
ecx
004262C6 |. E8 B3080100
call winimp32.00436B7E ; key2 ->
eax
004262CB |. 31F0
xor eax ,
esi ; tempB = hex(key2)
xor TempB(esi上面算法中得到的值)
004262CD |. 5E
pop esi ; 如要注册成功,则必须: TempA = TempB
004262CE |. 59
pop ecx ; 即推出:Key2 = TempA
xor TempB;
004262CF |. 5B
pop ebx
004262D0 \. C3
retn
》》》》》》》》
也就是说:Key2的值是由上面分析并得到的tempA(由 注册名 运算后得到)和tempB(由 Key1 运算后得到)异或之后得到的,通过上面的完整分析,我们便可以写出一个完整的注册机来玩玩了,呵呵!注册机(Delphi + KOL/MCK)源代码如下:(已写成为一个string函数格式,方便你的调用和修改,嘿嘿 :)
//WinIMP v1.11注册算法
function WinIMP_sn(RegName, KeyCode1:
string ):
string ;
//定义为string函数
var
i, ii :
integer ;
TempA, TempB, Key1 : longInt;
Tesi, Tedi, Teax, Tebx, Tecx, Tedx, Tebp :
cardinal ;
sumALL,strEDX, strEAX, strEDX_EAX :
string ;
sum :
array [0 .. 3]
of byte ;
label
cz50, cz59, cz73, cz99, cz9F;
const
key :
array [0 .. 255]
of byte =
//字符表常量,不变
($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F,
$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,
$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2A,$2B,$2C,$2D,$2E,$2F,
$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$3F,
$40,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6A,$6B,$6C,$6D,$6E,$6F,
$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7A,$5B,$5C,$5D,$5E,$5F,
$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6A,$6B,$6C,$6D,$6E,$6F,
$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7A,$7B,$7C,$7D,$7E,$7F,
$80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F,
$90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F,
$A0,$A1,$A2,$A3,$A4,$A5,$A6,$A7,$A8,$A9,$AA,$AB,$AC,$AD,$AE,$AF,
$B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB,$BC,$BD,$BE,$BF,
$C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7,$C8,$C9,$CA,$CB,$CC,$CD,$CE,$CF,
$D0,$D1,$D2,$D3,$D4,$D5,$D6,$D7,$D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF,
$E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7,$E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF,
$F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF);
begin
if RegName=
'' then
begin
showmessage (
'输入的 注册名 不能为空!' );
exit;
end ;
for i:=0
to 3
do sum[i] := $00;
//初始化变量sum
ii := 0;
//初始化变量ii
for i:=1
to length (RegName)
do //开始循环计算:
begin
if (ord(RegName[i])=$20)
or (ord(RegName[i])=$2E)
then ii := (ii
and $3)
else begin
sum[ii] := sum[ii] + key[ord(RegName[i])
and $FF];
//取字符表中的相应值
ii := ii + 1;
ii := (ii
and $3);
end ;
end ;
sumAll := int2hex(sum[3],2)+int2hex(sum[2],2)+int2hex(sum[1],2)+int2hex(sum[0],2);
TempA := Hex2Int(
'$' + sumAll);
//得到的前部分的结果(RegName -> TempA)
Key1 := hex2int(
'$' + KeyCode1);
Tecx := Key1;
Tebp := $2;
Tedi := Key1;
goto cz59;
cz50:
Tebp := Tebp
shl $1;
if (Tebp - 0) = 0
then goto cz9F;
cz59:
Tesi := $F527789F;
Teax := Tedi;
Tedx := Tedi;
// Tedx_eax := Teax * Tedx;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
MUL EDX
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
if Tesi > Tedx
then goto cz73;
Tebx := Teax;
Teax := Tedx;
Tedx := Tedx
xor Tedx;
//Tedx := Tedx_eax mod Tesi;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
DIV ESI
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
Teax := Tebx;
cz73:
//Tedx := Tedx_eax mod Tesi;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
DIV ESI
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
Tesi := $E8B8D413;
Teax := Tedx;
Tedi := Tedx;
if (Tebp
and Tesi)=0
then goto cz50;
Tesi := $F527789F;
Tedx := Tecx;
//Tedx_eax := Teax * Tedx;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
MUL EDX
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
if Tesi > Tedx
then goto cz99;
Tebx := Teax;
Teax := Tedx;
Tedx := Tedx
xor Tedx;
//Tedx := Tedx_eax mod Tesi;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
DIV ESI
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
cz99:
//Tedx := Tedx_eax mod Tesi;
asm
MOV ESI ,[Tesi]
MOV EAX ,[Teax]
MOV EDX ,[Tedx]
DIV ESI
mov [Teax],
EAX
mov [Tedx],
EDX
end ;
Tecx := Tedx;
goto cz50;
cz9F:
TempB := Tecx;
//得到的后部分的结果(KeyCode1 ->TempB)
Result := int2hex((TempA
xor TempB),8);
//最终返回的 KeyCode2 结果是由 TempA xor TempB 后得到的
end ;
好了,就到这里结束吧!分析难免有不当之处,还望大家给我指出来!
放上一组可用的Key:
name: aCaFeeL
key1: ABF8FB42
key2: 8DB47F89
注册机的算法在多台机器上使用不同注册名通过验证,但没有时间再优化它了,应该不存在bug的问题,附件中为我打包后的注册机源代码。
另:如果问我这次分析最大的收获是什么?我会说,那就是学会了如何将大数运算的高位数和低位数分配到相应的EDX和EAX中了!别笑,呵呵!
[课程]Linux pwn 探索篇!
上传的附件: