[BUUCTF]Reverse——[WUSTCTF2020]funnyre

本文档介绍了如何修复一个无壳ELF文件,通过IDA64进行汇编分析,修复花指令并创建未识别的函数。通过观察主要的加密逻辑,包括XOR和移位操作,利用IDAPython或angr进行逆向工程和暴力求解,最终揭示加密后的值。提供了三种不同的解密方法,包括暴力求解、IDAPython脚本和angr约束求解。
摘要由CSDN通过智能技术生成

[WUSTCTF2020]funnyre

  1. ELF文件,无壳,用ida64打开,程序没法f5,从程序入口点找到main函数的汇编部分
    因为这边没有创建函数,所以无法f5
    在这里插入图片描述

  2. 在选取汇编部分打算创建函数的过程中发现了不对劲的地方
    jz和jnz跳转到同一地址,花指令,nop掉,然后那个call看着也不太对的样子,先也nop掉,call下面的那条jz也nop掉。经过多次测试,要从第一条jz指令nop到xor eax,eax之前
    在这里插入图片描述

  3. 一共有4处需要修改nop掉,修改完后,发现一共有三个函数没有创建,拿一处说一下。
    在一段汇编的结束处,标识了这段汇编的起始地址
    在这里插入图片描述
    点击改地址,按热键G,点击ok即可快速跳转
    在这里插入图片描述点击起始地址,右击,选择creat functions(快捷键P)
    在这里插入图片描述

  4. 一共有三处要创建函数。到这里程序就修复好了,f5 main函数看一下
    在这里插入图片描述
    在这里插入图片描述
    可以看到逻辑,进行了数次xor操作,又进行了数次移位操作,最后得到4025c0处的值
    在这里插入图片描述

  5. 这里可以使用IDAPython获取每一个操作的详细数据,然后化简,也可以使用angr进行暴力求解。

贴一下官方wp
解法一:暴力求解:

dt = [0xd9, 0x2c, 0x27, 0xd6, 0xd8, 0x2a, 0xda, 0x2d, 0xd7, 0x2c, 0xdc, 0xe1, 0xdb, 0x2c, 0xd9, 0xdd, 0x27, 0x2d, 0x2a, 0xdc, 0xdb, 0x2c, 0xe1, 0x29, 0xda, 0xda, 0x2c, 0xda, 0x2a, 0xd9, 0x29, 0x2a]


def kaisa(xx, kk):
    return [(x+kk) & 0xFF for x in xx]


def xor(xx, kk):
    return [x ^ kk for x in xx]


def check(xx):
    for x in xx:
        if x < ord('0') or (x > ord('9') and x < ord('a')) or x > ord('f'):
            return False
    return True


if __name__ == '__main__':
    for k1 in range(0x100):
        tt = kaisa(dt, k1)
        for k2 in range(0x100):
            tt2 = xor(tt, k2)
            if check(tt2):
                print(bytes(tt2))
                print(k1, k2)

解法二:IDAPython根据指令去逆向:

def trans(xx, kk):
    return [(x-kk) & 0xFF for x in xx]
def xor(xx, kk):
    return [x^kk for x in xx]
def not_(xx):
    return [~x for x in xx]

dt = [0xd9, 0x2c, 0x27, 0xd6, 0xd8, 0x2a, 0xda, 0x2d, 0xd7, 0x2c, 0xdc, 0xe1, 0xdb, 0x2c, 0xd9, 0xdd, 0x27, 0x2d, 0x2a, 0xdc, 0xdb, 0x2c, 0xe1, 0x29, 0xda, 0xda, 0x2c, 0xda, 0x2a, 0xd9, 0x29, 0x2a]

ads = 0x4005B0
end = 0x401DC0
i = PrevHead(end)
while i > ads:
    if GetMnem(i) == 'xor' and GetOpnd(i, 0) == 'byte ptr [rdx+rax+5]':
        k = int(GetOpnd(i, 1).rstrip('h'), 16)
        dt = xor(dt, k)
        print("xor: {}".format(k))
    if GetMnem(i) == 'add' and GetOpnd(i, 0) == 'byte ptr [rdx+rax+5]':
        k = int(GetOpnd(i, 1).rstrip('h'), 16)
        dt = trans(dt, k)
        print("trans: {}".format(k))
    if GetMnem(i) == 'not' and GetOpnd(i, 0) == 'byte ptr [rdx+rax+5]':
        dt = not_(dt)
        print("not: {}".format(k))
    i = PrevHead(i)

print(dt)

解法三:符号执行工具约束求解:

import angr
import claripy

p=angr.Project('./attachment',load_options={"auto_load_libs": False})
f=p.factory
state = f.entry_state(addr=0x400605)	  #设置state开始运行时的地址
flag = claripy.BVS('flag',8*32)			  #要求的内容有32个,用BVS转成二进制给flag变量
state.memory.store(0x603055+0x300+5,flag) #因为程序没有输入,所以直接把字符串设置到内存
state.regs.rdx=0x603055+0x300
state.regs.rdi=0x603055+0x300+5           #然后设置两个寄存器

sm = p.factory.simulation_manager(state)  #准备从state开始遍历路径

print("ready")

sm.explore(find=0x401DAE)                #遍历到成功的地址
if sm.found:
    print("[+] found!")
    x = sm.found[0].solver.eval(flag, cast_to=bytes)
    print(x)

在这里插入图片描述

ubuntu16.04上python的angr库的安装参考文章

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值