吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 14384|回复: 46
收起左侧

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

  [复制链接]
zsky 发表于 2020-5-11 17:09
本帖最后由 L15263458908 于 2020-5-12 21:53 编辑

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

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

1.png


进入关键函数进行分析

2.png


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

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

3.png

代码如下
[C++] 纯文本查看 复制代码
#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[114] = {};        //顺序         即i
        char flag[100]; // [esp+13h] [ebp-E5h]
        char v4[100]; // [esp+77h] [ebp-81h]
        char v5; // [esp+DBh] [ebp-1Dh]
        int j; // [esp+DCh] [ebp-1Ch]
        int m; // [esp+E0h] [ebp-18h]
        int k; // [esp+E4h] [ebp-14h]
        int n; // [esp+E8h] [ebp-10h]
        int i; // [esp+ECh] [ebp-Ch]
        int s = 0;

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

        return 0;
}

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


得到结果

4.png
v4 = { 0X22, 0X3F, 0X34, 0X32, 0X72, 0X33, 0X18, 0XFFFFFFA7, 0X31, 0XFFFFFFF1, 0X28, 0XFFFFFF84, 0XFFFFFFC1, 0X1E, 0X7A };
order[100] = { 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
[C++] 纯文本查看 复制代码
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[100] = { 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[100] = {};
        int m = 15;
        int n = 15;
        int j = 15;
        int v5;
        for (int k = strlen(order) - 1; k >= 0 ; k--)
        {
                i = order[k];
                switch (opcode[i])                                // 倒序执行
                {
                case 1:
                        --m;
                        --n;
                        v5 = v4[m];
                        break;
                case 2:
                        flag[n] = v5 - char(opcode[i + 1]) ;
                        break;
                case 3:
                    flag[n] = v5 + char(opcode[i + 1]);
                        break;
                case 4:
                        flag[n] = (v5 ^ opcode[i + 1]) & 0XFF;
                        break;
                case 5:
                        flag[n] = v5 / opcode[i + 1];
                        break;
                case 6:
                        break;
                case 8:
                        v5 = flag[--j];
                        break;
                case 11:
                        flag[n] = v5 + 1;
                        break;
                case 12:
                        flag[n] = v5 - 1;
                        break;
                }
        }

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


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

6.png

关于Ponce插件下介绍及下载->https://github.com/illera88/Ponce
方法三: 使用python angr符号执行解决
代码如下
[Python] 纯文本查看 复制代码
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[0].posix.dumps(0))


QQ截图20200512215220.png

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

7.png



手动修复下栈指针

8.png


问题出现在401838那里

9.png

对401833那个位置按ALT+ K

10.png

修改栈偏移

11.png

F5看伪代码

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

13.png

一个简单的异或判断
写脚本打印出flag的前一半
[Python] 纯文本查看 复制代码
a = [0XE, 0XD, 9, 6, 0X13, 5, 0X58, 0X56, 0X3E, 6, 0XC, 0X3C, 0X1F, 0X57, 0X14, 0X6B, 0X57, 0X59, 0XD]
b = "hahahaha_do_you_find_me?"
c = [chr((a[i] ^ ord(b[i]))& 0xff) for i in range(len(a))]
print "".join(c)

结果为:
flag{d07abccf8a410c

最后进入finally函数
14.png
根据提示说 我隐藏了后一半部分,,前面
flag{d07abccf8a410c是19个字符,而flag是24个字符,还差5个,最后一个肯定是 “}”
于是将v7 与 } 异或得到 71
写个脚本,将37,116,112,38,58 全部异或71
[Python] 纯文本查看 复制代码
a = [37,116,112,38,58]
flag = "".join([chr(i ^ 71) for i in a])
print flag


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

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

免费评分

参与人数 21吾爱币 +20 热心值 +20 收起 理由
世不待 + 1 用心讨论,共获提升!
晓``~dong东 + 1 + 1 用心讨论,共获提升!
Peppermint + 1 谢谢@Thanks!
Sins + 1 + 1 谢谢@Thanks!
温柔的一哥 + 1 + 1 用心讨论,共获提升!
gaosld + 1 + 1 用心讨论,共获提升!
zuohaoda + 1 + 1 热心回复!
BrainFlower + 1 + 1 热心回复!
deoplljj + 1 + 1 谢谢@Thanks!
Ginobili + 1 + 1 谢谢@Thanks!
SinnerDusk + 1 + 1 用心讨论,共获提升!
soyiC + 1 + 1 用心讨论,共获提升!
镇北看雪 + 1 + 1 我很赞同!
smile5 + 1 热心回复!
FinchK + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Hotspur + 1 + 1 我很赞同!
Oohuo + 1 + 1 用心讨论,共获提升!
2008yxp + 1 + 1 用心讨论,共获提升!
Ps出来的小赵 + 3 + 1 赶在黑米之前加分再说
fishinwhater + 1 虽然我看不太懂,但确实大佬牛逼

查看全部评分

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

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

请详细说说

Shife + E  Expore Data  IDA 自带的. 可以 Edit选项中看到.
 楼主| zsky 发表于 2020-5-11 18:59
xmhwws 发表于 2020-5-11 18:55
大佬,这个是怎么操作的?还是通过插件实现的?

请详细说说

变成数组类型之后 shift +e

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
xmhwws + 1 + 1 谢谢@Thanks!

查看全部评分

赤座灯里 发表于 2020-5-11 17:51
我傻傻地把十五个方程列出来了,浪费太多时间
xmhwws 发表于 2020-5-11 18:55
大佬,这个是怎么操作的?还是通过插件实现的?
2020-05-11_18-53-23.png
请详细说说
FinchK 发表于 2020-5-11 19:09
厉害了,学到了。
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个多小时,硬是没扫出来,,,
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-25 14:23

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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