CTF逆向-[RoarCTF2019]polyre-WP_控制流扁平化去混淆idcpy去指令

CTF逆向-[RoarCTF2019]polyre-WP_控制流扁平化去混淆idcpy去指令

来源BUUCTF在线评测/

内容:无

附件百度网盘 请输入提取码 提取码:nyty

答案:flag{6ff29390-6c20-4c56-ba70-a95758e3d1f8}

总体思路

使用deflat.py对程序扁平化处理。

使用ida的python idc工具对多余指令去除。

检查算法发现是crc64,按其流程逆运算

详细步骤

  • 检查文件信息

  • 打开程序发现控制流特别大,可能是进行了混淆

使用deflat.py(见附件),在ida中查看main方法的地址为0x400620'

python ./deflat.py 1 0x4006200

  • 编写idc脚本,去除多余的永真分支

    idc是一个ida中非常强大的工具集,可以通过使用everything或者utools搜索idc.py,查看一下它实现了哪些可调用的方法。学习掌握它。

st = 0x400620
end = 0x401f54
​
​
def patch_nop(start, end):
    for i in range(start, end):
        idc.patch_byte(i, 0x90)  # 修改指定地址处的指令  0x90是最简单的1字节nop
​
​
def next_instr(addr):
    return addr + idc.get_item_size(addr)  # ItemSize获取指令或数据长度,这个函数的作用就是去往下一条指令
​
​
addr = st
while(addr < end):
    next = next_instr(addr)
    # idc.get_disasm(addr)得到addr的反汇编语句
    if "ds:dword_603054" in idc.get_disasm(addr):
        while(True):
            addr = next
            next = next_instr(addr)
            if "jnz" in idc.get_disasm(addr):
                dest = idc.get_operand_value(addr, 0)  # 得到操作数,就是指令后的数
                idc.patch_byte(addr, 0xe9)
                idc.patch_byte(addr+5, 0x90)
                offset = dest - (addr + 5)
                idc.patch_dword(addr + 1, offset)
                print("patch bcf: 0x%x" % addr)
                addr = next
                break
    else:
        addr = next

  • 检查加密算法为简单加密

在比对的g_key中按shift+e复制值,得到解密脚本

import struct
g_key = '966253436DF28FBC16EE300578000152EC085F93EAB5C04D50F453D8AF902B3481362CAABC0E258BE48AC6A2819F7555B326FA79764B00'
g_key = bytearray.fromhex(g_key)
single_len = 8
g_output = [g_key[x:x+single_len] for x in range(0, 6*single_len, single_len)]
g_output = [struct.unpack('<Q', x)[0] for x in g_output]
​
# 内层循环
def decode_k(v):
    is_negative = v & 1  # 判断当前值是否为负数
    if is_negative:  # 如果是负数,说明之前也是负数
        v ^= 0xB0004B7679FA26B3
    v >>= 1  # 右移一位表示除以2
    if is_negative:  # 防止负数除了以后变成正数
        v |= 0x8000000000000000
    return v
​
# 外层循环
def decode_j(v):
    for k in range(64):
        v = decode_k(v)
    return v
​
​
r = [decode_j(x) for x in g_output]
flag = [struct.pack('<Q', x) for x in r]
flag = [x.decode() for x in flag]
print(''.join(flag))
// flag{6ff29390-6c20-4c56-ba70-a95758e3d1f8}

参考文档

  • struct.unpack用法 <Q表示按小端取unsign long long

  • unsign long long中,因为总长度是8位且无符号,所以0x8000000000000000是最小的负数,0x7fffffffffffffff是最大的正数。

更多CTF逆向题通用性做法和常用工具下载参考该博文内容:CTF逆向Reverse题的玩法

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值