KeyFile保护CrackMe
## 0x01 监视文件相关操作运行程序,打开任务管理器,查看进程名称如下:
![](https://s2.ax1x.com/2020/02/10/1IeAXV.png)
Process Monitor添加条件如下:
![](https://s2.ax1x.com/2020/02/10/1Iek60.png)
只监视文件相关操作,可以看到程序要读取的文件名称如下:
![](https://s2.ax1x.com/2020/02/10/1IeFlq.png)
## 0x02 使用IDA Pro分析
程序先使用`CreateFile()`函数来打开KeyFile文件,故通过该函数定位:
![](https://s2.ax1x.com/2020/02/10/1Iee7F.png)
#### 0x02.1 三处`ReadFile()`
成功打开文件后下面有三处`ReadFile()`操作:
![](https://s2.ax1x.com/2020/02/10/1IeZ0U.png)
----
第一处`ReadFile()`操作读取1个字节到缓冲区中,笔者将其命名为`StringLength`。接下来判断该值是否为0,若为0,直接跳转到`CloseHandle()`函数处;不为0,继续下面的操作。
----
第二处`ReadFile()`操作读取`StringLength`个字节到缓冲区中,然后调用`sub_401000()`。跟进`sub_401000()`查看:
![](https://s2.ax1x.com/2020/02/10/1Ienk4.png)
`403288h`处存放的是刚刚`ReadFile()`读取内容,故该函数功能是将读取内容逐字节相加,取其低8位保存于`String_Char_Add`(由笔者命名)中。
----
第三处`ReadFile()`读取18个字节,然后调用`sub_4010C9`,跟进查看。
#### 0x02.2 核心验证函数
![](https://s2.ax1x.com/2020/02/10/1IeutJ.png)
先跟进`sub_40101D`函数查看其功能:
![](https://s2.ax1x.com/2020/02/10/1IeKh9.png)
该函数功能是将上述第三处`ReadFile()`读取出来的18字节(笔者名之为`String_Char_Xor`)逐个与`String_Char_Add`作异或运算。
----
将下面的指令粗略转成C语言形式(分析时随手写成,仅为表达程序逻辑,无法运行):
![](https://s2.ax1x.com/2020/02/10/1IeQpR.png)
注意上图红色方框中的两个向上箭头明显是`Do...While`的标志。
```
int tmp1=0; //
int tmp2; //
int ecx=0;
char String_Char_Xor;
char aC_0_After_C[]="C*......*...****.*.****...*....*.*..**********.*..*....*...*...**.****.*.*...****.*....*.*******..*.***..*.....*.*..***.**.***.*...****....*X..*****************";
int ret;
do
{
tmp2=8;
do
{
tmp2-=2;
ecx=tmp1;
ch=String_Char_Xor;
ch>>=ecx;
ch&=3;
sub_401033();
if()
;
}while(tmp2!=0)
tmp1+=1;
}while(tmp1!=18)
```
由于函数`sub_401033()`功能暂不清楚,故只写下`if`框架,等待分析完函数`sub_401033()`功能后再补充。
> 注:笔者起初没有使用IDA Pro的F5,分析并写完后方才以F5验证是否正确,但发现其不靠谱...
----
跟进函数`sub_401033()`查看,首先是一处`if...else if...else`代码块:
![](https://s2.ax1x.com/2020/02/10/1Iel11.png)
粗略转成C语言形式:
```
char* loc;
char tmp1;
if(ch!=0)
{
if(ch==1)
loc=aC_0_After_C+1;
else if(ch==2)
loc=aC_0_After_C+16;
else
loc=aC_0_After_C-1;
}
else
loc=aC_0_After_C-16;
tmp1=*loc;
```
下面是一处`if...else`代码块:
![](https://s2.ax1x.com/2020/02/10/1Ie16x.png)
粗略转成C语言形式:
```
if(tmp1!='*')
{
if(tmp1=='X')
printf("Success");
else
{
*loc='C';
*aC_0_After_C=' ';
return 1;
}
}
else
return 0;
```
----
将之前`Do...While`中的`if`补齐如下:
```
do
{
tmp2=8;
do
{
tmp2-=2;
ecx=tmp1;
ch=String_Char_Xor;
ch>>=ecx;
ch&=3;
ret=sub_401033(ch);
if(!ret)
return ret;
}while(tmp2!=0)
tmp1+=1;
}while(tmp1!=18)
```
#### 0x02.3 验证思路
综合上述分析,可以总结出该程序的验证思路。
1. 读取KeyFile文件中第一个字节,该字节存储的是`Len(Name)`
2. 根据长度读取`Name`,将`Name`逐字节相加,取其低8位,存储于`L8`中
3. 于KeyFile文件中继续读取18个字节内容,逐个与`L8`作异或运算
关键在于第3步中读取的18个字节是何种意义。
----
将奇怪字符串以16(16是由`aC_0_After_C`起始位置得来)为单位分开,可以发现端倪:
```
****************
C*......*...****
.*.****...*....*
.*..**********.*
..*....*...*...*
*.****.*.*...***
*.*....*.*******
..*.***..*.....*
.*..***.**.***.*
...****....*X..*
****************
```
`.`是路径,`*`是墙壁,`C`是起点,`X`是终点。由`C`沿`.`走到`X`,验证通过;其间若碰到`*`,验证失败。
那么,`sub_401033()`函数一开始的`if...else if...else`代码块的功能:
- 0:上
- 1:右
- 2:下
- 3:左
而下面的`if...else`代码块则是判断是否碰壁或者到达终点。
#### 0x02.4 路径计算
既然`sub_401033()`函数功能是移动一步并判断,那么第3步中读取的18个字节存储的应是与路径相关。那么就来走一下这个迷宫(只写出部分,后面请自行补充):
> 2 2 2 1 2 2 2 3 2 2 1 1...
外层的`Do...While`循环是18次,那么每次处理1字节。内层的`Do...While`循环是4次,1Byte=8bits,故`2 2 2 1`——>>`10 10 10 01`——>>`A9`。
`A9`是KeyFile文件于第3步中被读取出的字节与第2步`L8`异或所得,那么将路径按上述过程全部转换之后再与`L8`异或再加上`Len(Name)`及`Name`就能得到KeyFile文件。 附CrackMe文件 萌新冒下泡 向大佬学习经验 大佬相当牛逼 如果从一开始就往左走跑到迷宫外会不会崩;www 向大佬学习 支持一下,学习了 厉害了,学习到了,感谢。 谢谢贴主了,值得学习
页:
[1]
2