首页
社区
课程
招聘
[原创]签到题目解法
2019-9-18 12:26 3340

[原创]签到题目解法

2019-9-18 12:26
3340

0x01 题外话

拿到题目的时候还是比较激动的,想着签到题应该是最简单的,所以先拿它进行练习,但是没啥经验,还是花了不少时间在弯路上。

0x02 解法

###0x21 先看看执行文件
通过IDA上去,发现程序没有反调试,没有啥保护,很容易就定位到关键函数sub_4019D0()
通过OD的调试过程,需要输入用户名和序列号信息,通过跟踪调试后,可以通过监控内存发现下面这段是做了字符向16进制转换。

v1 = 0;
  do                                            // 将输入的字符串转成内存格式,即将ASCII码转成内存十六进制形式内容,如:F3 => 0xF3
  {
    v2 = *((_BYTE *)&InputSerial_v27 + 2 * v1);
    v3 = v2 - 55;
    if ( v2 <= '9' )
      v3 = *((_BYTE *)&InputSerial_v27 + 2 * v1);
    *((_BYTE *)&xmmword_13C12F8 + v1) = *((_BYTE *)&InputSerial_v27 + 2 * v1 + 1)
                                      + 16 * v3
                                      - (*((_BYTE *)&InputSerial_v27 + 2 * v1 + 1) > (unsigned __int8)'9' ? '7' : '0');
    ++v1;
  }
  while ( v1 < 16 );                            // Serial should be lenght = 32

下面的这段函数调用有一点复杂,但是从后续的验证来看,它只是验证了输入的序列号是否正确,
而且通过调用完后的结果,发现它其实是把上面的内存数据xmmword_13C12F8转换成了字符串(一个逆操作);

 v5 = &a1;                                     // v33 结果应该和输入的Serial一致。
  do
  {
    sub_13A1990(v5, "%02X", *((unsigned __int8 *)&xmmword_13C12F8 + v4++));// 将一个内存十六进制数据以字符格式转换出来,如:0xAF => "AF"
    v5 = (__int128 *)((char *)v5 + 2);          // 字符串拼接,因为生成的占两位,所以+2
  }
  while ( v4 < 16 );

然后再验证两次转换的结果是否相等,如果不相同,就给出了错误提示(其实只要满足序列号是32位就OK了)。
通过上面的分析,跳过了验证后,到了下面的else分支,里面计算比较复杂,各种变量和转换(第一次的感觉头大啊),在这个地方的分析卡了段时间就放着了,有空的时候突发奇想的,找了一个特征值0x67452301;0x67452301;0x67452301;0x10325476; 从其它文章里的介绍这个是MD5的特征,自己根据其它特征基本也验证下面的算法部分就是MD5过程,其中Md5Update_sub_13A1000(),这样就把下面的处理过程分析清楚了,整理如下:

(String)UserName
(String)Serial
(Bytes)Serial1 //转换后的序列号。
...
MD5Init(&md5Context) //md5Context =>v22地址
v28 = UserName XOR Serial1
MD5Update(&v28, &md5Context, 16)
{//下面的一大段,其实就是MD5Final()
    ...
}
// 获取设置的常量值
v18 = &unk_13C08B0; // [0xDA, 0xE5, 0x23, 0x10, 0x06, 0x71, 0x95, 0x71, 0x4B, 0xA2, 0xCE, 0xE2, 0x33, 0x2B, 0xB8, 0x66];
// 获取md5Context->state值,即v24地址位置,与V18比较。
    while ( *(_DWORD *)v17 == *v18 )            // 按四字节进行内容比较,成功后,进入正确流程。
    {
      v17 = (__int128 *)((char *)v17 + 4);
      ++v18;
      v10 = v19 < 4;                            // 当V19 < 4的时候,已经比较完成所有内容,如果不小于4,说明有内容V17,V18不相等,会跳出循环。
      v19 -= 4;
      if ( v10 )
      {
        v20 = &unk_13BE700;                     // correct input.
        goto LABEL_22;
      }
    }
    v20 = &unk_13BE714;                         // Failed to verify

0x03 计算结果

看到MD5还是挺怕的,以为题目要考虑暴破获取序列号之类的,不过自己算了一下可能的序列号组合:
字典:1234567890ABCDEF,长度是32位,那这样基本不太可能破解,所以自己又回退分析上在的计算过程。

"5D78C3FDF21998AC" XOR F3A0FD8D8DE1FEB889808A8FF2D7FDA2 \
                                                         ====> v28 -----MD5----->v29 ---->(v29 === v18???)
"KCTF" XOR ?                                            /

从上面的过程,可以看到v28是关键,根本不需要关注后面的MD5算法,如果KCTF XOR ? 等于V28就OK了。
使用给定的信息获取v28结果为:
v28 = {0xC6,0xE4,0xCA,0xB5,0xCE,0xD2,0xB8,0xFC,0xCF,0xB2,0xBB,0xB6,0xCB,0xEF,0xBC,0xE1} = "其实我更喜欢孙坚"
这个值有点意思,而且计算上"KCTF" xor B = v28 , B = v28 xor "KCTF",可以计算如下:

    unsigned __int8 v28[16] = 
    { 0xC6, 0xE4, 0xCA, 0xB5, 0xCE, 0xD2, 0xB8, 0xFC, 0xCF, 0xB2, 0xBB, 0xB6, 0xCB, 0xEF, 0xBC, 0xE1 };
    将"KCTF"转成数组
    unsigned __int8 UserName[16] = 
    { 0x4B, 0x43, 0x54, 0x46, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
    这样基本只有前4字节需要进行XOR操作,结果为:
    { 0x8D, 0xA7, 0x9E, 0xF3} ,后续位添加{ 0xCE, 0xD2, 0xB8, 0xFC, 0xCF, 0xB2, 0xBB, 0xB6, 0xCB, 0xEF, 0xBC, 0xE1}
}

由于序列号是由字符类型换16进制类型的数据,所以逆过程基本就是上面的16进制读成字符串就是题目序列号了,
计算出序列号为8D A7 9E F3 CE D2 B8FCCFB2BBB6CBEFBCE1
图片描述


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2019-9-18 12:28 被nevinhappy编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回