当前位置:网站首页>[buuctf.reverse] 144_[XMAN2018排位赛]easyvm
[buuctf.reverse] 144_[XMAN2018排位赛]easyvm
2022-07-01 11:07:00 【石氏是时试】
虚拟机的题很少,感觉都差不多,不过这个确实感觉麻烦了点。
没有删除符号表这让处理起来方便了不少。代码除循环和结束命令外都是3字节,1字节命令2字节数据。
printf("Please input your flag:");
flag = malloc(0x20u);
scanf("%32s", flag);
v3[1] = (int)&flag;
memcpy(cipher, &unk_3E75, sizeof(cipher));
v3[0] = (int)cipher;
v2[1] = (int)v3;
v2[0] = 0xEFBEADDE;
R[0] = (char **)&v17;
R[1] = (char **)&v11;
R[2] = (char **)&v10;
R[3] = (char **)&v16;
R[4] = (char **)&v15; // R4,V15存计算结果
R[5] = &v7;
R[6] = (char **)&v9;
R[7] = (char **)&v8;
R[8] = (char **)&v14;
R[9] = (char **)&v13;
R[10] = (char **)&v12;
R[11] = (char **)&flag;
R[12] = (char **)v3; // cipher
R[13] = (char **)v2;
while ( 1 )
{
v22 = read_code(code, &ptr); // pop
v21 = v22 & 0xFE;
v20 = v22 & 1;
switch ( v22 & 0xFE )
{
case 0:
v6 = read_code(code, &ptr); // op a b : mov R[a],(char)R[b] mov R[b],(char)b
v5 = read_code(code, &ptr);
if ( v20 )
{
if ( v20 == 1 )
mov((int *)R[v6], (char)*R[v5]);
}
else
{
mov((int *)R[v6], v5);
}
break;
case 2:
v6 = read_code(code, &ptr); // op a b : mov R[a],(int)R[b] mov R[b],(int)b
v5 = read_code(code, &ptr);
if ( v20 )
{
if ( v20 == 1 )
mov32((int *)R[v6], (int)*R[v5]);
}
else
{
mov32((int *)R[v6], v5);
}
break;
case 4:
循环没有开始结束标志,只是个二选一第一次进第二次出,所以没有嵌套
case 0x28:
if ( inloop ) // 单字节指令 循环
{
if ( v9 )
ptr = loopstart;
else
inloop = 0;
}
else
{
inloop = 1;
loopstart = ptr;
}
break;操作命令一共20个,包含赋值,加,移位,逻辑运算,栈运算等。先把操作命令按这些功能打印出来(不大准确,只为方便观看)
def printcode(code):
i = 0
while i<246:
op = code[i]; i+=1
v1 = op&0xfe
v2 = op&1
if v1 < 0x28:
a = code[i]; i+=1
b = code[i]; i+=1
if v1 == 0 and v2 == 1:
print(f'mov R[{a}] R[{b}]')
if v1 == 0 and v2 == 0:
print(f'mov R[{a}] {b}')
if v1 == 2 and v2 == 1:
print(f'mov32 R[{a}] R[{b}]')
if v1 == 2 and v2 == 0:
print(f'mov32 R[{a}] {b}')
if v1 == 4 and v2 == 1:
print(f'lea_ch R[{a}] R[{b}]')
if v1 == 6 and v2 == 1:
print(f'lea_int R[{a}] R[{b}]')
if v1 == 8 and v2 == 1:
print(f'ldr_int R[{a}] R[{b}]')
if v1 == 10 and v2 == 1:
print(f'ldr_ch R[{a}] R[{b}]')
if v1 == 12 and v2 == 1:
print(f'add R[{a}] R[{b}]')
if v1 == 12 and v2 == 0:
print(f'add R[{a}] {b}')
if v1 == 14 and v2 == 1:
print(f'add_pint R[{a}] R[{b}]')
if v1 == 14 and v2 == 0:
print(f'add_pint R[{a}] {b}')
if v1 == 16 and v2 == 1:
print(f'add_pch R[{a}] R[{b}]')
if v1 == 16 and v2 == 0:
print(f'add_pcj R[{a}] {b}')
if v1 == 18 and v2 == 1:
print(f'xor R[{a}] R[{b}]')
if v1 == 18 and v2 == 0:
print(f'xor R[{a}] {b}')
if v1 == 20 and v2 == 0:
print(f'mod R[{a}] {b}')
if v1 == 22 and v2 == 1:
print(f'or R[{a}] R[{b}]')
if v1 == 22 and v2 == 0:
print(f'or R[{a}] {b}')
if v1 == 24 and v2 == 1:
print(f'and R[{a}] R[{b}]')
if v1 == 24 and v2 == 0:
print(f'and R[{a}] {b}')
if v1 == 26 and v2 == 1:
print(f'push R[{a}] R[{b}]')
if v1 == 26 and v2 == 0:
print(f'push R[{a}] {b}')
if v1 == 28 and v2 == 1:
print(f'pop R[{a}] R[{b}]')
if v1 == 30 and v2 == 1:
print(f'shr R[{a}] R[{b}]')
if v1 == 30 and v2 == 0:
print(f'shr R[{a}] {b}')
if v1 == 32 and v2 == 1:
print(f'shl R[{a}] R[{b}]')
if v1 == 32 and v2 == 0:
print(f'shl R[{a}] {b}')
if v1 == 34 and v2 == 1:
print(f'ror R[{a}] R[{b}]')
if v1 == 34 and v2 == 0:
print(f'ror R[{a}] {b}')
if v1 == 36 and v2 == 1:
print(f'cmp_l R[{a}] R[{b}]')
if v1 == 36 and v2 == 0:
print(f'cmp_l R[{a}] {b}')
if v1 == 38 and v2 == 1:
print(f'cmp_eq R[{a}] R[{b}]')
if v1 == 38 and v2 == 0:
print(f'cmp_eq R[{a}] {b}')
if v1 == 40:
print('loop')
if v1 == 42:
print('end')
return
code = open('easyvm', 'rb').read()[0x2e95: 0x2e95+246]
print(list(code))
printcode(code)
然后对输出的结果一点点啃。大概分成4段,
第一段是对输入的flag进行换位
'''
lea_ch R[1] R[11] #R1 = flag
xor R[3] R[3]
xor R[0] R[0]
xor R[4] R[4]
'''
#第1段换位置
j=0
for i in range(32):
j = (j + 51)%32
stack[i] = flag[j]
'''
loop
add R[0] 51
mod R[0] 32
lea_ch R[9] R[1]
add_pch R[9] R[0]
ldr_ch R[10] R[9]
mov R[4] R[10]
push R[5] R[4]
add R[3] 1
cmp_l R[3] 32
loop
'''
第二段是将每个字符分成前3后5然后用后一个的后5和前一个的前3拼成新的字节
#第1字符的前3位
'''
xor R[0] R[0]
lea_int R[8] R[5]
add_pint R[8] 224
lea_int R[2] R[8]
ldr_int R[10] R[2]
mov R[0] R[10]
and R[0] 224
shr R[0] 5
mov R[4] R[0]
xor R[3] R[3]
'''
#第2段,前5后3组合
[((flag[i]<<3)|(flag[(i-1) %32]>>5))&0xff for i in range(32)]
'''
loop
ldr_int R[10] R[2]
mov R[0] R[10]
and R[0] 31
shl R[0] 3 # a&0x1f;a<<=3
push R[5] R[0]
lea_int R[8] R[5]
add_pint R[8] 224
lea_int R[2] R[8]
ldr_int R[10] R[2]
mov R[0] R[10]
and R[0] 224 # a&0xe0;a>>5
shr R[0] 5
pop R[5] R[10]
add R[10] R[0]
push R[5] R[10]
add R[3] 1
cmp_l R[3] 31
loop
'''
#最后一个
'''
ldr_int R[10] R[2]
mov R[0] R[10]
and R[0] 31
shl R[0] 3
add R[0] R[4]
push R[5] R[0]
'''第3段是先把key和第i%4位与i相加后再与原文作异或
#第3段 与key循环+序号 异或
def ror8(a):
return (a>>i)|((a&0xff)<<24)
r3=0
r4=0xEFBEADDE
for i in range(32):
stack[i] = flag[i]^(r4+i)
r4 = ror8(r4)
'''
xor R[3] R[3]
mov32 R[4] R[13] #0xEFBEADDE
loop
lea_int R[8] R[5]
add_pint R[8] 224
lea_int R[2] R[8]
ldr_int R[10] R[2]
mov R[0] R[10]
push R[5] R[0]
mov R[0] R[4]
add R[0] R[3]
pop R[5] R[10]
xor R[10] R[0]
push R[5] R[10]
ror R[4] 8
add R[3] 1
cmp_l R[3] 32
loop
'''第4段看了半天没看懂,大概意思是没有,因为先是pop后边马上就push了,似乎没有作什么改动
#似乎没用,并没有改变数据
'''
xor R[3] R[3]
xor R[4] R[4]
lea_ch R[1] R[12]
loop
lea_ch R[9] R[1]
add_pch R[9] R[3]
ldr_ch R[10] R[9]
mov R[0] R[10]
push R[5] R[0]
lea_int R[8] R[5]
add_pint R[8] 223
ldr_int R[10] R[8]
pop R[5] R[0] #pop后直接push
push R[5] R[0]
cmp_eq R[0] R[10] #v8 = (r0 != r10)? 1: 0; r7=v8
or R[4] R[7]
add R[3] 1
cmp_l R[3] 32
loop
end
'''根据这个反过来写出3句来解密
cipher = open('easyvm', 'rb').read()[0x2e75: 0x2e75+32]
#print(cipher)
key = [0xDE, 0xAD, 0xBE, 0xEF]
m = [cipher[i]^(key[i%4] + i) for i in range(32)] #3
v = [( (m[(i-1)%32]<<5) | (m[i]>>3) )&0xff for i in range(32)] #2
flag = [0]*32 #1
p = 0
for i in range(32):
p = (p+51)%32
flag[p] = v[i]
print(bytes(flag))
#xman{ae791f19bdf77357ff10bb6b0e}
#flag{ae791f19bdf77357ff10bb6b0e}边栏推荐
- 英特爾實驗室公布集成光子學研究新進展
- Guys, how to export iceberg data to MySQL? What tools are there? Neither sqoop nor dataX
- CVPR 2022 | self enhanced unpaired image defogging based on density and depth decomposition
- PHP有哪些优势和劣势
- Leetcode 181 Employees exceeding the manager's income (June 29, 2022)
- 谷歌新论文-Minerva:用语言模型解决定量推理问题
- 商城小程序源码开源版-可二开
- I'd like to know where I can open an account in Guangzhou? Is it safe to open an account online now?
- CANN算子:利用迭代器高效实现Tensor数据切割分块处理
- 金鱼哥RHCA回忆录:DO447使用Ansible与API通信--使用Ansible Tower API启动作业
猜你喜欢

“目标检测”+“视觉理解”实现对输入图像的理解及翻译(附源代码)

華為設備配置大型網絡WLAN基本業務

node版本管理器nvm安装及切换

数据库实验报告(一)

谷歌新论文-Minerva:用语言模型解决定量推理问题

mysql如何把 一个数据库中的表数据 复制到 另一个数据库中(两个数据库不在同一个数据库链接下)

bash: ln: command not found

In June 2022, it was the first programming language?!

Neurips 2022 | cell image segmentation competition officially launched!
![[encounter Django] - (II) database configuration](/img/23/aed472757f7e238a146b043c0405d7.png)
[encounter Django] - (II) database configuration
随机推荐
Mobile hard drive reads but does not display drive letter
商汤进入解禁期:核心管理层自愿禁售 强化公司长期价值信心
英特尔实验室公布集成光子学研究新进展
内存泄漏定位工具之 valgrind 使用
Valgrind usage of memory leak locating tool
金鱼哥RHCA回忆录:DO447使用Ansible与API通信--使用Ansible Tower API启动作业
Is it safe to open a stock account online in 2022? Is there any danger?
移动硬盘驱动器读到,但不显示盘符
NC | intestinal cells and lactic acid bacteria work together to prevent Candida infection
TEMPEST HDMI泄漏接收 5
Database experiment report (I)
关于Keil编译程序出现“File has been changed outside the editor,reload?”的解决方法
12 plateformes de gestion de produits utilisées par tout le monde
LeetCode.515. 在每个树行中找最大值___逐一BFS+DFS+按层BFS
flutter path_ Provider: ^2.0.10 can get temporary directory
The project bar on the left side of CodeBlocks disappears, workspace automatically saves the project, default workspace, open the last workspace, workspace (Graphic tutorial, solved)
Huawei equipment is configured with large network WLAN basic services
基金国际化的发展概况
MIT最新论文《对可解释特征的需求:动机和分类》:在机器学习模型的组成元素中建立可解释性
The first anniversary of the data security law, which four major changes are coming?