吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6991|回复: 11
收起左侧

[原创] 【i春秋】第十届全国大学生信息安全大赛之逆向--溯源

[复制链接]
skywilling 发表于 2017-12-25 21:58
本帖最后由 skywilling 于 2017-12-25 21:59 编辑

0x00前言
考研结束了,终于可以有一段闲暇的时间了。在睡了一天后,不忘发个帖子,疏解一下空虚寂寞的心情,再加上今天是圣诞节。这个题目其实在暑假就已经解出来了,是准备等到考完研再发出来的,也就是现在

下面开始切入正题
0x01运行
1.png
运行很简单,输入错误即返回fail提示。
0x02静态分析
首先放到IDA中看一下,入口在哪里
2.png
3.png
三个关键字也很显眼
根据"please input key:"找到输入口,直接F5
[C] 纯文本查看 复制代码
int sub_4014B0()
{
  int v0; // eax@1
  int v1; // ecx@1
  int v2; // eax@1
  int v3; // ebx@1
  signed int v4; // eax@2
  unsigned int v5; // ecx@3
  int v6; // edx@3
  int v7; // eax@5
  int v8; // esi@5
  int v9; // edx@5
  int v10; // eax@5
  char *v11; // edi@9
  int v12; // ecx@9
  int v13; // esi@9
  void *v14; // esi@11
  int v15; // eax@11
  int v16; // ebx@11
  const char *v17; // edx@14
  int v18; // eax@15
  int v19; // eax@17
  char *v20; // ecx@19
  unsigned int v21; // eax@22
  unsigned int v22; // ecx@24
  signed int v24; // [sp+10h] [bp-1008h]@3
  int v25; // [sp+14h] [bp-1004h]@5
  int v26; // [sp+18h] [bp-1000h]@1
  void *Memory; // [sp+1Ch] [bp-FFCh]@9
  int v28; // [sp+20h] [bp-FF8h]@5
  int v29; // [sp+24h] [bp-FF4h]@5
  int v30; // [sp+28h] [bp-FF0h]@1
  int v31; // [sp+2Ch] [bp-FECh]@2
  void *v32; // [sp+30h] [bp-FE8h]@1
  int v33; // [sp+40h] [bp-FD8h]@1
  unsigned int v34; // [sp+44h] [bp-FD4h]@1
  char v35; // [sp+48h] [bp-FD0h]@1
  __int128 v36; // [sp+FE8h] [bp-30h]@3
  __int128 v37; // [sp+FF8h] [bp-20h]@5
  int v38; // [sp+1014h] [bp-4h]@1

  v0 = sub_401A60(std::cout, "please input key:");
  std::basic_ostream<char,std::char_traits<char>>::operator<<(v0, sub_401C90);
  v33 = 0;
  v34 = 15;
  LOBYTE(v32) = 0;
  v38 = 0;
  sub_401DC0(std::cin, (int)&v32);
  sub_401300((unsigned int)&v32, (int)&v35);
  sub_401120((int)&v26, (int)&v35, v1);         // 将堆栈数据复制到数据段
  v2 = 999;
  LOBYTE(v38) = 1;
  v3 = v26;
  v30 = 999;
  while ( 2 )
  {
    v4 = (unsigned __int8)byte_403230[v2];
    v31 = 0;
    do
    {
      v5 = v4 & 3;
      v24 = v4 >> 2;
      v6 = 5 - v5;
      v36 = xmmword_403660;
      if ( v5 < 2 )
        v6 = 1 - v5;
      v37 = xmmword_403620;
      v7 = *((_DWORD *)&v36 + 2 * v6 + 1);
      v8 = v28 + *((_DWORD *)&v36 + 2 * v6);
      v9 = v29;
      v10 = v29 + v7;
      v25 = v8;
      if ( v8 < 0 || v8 >= v3 || v10 < 0 || v10 >= v3 )// v3=0xA
      {
        v19 = sub_401A60(std::cout, "fail");
        std::basic_ostream<char,std::char_traits<char>>::operator<<(v19, sub_401C90);
        v14 = Memory;
        goto LABEL_18;
      }
      v29 = v10;
      v11 = (char *)Memory + 4 * (v9 + v28 * v3);
      v12 = v10 + v8 * v3;
      v4 = v24;
      v13 = *((_DWORD *)Memory + v12);
      *((_DWORD *)Memory + v12) = *(_DWORD *)v11;
      *(_DWORD *)v11 = v13;
      v28 = v25;
      ++v31;
    }
    while ( v31 < 4 );
    v2 = v30-- - 1;
    if ( v30 >= 0 )
      continue;
    break;
  }
  v14 = Memory;
  v15 = 0;
  v16 = v3 * v3;
  if ( v16 <= 0 )
  {
LABEL_14:
    v17 = "success";
  }
  else
  {
    while ( *((_DWORD *)Memory + v15) == v15 )
    {
      if ( ++v15 >= v16 )
        goto LABEL_14;
    }
    v17 = "fail";
  }
  v18 = sub_401A60(std::cout, v17);
  std::basic_ostream<char,std::char_traits<char>>::operator<<(v18, sub_401C90);
LABEL_18:
  j_j_free(v14);
  if ( v34 >= 0x10 )
  {
    v20 = (char *)v32;
    if ( v34 + 1 >= 0x1000 )
    {
      if ( (unsigned __int8)v32 & 0x1F )
        invalid_parameter_noinfo_noreturn(v32);
      v21 = *((_DWORD *)v20 - 1);
      if ( v21 >= (unsigned int)v20 )
        v21 = invalid_parameter_noinfo_noreturn(v20);
      v22 = (unsigned int)&v20[-v21];
      if ( v22 < 4 )
        v21 = invalid_parameter_noinfo_noreturn(v22);
      if ( v22 > 0x23 )
        v21 = invalid_parameter_noinfo_noreturn(v22);
      v20 = (char *)v21;
    }
    j_free(v20);
  }
  return 0;
}

三个关键字都在这里了
逐一分析这段代码功能
4.png
这里把输入的数据直接存到v32

然后调用了 sub_401300((unsigned int)&v32, (int)&v35),进去查看,发现函数名是_DWORD *__fastcall sub_401300(unsigned int input, int a2)
这时v32对应到input,v35对应a2,再往下看
5.png
这时,a2赋值到temp,input赋值到v3,
6.png
这里有个判断是否为200的地方,其实就是看输入的字符长度是否为200
7.png
再往下有个循环
8.png
这里其实就是i++,再看一下循环结束条件 while ( v14 != v15 ),往上看v14=0,再找v15,
9.png
v3=input,算来算去,v15就是200
这时可以还原出C代码:
[C] 纯文本查看 复制代码
for(i=0;i<100;i++){
        temp[i]=i;
    }
    for(i=0;i<200;i++){
        temp[i/2]=temp[i/2]*16+input[i]-65;
        if((i+1)%2==1){
            temp[i/2+1]=0;
        }
    }

注意这里有个65,也就是A,到这里可以确认的输入格式是长度为200的大写英文字母,而这个循环就是要将长度为200的输入缩合为长度为100的数据,格式就是A,A,B,B,C,C转换为00,11,22
再往下看
sub_401120((int)&v26, (int)&v35, v1);         // 将堆栈数据复制到数据段
这里是保存到了数据段v26
10.png
这里可以看到一个长度为1000的数组,类似于置换表
再往下看就是关于数据置换的代码了,下面给出还原后的代码
[C] 纯文本查看 复制代码
while(1) {
        n=table[i];
        num=0;
        do {
            low = n & 3;  //低三位
            high = n >> 2; //高五位
            j = 5 - low;
            if (low < 2) {
                j = 1 - low;
            }
            a = xmm[j * 2] + l;
            b = xmm[j * 2 + 1] + k;
            //printf("j=%X b=%X a=%X low=%X high=%X n=%X k=%X l=%X\n", j,b, a, low, high, n, k, l);
            if (a < 0 || a >= c || b < 0 || b >= c) {
                printf("fail\n");
                return 0;
            }
            //交换
            c = 0xA * l;
            c += k;
            d = temp[c];
            //printf("c=%X temp[%d]=%X\n",c,c,d);
            temp_ = temp + c;
            c = 0xA * a;
            c += b;
            d_ = temp[c];
            temp[c] = d;
            //printf("c=%X temp[%d]=%X\n",c,c,d_);
            *temp_ = d_;
            //
            l = a;
            k = b;
            n = high;
            c = 0xA;
            num++;
        } while (num < 4);
        //print(temp,100);
        i--;
        if(i<0){
            break;
        }
    }

由于是直接按照汇编还原,代码实现比较冗长
[C] 纯文本查看 复制代码
//判断
    for(i=0;i<100;i++){
        if(temp[i]!=i){
            printf("fail\n");
            return 0;
        }
    }

置换后的数据与0-99比较,如果相等就成功了,否则失败
解密过程我会在附件中给出
0x03结尾
老规矩,题目和c代码会在文章最后的附件中给出,下面献上成功的截图:
11.png
附件:https://pan.baidu.com/s/1o8wvQAY 密码:i46l
版权声明:允许转载,但是一定要注明出处

免费评分

参与人数 14吾爱币 +18 热心值 +12 收起 理由
liuchang2017 + 1 + 1 热心回复!
让导弹飞 + 1 漫漫学习道路,加油
Three_fish + 1 + 1 用心讨论,共获提升!
1455018613 + 1 已答复!
无影寒冬 + 1 + 1 谢谢@Thanks!
Lg.Odds + 1 + 1 谢谢@Thanks!
Sound + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
夏雨微凉 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
keats + 1 + 1 厉害了!!!
Tim-52Pojie + 1 + 1 用心讨论,共获提升!
小瓜 + 1 我很赞同!
games + 1 + 1 祝考研成功!!
a2001103 + 1 + 1 用心讨论,共获提升!
朱朱你堕落了 + 1 还是以附件上传到论坛吧,网盘容易失效。

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| skywilling 发表于 2017-12-26 20:48
90182si 发表于 2017-12-26 19:20
我是一个新手,想问这里的的input+16什么意思

input是指针,16是偏移量
诗和远方2018 发表于 2017-12-25 22:22
zyx1211 发表于 2017-12-25 22:38
games 发表于 2017-12-25 22:56
祝考研成功!!!!
wtuaixk 发表于 2017-12-26 09:03
顶一个,路过回复。
90182si 发表于 2017-12-26 19:20
我是一个新手,想问这里的的input+16什么意思
无影寒冬 发表于 2017-12-26 20:18
祝考研成功。
90182si 发表于 2017-12-26 21:10
skywilling 发表于 2017-12-26 20:48
input是指针,16是偏移量

哦,知道了,谢谢
OnlyYu 发表于 2017-12-27 10:48
看都看不懂...
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-17 04:38

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表