angr 符號執行爆破 CTF-RE 入門


感謝 https://github.com/jakespringer/angr_ctf/blob/master/SymbolicExecution.pptx 這篇 PPT 和 https://www.bilibili.com/video/BV167411o7WK?t=1043 這個視頻,本文章的出現和我能入門angr,這兩個教程功不可沒,如果你們有興趣也可以看看。angr 官方項目地址:https://github.com/angr/angr

這篇文章主要是帶大家入門如何用 angr 進行符號執行。

符號執行介紹

隨着時代的發展,程序的流程越來越復雜,如果我們繼續像以前那樣在 ida 里仔細分析,肯定是太累了,所以有些科學家想要用自動化的算法來進行逆向工程,然后,他們就想到了符號執行這個算法。

符號執行算法聽起來很高端,其實內部算法卻並不難理解。接下來就介紹一下這個符號執行的內部算法:

假如有這樣一個程序

這里采用 Python 只是為了方便理解。。。事實上符號執行可以解決所有語言的程序,這個算法和程序所采用的語言沒啥關系

user_input = int(input())
if user_input - 10 >= 0:
	print('Success.')
else:
	print('Try again.')

我們現在想要知道為了讓程序到達 print('Success.')這一行,需要的輸入條件是什么,那我們要怎么得出到達這一行的條件呢?首先我們來看看執行這個程序的時候,user_input 都經歷了什么。

user_input 經過了一個判斷語句,其中 user_input - 10>= 0 就是成功的條件。所以很顯然,我們只要將這個不等式接出來,就能知道需要的條件了。

那么接下來假如說有一個這樣的程序呢:

user_input = int(input())
if user_input - 10 >= 0:
	if user_input <= 20:
    print('Success.')
  else:
    print('Try again.')
else:
	print('Try again.')

這個程序稍微復雜了那么一點。但是這不是問題,我們照着解決上一個程序的方法,先看看 user_input 都經歷了什么:

不難看出,user_input經歷了個兩個判斷條件,所以這回我們為了得出輸出成功的條件,我們得解一個方程組:

\[\left\{ \begin{aligned} user\_input - 10 \ge 0 \\ user\_input \le 20 \end{aligned} \right. \]

然后我們只要愉快的解出這個不等式組,就可以得到可能的輸出了。

不難發現,就算你if語句再多,只要我能夠一個個收集齊全,然后將這些條件形成一個不等式組,然后解出這個不等式組,就可以得到我們想要的輸出了。

但是現實生活中的程序不可能這么簡單,單憑人力是無法收集全的,那么我們自然是要用程序來收集。這個時候就該我們的angr登場了。

接下來我們通過一個程序來看看angr的使用方法和大概的工作流程。

angr 的安裝

在用之前,我們得先安裝這個東西。安裝這個十分的簡單,為了避免 python 庫版本混亂的問題。我們在使用這個庫之前將這個庫裝進 python 虛擬環境里隔離起來。如何建立虛擬環境這個可以自行百度,畢竟這屬於python的基礎知識。建立好以后,我們在終端中激活這個虛擬環境,然后用 pip3 install angr 安裝 angr即可。

angr 上手教程

樣例程序下載:

百度網盤鏈接: https://pan.baidu.com/s/1tdL3RmAm9VZz5wsR-IGA6g 密碼: 6tf2

Github 鏈接: https://github.com/jakespringer/angr_ctf/blob/master/dist/00_angr_find

由於這個程序比較簡單,因此我們這次用 ipython 來操作。(沒裝的自己百度哦)

首先進入 python 虛擬環境的 ipython,然后我們 import angr,如果沒有問題,那就是安裝好了。如果有報錯,建議自行百度。其實 angr 官方有一個打包好的 docker 鏡像,如果本機因為各種問題沒法正常使用,就用這個docker環境吧。

接下來我們要新建一個 angr 工程:

>>> proj = angr.Project('程序的路徑') # 相對路徑和絕對路徑均可

接下來我們就要新建一個模擬運行管理器,然后讓angr搜索需要的分支信息。

>>> sm = proj.factory.simulation_manager()
>>> sm = sm.explore(find=0x08048675) # 探索到達 0x08048678 的路徑

其中 factory 這個對象是用來生成和項目有關的一些分析工具,然后我們用這個對象生成了一個SimulationManager對象,存儲在變量 sm 中。那么什么是模擬運行管理器呢。那就要涉及到angr是如何收集所有的分支信息了。

用過 ida 的人,應該都相當熟悉這個畫面

可以說,這個圖中的一個個代碼塊就是 angr 框架中所謂的 state(這只是方便說明的說辭,實際上angr的一個state還存儲了執行這個代碼塊后的寄存器狀態,內存狀態等信息),這一個一個state組合在一起,就形成了執行路徑,然后我們用 SimulationManager 來生成,管理執行路徑。

然后 angr 會將入口點那塊 state 作為起點,將find的值對應的那塊匯編代碼作為終點,進行寬度優先搜索(還是要了解一下這個算法,這樣才能理解其他的一些參數設置,如avoid參數的含義)。找到一條從起點到達終點的可行路徑,然后將這條路上的所有if條件收集起來。最后自動對收集起來的條件形成的不等式組進行求解。(貌似具體的方法較為復雜,這里可以稍微這樣簡單理解一下)

其實我們還可以用 proj.factory.entry_state()來生成一個關於該程序入口點的state。然后將這個state作為proj.factory.simulation_manager()的參數,實際上proj.factory.simulation_manager()的默認參數就是proj.factory.entry_state()所以我就不手動指定了。

如果這步執行結束了,那么我們就可以導出能夠讓程序到達成功狀態的輸入了,

>>> final_state = sm.found[0] # 0 代表找到的第一個結果
>>> final_state.posix.dumps(0) # 導出結果

其中 posix 表示終點狀態中存儲的系統接口信息,然后通過dumps函數來導出系統輸入,系統輸出等信息。

final_state.posix.dumps(0) 表示導出輸入,final_state.posix.dumps(1)表示導出輸出。

然后我們就可以找到angr爆破出來的輸出 b'JXWVXRKX'

如何進階

1: 學習一下寬度優先搜索。

2: https://github.com/jakespringer/angr_ctf 這個項目的 dist 文件夾中存着難度從易到難的題目。完成這些水平就會有不小的提升。

3: https://space.bilibili.com/386563875 這個 UP 有關於上面這個題庫的題解視頻,上面的這些題目完全沒必要自己先做,可以先看一下這個 UP 如何操作,然后在吸收 angr 的不同用法。


免責聲明!

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



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