CTF——angr使用学习记录
?初始化:
p = angr.Project('./test',load_options={"auto_load_libs":False})
載入文件,auto_load_libs設置為false,大概是啟用angr自帶的函數定義,避免一些邏輯過于復雜,機器跑不出來。
import?claripy?
arg?=?claripy.BVS(‘arg1′,?8)
我們使用claripy這個模塊來定義抽象的數據,claripy的BVS函數可以創建一個指定長度的抽象數據,BVS函數要求兩個參數,第一個參數為變量名,第二個參數為變量長度。符號化變量;
state?=?p.factory.entry_state(args=argv)?
entry_state()函數接收一個list作為程序的命令行參數并且返回程序入口的狀態
state.posix.files[0].read_from(1)
?表示從標準輸入讀取一個字節?
st?=?p.factory.blank_state(addr=)
創建一個?blank_state?對象,這個對象里面很多東西都是未初始化的,當程序訪問未初始化的數據時,會返回一個不受約束的符號量
sm = p.factory.simulation_manager(state)
表示從state這個地址開始執行。
sm.explore(find=0x400676,avoid=[0x40073d])
當探索到find地方,就是想要的答案,avoid就是需要避免的地方。
sm.found.posix.dumps(1)?
?最后的輸出
sm.found.posix.dumps(0)?
found的輸入
sm.found.solver.eval(arg1,cast_to?= str)
使用約束求解引擎獲取命令行參數,類型為字符串,在使用符號變量后,不能通過posix.dump來獲取標準輸入,而應該獲取符號變量的值,simgr.one_found.solver.eval函數可以獲取符號變量的值
相關使用方法:
寄存器的符號化:
import angr import claripy p = angr.Project('')init_addr = 0x08048980 #scanf的下一條指令地址 state = p.factory.blank_state(addr=init_addr) #創建一個狀態,并將該地址賦給它,也就是跳過輸入,直接執行下一條指令,此處使用.blank_state()而不再是.entry_state()#定義三個位向量,即三個輸入 p1 = claripy.BVS('p1',32) #32位寄存器(符號向量) p2 = claripy.BVS('p2',32) p3 = claripy.BVS('p3',32)state.regs.eax = p1 #.regs.eax 訪問eax這個寄存器 state.regs.ebx = p2 state.regs.edx = p3 sm = p.factory.simulation_manager(state) def good(state):return b'Good Job.' in state.posix.dumps(1) def bad(state):return b'Try again.' in state.posix.dumps(1) sm.explore(find = good, avoid = bad) if sm.found:find_state = sm.found[0]flag1 = find_state.solver.eval(p1)#將探索成功時的第一個輸入賦給flag1,下面兩個類似flag2 = find_state.solver.eval(p2)flag3 = find_state.solver.eval(p3)print('{:x} {:x} {:x}'.format(flag1,flag2,flag3))棧的符號化:
import angr import claripy import sys def main(argv):p = angr.Project('')def good(state):return b'Good Job.' in state.posix.dumps(1)def bad(state):return b'Try again.' in state.posix.dumps(1)#創建開始狀態start_addr = 0x08048697 #scanf之后的地址,之所以是這兒,是因為上一行'add esp,10h'的作用是清理scanf的棧空間state = p.factory.blank_state(addr=start_addr)#因為跳過了scanf函數,所以我們需要模擬它的整個操作(對棧的操作)#state.stack_push(state.regs.ebp)state.regs.ebp = state.regs.esp #初始化ebp、espspace = 0x8 #一個變量占4個空間,所以兩個就是8state.regs.esp -= space #模擬scanf時棧的情況(剔除了對空間的浪費,即只開辟了兩個變量的空間)ps1 = claripy.BVS('ps1',32) #符號化兩個輸入ps2 = claripy.BVS('ps2',32)state.stack_push(ps1) #將符號化的輸入入棧state.stack_push(ps2)#至此對scanf的模擬過程就完成了#創建模擬管理器simulation = p.factory.simgr(state)#開始探索simulation.explore(find=good,avoid=bad)if simulation.found:solution_state = simulation.found[0]flag1 = solution_state.solver.eval(ps1)flag2 = solution_state.solver.eval(ps2)print('{} {}'.format(flag1,flag2))if __name__ == '__main__':main(sys.argv)內存的符號化:
import angr import claripy import sysdef main(argv):path = argv[1]p = angr.Project(path)start_addr = 0x08048601state = p.factory.blank_state(addr=start_addr)#創建四個位向量,模擬輸入p1 = claripy.BVS('p1',64) #一個變量輸入8個字符,一個字符8位bit,總共64bitp2 = claripy.BVS('p2',64)p3 = claripy.BVS('p3',64)p4 = claripy.BVS('p4',64)#開始對輸入進行模擬state.memory.store(0x0A1BA1C0,p1)#讓四個位向量指向輸入在內存中的地址state.memory.store(0x0A1BA1C8,p2)state.memory.store(0x0A1BA1D0,p3)state.memory.store(0x0A1BA1D8,p4)#scanf模擬結束sm = p.factory.simgr(state) #創建模擬管理器 def good(state):return b'Good Job.' in state.posix.dumps(1)def bad(state):return b'Try again.' in state.posix.dumps(1)sm.explore(find = good,avoid = bad)if sm.found:solution_state = sm.found[0]flag1 = solution_state.solver.eval(p1,cast_to=bytes)flag2 = solution_state.solver.eval(p2,cast_to=bytes)flag3 = solution_state.solver.eval(p3,cast_to=bytes)flag4 = solution_state.solver.eval(p4,cast_to=bytes)print("{} {} {} {}".format(flag1.decode('utf-8'),flag2.decode('utf-8'),flag3.decode('utf-8'),flag4.decode('utf-8')))else:print("NO")if __name__ == '__main__':main(sys.argv)?hook:
在?angr?中使用?hook?來把指定地址的二進制代碼替換為?python?代碼。angr?在模擬執行程序時,執行每一條指令前會檢測該地址處是否已經被?hook?,如果是就不執行這條語句,轉而執行hook?時指定的?python?處理代碼。
#!/usr/bin/env python # coding=utf-8 import angr import claripy def hook_demo(state):state.regs.eax = 0state.regs.ebx = 0xdeadbeef p = angr.Project("./examples/sym-write/issue", load_options={"auto_load_libs": False}) p.hook(addr=0x08048485, hook=hook_demo, length=2) # 使用 p.hook 把 0x08048485 處的 2 字節的指令 為 hook_demo,之后執行 0x08048485就會去執行 hook_demo state = p.factory.blank_state(addr=0x0804846B, add_options={"SYMBOLIC_WRITE_ADDRESSES"})#創建一個 state , 因為要往內存里面設置 符號量 ( BVS ),設置SYMBOLIC_WRITE_ADDRESSES u = claripy.BVS("u", 8) state.memory.store(0x0804A021, u) #新建一個 8 位長度的符號量,并把它存到 0x0804A021 (全局變量 u 的位置) sm = p.factory.simgr(state) sm.explore(find=0x080484DB) st = sm.found[0] print hex(st.se.eval(st.regs.ebx))?p.hook(addr=0x08048485,?hook=hook_demo,?length=2)
p.hook_symbol('想要被hook的函數名', 自己定義的替換函數名,replace=True)
-
addr?為待?hook?指令的地址
-
hook?為?hook?的處理函數,在執行到?addr?時,會執行 這個函數,同時把 當前的?state?對象作為參數傳遞過去
-
length?為 待?hook?指令的長度,在 執行完?hook?函數以后,angr?需要根據?length?來跳過這條指令,執行下一條指令
優化:
simgr.one_active.options.add(angr.options.LAZY_SOLVES)
對simgr開啟LAZY_SOLVES選項,該選項可不在運行時實時檢查當前條件能否到達目標位置。雖然這樣無法規避一些無解的情況,但可以顯著提高效率
報錯:?
The main binary is a position-independent executable. It is being loaded with a base address of 0x400000.
我們后面程序的地址要加上基址偏移。
參考:
??????大佬的代碼
大佬的博客
大佬的博客
總結
以上是生活随笔為你收集整理的CTF——angr使用学习记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BUUCTF-[网鼎杯 2020 青龙组
- 下一篇: BUUCTF——[ACTF新生赛2020