angr學習(二)


Surveyor
 
作為符號執行的引擎,它跟蹤可執行的路徑,標志出向前進的路徑和倒退的路徑,並且優化資源配置.
surveyor類並不直接使用,一般會被開發者子類化后來用作他們自己的分析。
最常見的符號分析(類似探索從A達到B,並避開C)已經在Explore類中實現。
 
 
Explorer
surveyors.Explorer 是surveyor的子類,用來執行符號搜索。
它可以被指定從哪兒開始,執行到哪兒,避開哪兒,和跟蹤哪條路徑。
它也會嘗試避免死循環。
import  angr
 
b= angr.Project('.../../...')
 
一個surveyor對象在程序的入口開始執行,通過“Project.initial_exit”來退出。
它通過使用“Project.initial_state”來創建一個狀態塊。
經常使用的SimExit,創建了一個自定義狀態塊,能夠提供“start”的可選參數,或者“starts”的可選參數列表。
e=b.surveyors.Explorer()

 

現在我們可以運行幾步了,打印一個Explorer對象來知道現在有多少條可行路徑。
print e.step()

 

你可以使用'Explorer.run'來運行一段時間。
e.run(10)

 

不指定時間時,explorer對象一直運行知道跑完所有路徑(但對於大部分程序來說不是這樣的)。在本例子中,我們不會遇到,程序時並不無限循環。
e.run()

 

我們可以知道哪條路徑可通,哪條是死路(不提供可行退出),哪條出錯。但在一些實例中,一條給定路徑存在多種情況(即出錯又無法退出)。
print "%d paths are still running" % len(e.active)
print "%d paths are backgrounded due to lack of resources" % len(e.spilled)
print "%d paths are suspended due to user action" % len(e.suspended)
print "%d paths had errors" % len(e.errored)
print "%d paths deadended" % len(e.deadended)

 

到目前為止,所有我們討論的都適用於所有的Surveyors。但是,更棒的是一個Explorer對象可以被告知要尋找時,或避免去某個區塊。
例子:
創建一個Explorer對象嘗試去找到0x4006ed,並避開0x4006fd和0x4006aa。
e=p.surveyors.Explorer(find=(0x4006ed,),avoid = (x04006aa,0x4006fd))
e.run()
 
打印我們發現的后門和避開了多少條路徑
if len(e.found) >0:
    print "found backdoor path:",e.found[0]
 
print "Avoided %d paths" % len(e.avoided)

 

 
Caller
 
Caller使被調函數更簡單得計算出程序到底做了些什么 
加載程序:
b = angr.Project('../../..')
 
初始化state,並得到我們的username和password 的符號表達式為了之后的檢查。這里,我們多偽造一位因為我們知道username和password都是8字節。
p=b.factory.path()
username= p.state.memory.load(0x1000,9)
password = p.state.memory.load(0x2000,9)

 

調用關鍵函數,把username和password的指針傳入
c=b.surveyors.Caller(0x400664,(0x1000,0x2000),start=p)

 

查看不同路徑的返回
print tuple(c.iter_returns())
 
其中返回1的路徑
print tuple(c.iter_returns(solution=1))

 

現在我們能看到要到達目標點所需要的username和password。
'c.map_se' 調用 state.se.any_n_str(或者所提供的任意其他函數)
credentials = username.concat(password)
tuple(c.map_se('any_n_str',credentials,10,solution =1))

  

 
Inerrupting Surveyors
Surveyor對象保存它的內核狀態在每個tick之后.在IPython中,你應該能夠暫停一個 surveyor用Ctrl-C,然后檢查到目前為止有什么結果,但這是一個不好的做法。有兩個簡潔的官方方式:SIGUSR1和SIGUSR2。
如果你發送SIGUSR1到運行surveyor的python進程,它會導致主循環 Surveyor.run()在當前Surveyor.step()結束時終止。然后可以分析結果。要繼續運行surveyor,要調用angr.surveyor.resume_analyses()(清除 “signalled”標志),然后調用surveyor的run()函數。因為SIGUSR1會導致run()返回,這在腳本化分析中很少有用,因為程序的其余部分將在run()之后運行, 返回。相反,SIGUSR1意味着提供一個干凈的替代Ctrl-C。 另一方面,將SIGUSR2發送到python進程會導致run()調用ipdb斷點 后每個步驟()。這允許您調試,然后繼續您的程序。確保運行angr.surveyor.disable_singlestep(),然后繼續清除“信號”標志。
 
 
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
path_group
path_group允許我們監視多條路徑以一個確切的方式。路徑被設置為“stashes”,我們可以控制前進、步過、合並,隨意移動。
有不同種類的“stashes”。
Paths:
我們可以以不同的規律來跑不同的stash,並使其一起匯合。
import angr
 
p=angr.Project('...',load_option={'auto_load_lib':false})
pg=p.factory.path_group()

 

當有可行路徑時

while len(pg.active) > 0:
    pg.step()
 
print (pg)

 

當我我們遇到死路后,我們怎么做?
path = pg.deadended[0]
Print('path length: {0} steps'.format(path.length))

 

得到路徑步驟:
Print('Trace:')
For step in path.trace:
    Print(step)

 

得到路徑中的限制:
print ('There are %d constraints.' % len(path.state.se.constraints))
 
得到在結束時的內存狀態
print ('rax:{0}'.format
(path.state.regs.rax))
 
assert path.state.se.any_int(path.state.regs.rip)==path.addr

 

 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Pathgroup.Explorer
pathgroup被認為會取代 surveyors.Explorer,它更靈活更有效。
當path_group.Explorer運行中得到find區塊,多條路徑將會運行步進直到發現我們所要尋找的地址。路徑到達avoided地址,如果發生,將會被記錄在avoided stash中。如果一個行進的的路徑到達一個我們感興趣的地址,它會被stash進found stash,並且其他路徑繼續行進。我們可以研究這個found 路徑,或者舍棄它讓其他路徑繼續。
 
載入二進制文件
p=angr.Project('../../..')
 
我們創建一個path group
pg=p.factory.path_group()
 
現在,我們符號化執行直到發現一條路徑符合我們的條件
pg.explore(find=lambda p:"Congrats" in p.state.posix.dumps(1))
 
現在,我們從狀態塊中得到了flag
s=pg.found[0].state
print s.posix.dumps(1)
 
flag=s.posix.dumps(0)
print (flag)
 

在path_group執行時,路徑會被歸為不同類型的stash

stash        描述
active  包含了默認執行的路徑(除非一個替換的stash被指定給path_group.step())
deadended  一條進入deadended stash的路徑,是指它因為一些原因而無法繼續執行,包括沒有有效指令、無效的指令指針、unsat狀態的后續。
found 一條到達found stash 的路徑,是指它滿足path_group.explore的find節所給出的條件
avoided 是指它滿足path_group.explore的avoid節所給出的條件
pruned  當使用LAZY_SOLVES時,路徑不會被檢查是否會滿足,除非它很重要。當state未指定LAZY_SOLVES時,路徑一旦狀態變為unsat后,層次就被划分了。所有從這個點派生的路徑會被刪除並把這個路徑作為pruned stash。
errored 當引起python異常時執行,這意味着angr或者自己的代碼中有錯誤。
unconstrained 如果path_group的構造函數被指定save_unconstrained參數,路徑就確定為無約束的(其中指令指針被用戶數據或一些其他符號數據源所控制)放在此處
unsat 如果path_group的構造函數被指定save_unsat參數,路徑就確定為不可滿足的(他們具有矛盾的約束條件,例如同時輸入“AA”和“BB”)放在此處

 

你可以使用path_group.move函數來在不同的stash中移動路徑。這個函數接受很多參數來控制這些路徑移動。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM