序言
最近一直在学习汇编语言、C语言和PE相关的知识,想更好地理解一下底层相关的知识,刚好自己又对逆向工程很有兴趣,因此就拿CrackMe练练手,毕竟光学不练假把式。
CrackMe
之前想的是从头开始练习,也就是从第一个开始练习,结果发现第一个是Delphi编写的,自己对Delphi编写的程序不太了解,因此就选择了第018,它是VC++编写的,比较简单,就拿它开刀了。
STEP 0x0 准备工作
工具:OllyDbg(吾爱破解)、exeinfo PE
CrackMe:Brad Soblesky.1.exe
STEP 0x1 查壳
用exeinfo PE 工具打开Brad Soblesky.1.exe这个可执行文件,可以看到是没有加壳的:
STEP 0x2 打开软件
打开软件,并随机输入注册码,看看会提示什么信息,可以看到含有“Incorrect try again”字符串:
STEP 0x3 OllyDbg爆破
直接使用OllyDbg打开程序,加载完程序,一般会停在程序入口点。直接鼠标右键 -》中文搜索引擎 -》搜索ASCII
很明显“Correct way to go!!”是注册码正确时的提示,下面的是注册码错误时的提示。双击“Incorrect try again”这一行,跳转到CPU指令界面。
分析这一块的汇编代码:
004015AD |> \6A 40 push 0x40
004015AF |. 68 6C304000 push Brad_Sob.0040306C ; CrackMe
004015B4 |. 68 74304000 push Brad_Sob.00403074 ; Incorrect try again!!
004015B9 |. 8B4D E0 mov ecx,[local.8]
004015BC |. E8 3D050000 call <jmp.&MFC42.#CWnd::MessageBoxA_4224>
push指令一般是将函数的参数压入堆栈,call一般是调用函数,因此这里就相当于调用弹出窗口函数,弹出的是注册码错误的提示信息窗口,再上面就是正确时的提示串口了,继续向上找,在push 0x40
指令,很明显是其他指令跳转而来
jnz指令:jump if not zero,意思是标志寄存器ZF不为0时跳转,jz指令与其相反,jump if zero,标志寄存器ZF为0 时,跳转,test指令:两操作数作与运算,仅修改标志位,不回送结果。
红色的箭头表示当前满足跳转条件,进行跳转。因此jnz指令是关键跳转,它把注册码正确时的窗口跳过了,只需要把jnz跳转到正确时的窗口,也就是跳转到它的下一条指令,就相当于不论填写什么注册码,都会执行注册码正确时的窗口,达到自己想要的目的,我们可以试一下:
达到目的,爆破完成。
STEP 0x4 OllyDbg追码
爆破会修改程序本身,给人一种不安全的感觉,尤其是那些有强迫症的人来说,因此为了提升自我,我就继续追码。代码分析如下:
00401512 /. 55 push ebp
00401513 |. 8BEC mov ebp,esp
00401515 |. 83EC 20 sub esp,0x20
00401518 |. 894D E0 mov [local.8],ecx
0040151B |. 66:A1 5C31400>mov ax,word ptr ds:[0x40315C]
00401521 |. 66:8945 F4 mov word ptr ss:[ebp-0xC],ax
00401525 |. 33C9 xor ecx,ecx
00401527 |. 894D F6 mov dword ptr ss:[ebp-0xA],ecx
0040152A |. 894D FA mov dword ptr ss:[ebp-0x6],ecx
0040152D |. 8B15 20304000 mov edx,dword ptr ds:[0x403020] ; <BrD-SoB>
00401533 |. 8955 E4 mov [local.7],edx ; 堆栈地址[local.7]存的是<BrD-SoB>
00401536 |. A1 24304000 mov eax,dword ptr ds:[0x403024] ; -SoB>
0040153B |. 8945 E8 mov [local.6],eax
0040153E |. 66:8B0D 28304>mov cx,word ptr ds:[0x403028] ; >
00401545 |. 66:894D EC mov word ptr ss:[ebp-0x14],cx
00401549 |. 6A 0A push 0xA
0040154B |. 8D55 F4 lea edx,[local.3]
0040154E |. 52 push edx
0040154F |. 68 E8030000 push 0x3E8
00401554 |. 8B4D E0 mov ecx,[local.8] ; mfc42.5F1D0040
00401557 |. E8 A8050000 call <jmp.&MFC42.#CWnd::GetDlgItemTextA_>
0040155C |. 8D45 F4 lea eax,[local.3] ; 自己输入的假码,将假码放入eax
0040155F |. 50 push eax ; /eax作为函数的参数压入堆栈
00401560 |. FF15 04204000 call dword ptr ds:[<&KERNEL32.lstrlenA>] ; \lstrlenA
00401566 |. 8945 F0 mov [local.4],eax ; 上面一行是获取长度,返回值一般存在eax中,再将eax的值存入[local.4]堆栈中
00401569 |. 837D F0 01 cmp [local.4],0x1 ; 将[local.4]的值与1比较,也就是比较长度
0040156D |. 73 16 jnb short Brad_Sob.00401585 ; 长度大于或等于1就跳转
0040156F |. 6A 40 push 0x40
00401571 |. 68 2C304000 push Brad_Sob.0040302C ; CrackMe
00401576 |. 68 34304000 push Brad_Sob.00403034 ; Enter Registration Number
0040157B |. 8B4D E0 mov ecx,[local.8] ; mfc42.5F1D0040
0040157E |. E8 7B050000 call <jmp.&MFC42.#CWnd::MessageBoxA_4224>
00401583 |. EB 3C jmp short Brad_Sob.004015C1
00401585 |> 8D4D E4 lea ecx,[local.7] ; 将堆栈[local.7]存入edx寄存器中
00401588 |. 51 push ecx ; /String2 = NULL
00401589 |. 8D55 F4 lea edx,[local.3] ; |将堆栈[local.3]存入edx寄存器中
0040158C |. 52 push edx ; |String1 = NULL
0040158D |. FF15 00204000 call dword ptr ds:[<&KERNEL32.lstrcmpA>] ; \lstrcmpA
00401593 |. 85C0 test eax,eax
这一段就是校验自己输入的注册码是否正确的函数,其中local.x代表的是ebp-(x*4),EBP加一个值一般存储的是函数的参数,减一个值一般存储的是函数的局部变量和返回值,local.x是被OD处理过的,使代码容易阅读。
经过分析,在跳转之前,对堆栈中的local.3和local.7进行了比较,因为是在一个函数内,EBP一般来说是不会变动的,对代码分析发现local.7存储的是“<BrD-SoB>”,而local.3是我们自己输入的注册码,因此基本上确定注册码是固定的“<BrD-SoB>”,尝试一下:
事实说明,注册码是这个。
结语
这个CrackMe是很简单的,是我人生中吃到的第一个草莓(CM:CrackMe),虽然简单,但还是给我了很多启发,让我有了很大的进步,但还需努力。以上只是一个新手的一己之言,见谅
如有错误,敬请指出,感谢指正! —2019-04-08 22:57:43
最新评论
没有收到邮件通知
我的评论通知貌似坏掉了,定位一下问题
测试一下重新部署后的邮件功能
居然看到自己公司的MIB库,诚惶诚恐
那可能是RobotFramework-ride的版本问题。我装的1.7.4.2,有这个限制。我有空再尝试下旧版本吧,感谢回复。
你好!我在python2.7中安装RobotFramework-ride的时候提示wxPython的版本最高是2.18.12,用pip下载的wxPython版本是4.10,而且我在那个路径下没有找到2
真的太好了,太感谢了,在bilibili和CSDN上都找遍了,终于在你这里找到了
看到下面的链接了,不用了。