海天一色001 发表于 2019-4-22 09:15

160个Crackme之019学习笔记

打开019程序,与018一样的作者,只是要输入用户名和注册码后进行检测:
   
直接点击“Check it”按钮,程序弹出提示,要求用户名长度要5个以上;
用户名随意输入“11111”,注册码输入“22222”再点击,弹出错误提示:

仍然先查壳,C++ 6.0编写,无壳:

第一步、爆破程序:
用OD加载程序,用“中文搜索引擎”的智能搜索功能,找到了如下字符串:

这次有两个地方要爆破,一个是用户名输入时的限制,一个是爆破注册码:
很容易知道00401582处是用户名长度限制,00401669处是注册成功的提示,那么先双击00401582地址,回到CPU窗口:
随意看了一下代码,很容易就找到了关键跳等信息:
00401579处地址跳过了用户名长度的限制,jge直接改成jmp:
00401572|.8945 E4       mov ,eax
00401575|.837D E4 05    cmp ,0x5
00401579|.7D 43         jge short Brad_Sob.004015BE
0040157B|.6A 40         push 0x40
0040157D|.68 20404000   push Brad_Sob.00404020                   ;CrackMe
00401582|.68 28404000   push Brad_Sob.00404028                   ;User Name must have at least 5 characters.
............
004015BE|>C745 E0 00000>mov ,0x0


先保存成可执行文件Brad Soblesky.2-user.nop.exe,试运行一下,不管输不输入,输入什么都不再限制了;
再向下找到00401669处,注册成功的提示,向上查看,到00401642处,命令是jnz Brad_Sob.00401747,跳过成功,走向失败,将这一句nop掉:
00401640          |.85C0                     test eax,eax                                           ;Brad_Sob.00403430
00401642            0F85 FF000000            jnz Brad_Sob.00401747                                  ;跳过成功,走向失败

将所有修改保存为可执行文件Brad Soblesky.2-user-Serial.nop.exe,运行Brad Soblesky.2-user-Serial.nop.exe,直接点击“Check“按钮,弹出成功,说明用户名长度限制与注册码都爆破了。

第二步、追注册码:
接下来找注册码,可以先向上翻到“Check”按钮事件的代码段首004014DF处下断,这次我是直接在004015BE处(过了用户名长度限制)下断:
Ctrl+F2键返回程序开始(将刚才修改的两个爆破处还原),
F9运行程序,
输入用户名“52pojie”,注册码“123450”,点击“Check”按钮,程序中断于004015BE处:
查看了一下寄存器窗口,看到EBP-18存入假码,EBP-14存入用户名;

F8单步向下,从004015BE到0040161A之间是生成注册码的代码段,头疼的是一大堆的逻辑与运算、有符号数乘法、异或运算,心里就发怵。
004015BE    |> \C745 E0 >mov ,0x0                         ;此时eax=用户名长度,首次为0,以后每次+1
004015C5    |.EB 09    jmp short Brad_Sob.004015D0
004015C7    |>8B55 E0/mov edx,                        ;edx=;循环开始,edx开始取值?
004015CA    |.83C2 01|add edx,0x1                              ;edx=edx+1
004015CD    |.8955 E0|mov ,edx                        ;=edx
004015D0    |>8B45 E0   mov eax,                        ;eax=;第一次从上面跳过来,第二次从循环中来
004015D3    |.3B45 E4|cmp eax,                        ;eax与长度比较:=len(user)
004015D6    |.7D 42    |jge short Brad_Sob.0040161A            ;eax>=len(user)时跳,即循环了用户名长度次数后跳
004015D8    |.8B4D E0|mov ecx,
004015DB    |.51       |push ecx
004015DC    |.8D4D EC|lea ecx,                        ;ecx=用户名 ==user
004015DF    |.E8 1C030>|call <Brad_Sob.ASC(Strings(n))>          ;al=asc(user(n))
004015E4    |.0FBED0   |movsx edx,al                           ;edx=al=ASC(user(n));n为每次循环的当次序数
004015E7    |.8B45 F0|mov eax,                        ;=,第一次循环前值为0x81276345,固定值
004015EA    |.03C2   |add eax,edx                              ;eax=eax+edx(16进制)
004015EC    |.8945 F0|mov ,eax                        ;=+hex(asc(user(n)))
004015EF    |.8B4D E0|mov ecx,                        ;ecx=(),ecx(当前循环次数(从0开始))=n
004015F2    |.C1E1 08|shl ecx,0x8                              ;ecx左移8位:ecx=ecx*(2^8)(10进制的算法)
004015F5    |.8B55 F0|mov edx,
004015F8    |.33D1   |xor edx,ecx                              ;按位'异或'运算,结果送至edx中
004015FA    |.8955 F0|mov ,edx                        ;    = xor
004015FD    |.8B45 E0|mov eax,
00401600    |.83C0 01|add eax,0x1                              ;循环次数+1:n=n+1
00401603    |.8B4D E4|mov ecx,                        ;=len(user)
00401606    |.0FAF4D E>|imul ecx,                     ;ecx=*=len(user)*(n+1)
0040160A    |.F7D1   |not ecx                                  ;对ecx按位求反运算(即0变1,1变0),结果返回ecx?
0040160C    |.0FAFC1   |imul eax,ecx                           ;eax=eax*ecx=(n+1)*(not ecx)????
0040160F    |.8B55 F0|mov edx,
00401612    |.0FAFD0   |imul edx,eax                           ;edx=edx*eax=*{(n+1)*)????
00401615    |.8955 F0|mov ,edx                        ;存入以上结果(即注册码)
00401618    |.^ EB AD    \jmp short Brad_Sob.004015C7
0040161A    |>8B45 F0mov eax,                         ;循环运算后得到注册码
运行到004015F2处,命令是shl ecx,0x8,意思是ecx里的数逻辑左移8位?ecx=0,执行命令后,寄存器窗口中ECX 为0不变,下面的标志位中P、A、Z均变成了1,S变成了0;
Shl命令给我难住了,不知道该如何进行下去。再向下看,Not命令后的乘法又不会了!什么意思嘛!从网上疯狂地搜索,搞明白了shl和not这两个命令,基本上ecx=shl ecx,0x8是说ecx中的10进制数值*2的N次方再存入ecx中,Not命令后的结果是10进制数4294967296减去寄存器中的10进制值:
再向下基本上算法出来了:
Result = 0x81276345
For n=0 to len(user)-1
Result = Result + Hex(asc(user(n)    ’
Result = Result xor (n shl,0x8)
Result = (n+1) * (not len(user) * n) * Result
Next n
循环7次后,得到注册码,继续向下,对得到的数值进行格式化,是无符号数格式:
0040161D    |.50       push eax
0040161E    |.68 54404>push Brad_Sob.00404054                  ;%lu无符号数格式
00401623    |.8D4D DClea ecx,                         ;=:存入计算出的注册码
00401626    |.51       push ecx
00401627    |.E8 52070>call <jmp.&MFC42.#CString::Format_2818>   ;可能是字符串格式函数,ecx=真码
0040162C    |.83C4 0Cadd esp,0xC
0040162F    |.8D4D DClea ecx,
00401632    |.E8 79020>call Brad_Sob.004018B0                  ;eax=真码,经格式化转变后得到
到0040162C处运行后寄存器窗口中数值如下,感觉“3186769159”这一串数字就是注册码了:试着往程序019中输入,成功了,说明感觉是正确的。

继续到0040163B处,调用检测代码段进行计算:
00401637    |.50       push eax
00401638    |.8D4D E8lea ecx,                         ;=:存入的假码
0040163B    |.E8 80020>call <Brad_Sob.IsTrue(Sn)>                ;应该是检测注册码真假,存入eax中
00401640    |.85C0   test eax,eax
00401642      0F85 FF0>jnz Brad_Sob.00401747                     ;跳过成功,走向失败
到这里,信心满满啊,这个程序也不复杂嘛!开始编写注册机,由于自己不会C语言,仍用VB进行,就在这一步卡了一个多星期!!!
注册算法正确,可是第一次循环过程中,Result+asc(user(n)就开始出错,开始了漫漫的调试修改之路。程序一运行,就是提示6号数值溢出错误,于是将Result定义为双精度型,继续运行,仍然超出了范围!从网上搜索了大量的资料,基本上都是C++及其他语言的,极少有VB的!自己按说明将大数定义为字符,反反复复地修改,几乎要崩溃了!后来,后来,借网上几个大数运算的函数套了进去,然后运行,仍是错误重重,不是首位多了空格,就是结果少了1位,等等。
现在的注册机虽然写出来了,但肯定也会有数据溢出的问题存在,只是精力不足,只能留待以后学习完善,更盼望大神指导!

附件,含CM原程序、爆破后的程序及019注册机。百度链接是:http://pan.baidu.com/s/1skMkJY9密码: 86pm,160个CM、我已练习过的前19个crackme程序(不含012)都在里面。

海天一色001 发表于 2019-4-22 15:19

鬼手56 发表于 2019-4-22 09:42
这个程序用IDA的话注册机算法直接就能抠出来

感谢你的指导!
不过我现在正处于初学阶段,语言只学了点VB,连C都不会;反编译工具很多,现在也只是会用了有限的几个,IDA打开过,基本不懂!
其实更重要的,是基础太差,汇编指令都需要在用到时猛查,数据的存储更是迷糊,这次大数计算时才算是深入学习了一下原码、反码和补码,真的感觉学习的任务很重,盼望大神给我多指点啊!

小城微风 发表于 2019-4-22 09:39

谢谢大佬的分享

鬼手56 发表于 2019-4-22 09:42

这个程序用IDA的话注册机算法直接就能抠出来

newchange452pj 发表于 2019-4-22 10:10

谢谢分享

shelly1314 发表于 2019-4-22 12:39

感谢楼主分享

lshfyq 发表于 2019-4-22 13:47


谢谢大佬的分享

rickw 发表于 2019-4-22 14:18

19/160,进步呀。

networkbox 发表于 2019-4-22 17:07

同新手,一起学习,共同进步{:1_893:}

li4ming 发表于 2019-4-22 20:18

共同进步、加油
页: [1] 2
查看完整版本: 160个Crackme之019学习笔记