2016/12/3-问鼎杯线上赛6-2逆向分析

这道题目的文件给我们的是一个压缩包a2ia8-6-2.rar,解压之后得到一个crackme.exe和readme.txt

打开readme.txt可以看到对我们目标的描述。

从这里我们知道,这个就是逆向当中很平常的求serial计算算法(或者更具提示暴力跑?这里我们分析来逆向算法),

并且我们也知道了8位name,还有4位不知道,得到name = "{hdu?b???0_}"但是我们可以根据序列号来计算出来.

拿到一个程序之后,首先使用PEID来查壳,这道题目没有壳,先运行一遍(这里先尝试使用"{hdu4b3210_}")

可以看到这个就是输入错误的时候,程序的反应了。。我们可以看到许多的关键字符串。

直接将程序用OD打开(我这里使用的是吾爱破解OD(ps:竟然不能F8----0.0))

所以我们就先搜索关键字符串了,input name:    input serial:等  Sorry等

我们可以看到许多的关键字,我们就先从在这几个关键字的地方下断,然后跟踪程序运行。(ps:这里我们有删掉我之前分析的工程文件)

我们从0x000B116D那里开始单步执行,我们会看到程序依次输出提示消息,并且我们从将输入一组name和serial数据进去,这里我们输入

name = "{hdu4b3210_}" 和图片中的序列号  serial = 78767-77666-76786-87788-77778-66867-66777-86767-66877-77778-88887

并且我们知道了我们输入的数据是保存在那个地方的。name = local16 , serial = local10

下好断点之后,直接运行,然后程序就会停在我们下的断点0x000B116D处,从这里我们就开始单步动态调试这个程序。

单步完成我们的输入之后,我们就继续分析。我们找到第一个Sorry的地方,在OD里右键分析代码,就可以看到跳转到错误输出的地址。

继续分析下去,我们会看到对name字符串长度的检测,等等之类的,但是我们要找的是生成serial的算法,我们继续单步分析,在下面看到了一个关键的函数

我们找到了crackme.000B2080这个函数,这个函数执行完之后,就跳转到系统暂停,然后就退出,所以我们跟进crackme.000B2080去看一下

(在调试的过程中记录name的地址),进入这个函数之后,我们单步调试,慢慢地我们发现这一个函数之前,传入了name中的两个字符作为参数。

我们看到程序传递了2个参数给crackme.000B1F30函数,我们跟进去看一下(在跟踪的时候发现这个就是计算serial的关键函---)

发现了一堆位运算和加法运算,运算完之后将结果保存下来(你可以观察程序内存中的数据变化,最后要返回的时候,我可以看到内存中生成了一个5位数的序列号)

他这里是分批计算每一位的数据,然后存储在临时变量中。最后在总的存储。

我们可以看到程序已经在保存生成的数据了。(这里注意第4和第5位,是保存在ecx和ebx中的,)

第4和第5位我们可以倒退跟踪上去找到它的最终表达式。。。在这个函数中,在结合readme.txt,我们发现serial一共有11个5位数,然后我们的name

是12位,并且前后组合生成序列号,总共计算11次之后,生成所有的序列号。所以得到下面的生成函数。

 1 //decode(前一个字符,后一个字符,存储结果的整形数组指针)
 2 void decode(int forward, int back, int re[]){ 
 3     int i;
 4     int local1, local2, local3, local4, local5 = 0;//, eax, ecx, ebx;
 5     int result[5] = {0};
 6     printf("%c %c ", (char)forward, (char)back);
 7     //temp = (forward & 1) + 6; // forward % 2 + 6;
 8     //temp1 = (back >> 2 ) & 1; // back / 4 % 2
 9     //local3为第一位
10     // forward % 2+6+back / 4 % 2
11     local3 = (forward & 1) + 6 + ((back >> 2 ) & 1);
12     result[0] = local3;
13     //local4为第二位
14     //ecx = ((forward >> 3)& 1)+6;// >> 3 == / 8; & 1 == % 2
15     //eax = (back >> 3) & 1;
16     //forward / 8 % 2 + 6 + back / 8 % 2;
17     local4 = ((forward >> 3)& 1)+6+((back >> 3) & 1);
18     result[1] = local4;
19     //local1为第三位
20     // forward / 2 % 2 + 6 + back / 8 % 2;
21     local1 = ((forward >> 1) & 1)+6 + ((back >> 4) & 1);
22     result[2] = local1;
23     //第4位在ecx即local2中
24     local2 = (back & 1 )+6+((forward>>2)&1);
25     result[3] = local2;
26     //第5位在ebx中
27     local5 = ((back >> 1) & 1)+6+((forward >> 4) & 1);
28     result[4] = local5;
29     printf("%d%d%d%d%d  ", result[0], result[1], result[2], result[3], result[4]);
30     for(i = 0; i < 5; i++){ 
31         re[i] = result[i];
32     }
33     //return result;
34 }

我们的name是{hdu?b???0_},并且我们的正确序列号你是知道的,所以我们就可以用一个爆破来将正确的name计算出来了。

最后的name是{hdu_brav0_}。好了,程序的主体就分析到这里了。其他的自己去弄就行了。

程序地址我放到云盘上面:想学习的可以下载http://pan.baidu.com/s/1slCPzsT

好了,这道题目到这里结束了。

原文地址:https://www.cnblogs.com/binlmmhc/p/6130035.html