[MRCTF2020]VirtualTree(花指令、二叉树、交叉引用)

4 篇文章 0 订阅

参考博客CTF逆向-[MRCTF2020]VirtualTree-恒成立的jz花指令去除及smc变换原执行流程在二叉树上的应用,通过逆向思维编写脚本以解决_serfend的博客-CSDN博客

main函数逻辑比较清晰,开头的sub_401510是去掉花指令(此题最关键的操作之一)后的函数,中间经过sub_6F1610函数和sub_6F16F0函数的变换,最后和byte_7108EC数组做对比

先看sub_401680函数,a1、a1+4、a1+8可以联想到二叉树

右键a1,创建新的结构体

改成这样继续看,先判断左子树,然后异或,再判断右子树,是中序遍历

对401680交叉引用,发现还有其他的函数引用,跟进

先将所有的401510函数替换成off_4208B0为起点的内容(off_4208B0也是有花指令的,需要去除),再将所有的中序遍历改为后序遍历

这里的14个操作分别对应了off_4208B0为起点的14个函数,需要一一替换

其实只有三种函数

ps:这些函数的去花需要先D,然后对下面有意义的语句一行行C,最后对0EBh nop,就能去花了

int __cdecl sub_401470(int a1, int a2)
{
  int result; // eax

  result = *(&input + a2);
  *(&input + a1) ^= result;
  return result;
}
//input[a1] ^= input[a2]
int __cdecl sub_4014A0(int a1, int a2)
{
  __int64 v2; // rax
  int result; // eax

  v2 = *(&input + a1) - *(&input + a2);
  result = (HIDWORD(v2) ^ v2) - HIDWORD(v2);
  *(&input + a1) = result;
  return result;
}
//input[a1] = abs(input[a1] - input[a2])
int __cdecl sub_4014E0(int a1, char a2)
{
  int result; // eax

  result = a1;
  *(&input + a1) += a2;
  return result;
}
//input[a1] += input[a2]

对这个数组交叉引用,可以找到函数sub_401120,里面找到二叉树的顺序以及这个数组的值

用同样的方法改成结构体

画出二叉树,后序遍历的顺序如下

dword_421310数组的值就是从65递增

捋一捋顺序,先对输入异或操作(异或对象就是dword_421310数组),再进行14项操作,最后与已知数组对比。逆向一下,脚本如下

flag = '17637703522E4A28521B17123A0A6C6200000000'
flag = [x for x in bytearray.fromhex(flag)]


def f_add_a2(a1: int, a2: int):
    flag[a1] -= a2


def f_xor_ginputIndexOfa2(a1: int, a2: int):
    flag[a1] ^= flag[a2]


def f_abs_inputA1_minus_inputA2(a1: int, a2: int):
    if flag[a1] < flag[a2]:
        flag[a1] = -flag[a1]
    flag[a1] += flag[a2]


commands = '''
f_add_a2(0, 10)
f_xor_ginputIndexOfa2(1, 2)
f_add_a2(2, 7)
f_abs_inputA1_minus_inputA2(3, 7)
f_xor_ginputIndexOfa2(4, 5)
f_abs_inputA1_minus_inputA2(6, 1)
f_add_a2(7, 3)
f_xor_ginputIndexOfa2(8, 7)
f_abs_inputA1_minus_inputA2(9, 8)
f_abs_inputA1_minus_inputA2(10, 7)
f_xor_ginputIndexOfa2(11, 12)
f_abs_inputA1_minus_inputA2(12, 2)
f_xor_ginputIndexOfa2(14, 15)
f_add_a2(15, 2)
'''.split('\n')
commands = commands[::-1]
for command in commands:
    if len(command) < 5:
        continue
    eval(command)

order = [13, 12, 7, 16, 15, 11, 6, 3, 10, 5, 14, 9, 8, 4, 2, 1]
order = [x-1 for x in order]

for index, i in enumerate(order):
    flag[index] ^= (65+i)

flag = [chr(x) for x in flag]
flag = ''.join(flag)
print(flag)  
# @_7r3e_f0r_fuNN!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值