Just for fun.
动手keygen Winlicense 1.8.5.5. 会了这个基本上Winlicense 加授权系列的其他版本的都会了。用1.8.5.5 做样例是因为1.8.5.5的RSA校验是摆看的。
现在都是无key脱壳,无key过授权。所以仅仅是学习一下。没什么用,大牛们就直接略过。
Keygen Winlicense softworm、shoooo、HyperChem 都讲过步骤,HyperChem还发了个视频,但是视频中找关键的数据涉及到VM,也就没讲了。
我们主要是找到License Unique Key的三部分数据,就可以keygen了。我这有一个License Unique Key是我自己找的正确的key:
111111115UZHI2H92Ab07JaAu4im5QOik0vRqGsYCWQ374g3eEKA9RTARUR9pXJ0XzN88RFa2D39Sajm5c8kuo0hTUErpsCnj3ro1111111111111111111111111111111111111111111111111
License Unique Key的结构:
0-0x7 可以任意指定 11111111
0x8 + -0xC 5UZH + I2H9为realkey的解密后+0位的dword值。即:0x35555A48 + 0x 49324839 =0x7E87A281
0x10 + -0x14 2Ab0 + 7JaA为realkey的解密后+16位的dword值。0x32416230 + 0x374A6141 =0x698BC371
+0x18 u4 + im 为realkey的解密后+33位的word值。0x 7534 + 0x 696D =0xDEA1
+0x1C + -0x2C = 0x9CB6856C
+0x20 + -0x30 = 0x9CB6856C
+0x24 + -0x34 = 0x9AC799AA
+0x28 + -0x38 = 0x6CA3AC95
+0x3C + -0x40 = 0xC8D29868 这上面的数据都是在key运行解密的时候要用到的。(+0x3C + -0x40只有在1.8.5.5的这个版本 解密key的时候用到,高版本可以任意填写,我最开始keygen的时候就卡在这里,先入为主的认为这个数据是没用的)
+0x44 8RFa2D39Sajm5c8kuo0hTUErpsCnj3ro 上面的都可以在程序解密key文件的时候找到。明码存储。
+0x64任意指定1111111111111111111111111111111111111111111111111
两两之和的数据只要拆分成数字和字母组成字符串的就可以了。
(逆向调试WinlicenseSDK.dll可以得到这些信息)
现在我们来找上面的数据。od载入主程序,下断CreateFileA函数尾。已知F9直到ESP+4为$+4 > 0073DACB ASCII "C:\WINDOWS\system32\KERNEL32.dll" 。修改eax为-1(0x0FFFFFFFF).这个主要是为了防止wl模拟dll 造成调试障碍。继续F9直到
0012FF20 00F118AE 返回到 WinLicen.00F118AE
0012FF24 00DD8C13 WinLicen.00DD8C13
0012FF28 80000000
0012FF2C 00000001
0012FF30 00000000
0012FF34 00000003
0012FF38 00000020
0012FF3C 00000000
0012FF40 03B80270
0012FF44 00DDA2F7 ASCII "WLlicense.dat"
打开 key文件为止。取消断点,F7单步走。看到retn 0xC ,单击F4 再F7.
00F11A68 8985 5CA44906 mov dword ptr ss:[ebp+649A45C],eax
00F11A6E E8 16000000 call WinLicen.00F11A89
00F11A73 C785 60A44906 0>mov dword ptr ss:[ebp+649A460],0
00F11A7D 8B85 5CA44906 mov eax,dword ptr ss:[ebp+649A45C]
00F11A83 FFA5 64A44906 jmp dword ptr ss:[ebp+649A464]
00F11A89 60 pushad
00F11A8A BB 78563412 mov ebx,12345678
00F11A8F 8DB5 F6954906 lea esi,dword ptr ss:[ebp+64995F6]
00F11A95 8DBD 97A34906 lea edi,dword ptr ss:[ebp+649A397]
00F11A9B E9 07000000 jmp WinLicen.00F11AA7
00F11AA0 301E xor byte ptr ds:[esi],bl
00F11AA2 003E add byte ptr ds:[esi],bh
00F11AA4 D1CB ror ebx,1
00F11AA6 46 inc esi
00F11AA7 3BF7 cmp esi,edi
00F11AA9 ^ 0F82 F1FFFFFF jb WinLicen.00F11AA0
00F11AAF 61 popad
00F11AB0 C3 retn
在010D9E03 下断点,F9 两次。取消断点,这个时候 key已经被加载到内存了。Alt+M 打开内存窗口,复制WLlicense.dat 文件里面的一段数据,在内存窗口中搜索,找到key加载的内存,
Memory map, 条目 91
地址=03410000
大小=00002000 (8192.)
属主= 03410000 (自身)
区段=
类型=Priv 00021004
访问=RW
初始访问=RW
(这个段一般位于0x10000000这个地址前面,是新申请的内存 大小为0x2000)
在这个内存段下内存访问断点,F9运行断下,
018B19C2 FF32 push dword ptr ds:[edx]
018B19C4 53 push ebx
018B19C5 BB 6F59010C mov ebx,0C01596F
018B19CA 816C24 04 DE467>sub dword ptr ss:[esp+4],7B7646DE
018B19D2 015C24 04 add dword ptr ss:[esp+4],ebx
018B19D6 814424 04 DE467>add dword ptr ss:[esp+4],7B7646DE
018B19DE 5B pop ebx
018B19DF FF3424 push dword ptr ss:[esp]
在反汇编代码窗口搜索命令序列:
popad
popfd
retn
找到9处 retn全下F2断点。这个地方是VM的出口。
删除key内存段的内存访问断点,f9运行。直到寄存器出现(不用多少次,一般第七次)
EAX 00000000
ECX 00000000
EDX 89B8A74D
EBX 00F0A4D4 ASCII "8RFa2D39Sajm5c8kuo0hTUErpsCnj3ro"
ESP 0012FF1B
EBP FAA775CE
ESI 00F1388B WinLicen.00F1388B
EDI 03A90000
EIP 018F1C84
"8RFa2D39Sajm5c8kuo0hTUErpsCnj3ro"这个数据就是上面的+44数据。
删除所有断点,记住key内存段的位置,F9运行,主程序运行了。在数据窗口中ctrl+g 输入key内存段,可以看到key文件解密后的数据,复制出来:
7E 87 A2 81 6C CC 2C 1C 01 3D 6C 1D 01 3D 88 1C
01 3D E8 1C 01 3D 69 8B C3 71 48 A0 F4 48 9C F0
44 98 EC BC 1D 00 00 58 05 01 3D C8 E3 BB F0 AC
05 01 3D DE A1 C8 E3 A7 DC FF FF FF FF FF FF FF
FF 4A 65 66 66 72 65 79 20 53 69 6C 66 65 72 FF
FF FF FF FF FF FF FF 71 65 6E 74 79 6E 73 63 6F
6C 6F 72 40 65 61 72 74 68 6C 69 6E 6B 2E 6E 65
74 FF FF FF FF FF FF FF FF 31 30 31 30 2D 32 34
32 34 2D 32 33 35 32 2D 33 38 37 36 FF FF FF FF
FF FF FF FF FE FF FF FF FE FF FF FF 61 70 E9 2C
4F EE 41 88 43 88 AE BA B2 38 43 C3 EF 94 24 C7
9C 47 B5 96 4B 5B 71 0D EF 57 96 C7 8B 92 34 79
91 BF C3 30 11 E7 EF 9C 7C 3A 66 73 E2 FB A7 FB
D6 95 14 2E 45 46 A9 36 82 A2 8A 3A 2F 55 1B 0A
DE 68 D7 80 82 65 FC 3A 1E A0 9A EC 24 CD 29 A4
A4 F4 55 10 0F 48 CC E6 75 09 0E 6F 69 A3 7A A1
D8 53 0F AA 15 B0 F0 AD C2 62 81 7D 71 76 3D F4
15 73 62 AE B1 AD 00 60 B7 DA 8F 17 37 02 BC 83
A2 55 32 5A 08 17 74 E2 FC B0 E0 14 6B 61 75 1D
A8 BD 56 21 55 70 E7 F0 04 84 A3 67 A8 80 C8 21
44 BB 66 D3 4A E8 F5 8A CA 0F 22 F7 35 63 98 CD
9B 24 DA 55 8F BE 46 88 FE 6E DB 90 3B CB BC 94
E8 7D 4D 64 97 91 09 DB 3B 8E 2E 95 D7 C8 CC 46
DD F5 5B FE 5D 1D 88 6A C8 70 FE 40 2E 32 40 C9
22 CC AC FB 91 7C 41 04 CE D8 22 08 7B 8B B3 D7 我们只要前面的数据
7E 87 A2 81 6C CC 2C 1C 01 3D 6C 1D 01 3D 88 1C
01 3D E8 1C 01 3D 69 8B C3 71 48 A0 F4 48 9C F0
44 98 EC BC 1D 00 00 58 05 01 3D C8 E3 BB F0 AC
05 01 3D DE A1 C8 E3 A7 DC FF FF FF FF FF FF FF
红色标出来的数据 就是我们要找的 +0x8 - +0x18
4F EE 41 88 这个是前面数据的校验和
当然 如果 你需要替换RSA数据,
43 88 AE BA B2 38 43 C3 EF 94 24 C7
9C 47 B5 96 4B 5B 71 0D EF 57 96 C7 8B 92 34 79
91 BF C3 30 11 E7 EF 9C 7C 3A 66 73 E2 FB A7 FB
D6 95 14 2E 45 46 A9 36 82 A2 8A 3A 2F 55 1B 0A
DE 68 D7 80 82 65 FC 3A 1E A0 9A EC 24 CD 29 A4
A4 F4 55 10 0F 48 CC E6 75 09 0E 6F 69 A3 7A A1
D8 53 0F AA 15 B0 F0 AD C2 62 81 7D 71 76 3D F4
15 73 62 AE B1 AD 00 60 B7 DA 8F 17 37 02 BC 83
A2 55 32 5A 08 17 74 E2 FC B0 E0 14 6B 61 75 1D
A8 BD 56 21 55 70 E7 F0 04 84 A3 67 A8 80 C8 21
44 BB 66 D3 4A E8 F5 8A CA 0F 22 F7 35 63 98 CD
9B 24 DA 55 8F BE 46 88 FE 6E DB 90 3B CB BC 94
E8 7D 4D 64 97 91 09 DB 3B 8E 2E 95 D7 C8 CC 46
DD F5 5B FE 5D 1D 88 6A C8 70 FE 40 2E 32 40 C9
22 CC AC FB 91 7C 41 04 CE D8 22 08 7B 8B B3 D7
这个就是的了。
接下来就是最麻烦的几个数据了。
+0x1C + -0x2C = 0x9CB6856C
+0x20 + -0x30 = 0x9CB6856C
+0x24 + -0x34 = 0x9AC799AA
+0x28 + -0x38 = 0x6CA3AC95
+0x3C + -0x40 = 0xC8D29868
不懂wl vm的童鞋可以去看看softworm天书,只要看到第三部分就可以了(当然你也可以深入了解,多看看没坏处)。我找数据纯粹是取巧。没有还原VM的能力,没办法。
HyperChem 在keygen wl 的视频教程里讲了这里四个数据的用途。
汇编大致是
sub xx,1c-2c
xor xx,xx
以及类似的操作,可以去看看HyperChem的教程。这里我们可以看到WinlicenseSDK.dll是怎么使用这五组数据的,其中
+0x1C + -0x2C = 0x9CB6856C
+0x20 + -0x30 = 0x9CB6856C
+0x24 + -0x34 = 0x9AC799AA
+0x28 + -0x38 = 0x6CA3AC95
是在一起使用的,
+0x3C + -0x40 = 0xC8D29868
单独使用。
text:100023BF add eax, 9E3779B9h
.text:100023C4 mov edx, ecx
.text:100023C6 shl edx, 4
.text:100023C9 add ebx, edx
.text:100023CB mov edx, [esi]
.text:100023CD xor edx, ecx
.text:100023CF add ebx, edx
.text:100023D1 mov edx, ecx
.text:100023D3 shr edx, 5
.text:100023D6 xor edx, eax
.text:100023D8 add ebx, edx
.text:100023DA add ebx, [esi+4]
.text:100023DD mov edx, ebx
.text:100023DF shl edx, 4
.text:100023E2 add ecx, edx
.text:100023E4 mov edx, [esi+8]
.text:100023E7 xor edx, ebx
.text:100023E9 add ecx, edx
.text:100023EB mov edx, ebx
.text:100023ED shr edx, 5
.text:100023F0 xor edx, eax
.text:100023F2 add ecx, edx
.text:100023F4 add ecx, [esi+0Ch]
这个是前面四组数据,基本上是 相加移位和异或。
所以在解密key数据的时候,下断在 Vm_sub 和 Vm_xor 是可以获取到正确的数据的。据说这个四个数据在主程序里面是在特定的时候明文出现的,可以直接替换,估计海风月影的通杀lpk就是这么做的,不过替换的地方我暂时没找到。希望大牛们指点指点。
知道这些,我们开始动手找数据。
先重新载入主程序,运行到key访问。(由于多次需要这样操作,我写了个脚本,自动运行到这个地方,打包在附件里面)
018B19C2 FF32 push dword ptr ds:[edx]
018B19C4 53 push ebx
018B19C5 BB 6F59010C mov ebx,0C01596F
018B19CA 816C24 04 DE467>sub dword ptr ss:[esp+4],7B7646DE
018B19D2 015C24 04 add dword ptr ss:[esp+4],ebx
018B19D6 814424 04 DE467>add dword ptr ss:[esp+4],7B7646DE
018B19DE 5B pop ebx
018B19DF FF3424 push dword ptr ss:[esp]
停在这里。 把反汇编窗口拉到最上面,搜索指令序列:
sub RA,RB
pushfd
和
xor RA,RB
pushfd
在 所有找到的 32位寄存器操作的地方下断点。比如:
01839BB1 FF77 70 push dword ptr ds:[edi+70]
01839BB4 9D popfd
01839BB5 29C3 sub ebx,eax
01839BB7 9C pushfd
01839BB8 8F47 70 pop dword ptr ds:[edi+70]
01839BBB 08D2 or dl,dl
这种特征在高版本(我在keygen Winlicense 2.10 的时候是下面的特征)里面有些不同,可以搜索
xor dwrod ptr [esp],eax
pushfd
和
sub dwrod ptr [esp],eax
pushfd
(hc刚刚和我说,这个是CISC虚拟机的特征)
低版本搜索的时候可以找到大概8-10个的样子,而 高版本找到的地方只有2个。也就是只存在一份handler。低版本主要用的也只有两个,但是没有好的办法区分,只能全部都下断点。然后运行,发现数据完全看不出规律,而且杂乱数据太多了。
最后我写了个脚本,打印操作数到文件,从访问的这个地方一直到程序运行,获得到了一个60kb的数据文件。
脚本:
var sub1
var sub2
var sub3
var sub4
var sub5
var sub6
var xor1
var xor2
var xor3
var xor4
mov sub1,01839BB5
mov sub2,0184B953
mov sub3,018B5D6D
mov sub4,018CD945
mov sub5,0194A88E
mov sub6,0195EF1F
mov xor1,0184E9BF
mov xor2,01879AC8
mov xor3,018FFD40
mov xor4,0193CFE6
bp 01839BB5 //始终 sub ebx,eax
bp 0184B953 //始终 sub ecx,ebx
bp 0184E9BF //始终 xor ebx,eax
bp 01879AC8 //始终 xor eax,ebx
bp 018B5D6D //始终 sub eax,ebx
bp 018CD945 //始终 sub eax,ecx
bp 018FFD40 //始终 xor ecx,eax
bp 0193CFE6 //始终 xor ecx,edx
bp 0194A88E //始终 sub edx,eax
bp 0195EF1F //始终 sub ecx,ebx
loop:
run
cmp eip,sub1
je logsub1
cmp eip,sub2
je logsub2
cmp eip,sub3
je logsub3
cmp eip,sub4
je logsub4
cmp eip,sub5
je logsub5
cmp eip,sub6
je logsub6
cmp eip,xor1
je logxor1
cmp eip,xor2
je logxor2
cmp eip,xor3
je logxor3
cmp eip,xor4
je logxor4
jmp loop
logsub1:
WRTA "123.txt",ebx
WRTA "123.txt",eax
jmp loop
logsub2:
WRTA "123.txt",ecx
WRTA "123.txt",ebx
jmp loop
logsub3:
WRTA "123.txt",eax
WRTA "123.txt",ebx
jmp loop
logsub4:
WRTA "123.txt",eax
WRTA "123.txt",ecx
jmp loop
logsub5:
WRTA "123.txt",edx
WRTA "123.txt",eax
jmp loop
logsub6:
WRTA "123.txt",ecx
WRTA "123.txt",ebx
jmp loop logxor1:
WRTA "123.txt",ebx
WRTA "123.txt",eax
jmp loop
logxor2:
WRTA "123.txt",eax
WRTA "123.txt",ebx
jmp loop
logxor3:
WRTA "123.txt",ecx
WRTA "123.txt",eax
jmp loop
logxor4:
WRTA "123.txt",ecx
WRTA "123.txt",edx
jmp loop
高版本的脚本要简单多了。只有两个断点,打印也只要打印[esp]和eax的值。
但是这个时候我们是不知道那些是正确的数据。我们从HyperChem的教程可以知道,数据最多的几个,就是我们需要的。这个时候,我们祭出神器Excel 。先进行排序,然后计数统计,最后可以看到比较多的数据都是192个,我们排除掉一些不符合规则的,规则是
0x60606060<= X <= 0x0F4F4F4F4
就能找到:
74BD658D
9CB6856C
9CB6856C
9AC799AA
6CA3AC95
这五个数据 ,那四个数据肯定是在这五个数据里面。我们需要排除掉一个。
找到四个数据,我们还不知道四个数据在License Unique Key对应的位置是那里。这里我找到一个方法,既然我们不能从逆向得到正确的数据,就只有正向操作了。
用1.8.5.5加密一个测试程序,加授权,这个时候,这个程序的License Unique Key是已知的,我们把这个程序也进行上面的操作,把Vm_xor 和 Vm_sub 的操作数据都记录下来。
结合License Unique Key 我们知道了四个数据的排列。
9BE4D994 + 24 - 34
10E557D3
1922A40E
8B018E47
872ABE
C6EF3720
8E2115C7
C6681D9E
BD293B97
665D917E
C7B8F829
DB74AAE9 + 28 - 38
10E557D3
C444D400
B6FB7794
108FD514
A674A280 + 1C - 2C
EC444D40
4CA083D3
4A30EFC0
762226A
C6EF3720
26F9413
C18D154A
DA41F999
69EE573D
40E27EC9
B3AFAEA4 + 20 – 30
然后我们对比主程序找到的数据:
74BD658D +
9AC799AA +
A1E582C3
B52D6A50
3B221B69
50F2C16
C6EF3720
7A0B4EE7
C3E01B36
5E9EC73E
323D6BAB
B62B33B1
6CA3AC95 +
A1E582C3
987871C0
C609D9B6
5ABF5CDA
9CB6856C +
4987871C
96D1103
D5310270
24C3C38
C6EF3720
343C0E93
C4A30B18
E2D25295
71132745
6F99037B
93C175D0 +
这里有五个数据是192 的,但是对照发现,第一个数据肯定是不对的。可以直接排除掉。然后我们也可以知道:
+0x1C + -0x2C = 0x9CB6856C
+0x20 + -0x30 = 0x9CB6856C
+0x24 + -0x34 = 0x9AC799AA
+0x28 + -0x38 = 0x6CA3AC95
这样我们四个数据找出来了。
我keygen 2.10的时候这个方法是可以使用的。
这个时候数据找的差不多了,但是离keygen还差一点,还需要找
+0x3C + -0x40 = 0xC8D29868
这个数据,在高版本上是不要找的。因为高版本根本不用这个解密。
WinlicenseSDK.dll 里面是这么使用这个数据的:
.text:1000243C add edx, 89421025h
.text:10002442 bswap edx
.text:10002444 mov eax, [esi]
找这个数据我们要用到刚刚的两个数据文件和测试程序的License Unique Key。我们计算一下这个License Unique Key +0x3C + -0x40 的值。然后add edx, 89421025h /bswap edx
我们得到一个数据:9F96D4FF 刚刚好在测试程序的数据文件中能找到:
49A8B1C
424C5961
49A8B1C
0
49A8B1C
7EBB1279
75C05EA6
929634D5
929634D5
929634D5
1C03AE5B
B07C2CD2
9F96D4FF + 3C - 40
10E557D3
0
BBE9E614
24E5D828
97040DEC
我们继续对比数据文件,发现主程序的数据很符合
49A8B1C
6F72336A
49A8B1C
0
49A8B1C
172FAD15
11668267
798056CB
798056CB
798056CB
10E78403
8FC85DB4
EDE2DAF1
A1E582C3
0
7338EFAB
16EB2477
5C4DCB34
这样,把这个数据进行逆操作, bswap edx/ sub edx, 89421025h
就得到0xC8D29868。
这样全部需要的数据都找齐了,我花时间分解了一组key
111111115UZHI2H92Ab07JaAu4im5QOik0vRqGsYCWQ374g3eEKA9RTARUR9pXJ0XzN88RFa2D39Sajm5c8kuo0hTUErpsCnj3ro1111111111111111111111111111111111111111111111111
你也可以不用分解,用ollydbg加载生成key的程序,动态填充数据。毕竟数据拆分太累了,而且还容易出错。
测试完全可以用,keygen了主程序。
我生成了一个key,发个效果图:
高版本的key文件 多了一层加密,导致无法直接替换RSA数据,我没有跟加密的流程,暂时用的替换RSA过的搞版本RSA校验。 替换的方法,可以看HyperChem的keygen wl教程。
很简单。
我简单的说说:
先运行到打开授权key 的时候。然后 在内存中搜索第二个解压函数的下断点。
特征码:60 8B 74 24 24 8B 7C 24 28 FC B2 80 8A 06 46 88 07 47
一点要在运行打开key的时候再搜索。第一个找到的就是了。一般是在wl倒数第二个段。
F9 断下之后,在内存中找到新分配的一个大小为0xA000的 内存。key附近的一个内存块。 下内存访问断点。
然后F9。直到出现这个函数。
03FD1021 55 push ebp
03FD1022 8BEC mov ebp,esp
03FD1024 81C4 70FBFFFF add esp,-490
03FD102A 60 pushad
03FD102B 8D85 78FBFFFF lea eax,dword ptr ss:[ebp-488]
03FD1031 50 push eax
03FD1032 FF75 18 push dword ptr ss:[ebp+18]
03FD1035 FF75 14 push dword ptr ss:[ebp+14]
03FD1038 E8 E70E0000 call 03FD1F24 $ ==> > 01153651 WinLicen.01153651
$+4 > 03FB0000
$+8 > 00000197
$+C > 04030000
$+10 > 0114B0D0 WinLicen.0114B0D0 //这个内存块就是RSA所在的内存块。
$+14 > 00000089
$+18 > 01153C1D 返回到 WinLicen.01153C1D
找到地址之后,重载程序,在解压函数下断点替换。即可。
第一次发帖,有错误在所难免,希望大家指点指点。
最后,感谢观看,感谢thecjw和HyperChem 的指点。
KeyKernel
2012-09-18
转载请保持本文完整。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: