zsky 发表于 2020-5-11 17:09

2020网鼎杯青龙组部分逆向题

本帖最后由 L15263458908 于 2020-5-12 21:53 编辑

2020网鼎杯青龙组部分逆向题

signal
方法一
打开程序,可以很明显的看到,这是一个虚拟机指令的逆向




进入关键函数进行分析




进行观察,可以发现,v4 与 a1比较 是判断条件
a1是输入的opcode, 而v4来自v5,v5由flag进行运算得到
flag--->v5---->v4
所以我们要得到v4,然后推v5,在得到flag

我们复制IDA中的代码,进行修改,来得到v4的值和执行顺序,即上图的V10



代码如下
#include "pch.h"
#include <stdio.h>
#include <string.h>

unsigned char vmcode[] =
{
0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x21, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x51, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3F, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xA7, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x84, 0xFF,
0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xC1, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x7A, 0x00, 0x00, 0x00
};

int * a = (int *)vmcode;

int __cdecl vm_operad(int *opcode, int len_114)
{
      char order = {};      //顺序         即i
      char flag; //
      char v4; //
      char v5; //
      int j; //
      int m; //
      int k; //
      int n; //
      int i; //
      int s = 0;

      i = 0;
      n = 0;
      k = 0;
      m = 0;
      j = 0;
      while (1)
      {
                if (i >= len_114)                         // 成功的地方
                        break;
                switch (opcode)
                {
                case 1:
                        v4 = v5;
                        ++i;
                        ++m;
                        ++n;
                        break;
                case 2:
                        v5 = opcode + flag;
                        i += 2;
                        break;
                case 3:
                        v5 = flag - opcode;
                        i += 2;
                        break;
                case 4:
                        v5 = opcode ^ flag;
                        i += 2;
                        break;
                case 5:
                        v5 = opcode * flag;
                        i += 2;
                        break;
                case 6:
                        ++i;
                        break;
                case 7:
                        v4 = opcode;                        // 打印关键数据V4
                        printf("%#X, ", v4);               
                        ++k;
                        i += 2;
                        break;
                case 8:
                        flag = v5;
                        ++i;
                        ++j;
                        break;
                case 10:
                        scanf("%s", flag);                              // 输入flag                //长度是15
                        ++i;
                        break;
                case 11:
                        v5 = flag - 1;
                        ++i;
                        break;
                case 12:
                        v5 = flag + 1;
                        ++i;
                        break;
                }
                order = i;
      }
      printf("执行顺序是: ");
      for (int ss = 0; ss < strlen(order); ss++) {
                printf("%d, ", order);
      }

      return 0;
}

int main()
{      
      vm_operad(a, 114);
      
      return 0;
}

得到结果


v4 = { 0X22, 0X3F, 0X34, 0X32, 0X72, 0X33, 0X18, 0XFFFFFFA7, 0X31, 0XFFFFFFF1, 0X28, 0XFFFFFF84, 0XFFFFFFC1, 0X1E, 0X7A };
order = { 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 81, 82, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114 };
再写解密函数逆推flag
int decode(int * opcode, int len_114)
{
      int i;
      //获取flag 的关键数据
      unsigned char v4[] = { 0X22, 0X3F, 0X34, 0X32, 0X72, 0X33, 0X18, 0XFFFFFFA7, 0X31, 0XFFFFFFF1, 0X28, 0XFFFFFF84, 0XFFFFFFC1, 0X1E, 0X7A };
      //执行opcode 的索引,即执行顺序
      char order = { 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 81, 82, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114 };
      unsigned char flag = {};
      int m = 15;
      int n = 15;
      int j = 15;
      int v5;
      for (int k = strlen(order) - 1; k >= 0 ; k--)
      {
                i = order;
                switch (opcode)                              // 倒序执行
                {
                case 1:
                        --m;
                        --n;
                        v5 = v4;
                        break;
                case 2:
                        flag = v5 - char(opcode) ;
                        break;
                case 3:
                  flag = v5 + char(opcode);
                        break;
                case 4:
                        flag = (v5 ^ opcode) & 0XFF;
                        break;
                case 5:
                        flag = v5 / opcode;
                        break;
                case 6:
                        break;
                case 8:
                        v5 = flag[--j];
                        break;
                case 11:
                        flag = v5 + 1;
                        break;
                case 12:
                        flag = v5 - 1;
                        break;
                }
      }

      printf("%s", flag);
      return 0;
}

得到flag是 757515121f3d478
方法二:
通过Ponce插件符号执行来一步步获取flag




关于Ponce插件下介绍及下载->https://github.com/illera88/Ponce
方法三: 使用python angr符号执行解决
代码如下
import angr
p = angr.Project('signal.exe')
st = p.factory.entry_state()
sm = p.factory.simulation_manager(st)
sm.explore(find=0x40175E, avoid=0x4016E6)
print(sm.found.posix.dumps(0))



jocker
打开程序,找到main函数,F5发现无法反编译





手动修复下栈指针




问题出现在401838那里



对401833那个位置按ALT+ K



修改栈偏移



F5看伪代码


wrong是对flag进行了一个简单的加密
omg对加密的flag进行判断,得到flag为flag{fak3_alw35_sp_me!!} 提交发现错误
然后调试起来,进入下面的encrypt函数



一个简单的异或判断
写脚本打印出flag的前一半
a =
b = "hahahaha_do_you_find_me?"
c = ^ ord(b))& 0xff) for i in range(len(a))]
print "".join(c)
结果为:
flag{d07abccf8a410c

最后进入finally函数

根据提示说 我隐藏了后一半部分,,前面
flag{d07abccf8a410c是19个字符,而flag是24个字符,还差5个,最后一个肯定是 “}”
于是将v7 与 } 异或得到 71
写个脚本,将37,116,112,38,58 全部异或71
a =
flag = "".join()
print flag

得到flag的后半部分
b37a}
拼接,即为flag--->flag{d07abccf8a410cb37a}

------------------------------
题目链接:
链接:https://pan.baidu.com/s/1atclBURdY8msXE889elidg
提取码:gemn

IBinary 发表于 2020-5-12 11:01

xmhwws 发表于 2020-5-11 18:55
大佬,这个是怎么操作的?还是通过插件实现的?

请详细说说

Shife + EExpore DataIDA 自带的. 可以 Edit选项中看到.

zsky 发表于 2020-5-11 18:59

xmhwws 发表于 2020-5-11 18:55
大佬,这个是怎么操作的?还是通过插件实现的?

请详细说说

变成数组类型之后 shift +e

赤座灯里 发表于 2020-5-11 17:51

{:1_909:}我傻傻地把十五个方程列出来了,浪费太多时间

xmhwws 发表于 2020-5-11 18:55

大佬,这个是怎么操作的?还是通过插件实现的?

请详细说说
{:301_999:}

FinchK 发表于 2020-5-11 19:09

{:1_921:}厉害了,学到了。

victoryang00 发表于 2020-5-11 19:40

大佬牛逼,这joker是个双线程的,我同伴弄了个假的flag

zsky 发表于 2020-5-11 19:48

victoryang00 发表于 2020-5-11 19:40
大佬牛逼,这joker是个双线程的,我同伴弄了个假的flag

这题最难的是flag后5位,,,,,脑洞题,

wh1sper 发表于 2020-5-11 21:10

本帖最后由 wh1sper 于 2020-5-11 21:13 编辑

这次逆向好像很难,不过最后半小时就看别人垂直上分

新手12138 发表于 2020-5-11 22:02

L15263458908 发表于 2020-5-11 19:48
这题最难的是flag后5位,,,,,脑洞题,

脑洞题我就很难受

zsky 发表于 2020-5-11 22:10

wh1sper 发表于 2020-5-11 21:10
这次逆向好像很难,不过最后半小时就看别人垂直上分

逆向除了第二道都很简单,,,,难的是杂项,,那个汉信码我拼了得1个多小时,硬是没扫出来:'(weeqw,,,
页: [1] 2 3 4 5
查看完整版本: 2020网鼎杯青龙组部分逆向题