[WUSTCTF2020]funnyre
-
ELF文件,无壳,用ida64打开,程序没法f5,从程序入口点找到main函数的汇编部分
因为这边没有创建函数,所以无法f5
-
在选取汇编部分打算创建函数的过程中发现了不对劲的地方
jz和jnz跳转到同一地址,花指令,nop掉,然后那个call看着也不太对的样子,先也nop掉,call下面的那条jz也nop掉。经过多次测试,要从第一条jz指令nop到xor eax,eax之前
-
一共有4处需要修改nop掉,修改完后,发现一共有三个函数没有创建,拿一处说一下。
在一段汇编的结束处,标识了这段汇编的起始地址
点击改地址,按热键G,点击ok即可快速跳转
点击起始地址,右击,选择creat functions(快捷键P)
-
一共有三处要创建函数。到这里程序就修复好了,f5 main函数看一下
可以看到逻辑,进行了数次xor操作,又进行了数次移位操作,最后得到4025c0处的值
-
这里可以使用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库的安装参考文章