本帖最后由 zbnysjwsnd8 于 2017-8-30 20:48 编辑
翻了一圈 好像论坛里还没有人成功破解这个CM 刚好今天看了一下 于是就有了这篇文章。
我并不是大神 就是一个菜鸟 如果有错误还希望各位大佬们指出来。
0x0 KeyFile的检测 CM首先会读取 crack.dat 如果这个文件不存在则失败
[Asm] 纯文本查看 复制代码 00401170 |. A1 6CCA4000 mov eax,dword ptr ds:[filebuf::openprot]
00401175 |. 50 push eax ; /Arg4 = 0019FE60
00401176 |. 68 81000000 push 0x81 ; |Arg3 = 00000081
0040117B |. 68 3EB44000 push thecodin.0040B43E ; |Arg2 = 0040B43E ASCII "crack.dat"
00401180 |. 8D95 D0FEFFFF lea edx,[local.datfile] ; |
00401186 |. 52 push edx ; |Arg1 = 0019FE74
00401187 |. E8 705A0000 call thecodin.fstreambase::open ; \fstreambase::open
0040118C |. 83C4 10 add esp,0x10
0040118F |. 8B8D D0FEFFFF mov ecx,[local.datfile]
00401195 |. F641 0C 86 test byte ptr ds:[ecx+0xC],0x86
00401199 |. 74 6B je short thecodin.00401206 ; 如果不存在则失败
0040119B |. 6A 00 push 0x0 ; /Arg3 = 00000000
0040119D |. 68 48B44000 push thecodin.0040B448 ; |Arg2 = 0040B448 ASCII "Kein Dat file vorhanden......"
004011A2 |. 56 push esi ; |Arg1 = 0040D830
004011A3 |. E8 34670000 call thecodin.ostream::outstr ; \ostream::outstr
004011A8 |. 83C4 0C add esp,0xC
004011AB |. 56 push esi ; /Arg1 = 0040D830
004011AC |. E8 DB510000 call thecodin.endl ; \endl
004011B1 |. 59 pop ecx ; 0019FE60
004011B2 |. 6A 00 push 0x0 ; /Arg3 = 00000000
004011B4 |. 68 66B44000 push thecodin.0040B466 ; |Arg2 = 0040B466 ASCII "Press a Key....."
004011B9 |. 56 push esi ; |Arg1 = 0040D830
004011BA |. E8 1D670000 call thecodin.ostream::outstr ; \ostream::outstr
004011BF |. 83C4 0C add esp,0xC
004011C2 |. 56 push esi ; /Arg1 = 0040D830
004011C3 |. E8 C4510000 call thecodin.endl ; \endl
004011C8 |. 59 pop ecx ; 0019FE60
004011C9 |. E8 2A0A0000 call thecodin.getch
004011CE |. 33C0 xor eax,eax
004011D0 |. 50 push eax
004011D1 |. 6A 02 push 0x2 ; /Arg2 = 00000002
004011D3 |. 8D95 D0FEFFFF lea edx,[local.datfile] ; |
004011D9 |. 52 push edx ; |Arg1 = 0019FE74
004011DA |. E8 0D5B0000 call thecodin.fstream::~fstream ; \fstream::~fstream
004011DF |. 83C4 08 add esp,0x8
004011E2 |. 6A 02 push 0x2 ; /Arg2 = 00000002
004011E4 |. 8D8D 68FFFFFF lea ecx,[local.checkfile] ; |
004011EA |. 51 push ecx ; |Arg1 = E6898150
004011EB |. E8 FC5A0000 call thecodin.fstream::~fstream ; \fstream::~fstream
004011F0 |. 83C4 08 add esp,0x8
004011F3 |. 58 pop eax ; 0019FE60
004011F4 |. 8B95 B0FEFFFF mov edx,[local.84]
004011FA |. 64:8915 00000>mov dword ptr fs:[0],edx
00401201 |. E9 E7010000 jmp thecodin.004013ED ; 返回
00401206 |> 6A 00 push 0x0 ; /Arg3 = 00000000
00401208 |. 68 77B44000 push thecodin.0040B477 ; |Arg2 = 0040B477 ASCII "SuCCeSS."
0040120D |. 56 push esi ; |Arg1 = 0040D830
0040120E |. E8 C9660000 call thecodin.ostream::outstr ; \ostream::outstr
00401213 |. 83C4 0C add esp,0xC
00401216 |. 56 push esi ; /Arg1 = 0040D830
00401217 |. E8 70510000 call thecodin.endl ; \endl
0040121C |. 59 pop ecx ; 0019FE60
0040121D |. 8D8D 98FEFFFF lea ecx,[local.CRCfile] ; 读文件(crack.dat)
00401223 |. 51 push ecx ; /Arg2 = E6898150
00401224 |. 8D85 14FFFFFF lea eax,[local.datfile+44] ; |
0040122A |. 50 push eax ; |Arg1 = 0019FE60
0040122B |. E8 6C620000 call thecodin.istream::operator >> ; \istream::operator
00401230 |. 83C4 08 add esp,0x8
00401233 |. 3BBD 98FEFFFF cmp edi,[local.CRCfile] ; 如果文件的内容(整数型)和edi(0xE6898150)不相等则失败
00401239 |. 74 6D je short thecodin.004012A8 ; 如果相等则转移
0040123B |. 6A 00 push 0x0 ; /Arg3 = 00000000
0040123D |. 68 80B44000 push thecodin.0040B480 ; |Arg2 = 0040B480 ASCII "
DON'T TOUCH MY FILE THATS ILLEGAL."
00401242 |. 56 push esi ; |Arg1 = 0040D830
00401243 |. E8 94660000 call thecodin.ostream::outstr ; \ostream::outstr
00401248 |. 83C4 0C add esp,0xC
0040124B |. 6A 00 push 0x0 ; /Arg3 = 00000000
0040124D |. 68 A4B44000 push thecodin.0040B4A4 ; |Arg2 = 0040B4A4 ASCII "
FILE KORRUPTED DON'T PATCH........"
00401252 |. 56 push esi ; |Arg1 = 0040D830
00401253 |. E8 84660000 call thecodin.ostream::outstr ; \ostream::outstr
00401258 |. 83C4 0C add esp,0xC
0040125B |. 6A 00 push 0x0 ; /Arg3 = 00000000
0040125D |. 68 C8B44000 push thecodin.0040B4C8 ; |Arg2 = 0040B4C8 ASCII "
Press a Key...."
00401262 |. 56 push esi ; |Arg1 = 0040D830
00401263 |. E8 74660000 call thecodin.ostream::outstr ; \ostream::outstr
00401268 |. 83C4 0C add esp,0xC
0040126B |. E8 88090000 call thecodin.getch
00401270 |. 33C0 xor eax,eax
00401272 |. 50 push eax
00401273 |. 6A 02 push 0x2 ; /Arg2 = 00000002
00401275 |. 8D95 D0FEFFFF lea edx,[local.datfile] ; |
0040127B |. 52 push edx ; |Arg1 = 0019FE74
0040127C |. E8 6B5A0000 call thecodin.fstream::~fstream ; \fstream::~fstream
00401281 |. 83C4 08 add esp,0x8
00401284 |. 6A 02 push 0x2 ; /Arg2 = 00000002
00401286 |. 8D8D 68FFFFFF lea ecx,[local.checkfile] ; |
0040128C |. 51 push ecx ; |Arg1 = E6898150
0040128D |. E8 5A5A0000 call thecodin.fstream::~fstream ; \fstream::~fstream
00401292 |. 83C4 08 add esp,0x8
00401295 |. 58 pop eax ; 0019FE60
00401296 |. 8B95 B0FEFFFF mov edx,[local.84]
0040129C |. 64:8915 00000>mov dword ptr fs:[0],edx
004012A3 |. E9 45010000 jmp thecodin.004013ED
新建一个crack.dat 内容是0xE6898150的十进制,即可过掉这步验证
第一步验证过掉后CM的截图:
0x1 Name Organization Serial的输入及Serial的检测 上一步验证成功以后 CM要求用户输入Name Organization Serial这三个信息 其中Serial必须为整数,否则失败。
[Asm] 纯文本查看 复制代码 004012CA |> \6A 00 push 0x0 ; /Arg3 = 00000000
004012CC |. 68 D9B44000 push thecodin.0040B4D9 ; |Arg2 = 0040B4D9 ASCII "Name: ->"
004012D1 |. 56 push esi ; |Arg1 = 0040D830
004012D2 |. E8 05660000 call thecodin.ostream::outstr ; \ostream::outstr
004012D7 |. 83C4 0C add esp,0xC
004012DA |. FFB5 A4FEFFFF push [local.pname] ; /Arg2 = 02023628
004012E0 |. 68 E4D74000 push offset thecodin.cin ; |Arg1 = 0040D7E4
004012E5 |. E8 FE5D0000 call thecodin.istream::operator >> ; \istream::operator
004012EA |. 83C4 08 add esp,0x8
004012ED |. 6A 00 push 0x0 ; /Arg3 = 00000000
004012EF |. 68 E3B44000 push thecodin.0040B4E3 ; |Arg2 = 0040B4E3 ASCII "Orga: ->"
004012F4 |. 56 push esi ; |Arg1 = 0040D830
004012F5 |. E8 E2650000 call thecodin.ostream::outstr ; \ostream::outstr
004012FA |. 83C4 0C add esp,0xC
004012FD |. FFB5 A0FEFFFF push [local.porg] ; /Arg2 = 02023638
00401303 |. 68 E4D74000 push offset thecodin.cin ; |Arg1 = 0040D7E4
00401308 |. E8 DB5D0000 call thecodin.istream::operator >> ; \istream::operator
0040130D |. 83C4 08 add esp,0x8
00401310 |. 6A 00 push 0x0 ; /Arg3 = 00000000
00401312 |. 68 EDB44000 push thecodin.0040B4ED ; |Arg2 = 0040B4ED ASCII "Serial:->"
00401317 |. 56 push esi ; |Arg1 = 0040D830
00401318 |. E8 BF650000 call thecodin.ostream::outstr ; \ostream::outstr
0040131D |. 83C4 0C add esp,0xC
00401320 |. 8D8D 9CFEFFFF lea ecx,[local.serial]
00401326 |. 51 push ecx ; /Arg2 = 0040D830
00401327 |. 68 E4D74000 push offset thecodin.cin ; |Arg1 = 0040D7E4
0040132C |. E8 6B610000 call thecodin.istream::operator >> ; \istream::operator
00401331 |. 83C4 08 add esp,0x8
00401334 |. A1 E4D74000 mov eax,dword ptr ds:[cin]
00401339 |. F640 0C 86 test byte ptr ds:[eax+0xC],0x86
0040133D |. 74 5B je short thecodin.0040139A ; 如果输入的是整数则转移
0040133F |. 6A 00 push 0x0 ; /Arg3 = 00000000
00401341 |. 68 F7B44000 push thecodin.0040B4F7 ; |Arg2 = 0040B4F7 ASCII "Eingabe Fehler !!"
00401346 |. 56 push esi ; |Arg1 = 0040D830
00401347 |. E8 90650000 call thecodin.ostream::outstr ; \ostream::outstr
0040134C |. 83C4 0C add esp,0xC
0040134F |. 6A 00 push 0x0 ; /Arg3 = 00000000
00401351 |. 68 09B54000 push thecodin.0040B509 ; |Arg2 = 0040B509 ASCII "
Press a key."
00401356 |. 56 push esi ; |Arg1 = 0040D830
00401357 |. E8 80650000 call thecodin.ostream::outstr ; \ostream::outstr
0040135C |. 83C4 0C add esp,0xC
0040135F |. E8 94080000 call thecodin.getch
00401364 |. 83C8 FF or eax,0xFFFFFFFF
00401367 |. 50 push eax ; thecodin.cout
00401368 |. 6A 02 push 0x2 ; /Arg2 = 00000002
0040136A |. 8D95 D0FEFFFF lea edx,[local.datfile] ; |
00401370 |. 52 push edx ; |Arg1 = 0040D838
00401371 |. E8 76590000 call thecodin.fstream::~fstream ; \fstream::~fstream
00401376 |. 83C4 08 add esp,0x8
00401379 |. 6A 02 push 0x2 ; /Arg2 = 00000002
0040137B |. 8D8D 68FFFFFF lea ecx,[local.checkfile] ; |
00401381 |. 51 push ecx ; |Arg1 = 0040D830
00401382 |. E8 65590000 call thecodin.fstream::~fstream ; \fstream::~fstream
00401387 |. 83C4 08 add esp,0x8
0040138A |. 58 pop eax ; thecodin.cout
0040138B |. 8B95 B0FEFFFF mov edx,[local.84]
00401391 |. 64:8915 00000>mov dword ptr fs:[0],edx ; thecodin.0040D838
00401398 |. EB 53 jmp short thecodin.004013ED ; 返回
然后,CM将Name作为第一个参数 Organization作为第二个参数 Serial作为第三个参数来调用0x004013F4这个函数
0x2 分析函数:0x004013F4 CM首先计算Name的长度
[Asm] 纯文本查看 复制代码 00401403 |. 8B7D 08 mov edi,[arg.name]
00401406 |. 33C0 xor eax,eax
00401408 |. 8945 FC mov [local.serial],eax
0040140B |. 57 push edi ; /s = Name
0040140C |. E8 0F0B0000 call thecodin.strlen ; \strlen
00401411 |. 59 pop ecx ; 02023628
00401412 |. 8945 F4 mov [local.len_name],eax ; Name长度
然后获取以time(0)的返回值为随机数种子 获取一个随机数r(无符号整数)
[Asm] 纯文本查看 复制代码 00401443 |. 6A 00 push 0x0 ; /timer = NULL
00401445 |. E8 1A980000 call thecodin.time ; \time
0040144A |. 59 pop ecx ; 02023628
0040144B |. 50 push eax ; /seed = 0x6
0040144C |. E8 3B6E0000 call thecodin.srand ; \srand
00401451 |. 59 pop ecx ; 02023628
00401452 |. E8 4D6E0000 call thecodin.rand ; [获取一个随机数 记为r
然后将r mod 10的结果保存
[Asm] 纯文本查看 复制代码 00401457 |. B9 0A000000 mov ecx,0xA
0040145C |. 99 cdq
0040145D |. F7F9 idiv ecx
0040145F |. 8955 F8 mov [local.dummy],edx ; r mod 10
然后就开始用Name和Organization来计算Serial(_Serial的初始值是0)
[Asm] 纯文本查看 复制代码 00401462 |. /EB 14 jmp short thecodin.00401478
00401464 |> |0FBE06 /movsx eax,byte ptr ds:[esi] ; Organization
00401467 |. |0FBE17 |movsx edx,byte ptr ds:[edi] ; Name
0040146A |. |F7EA |imul edx
0040146C |. |0145 FC |add [local.serial],eax
0040146F |. |3B5D F4 |cmp ebx,[local.len_name]
00401472 |. |75 02 |jnz short thecodin.00401476
00401474 |. |33DB |xor ebx,ebx
00401476 |> |46 |inc esi
00401477 |. |47 |inc edi
00401478 |> \56 |push esi ; /s = Organization
00401479 |. E8 A20A0000 |call thecodin.strlen ; \strlen
0040147E |. 59 |pop ecx
0040147F |. 85C0 |test eax,eax ; eax是Orgaization的长度
00401481 |.^ 75 E1 \jnz short thecodin.00401464
这里需要注意一下:Orgaization的长度要和Name的长度相等;观察一下Name和Serial在内存中存放的顺序 可以得知Name的长度不能超过16个字节。
最后开始校验用户输入的Serial
[Asm] 纯文本查看 复制代码 00401483 |. 33DB xor ebx,ebx
00401485 |. 8B45 10 mov eax,[arg.usernum]
00401488 |. F76D F8 imul [local.dummy]
0040148B |. 8B55 FC mov edx,[local.serial]
0040148E |. 0FAF55 F8 imul edx,[local.dummy]
00401492 |. 3BC2 cmp eax,edx ; 相等则成功 不相等则失败
00401494 |. 75 43 jnz short thecodin.004014D9
0x3 计算注册码
由这段代码可以得知:
当usernum(用户输入的serial) * dummy == serial(CM计算的serial) * dummy(均为无符号乘法)时 就会成功。 其中dummy = r mod 10. 因为dummy可能为0 所以应分为两种情况讨论: 当dummy为0时:
usernum * dummy == serial * dummy总是成立的 因此这时一定会成功
当dummy不为0时:
即usernum == serial时才能成功.
如果想让用户在任何情况下都能注册成功 我们直接考虑第二种情况即可,即dummy不为0的时候。 这样就可以写出一个注册机: 运行效果如图所示:
最后附上一组可用的Name Organization和Serial以及CM的注册成功图片和CM源文件(包括KeyFile)
Name:_KaQqi
Organization:_52pj_
Serial:48875 CM成功图片: CM源文件以及KeyFile: |