练习笔记之160Crackme-007
本帖最后由 xiaoyu2032 于 2022-4-30 11:50 编辑# 160CM-007
## 1.爆破
这道题和上一道类似,要求逆算法的,但不管他,先爆破一下试试,爽爽再说。
从爆破的角度来看,这道题其实难度和上一道一样,Delphi编程(可以IDR反编译)、字符串未加密(可以字符串搜索)。先拖进IDR中看一下,可以发现图片实际有两个按钮控件,一个是register,一个是again,分别对应一个OnClick的事件,双击事件函数可以直接查看到函数对应的代码。
IDR可以直接识别一些delphi的函数,但是OD识别不了,因为跟踪调试还是需要OD,因此需要在OD中对调用的函数设置一下标签,这样方便阅读理解代码。register对应的函数代码如下:
``` asm
00442F28 >/.55 push ebp ;reg_click
00442F29|.8BEC mov ebp,esp
00442F2B|.83C4 F8 add esp,-0x8
00442F2E|.53 push ebx
00442F2F|.56 push esi
00442F30|.33C9 xor ecx,ecx
00442F32|.894D F8 mov ,ecx
00442F35|.8BD8 mov ebx,eax
00442F37|.33C0 xor eax,eax
00442F39|.55 push ebp
00442F3A|.68 22304400 push aLoNg3x_.00443022
00442F3F|.64:FF30 push dword ptr fs:
00442F42|.64:8920 mov dword ptr fs:,esp
00442F45|.8D55 F8 lea edx,
00442F48|.8B83 DC020000 mov eax,dword ptr ds:
00442F4E|.E8 ED02FEFF call <aLoNg3x_.GetText>
00442F53|.8B45 F8 mov eax, ;comctl32.5D176109
00442F56|.8D55 FC lea edx,
00442F59|.E8 FAF9FBFF call <aLoNg3x_.Str2Long>
00442F5E|.8BF0 mov esi,eax
00442F60|.837D FC 00 cmp ,0x0
00442F64|.74 37 je short aLoNg3x_.00442F9D ;判断是否非数字
00442F66|.B8 38304400 mov eax,aLoNg3x_.00443038 ;ASCII 59,"ou MUST insert a valid Long Integer Value in the Code Editor... Thank you :)"
00442F6B|.E8 00F6FFFF call <aLoNg3x_.Showmessage>
00442F70|.8D55 F8 lea edx,
00442F73|.8B83 DC020000 mov eax,dword ptr ds:
00442F79|.E8 C202FEFF call <aLoNg3x_.GetText>
00442F7E|.8B45 F8 mov eax, ;comctl32.5D176109
00442F81|.E8 06FBFFFF call <aLoNg3x_.suanfa1> ;算法函数1 计算edi
00442F86|.A3 30584400 mov dword ptr ds:,eax
00442F8B|.BA 90304400 mov edx,aLoNg3x_.00443090 ;UNICODE "0"
00442F90|.8B83 DC020000 mov eax,dword ptr ds:
00442F96|.E8 D502FEFF call <aLoNg3x_.SetText>
00442F9B|.EB 6F jmp short aLoNg3x_.0044300C
00442F9D|>85F6 test esi,esi
00442F9F|.7E 5A jle short aLoNg3x_.00442FFB
00442FA1|.8D55 F8 lea edx,
00442FA4|.8B83 D8020000 mov eax,dword ptr ds:
00442FAA|.E8 9102FEFF call <aLoNg3x_.GetText>
00442FAF|.8B4D F8 mov ecx, ;comctl32.5D176109
00442FB2|.8BD6 mov edx,esi
00442FB4|.A1 30584400 mov eax,dword ptr ds:
00442FB9|.E8 EAF9FFFF call <aLoNg3x_.suanfa2> ;算法函数2
00442FBE|.84C0 test al,al
00442FC0|.74 30 je short <aLoNg3x_.Error2> ;判断是否正确
00442FC2|.33D2 xor edx,edx
00442FC4|.8B83 CC020000 mov eax,dword ptr ds:
00442FCA|.E8 6101FEFF call <aLoNg3x_.SetVisable> ;设置可见属性
00442FCF|.B2 01 mov dl,0x1
00442FD1|.8B83 E8020000 mov eax,dword ptr ds:
00442FD7|.E8 5401FEFF call <aLoNg3x_.SetVisable> ;设置可见属性
00442FDC|.33D2 xor edx,edx
00442FDE|.8B83 D8020000 mov eax,dword ptr ds:
00442FE4|.8B08 mov ecx,dword ptr ds:
00442FE6|.FF51 60 call dword ptr ds: ;SetEnable
```
从上述代码可以看到有两处调用的SetVisable函数,用于设置控件的可见属性。我们可以看一下这段代码:
``` asm
00442FC2|.33D2 xor edx,edx
00442FC4|.8B83 CC020000 mov eax,dword ptr ds:
00442FCA|.E8 6101FEFF call <aLoNg3x_.SetVisable>
```
代码第一行将edx清零,第二行将一个内存地址送如eax,第三行调用子函数。从这个地方可以很清楚的看出,第一行设置的是可见属性(0,隐藏;1,显示),第二行设置是是控件对应的ID。这就是一个典型的函数调用过程,call之前的代码都是为了将参数传递给子函数。
因此爆破的话就是要控制程序执行流程进入到00442FC2地址,因此直接将je改成jmp跳转。
``` asm
00442F64 /74 37 je short aLoNg3x_.00442F9D
改成:
00442F64 /EB 5C jmp short aLoNg3x_.00442FC2
```
改完以后运行,会发现register按钮隐藏了,另一个again按钮显示出来了。同样的办法进入到again Onclick函数里面,可以发现程序过程和register Onclick函数基本相同,因此同样做一下修改:
``` asm
004430F6 /74 3A je short aLoNg3x_.00443132
改成:
004430F6 /EB 63 jmp short aLoNg3x_.0044315B
```
复制修改、保存,然后运行,依次点击register按钮和again按钮,按钮全部隐藏完毕。
## 2.算法分析
通过前面的爆破分析,其实对于这个程序的结构已经比较了解了,在OD中将IDR识别的函数都进行标签标识后可以发现,仅剩两个函数没有识别出来(红框部分),应该对应为验证算法函数。
运行程序,输入name和Code,F8跟踪,可以发现程序直接跳过00442F81,执行到00442FB9代码段,因此先分析一下函数4429A8。函数4429A8的主要算法代码如下图:
在IDA中F5得到对应的伪代码如下:
这个代码通常看起来有点一头雾水,因为我们不知道其中变量v4~v15到底代表什么内容,这时就需要F8单步跟踪一下程序运行过程,将变量根据实际含义修改一下名字,最终能得到如下图的代码:
将代码复制到vs中,将其中不符合C语言语法的部分修改整理一下,就能得到下面的代码:
``` Cpp
i=0;
if ( Length > 0 )
{
k = Length;
j = 1;
do
{
m =Length;
if ( m >= 1 )
{
do
{
i=i+n*str1*str1;
}
while ( m );
}
++j;
--k;
}
while ( k );
}
a = abs(i) % 666666;
code = code % 80 + code/ 89 + 1;
if ( a == code )
result = 1;
else
result = 0;
```
其中有个参数n,对应汇编代码中edi地址中的参数,在F8跟踪时发现这个数值一直是0,将n=0代入计算算法中,发现无论输入什么字符串,计算出来的a值都是零,不可能等于code,无法通过算法验证。
``` asm
00442A16|.0FAFD7 ||imul edx,edi
```
因此,我们还需要找一下,程序哪里对这个n进行了赋值。我们往前查看一下代码,发现算法函数中,只有4429B7位置将eax赋值给了edi。
再往前查,发现在进入算法调用前,在442FB4位置对eax进行了赋值,将地址445830的数值赋给了eax。
那就先查一下什么地方对地址445830进行,在地址445830处[右键]-[查找参考]-[地址常量],可以查找到程序中所有涉及到这个地址常量的位置。
如下图,一共找出不少位置,依次排查,我们可以发现442F86就在算法2稍微前面一点的位置,在算法1执行完成后就将eax赋值给445830。其他位置除again Onclick中也有一处外,都是将445830进行清零的操作。
稍微往前查看一下程序代码就可以发现,前面有一处判断输入的code是否是数字,如果不是数字,就弹窗提示对话框告诉你code必须输入数字,然后执行算法1,跳过算法2;是数字的话,就跳过算法1,执行算法2。呃,原来是这里放了个烟雾弹迷惑人的,想要正确完成注册的话需要先在code其余输入非数字字符串,通过算法1的验证后,再输入数字字符串,通过算法2的验证。
同样的方法,通过IDA获得算法的伪代码后,稍加改造,就能得到对应的C代码如下:
``` Cpp
int Length2 = strlen(str2);
n=0;
i = 891;
m =Length2 - 1;
if ( m > 0 )
{
j = 1;
do
{
i = i + str2*(str2 % 17 + 1);
++j;
--m;
}
while ( m );
}
printf("i=%d\n",i);
n= abs(i % 29000);
printf("n=%d\n",n);
```
这样就能通过输入的注册码字符串计算得到n的大小。
由于算法2中对注册码的校验中的计算过程是code = code % 80 + code/ 89 + 1,这里面用了除余,没办法直接反向求解,只能用穷举法了算一下。
``` Cpp
i=1;
do
{
i++;
code=i%80+i/89+1;
}
while (code!=a);
```
最终完成的注册码计算算法如下:
``` Cpp
#include "stdafx.h"
#include <Windows.h>
#include<stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
char str1,str2;
int i,j,k,m,n,a,result,code=0;
printf("请输入用户名(长度5~10):");
scanf_s("%s",str1,30);
printf("请输入注册码字符(长度6以上):");
scanf_s("%s",str2,30);
int Length = strlen(str1);
int Length2 = strlen(str2);
n=0;
i = 891;
m =Length2 - 1;
if ( m > 0 )
{
j = 1;
do
{
i = i + str2*(str2 % 17 + 1);
++j;
--m;
}
while ( m );
}
printf("i=%d\n",i);
n= abs(i % 29000);
printf("n=%d\n",n);
i=0;
if ( Length > 0 )
{
k = Length;
j = 1;
do
{
m =Length;
if ( m >= 1 )
{
do
{
i=i+n*str1*str1;
}
while ( m );
}
++j;
--k;
}
while ( k );
}
a = abs(i) % 666666;
code = code % 80 + code/ 89 + 1;
printf("a=%d\n",a);
printf("code=%d\n",code);
/*
if ( a == code )
result = 1;
else
result = 0;
*/
i=1;
do
{
i++;
code=i%80+i/89+1;
}
while (code!=a);
printf("用户名为:%s\n",str1);
printf("注册码为:%d \n",i);
system("pause");
return 0;
}
```
运行注册码程序,输入用户名和注册码字符,结果如下:
运行aLoNg3x.2.exe程序,输入用户名abcde,注册码abcdef,注册。
然后再输入注册码58674159,注册,注册按钮隐藏了。
注册按钮隐藏了,但是又出来一个again按钮,同样分析again Onclick函数,可以发现程序流程和register Onclick函数一样,算法也一样,因此输入注册码abcdef,点击again按钮。
再输入注册码58674159,点击again按钮,完成。
## 3.总结
到目前为止,已经成功完成了几个算法题,想想之前都只敢四处改跳转爆破,一看算法就头大,还是很有成就感的。
如果大家想试试算法,从这几个入手,感觉还是不错的,不会直接打击到没有信心。不理解的汇编命令,百度一下,不理解的delphi函数,百度一下,一回生,二回熟,渐渐的就不怕他们了。
附:百度一下“Delphi反汇编内部字符串处理函数/过程不完全列表”,基本上反汇编后常见的delphi函数的功能都能查到。 不辍,很详细,连算法也逆出来了 感动!谢谢分享。 不辍,很详细,连算法也逆出来了 赞赞赞赞 存下以后备用 感动!谢谢分享。 学习了逆向算法的思路 白鱼啊 发表于 2022-6-17 19:08
IDR这个工具在哪下载啊 没找到 方便分享出来吗
论坛爱盘里有的
页:
[1]