当前位置: 代码迷 >> 综合 >> CrackMe-001
  详细解决方案

CrackMe-001

热度:82   发布时间:2024-01-25 05:36:45.0

逆向学习

工具

OllyDbg(OD):https://www.52pojie.cn/thread-350397-1-1.html
PEID:https://www.52pojie.cn/thread-170387-1-1.html
Exeinfo PE:https://www.52pojie.cn/thread-437586-1-1.html
樱花补丁制作工具:https://www.52pojie.cn/thread-62307-1-1.html
内存补丁生成器:https://www.52pojie.cn/thread-162411-1-1.html
注册机生成器:https://www.52pojie.cn/thread-159470-1-1.html
IDA Pro v7:https://www.52pojie.cn/thread-675251-1-1.html

第一关

首先用工具查看一些基本的信息,可以看到编译程序是Delphi3.0,没有壳

在这里插入图片描述

进去的第一个界面,嘲讽一下。。。

在这里插入图片描述

然后是程序主体,分别有三个按钮

一个是Serial/Name,需要输入用户名和注册码才能通过,另外一个Serial只需要输入一个注册码一类的东西,最后就是退出程序

在这里插入图片描述

这里先点击最左侧的Serial/Name

在这里插入图片描述

这里提示输入用户名和注册码,随便填入提交,观察提示

在这里插入图片描述

点击Check it Baby! 它会弹出一个对话框提示: Sorry, The Serial is incorrect !

再换几个随意试试,发现就这一种情况。

OK,出现了对话框这就很好办,说明作者在校验注册码之后发现如果错误了就直接弹窗,我们只要找到弹出对话框的地方,向上跟踪,就可以找出判断是否正确的地方了

接着就用到OD来分析

看了好久总算晓得一点OD的使用方法

OD打开需要调试的程序

打开之后,点击运行的图标

程序正常运行,可以随时暂停检测行为

使用OD打开程序后,进行上面重复的操作,在出现对话框提示Sorry, The Serial is incorrect !时,点击暂停,打开主线程调用堆栈信息

在这里插入图片描述

有一些攻略是这么写的

这里有两个MessageBox的地址,第一个地址为77D5082F这个地址明显太大,不在模块的领空,不是的。
第二个地址为0042A1AE,和00400100地址非常接近,十有八九就是它了。
右键 show call, 在Call上面设置断点。

然后自己去了解了一下MessageBox 的功能就是显示一个消息对话框,在弹窗时,我们暂停进程,然后在OD中找到那一段来分析判断错误弹窗的条件,我的理解大概就是这样

按照上面的操作,进去之后就是这样的

在这里插入图片描述
show call进去后按F2设置断点

注意反复调试需要关闭断点,不会一直卡在那个断点处

可以把断点理解为存档

在这里插入图片描述

上下查看,发现与弹窗内容相同的字符串,哈哈这可能是个突破点

在这里插入图片描述

JNZ会通过它上面的call 004039FC 判断我们的伪码是否正确,判断的结果存在EAX中,如果EAX不等于就跳转到错误提示信息框那里。

我们的目的是无论伪码是否正确都通过验证,所以最简单的办法就是将jnz这句使用NOP填充,我们尝试一下:选择JNZ这句,右键Binary->Fill with NOPS.回到原始程序,再次点击Check it baby!

提示Good Job!通过了!

但是经过测试,必须要用户名大于四位,才能通过

在这里插入图片描述

小于四位,运行会停止,这个校验字符串长度是在断点上方,查看上方jeg部分,如果想要输入的账户长度不大于4,只需要把JGE给修改成JMP让其强制跳转即可

在这里插入图片描述

在这里插入图片描述

上面这些就是爆破的部分,然后接下来尝试能否分析出注册机算法

将所有断点、修改的内容右键UNDO取消,然后重新一遍操作,随便输入然后报错,跳转show call

在这里插入图片描述

这里将选中代码复制出来查看

0042FAFE  |.  E8 F93EFDFF   call Acid_bur.004039FC ;  这个CALL的返回值
0042FB03  |.  75 1A         jnz XAcid_bur.0042FB1F   ;  上一个CALL的返回值不等于0则跳转到错误消息
0042FB05  |.  6A 00         push 0x0
0042FB07  |.  B9 CCFB4200   mov ecx,Acid_bur.0042FBCC
0042FB0C  |.  BA D8FB4200   mov edx,Acid_bur.0042FBD8
0042FB11  |.  A1 480A4300   mov eax,dword ptr ds:[0x430A48]
0042FB16  |.  8B00          mov eax,dword ptr ds:[eax]
0042FB18  |.  E8 53A6FFFF   call Acid_bur.0042A170
0042FB1D  |.  EB 18         jmp XAcid_bur.0042FB37 ;  强制跳转,跳过了错误显示。
0042FB1F  |>  6A 00         push 0x0
0042FB21  |.  B9 74FB4200   mov ecx,Acid_bur.0042FB74
0042FB26  |.  BA 80FB4200   mov edx,Acid_bur.0042FB80
0042FB2B  |.  A1 480A4300   mov eax,dword ptr ds:[0x430A48]
0042FB30  |.  8B00          mov eax,dword ptr ds:[eax]
0042FB32  |.  E8 39A6FFFF   call Acid_bur.0042A170 ;  函数内调用了MessageBox显示错误

所以在0042FAFE处设置断点,启动调试,注意将窗口最大化方便查看寄存器

在这里插入图片描述
这里可以看到,输入的注册码在寄存器中显示,同时上方还有一串字符,大胆猜测为计算出来后的注册码

尝试将输入的注册码替换为寄存器的,保留用户名

在这里插入图片描述
emmmm然后就得分析这个注册码怎么来的

就在0042FAFE往上翻翻,给出的部分注释

0042FA79  |> \8D55 F0       lea edx,[local.4]
0042FA7C  |.  8B83 DC010000 mov eax,dword ptr ds:[ebx+0x1DC]
0042FA82  |.  E8 D1AFFEFF   call Acid_bur.0041AA58            ;  获取账户,字符串,字符串首地址存储在EBP-0X10处
0042FA87  |.  8B45 F0       mov eax,[local.4]
0042FA8A  |.  0FB600        movzx eax,byte ptr ds:[eax]       ;  DWORD DATA = (DWORD)buff[0];
0042FA8D  |.  F72D 50174300 imul dword ptr ds:[0x431750]      ;  DATA * 0x43175 == DATA * 0x29
0042FA93  |.  A3 50174300   mov dword ptr ds:[0x431750],eax   ;  0x431750 = DATA * 0x29;
0042FA98  |.  A1 50174300   mov eax,dword ptr ds:[0x431750]
0042FA9D  |.  0105 50174300 add dword ptr ds:[0x431750],eax   ;  0x431750 *= 2
0042FAA3  |.  8D45 FC       lea eax,[local.1]
0042FAA6  |.  BA ACFB4200   mov edx,Acid_bur.0042FBAC
0042FAAB  |.  E8 583CFDFF   call Acid_bur.00403708            ;  将CW字符串首地址存储在EBP-0x4处
0042FAB0  |.  8D45 F8       lea eax,[local.2]
0042FAB3  |.  BA B8FB4200   mov edx,Acid_bur.0042FBB8         ;  CRACKED
0042FAB8  |.  E8 4B3CFDFF   call Acid_bur.00403708            ;  将字符串地址存储在EBP-0X8处
0042FABD  |.  FF75 FC       push [local.1]
0042FAC0  |.  68 C8FB4200   push Acid_bur.0042FBC8            ;  UNICODE "-"
0042FAC5  |.  8D55 E8       lea edx,[local.6]
0042FAC8  |.  A1 50174300   mov eax,dword ptr ds:[0x431750]
0042FACD  |.  E8 466CFDFF   call Acid_bur.00406718            ;  将0x431750存储的十六进制转换成字符串,地址存储在EBP-0x18处
0042FAD2  |.  FF75 E8       push [local.6]
0042FAD5  |.  68 C8FB4200   push Acid_bur.0042FBC8            ;  UNICODE "-"
0042FADA  |.  FF75 F8       push [local.2]
0042FADD  |.  8D45 F4       lea eax,[local.3]
0042FAE0  |.  BA 05000000   mov edx,0x5
0042FAE5  |.  E8 C23EFDFF   call Acid_bur.004039AC            ;  字符串拼接。(EBP-0X4)+(EBP-0X18)+(EBP-0X8) 存储在ebp-0xC
0042FAEA  |.  8D55 F0       lea edx,[local.4]
0042FAED  |.  8B83 E0010000 mov eax,dword ptr ds:[ebx+0x1E0]
0042FAF3  |.  E8 60AFFEFF   call Acid_bur.0041AA58            ;  得到输入的密码
0042FAF8  |.  8B55 F0       mov edx,[local.4]
0042FAFB  |.  8B45 F4       mov eax,[local.3]
0042FAFE  |.  E8 F93EFDFF   call Acid_bur.004039FC            ;  输入的密码与程序计算出来的KEY做比较
0042FB03  |.  75 1A         jnz XAcid_bur.0042FB1F            ;  上一个CALL的返回值不等于0则跳转到错误消息

攻略上把这一段转换成C语言,得出结论:在计算KEY中,只使用了用户的第一个字母,后三位没用。所以,账户abcd和aaaa使用的KEY是相同的

void Decryption(char* mima)
{char szBuff[260];unsigned long data = (unsigned long)mima[0];data *= 0X29;data *= 2;sprintf(szBuff, "CW-%d-CRACKED", data);printf("%s \r\n", szBuff);
}

emmm之后还得研究