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)都在里面。
鬼手56 发表于 2019-4-22 09:42
这个程序用IDA的话注册机算法直接就能抠出来
感谢你的指导!
不过我现在正处于初学阶段,语言只学了点VB,连C都不会;反编译工具很多,现在也只是会用了有限的几个,IDA打开过,基本不懂!
其实更重要的,是基础太差,汇编指令都需要在用到时猛查,数据的存储更是迷糊,这次大数计算时才算是深入学习了一下原码、反码和补码,真的感觉学习的任务很重,盼望大神给我多指点啊! 谢谢大佬的分享 这个程序用IDA的话注册机算法直接就能抠出来 谢谢分享 感谢楼主分享
谢谢大佬的分享 19/160,进步呀。 同新手,一起学习,共同进步{:1_893:} 共同进步、加油
页:
[1]
2