160个CrackMe之156 算法分析
本帖最后由 zbnysjwsnd8 于 2017-8-30 20:48 编辑翻了一圈 好像论坛里还没有人成功破解这个CM 刚好今天看了一下 于是就有了这篇文章。
我并不是大神 就是一个菜鸟 如果有错误还希望各位大佬们指出来。
0x0 KeyFile的检测CM首先会读取 crack.dat 如果这个文件不存在则失败
00401170|.A1 6CCA4000 mov eax,dword ptr ds:
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, ; |
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,
00401195|.F641 0C 86 test byte ptr ds:,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, ; |
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, ; |
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,
004011FA|.64:8915 00000>mov dword ptr fs:,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, ;读文件(crack.dat)
00401223|.51 push ecx ; /Arg2 = E6898150
00401224|.8D85 14FFFFFF lea eax, ; |
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, ;如果文件的内容(整数型)和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, ; |
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, ; |
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,
0040129C|.64:8915 00000>mov dword ptr fs:,edx
004012A3|.E9 45010000 jmp thecodin.004013ED
新建一个crack.dat 内容是0xE6898150的十进制,即可过掉这步验证
第一步验证过掉后CM的截图:
0x1 Name Organization Serial的输入及Serial的检测上一步验证成功以后 CM要求用户输入Name Organization Serial这三个信息 其中Serial必须为整数,否则失败。
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 ; /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 ; /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,
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:
00401339|.F640 0C 86 test byte ptr ds:,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, ; |
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, ; |
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,
00401391|.64:8915 00000>mov dword ptr fs:,edx ;thecodin.0040D838
00401398|.EB 53 jmp short thecodin.004013ED ;返回
然后,CM将Name作为第一个参数 Organization作为第二个参数 Serial作为第三个参数来调用0x004013F4这个函数
0x2 分析函数:0x004013F4CM首先计算Name的长度
00401403|.8B7D 08 mov edi,
00401406|.33C0 xor eax,eax
00401408|.8945 FC mov ,eax
0040140B|.57 push edi ; /s = Name
0040140C|.E8 0F0B0000 call thecodin.strlen ; \strlen
00401411|.59 pop ecx ;02023628
00401412|.8945 F4 mov ,eax ;Name长度
然后获取以time(0)的返回值为随机数种子 获取一个随机数r(无符号整数)
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的结果保存
00401457|.B9 0A000000 mov ecx,0xA
0040145C|.99 cdq
0040145D|.F7F9 idiv ecx
0040145F|.8955 F8 mov ,edx ;r mod 10
然后就开始用Name和Organization来计算Serial(_Serial的初始值是0)
00401462|. /EB 14 jmp short thecodin.00401478
00401464|> |0FBE06 /movsx eax,byte ptr ds: ;Organization
00401467|. |0FBE17 |movsx edx,byte ptr ds: ;Name
0040146A|. |F7EA |imul edx
0040146C|. |0145 FC |add ,eax
0040146F|. |3B5D F4 |cmp ebx,
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
00401483|.33DB xor ebx,ebx
00401485|.8B45 10 mov eax,
00401488|.F76D F8 imul
0040148B|.8B55 FC mov edx,
0040148E|.0FAF55 F8 imul edx,
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:48875CM成功图片:CM源文件以及KeyFile: 膜拜星斗
标题改一下,160cm之156 算法分析 大神 厉害,
160个cm在哪里下载呢 好文,分析到位!感谢分享 求一份1-156的算法解析,
我是渣渣,想学习学习 这是干嘛用的?
页:
[1]