zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    Item2:建造者替代多参数构造器
    Java常量赋值失败?
    0828 列表 增删改查
    字符 列表的切片规则
    0820 字符转换为数字
    使用 in 判断是否有敏感词
    while循环
    for循环
    isalnum 判断变量是否由字符或者数字组成
    使用lower upper等字符大小写指令选择为大小写单词转换大小写
  • 原文地址:https://www.cnblogs.com/binlmmhc/p/6130035.html
Copyright © 2011-2022 走看看