angr-doc:https://github.com/angr/angr-doc
angr-api-doc:http://angr.io/api-doc/
sub_4006F0检查password
希望执行到0x400844,不希望执行0x400855
p = angr.Project("r100")
simgr = p.factory.simulation_manager(p.factory.full_init_state())
simgr.explore(find=0x400844, avoid=0x400855)
print(simgr.found[0].posix.dumps(0))
#simgr.found[0].posix.dumps(0)代表该状态执行路径的所有输入
#simgr.found[0].posix.dumps(1)代表该状态执行路径的所有输出
import angr
import claripy
proj = angr.Project('./baby-re', auto_load_libs=False)
state = proj.factory.entry_state(add_options={angr.options.LAZY_SOLVES})
sm = proj.factory.simulation_manager(state)
sm.explore(find=0x4028E9, avoid=0x402941)
print(sm.found[0].posix.dumps(0))
#0000000077000000009700000001160000000104000000003200000001050000000115000000003200000001040000000097000000011400000001000000000033
#Math is hard!
verify
希望执行到0x400602,不希望执行0x40060e
使用claripy构造输入
claripy.BVS()创建位向量符号
claripy.BVV()创建位向量值
不能使用posix.dump(0)打印,使用found.solver.eval()获得符号执行结果
import angr
import claripy
p = angr.Project("./ais3_crackme")
argv1 = claripy.BVS("argv1",100*8)
state = p.factory.entry_state(args=["./crackme1",argv1])
simgr = p.factory.simulation_manager(state)
simgr.explore(find=0x400602,avoid=0x40060E)
solution = simgr.found[0].solver.eval(argv1, cast_to=bytes)
print(solution)
flag长度28,使用claripy构造28个变量,拼起来最后加上\n
flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(28)]
flag = claripy.Concat(*flag_chars + [claripy.BVV(b'\n')])
这是个C++程序,而angr只实现了C库,所以需要使用full_init_state方法和unicorn引擎
st = p.factory.full_init_state(
args=['./wyvern'],
add_options=angr.options.unicorn,
stdin=flag,
)
设置条件约束,flag中没有\x00和\x0a
for k in flag_chars:
st.solver.add(k != 0)
st.solver.add(k != 10)
import angr
import claripy
p = angr.Project('wyvern')
flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(28)]
flag = claripy.Concat(*flag_chars + [claripy.BVV(b'\n')])
st = p.factory.full_init_state(
args=['./wyvern'],
add_options=angr.options.unicorn,
stdin=flag,
)
for k in flag_chars:
st.solver.add(k != 0)
st.solver.add(k != 10)
sm = p.factory.simulation_manager(st)
sm.explore(find=0x40E02C)
print(sm.found[0].posix.dumps(0))
输入正确的值,输出flag
strtol将字符串转为整数,claripy构造的位向量符号无法转化,所以从0x4004AC开始,直接使rax为构造的位向量符号
state = p.factory.blank_state(addr=0x4004AC)
inp = state.solver.BVS('inp', 8*8)
state.regs.rax = inp
flag以ASIS{开头,}结尾
执行到0x400684时,flag在rdi中
对found状态下的rdi进行约束
flag_addr = found.regs.rdi
found.add_constraints(found.memory.load(flag_addr, 5) == int(binascii.hexlify(b"ASIS{"), 16))
flag = found.memory.load(flag_addr, 40)
for i in range(5, 5+32):
cond_0 = flag.get_byte(i) >= ord('0')
cond_1 = flag.get_byte(i) <= ord('9')
cond_2 = flag.get_byte(i) >= ord('a')
cond_3 = flag.get_byte(i) <= ord('f')
cond_4 = found.solver.And(cond_0, cond_1)
cond_5 = found.solver.And(cond_2, cond_3)
found.add_constraints(found.solver.Or(cond_4, cond_5))
flag是v5,v6,v7,v8,v9,最多40字节,这个38我寻思能试出来
我一直在想怎么分析出来flag套着的是个16进制串,翻了一波这比赛其他的题,flag都是这格式
import angr
import binascii
p = angr.Project("fake", auto_load_libs=False)
state = p.factory.blank_state(addr=0x4004AC)
inp = state.solver.BVS('inp', 8*8)
state.regs.rax = inp
simgr= p.factory.simulation_manager(state)
simgr.explore(find=0x400684)
found = simgr.found[0]
flag_addr = found.regs.rdi
found.add_constraints(found.memory.load(flag_addr, 5) == int(binascii.hexlify(b"ASIS{"), 16))
flag = found.memory.load(flag_addr, 40)
for i in range(5, 5+32):
cond_0 = flag.get_byte(i) >= ord('0')
cond_1 = flag.get_byte(i) <= ord('9')
cond_2 = flag.get_byte(i) >= ord('a')
cond_3 = flag.get_byte(i) <= ord('f')
cond_4 = found.solver.And(cond_0, cond_1)
cond_5 = found.solver.And(cond_2, cond_3)
found.add_constraints(found.solver.Or(cond_4, cond_5))
found.add_constraints(flag.get_byte(32+5) == ord('}'))
flag_str = found.solver.eval(flag, cast_to=bytes)
#num = found.solver.eval(inp)
#pirnt(num)
print(flag_str)
import angr
project = angr.Project('r100', auto_load_libs=False)
@project.hook(0x400844)
def print_flag(state):
print(state.posix.dumps(0))
project.terminate_execution()
project.execute()
hook 0x400844,project.execute()开始执行,执行到0x400844时执行print_flag,遇到terminate_execution()时结束
self-ModifyingCode
有ptrace反调试,需要绕一下
//ptrace_disable.c
int ptrace(int request, int pid, int addr, int data){
return 0;
}
//gcc -shared -fPIC -o ptrace_disable.so ptrace_disable.c
进gdb
pwndbg> set environment LD_PRELOAD=./ptrace_disable.so
pwndbg> break main
pwndbg> break *0x400875
si进去
pwndbg> si
pwndbg> x/128gi 0x7fffff790000
=> 0x7fffff790000: lea esi,[rsi+0x0]
0x7fffff790006: lea esi,[rsi+riz*1+0x0]
0x7fffff79000a: lea esi,[rsi+riz*1+0x0]
0x7fffff790011: lea edi,[rdi+riz*1+0x0]
0x7fffff790018: mov rax,rbx
0x7fffff79001b: mov al,BYTE PTR [rax+0x0]
0x7fffff79001e: and al,0x40
0x7fffff790020: je 0x7fffff790038
0x7fffff790022: lea rsi,[rip+0x34] # 0x7fffff79005d
0x7fffff790029: lods eax,DWORD PTR ds:[rsi]
0x7fffff79002a: mov rcx,rax
0x7fffff79002d: lods eax,DWORD PTR ds:[rsi]
0x7fffff79002e: xor DWORD PTR [rsi],eax
0x7fffff790030: add rsi,0x4
0x7fffff790034: loop 0x7fffff79002e
0x7fffff790036: jmp 0x7fffff790065
0x7fffff790038: push 0xa283a
0x7fffff79003d: mov eax,0x1
0x7fffff790042: mov edi,0x0
0x7fffff790047: mov rsi,rsp
0x7fffff79004a: mov edx,0x3
0x7fffff79004f: syscall
0x7fffff790051: mov eax,0x3c
0x7fffff790056: mov edi,0x1
0x7fffff79005b: syscall
0x7fffff79005d: or dl,BYTE PTR [rbx+0x28eb0000]
0x7fffff790063: rex.RX cmp al,0x66
0x7fffff790066: pop rsp
0x7fffff790067: (bad)
0x7fffff790068: cmp al,0xa3
0x7fffff79006a: movabs eax,ds:0x3e9f3e6235abb69e
0x7fffff790073: (bad)
0x7fffff790074: mov cl,0xde
0x7fffff790076: sbb al,0x46
0x7fffff790078: cmp al,0xeb
0x7fffff79007a: test DWORD PTR [rsi],ecx
0x7fffff79007c: mov ch,0x2a
0x7fffff79007e: test DWORD PTR [rdi+0x3a],esi
0x7fffff790081: movabs ds:0x8311add0093880ab,eax
0x7fffff79008a: adc ch,BYTE PTR [rsi+0x36]
0x7fffff79008d: jmp 0x7fffff79001f
0x7fffff79008f: rex.RXB cmp al,0xeb
0x7fffff790092: sub cl,bh
0x7fffff790094: cmp al,0xeb
0x7fffff790096: sub BYTE PTR [rsi+0x74],al
0x7fffff790099: (bad)
0x7fffff79009a: (bad)
0x7fffff79009b: cld
0x7fffff79009c: (bad)
0x7fffff79009d: jmp 0x7fffff7900c7
0x7fffff79009f: rex.RX xor r13d,esi
0x7fffff7900a2: nop
0x7fffff7900a3: jp 0x7fffff7900e1
0x7fffff7900a5: jmp 0x7fffff7900cf
0x7fffff7900a7: stc
0x7fffff7900a8: cmp eax,0x334628eb
0x7fffff7900ad: out dx,al
0x7fffff7900ae: fst st(4)
0x7fffff7900b0: cmp al,0xeb
0x7fffff7900b2: mov ebp,0x30e00501
0x7fffff7900b7: mov bh,0x5
0x7fffff7900b9: loopne 0x7fffff790078
0x7fffff7900bb: add DWORD PTR [rax+0x5019a5c],ecx
0x7fffff7900c1: loopne 0x7fffff790080
0x7fffff7900c3: mov WORD PTR [rcx-0x3a],?
0x7fffff7900c6: mov ebp,0xbdc6b18c
0x7fffff7900cb: add DWORD PTR [rip+0xffffffffdd88f5e0],eax # 0x7fffdd01f6b1
0x7fffff7900d1: push 0xfffffffffffffffd
0x7fffff7900d3: adc al,0x21
0x7fffff7900d5: lock leave
0x7fffff7900d7: (bad)
0x7fffff7900d8: rex.WRB ins DWORD PTR es:[rdi],dx
0x7fffff7900da: mov BYTE PTR [rip+0xffffffffacbde005],dh # 0x7fffac36e0e5
0x7fffff7900e0: imul r15,QWORD PTR [r12+rbp*4+0x34],0xffffffffc382f5e6
0x7fffff7900e9: in al,0x5f
0x7fffff7900eb: stc
0x7fffff7900ec: out dx,al
0x7fffff7900ed: int 0xd5
0x7fffff7900ef: cmp ebp,DWORD PTR [rip+0x4b9bdea] # 0x80000432bedf
0x7fffff7900f5: loopne 0x7fffff7900b4
0x7fffff7900f7: add DWORD PTR [rdx+0x501bde0],edi
0x7fffff7900fd: test al,0x34
0x7fffff7900ff: out 0xbf,eax
0x7fffff790101: jrcxz 0x7fffff7900c0
0x7fffff790103: add DWORD PTR [rip+0x39b9b8ef],eax # 0x80003932b9f8
0x7fffff790109: loopne 0x7fffff7900c8
0x7fffff79010b: add DWORD PTR [rdx+0x501bde1],edi
0x7fffff790111: out dx,eax
0x7fffff790112: mov eax,0xbde097da
0x7fffff790117: jrcxz 0x7fffff7900fc
0x7fffff790119: rcl DWORD PTR [rcx+0x6e],1
0x7fffff79011c: xchg ebp,eax
0x7fffff79011d: rcr esp,1
0x7fffff79011f: pop rdi
使用angr跑完所有分支,可以得到正确输入
添加support_selfmodifying_code=True参数使符号执行使可以selfmodifying
使用hook绕过ptrace
p = angr.Project("zwiebel", support_selfmodifying_code=True)
p.hook_symbol('ptrace', angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained'](return_value=0))
angr.SIM_PROCEDURES是angr对符号化函数的字典调用,angr.SIM_PROCEDURES[模块][库函数]()
import angr
def main():
# Uncomment the following two lines if you want to have logging output from
# SimulationManager
# import logging
# logging.getLogger('angr.manager').setLevel(logging.DEBUG)
p = angr.Project("zwiebel", support_selfmodifying_code=True) # this is important! this binary unpacks its code
p.hook_symbol('ptrace', angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained'](return_value=0))
# unicorn support makes execution, especially code unpacking, way faster
state = p.factory.full_init_state(add_options=angr.options.unicorn)
sm = p.factory.simulation_manager(state)
while sm.active:
# in order to save memory, we only keep the recent 20 deadended or
# errored states
#print(len(sm.active))
sm.run(n=20)
if 'deadended' in sm.stashes and sm.deadended:
sm.stashes['deadended'] = sm.deadended[-20:]
if sm.errored:
sm.errored = sm.errored[-20:]
assert sm.deadended
flag = sm.deadended[-1].posix.dumps(0).split(b"\n")[0]
import ipdb; ipdb.set_trace()
return flag
def test():
flag = main()
assert flag.startswith(b'hxp{1_h0p3_y0u_d1dnt_p33l_th3_0ni0n_by_h4nd}')
if __name__ == "__main__":
print(main())
# Here is the output (after 2 hours and 31 minutes on my machine running Pypy):
#
# ipdb> print(sm)
# <PathGroup with 20 errored, 21 deadended>
# ipdb> print(sm.deadended[-1])
# <Path with 160170 runs (at 0x20001e0)>
# ipdb> print(sm.deadended[-1].state.posix.dumps(0))
# hxp{1_h0p3_y0u_d1dnt_p33l_th3_0ni0n_by_h4nd}
# :)
每次跑20个,正确的输入在最后一个deadended
没想明白为啥,我寻思还是验一下deadended里面有没有flag,没有就扔
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议(CC BY-NC-ND 4.0)进行许可。
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).