160个Crackme之020学习笔记
本帖最后由 海天一色001 于 2019-4-23 20:15 编辑第20个CM,一看图标是应该是Delphi的,打开程序:
这个界面有点花啊,看不大懂,蜘蛛是个什么意思?试着在Serial文本框中输入字符,点击“Spider”按钮,有提示,不是有效的数字;再重新输入数字,点击按钮,下方的Reg N框中出现文本,但与下方的字符不一样,猜测是输入Serial,经过运算得到“3E74984B”这串数字吧!
无意中又点中“Spider”按钮,左下方的蜘蛛竟然向上动了一下!再点击,再向上;直到爬到蛛网处,程序自动关闭!可能这个程序不是那么简单地让人破了!
先不管那么多,查壳:
有壳,得先脱壳。试着用PEiD插件中的PEiD通用脱壳器,生成一个BuLLeT.8.exe.unpacked_.exe文件,再用PeiD查壳,发现已脱,程序是用Delphi编写的。
学习破解,不光要用工具脱壳,更得学会基本的原理和手动脱壳方法,所以要练习一下手工脱壳:
将程序载入OD中,提示加了密,其实就是加了壳,
点“是”按钮,进入CPU界面,一看就不是熟悉的程序入口点:
利用以前学习的单步直达法,F8向下一步,在寄存器窗口里右键点击ESP数值,选“数据窗口中跟随”命令:
在地址栏中右击,选择“断点-硬件访问-word”;
F9键运行,CPU窗口到达00465262地址处,
看命令,是跳到0044A648地址,这个跳转很大,可能跳过去就是程序入口点了,F8运行,
这个界面很熟悉了,就是程序真正的入口:
用OD的插件来脱壳:
使用方式1和方式2脱壳,生成文件1.exe和2.exe;
分别打开这两个脱壳后的文件均能正常运行,就不需要修复了。再用PEiD查壳,均显示无壳,使用Delphi编程:
第一步、爆破:
OD载入1.exe:老习惯,查找字符串,可这一次不行了,没找到有关的文字:
Delphi语言也不熟,但肯定有按钮事件,用Dark查找一下按钮事件:
看到按钮事件开始的内存地址为0044A2E8,在内存地址上双击,进入反编译界面:
和VB Decompiler有点相似,看了一下,按钮事件的代码并不长。
回到OD,将相关的注释复制到OD中进行对照,基本上程序就很清楚了。从按钮事件开始一直到0044A387才有第一个跳转(jnz short 1.0044A398),这个跳转跳过了另一个jmp,根据以往的经验,很可能这就是关键跳:在这两个跳转之后又有一个跳转命令,观察代码后发现前两个跳都不到这里,所以不是关键跳。于是大胆试验一下,将0044A387处的指令nop掉,生成1_nop.exe,试一试,在文本框中输入“12345”,点按钮,下面文本框中出现“0090AB”,右边出现了一个奖杯,成功了!
第二步、追码:
Ctrl+G到0044A2E8处下断,F9运行,输入“12345”,点按钮,程序中断;单步向下,至0044A30C处,看到命令是call 1.0042440C,运行后看到信息框中内容为堆栈载入了Serial,eax=5;
继续向下,0044A314处Dark注释的函数是StrToInt(S:,猜测是字符串转整数,运行后=0x3039,是十进数12345的16进制形式:继续向下,到0044A31E处应该还是字符串转整数,可能是64位的吧;再向下,到0044A337处,=*3=0x90AB;继续到0044A34B处,字符串转16进制数(其实从寄存器中看到的本来就是16进制数了);继续向下,注释中TControl.SetText(TControl;TCaption) Edit3 : TEdit 、TControl.GetText(TControl):Tcaption、control Label2 : TAHMLabel、controls.TControl.SetVisible(TControl;Boolean)、control Label6 : TLabel等,结合以往的经验,应该是020程序界面上的文本框、标签等的名称、内容之类的内容:
0044A314|.E8 EFD6FBFF call 1.00407A08 ;* Reference to: sysutils.StrToInt(S:
0044A319|.8BF0 mov esi,eax ;上一句call应该是对Serial进行运算:=0x3039=D12345
0044A31B|.8B45 FC mov eax,
0044A31E|.E8 5DD7FBFF call 1.00407A80 ;* Reference to: sysutils.StrToInt64(S: =0x3039
0044A323|.52 push edx
0044A324|.50 push eax
0044A325|.8BC6 mov eax,esi
0044A327|.99 cdq ;cdq大多出现在除法运算之前,实际的作用把EDX的所有位都设成EAX最高位的值。也就是说,当EAX <80000000, EDX=00000000; 当EAX >= 80000000, EDX 则为FFFFFFFF。
0044A328|.030424 add eax,dword ptr ss: ;=+SS:=*2
0044A32B|.135424 04 adc edx,dword ptr ss: ;带进位加法指令:edx=edx + + CF
0044A32F|.83C4 08 add esp,0x8
0044A332|.52 push edx
0044A333|.50 push eax
0044A334|.8BC6 mov eax,esi
0044A336|.99 cdq
0044A337|.030424 add eax,dword ptr ss: ;实际上是= +SS:= *3
0044A33A|.135424 04 adc edx,dword ptr ss: ;1.0044A3E4
0044A33E|.83C4 08 add esp,0x8
0044A341|.52 push edx
0044A342|.50 push eax
0044A343|.8D55 F8 lea edx,
0044A346|.B8 06000000 mov eax,0x6
0044A34B|.E8 78D6FBFF call 1.004079C8 ;* Reference to: sysutils.IntToHex(Value:
0044A350|.8B55 F8 mov edx,
0044A353|.8B83 CC020000 mov eax,dword ptr ds: ;* Reference to control Edit3 : TEdit
0044A359|.E8 DEA0FDFF call 1.0042443C ;controls.TControl.SetText(TControl;TCaption);
0044A35E|.8D55 F4 lea edx,
0044A361|.8B83 CC020000 mov eax,dword ptr ds: ;* Reference to control Edit3 : TEdit
0044A367|.E8 A0A0FDFF call 1.0042440C ;controls.TControl.GetText(TControl):TCaption;
0044A36C|.8B45 F4 mov eax,
0044A36F|.50 push eax
0044A370|.8D55 F0 lea edx,
0044A373|.8B83 F0020000 mov eax,dword ptr ds: ;* Reference to control Label1 : TAHMLabel
继续到0044A379处调用ASCII值“3E74984B”, 下一句将这个值存入edx中,再下一句=0x90AB,到0044A382处调用比较子程序(call 1. 00403BE8)对和进行比较,因为不相等,所以下一句会跳;
0044A379|.E8 8EA0FDFF call 1.0042440C ;调用字符串* Reference to: controls.TControl.GetText(TControl):TCaption;
0044A37E|.8B55 F0 mov edx, ;=="3E74984B",即下面显示的字符串
0044A381|.58 pop eax ;0012F734
0044A382|.E8 6198FBFF call 1. 00403BE8 ;此call应该是比较,运行后=FFFFFFFF
0044A387|.75 0F jnz short 1.0044A398 ;关键跳,跳走则失败
观察运行到此,其实注册算法已经出来了,就是Serial=dec(0x3E74984B/3)= “349276185”!将“349276185”输入文本框,点击按钮,成功!
虽然已经找出了注册算法,可是里面有好几个Call,怎么转化的还不清楚,所以重新在OD中看一看:
重新运行程序,中断在按钮事件段首处,再单步至0044A314处,注释中说明是从字符串转整数的,F7键进call看看:
0044A314|.E8 EFD6FBFF call 1.00407A08 ;* Reference to: sysutils.StrToInt(S:
F8至00407A2A处,又一个call,因为这一个段内共有4个call,所以需要耐心进去看看是什么:
00407A2A |.E8 49AFFFFF call <1.IsNum(Serial(n))>
进入00402978处后,经单步运行,基本上确定是取字符串转整数类型就是这个call里了:
继续运行,可知是取出字符串的每一位字符,先转化成ASCII值,判断是空格、加号、减号、大小写的字母X、数字0时跳到错误处理程序;不是,则继续向下进行:
到004029CA---004029E2这段循环时,将字符串“12345”转化成了数字0x3039;
004029CA |>80EB 30 /sub bl,0x30 ;=-0x30,判断是否为数字
004029CD |. |80FB 09 |cmp bl,0x9 ;cmp(,0x9),相等则ZF=1,不等则ZF=0
004029D0 |. |77 2C |ja short 1.004029FE ;(无符号)大于则跳,弹出不是数字的错误提示框
004029D2 |. |39F8 |cmp eax,edi
004029D4 |. |77 28 |ja short 1.004029FE
004029D6 |. |8D0480 |lea eax,dword ptr ds:
004029D9 |. |01C0 |add eax,eax ;=+
004029DB |. |01D8 |add eax,ebx ;=+
004029DD |. |8A1E |mov bl,byte ptr ds: ;取后1个字符
004029DF |. |46 |inc esi
004029E0 |. |84DB |test bl,bl
004029E2 |.^\75 E6 \jnz short 1.004029CA ;Serial(n) 循环运算后存入eax中
继续向下运行,又经过几个call,F7进入后没有什么新的变化,几个retn,返回到了0044A319 处,所以在00402978处加了个IsNum(Serial(n))标签,返回到00407A08处加了StrToInt标签,更清楚了子程序的作用。
这个程序破解就到这里,注册机就不用再写了,很简单的一个计算就行了!Serial=dec(0x3E74984B/3)= “349276185”。
如何在原程序上打补丁还远没有学习到,下步会学习的。
附件含CM原程序、脱壳后的程序、爆破后的程序(无注册机)。
百度链接是:http://pan.baidu.com/s/1skMkJY9密码: 86pm,160个CM、我已练习过的前20个crackme程序(不含012)都在里面。
学习了,谢谢楼主的热性分享 收藏备用学习感谢分享 真的是优秀 收藏一下 目前也正在看这个160个 挺好的,看着不错哈。 支持一下 收藏学习,感谢分享 学习了,谢谢楼主分享! 谢谢分析
页:
[1]
2