练习笔记之160Crackme-006
本帖最后由 xiaoyu2032 于 2022-4-27 12:23 编辑# 160CM-006
## 前言
这次直接跳过005了,因为005要求逆算法,而这个算法的表述方式有些变态,类似于格斗游戏中的必杀技连招 ↑ ↓ ← → A B A B …… ,要去找出连招的正确出招顺序。因为一般的程序保护算法不大会这样去表述,因此不搞它了(关键是不会,看完别人破解过程仍觉得一头雾水)。
爆破的话005其实不难,如果前面几个都能解决的话,这道题借助IDR对delphi程序进行反汇编,还是比较容易搞清楚程序的主要流程走向的。
另外,这个程序IDA进行分析的时候,会遇到自动分析将部分数据和代码识别不对的地方,这时可以右键code或data进行转换,然后再从编辑下选择功能,创建函数将其识别成函数。之后就可以按F5查看伪代码了。
## 正题
接下来看这次的正主,首先,通过help的介绍,破解要求隐藏界面下方图片区域上的两个按钮,其中有一个按钮初始状态还是禁用的。
很明显,这是一个不能用搜索关键字来解决的题。根据通用的编程经验,程序肯定是在输入框字符变化时,进行相应的事件响应,通过判断输入内容是否正确来确定是否解除Ok按钮的禁用状态,另外还有就是在按钮按下后通过事件响应,来确定是否隐藏按钮。
拖入EXEinfoPE看一下,没有壳,delphi编程,那就简单了。针对delphi程序,先用神器IDR打开程序后,可以直接查看到程序窗口以及相应的控件事件函数,双击控件函数可以直接跳转到函数对应的代码位置。通过自动的代码注释,可以很容易的发现SetEnable对应的是设置按钮是否禁用的状态。
SetVisible是设置按钮是否可见的状态。
在各事件的响应函数入口位置设下断点,然后F8跟踪调试,可以很容易的发现以下关键跳转:
``` asm
00442CD6 /75 0F jnz short aLoNg3x_.00442CE7 ;设置禁用属性的跳转
00442D84 /75 12 jnz short aLoNg3x_.00442D98 ;设置OK按钮可见性的跳转1
00442DC8 /74 0D je short aLoNg3x_.00442DD7 ;设置OK按钮可见性的跳转2
00442E26 /75 0F jnz short aLoNg3x_.00442E37;设置禁用属性的跳转
00442EEE /74 1C je short aLoNg3x_.00442F0C;设置Cancel按钮可见性的跳转
```
将上述是jnz改为je,是je的改为jnz,复制保存修改文件,爆破完成。运行结果如下:
## 算法分析
已经完成了爆破的话,对程序执行流程就基本弄清楚了,根据关键跳转位置,可以比较容易的确定比较函数在哪个位置。
首先跟踪输入框响应事件,可以发现两个输入框响应事件中都有同一个调用“call 00442A3C”,通过这个函数判断输入内容是否正确来确定是否将OK按钮的禁用状态解除。
其中主要算法过程如下:
借助IDR(IDR对一些delphi函数能识别出来,方便理解)和IDA(IDA可以生成伪代码,方便理解算法)以及OD单步跟踪,可以分析出算法为输入用户名字符串(第1个字母对应的ASCII码值×第2个字母的ASCII码值×1)+(第2个字母对应的ASCII码值×第3个字母的ASCII码值×2)+……+(第n-1个字母对应的ASCII码值×第n个字母的ASCII码值×(n-1))-666。
对应的注册机程序如下:
``` cpp
printf("请输入用户名(长度>=6):");
scanf_s("%s",str1,30);
int a=strlen(str1);
int j,k=a,m;
for (j=1;j<a;j++)
{
k=k+str1*str1*j;
}
printf("注册码为\n");
printf("%d \n",k-666)
```
输入用户名注册码后,Ok按钮禁用状态解除了,但是点击OK按钮,发现会清除注册码,按钮恢复到禁用状态。单步跟踪OK按钮的响应事件,发现442D80位置有一个比较,该处比较不通过,则会跳过后续的设置按钮可见状态的函数调用,而地址eax+0X47所指内容, OK按钮响应事件前面的代码并为对该地址进行操作,因此肯定是其他事件响应里面对其进行了操作。
尝试点击about按钮,发现并不改变该值状态,那就只剩下Cancel按钮响应事件了。
进入Cancel按钮响应事件响应代码段可以确定判断函数为442AF4
借助IDR和IDA以及OD单步跟踪分析函数442AF4,可以发现关键算法段如下
经分析,计算方法为((字符串中第5个字母的ASCII码值除7的余数+2)的阶乘)×(第1个字母的ASCII码值+……+第n个字母的ASCII码值)-31337。注册机程序代码如下:
``` cpp
printf("请输入用户名(长度>=6):");
scanf_s("%s",str1,30);
int a=strlen(str1);
int j,k=a,m,factorial=1;
m=str1%7+2;
for (j=1;j<=m;j++)
factorial=factorial*j;
k=0;
for (j=0;j<a;j++)
{
k=k+factorial*str1;
}
printf("注册码为\n");
printf("%d \n",k-31337);
```
输入正确内容后,点击Cancel按钮后,Cancel按钮消失,OK按钮的禁用状态也解除了。
点击OK按钮,没有反应,跟踪进去看一下,之前442D80处的比较已经正确通过了,后面还有另外一个验证算法函数。
借助IDR和IDA以及OD单步跟踪分析函数442BA0,可以发现关键算法段如下
经分析,计算方法为注册码的数字转换成字符串,然后((1×该字符串的第1个字母的ASCII码值×第1个字母的ASCII码值)除25的余数+65),按ASCII码表对应的字母为新的字符串的第一个字母,((2×该字符串的第2个字母的ASCII码值×第2个字母的ASCII码值)除25的余数+65)对应的字母为新字符串的第二个字母,以此类推到第n个字母,最后比较新的字符串与输入的用户名字符串是否相同。
因此,此处可以根据注册码去计算用户名,注册机程序代码如下:
``` cpp
printf("请输入注册码数字(长度>=6):");
scanf_s("%s",str1,30);
int a=strlen(str1);
int j;
for (j=1;j<=a;j++)
{
str1=((a-j+1)*str1*str1)%25+65;
}
printf("用户名为\n");
printf("%s \n",str1);
system("pause");
return 0;
```
输入正确的用户名的注册码后,点击OK按钮,完成。
学习学习!! 不错,写的很详细
不过,我想知道你这160个cms是从哪搞的 hackerbob 发表于 2022-4-27 14:52
不错,写的很详细
不过,我想知道你这160个cms是从哪搞的
这个地方可以下载
https://www.52pojie.cn/thread-709699-1-1.html
学习学习!!感谢分享 破解离不开汇编,硬伤。 牛的牛的 ASM是基础,有基础才行,其他是白皮 感谢提供思路 学到了,谢谢
页:
[1]
2