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
xmhwws 发表于 2020-5-11 18:55
大佬,这个是怎么操作的?还是通过插件实现的?
请详细说说
Shife + EExpore DataIDA 自带的. 可以 Edit选项中看到. xmhwws 发表于 2020-5-11 18:55
大佬,这个是怎么操作的?还是通过插件实现的?
请详细说说
变成数组类型之后 shift +e {:1_909:}我傻傻地把十五个方程列出来了,浪费太多时间 大佬,这个是怎么操作的?还是通过插件实现的?
请详细说说
{:301_999:} {:1_921:}厉害了,学到了。 大佬牛逼,这joker是个双线程的,我同伴弄了个假的flag victoryang00 发表于 2020-5-11 19:40
大佬牛逼,这joker是个双线程的,我同伴弄了个假的flag
这题最难的是flag后5位,,,,,脑洞题, 本帖最后由 wh1sper 于 2020-5-11 21:13 编辑
这次逆向好像很难,不过最后半小时就看别人垂直上分 L15263458908 发表于 2020-5-11 19:48
这题最难的是flag后5位,,,,,脑洞题,
脑洞题我就很难受 wh1sper 发表于 2020-5-11 21:10
这次逆向好像很难,不过最后半小时就看别人垂直上分
逆向除了第二道都很简单,,,,难的是杂项,,那个汉信码我拼了得1个多小时,硬是没扫出来:'(weeqw,,,