angr 文檔翻譯(1-2):加載一個二進(jìn)制文件——CLE和angr工程

之前,你只看到了angr最原始的加載方法——你加載了/bin/true,之后又以不加載共享庫文件的方式加載了一遍。你也看到了proj.loader和它能做的一些事情?,F(xiàn)在,我們將會深入這些接口的細(xì)微之處,讓它們告訴你更細(xì)節(jié)的信息。

我們簡要提到了angr的二進(jìn)制加載組件,CLE。CLE代表“CLE Loads Everything”,負(fù)責(zé)加載二進(jìn)制文件(以及任何這個文件以來的庫),并用一種容易操作的方式將它們展示給angr的其余組件。

加載器 (The Loader)

讓我們重新加載/bin/true并且深入學(xué)習(xí)如何和loader交互:

markdown-img-paste-20180115212454645.png

已加載的對象

CLE加載器(cle.Loader)代表一整個被加載的二進(jìn)制對象的集合,它們被加載并且映射到同一個內(nèi)存空間中。每一個二進(jìn)制對象都被一個能夠處理對應(yīng)文件類型(cle.Backend的子類)的加載器后端加載。比如,cle.ELF被用來加載ELF格式的二進(jìn)制文件。

內(nèi)存中也會有一些和任何被加載的二進(jìn)制文件都無關(guān)的對象。比如,被用來提供線程本地存儲(Thread-Local storage)支持的對象和用于提供未解析的符號的外部對象。

譯者注:這里的線程本地存儲應(yīng)該指的是TLS

你可以使用loader.all_objects來獲取CLE已經(jīng)加載的所有對象,也可以指定更加具體的類別來訪問這些對象:

markdown-img-paste-20180115214429525.png

你可以直接和這些對象交互來獲取元數(shù)據(jù):

  • 獲取ELF的內(nèi)存分段和文件分段
markdown-img-paste-20180115215221539.png
  • 獲取PLT表信息

    markdown-img-paste-20180115215255922.png
  • 展示預(yù)鏈接 基址和實際裝載到的內(nèi)存基址:
markdown-img-paste-20180115215604429.png

我這里的obj.linked_base返回0,而文檔中返回的是和裝載地址一樣的值,由于不太了解預(yù)鏈接過程,目前猜測是系統(tǒng)相關(guān)的,這里不深究。

符號和重定位

在使用CLE的同時也可以使用符號。一個“符號”在形式化執(zhí)行的世界中是一個基礎(chǔ)概念,它將一個名字有效地(effectively)映射到一個地址。

從CLE中獲取符號,最簡單的方法是使用loader.find_symbol, 它接收一個名字或者一個地址并返回一個符號對象。

markdown-img-paste-20180115220536481.png

一個符號最有用的屬性是它的名字、父對象(owner)、和它的地址。但是一個符號的“地址”卻是一個含糊的概念。有三種方式來準(zhǔn)確表述一個符號的“地址”:

  • .rebased_addr 是一個符號在全局地址空間中的地址。這就是你直接打印symbol.addr會顯示的內(nèi)容。
markdown-img-paste-20180115221113593.png
  • .linked_addr是符號相對于二進(jìn)制文件預(yù)鏈接基址的地址,這個地址和用諸如readelf(1)顯示的地址是一樣的。

  • .relative_addr是符號相對于對象基址的地址。在一些文獻(xiàn)中(尤其在windows的文獻(xiàn)中),這樣的地址被稱為RVA(相對虛擬地址)

markdown-img-paste-20180115221928611.png

除了提供調(diào)試信息,符號還支持動態(tài)鏈接概念。libc提供了malloc作為導(dǎo)出函數(shù),并且主程序("/bin/true")使用這個函數(shù)。如果我們要求CLE直接從主程序?qū)ο笾薪o出一個malloc的符號,它將會告訴我們這是一個“導(dǎo)入符號”。導(dǎo)入符號沒有與其關(guān)聯(lián)的有意義的地址,但是它提供了能夠用于解析它的對象的引用,可以用.resolvedby來獲得引用。

markdown-img-paste-20180115223259981.png

說明:

  • 在之前的loader中,我們使用find_symbol方法,因為它執(zhí)行一個搜索操作來找到指定的符號。

  • 在一個獨立的對象中,這個方法是get_symbol,因為一個給定的名字只會對應(yīng)一個符號。

導(dǎo)入符號(import symbol)和導(dǎo)出符號(export symbol)的關(guān)系應(yīng)該在內(nèi)存中以一種特殊的方式被記錄,這種方式引出另一種特殊的概念——“重定位”?!爸囟ㄎ弧闭f的是:當(dāng)你將一個[import]和一個導(dǎo)出符號匹配的時候,請將導(dǎo)出符號的地址按照[format]的形式寫到[location]。我們可以通過obj.relocs(獲取Relocation實例)看到一個對象的完成重定位表,或者通過obj.imports看到符號名和他們的重定位地址的映射關(guān)系。對于導(dǎo)出符號表,angr中沒有相應(yīng)對象與之對應(yīng)。

markdown-img-paste-2018011621104094.png
markdown-img-paste-20180116211048369.png

一個對象中需要重定位的相應(yīng)導(dǎo)入符號可以用.symbol獲取。重定位將會寫入的地址可以通過訪問一個Symbol的地址的任何方式獲取,你還可以通過.owner_obj來獲得一個請求重定位的對象的引用。

譯者注:經(jīng)過測試,.symbol 似乎已經(jīng)被 .symbols_by_addr 替代,具體情況我詢問作者之后再來確認(rèn)。測試情況如下:

markdown-img-paste-20180116212725925.png

關(guān)于.owner_obj的測試,之前創(chuàng)建的之前創(chuàng)建的main_malloc返回的是主程序?qū)ο蟮囊茫?/p>

markdown-img-paste-20180116212844187.png

重定位信息不能以比較漂亮的形式展示出來,因為重定位的地址是python內(nèi)置的,是和我們的程序無關(guān)的。

譯者注:原文是“so”,我覺得邏輯不通,故譯為"because"
這里“和我們的程序無關(guān)”的意思應(yīng)該是重定位的地址有python內(nèi)部決定,對于我們的程序而言不需要關(guān)心。

如果一個導(dǎo)入符號不能被解析為任何導(dǎo)出符號,比如找不到對應(yīng)的共享庫文件,CLE將會自動更新loader.extern_obj來表明這個符號由CLE導(dǎo)出。

加載選項

如果你正在使用angr.Project加載一些東西并且你想要給cle.loader實例傳一個選項來創(chuàng)建Project,你可以直接傳入關(guān)鍵字參數(shù)給Project的構(gòu)造函數(shù),你傳入的關(guān)鍵字就會被傳給CLE。如果你想要知道所有能夠被作為選項傳入的參數(shù),你可以查看CLE的API文檔。在本文檔中,我們只看一些重要的并且被頻繁使用的選項。

基本選項

我們已經(jīng)用過了auto_load_libs選項——它控制CLE是否自動加載共享庫文件,默認(rèn)是自動加載的。另外,有一個相反的選項except_missing_libs,這個選項如果被設(shè)置為true,將在二進(jìn)制包含無法解析的共享庫時拋出一個異常。

你可以傳入一個字符串列表給force_load_libs選項,每一個被列出的字符串將會被當(dāng)做一個不可解析共享庫依賴,或者你可以傳入一個字符串列表給skip_libs來防止列表列出的共享庫的被作為依賴添加。另外,你可以傳入一個字符串列表給custom_ld_path選項,這個選項中的字符串會被作為額外的搜索共享庫文件的路徑,這些路徑將會比任何默認(rèn)路徑先被搜索,默認(rèn)路徑包括:被加載文件所在的路徑,當(dāng)前工作路徑,系統(tǒng)庫路徑。

Per-Binary 選項

如果你想要對一個特定的二進(jìn)制對象設(shè)置一些選項,CLE也能滿足你的需求。參數(shù)main_optslib_opts接收一個以python字典形式存儲的選項組。main_opts接收一個形如{選項名1:選項值1,選項名2:選項值2……}的字典,而lib_opts接收一個庫名到形如{選項名1:選項值1,選項名2:選項值2……}的字典的映射。

譯者注:lib_opts是二級字典,原因是一個二進(jìn)制文件可能加載多個庫,而main_opts指定的是主程序加載參數(shù),而主程序一般只有一個,因此是一級字典。

這些選項的內(nèi)容因不同的后臺而異,下面是一些通用的選項:

  • backend —— 使用哪個后臺,可以是一個對象,也可以是一個名字(字符串)
  • custom_base_addr —— 使用的基地址
  • custom_entry_point —— 使用的入口點
  • custom_arch —— 使用的處理器體系結(jié)構(gòu)的名字

例子:

markdown-img-paste-2018011622352591.png

譯者注:我嘗試修改/bin/true的加載基址,但是似乎沒有效果?

后臺(Backends)

CLE目前有能夠靜態(tài)加載ELF,PE,CGC,Mach-O和ELF核心轉(zhuǎn)儲文件的后臺,并且支持使用IDA加載二進(jìn)制和加載文件到一個平坦地址空間。大部分情況下,CLE將會自動檢測二進(jìn)制文件來決定使用哪個后臺,所以除非你在做一些很奇怪的工作,一般情況下你不需要指定使用哪個后臺。

你可以和上一節(jié)描述的一樣,用傳入一個鍵的方式強制CLE使用指定的后臺。一些后臺不能被自動檢測,因此必須用custom_arch指定。鍵值不需要匹配任何一個架構(gòu):根據(jù)你給出的任意架構(gòu)的任意通用標(biāo)識符,angr都能夠識別出你指的是哪個架構(gòu)。

為了指定使用的后臺,使用下表列出的名字:

名字 描述 是否需要用custom_arch指定?
elf 基于PyELFTools的ELF文件靜態(tài)加載器 不需要
pe 基于PEFile的靜態(tài)PE文件加載器 不需要
mach-o Mach-O文件的靜態(tài)加載器,不支持動態(tài)鏈接或者變基 不需要
cgc Cyber Grand Challenge系統(tǒng)中的二進(jìn)制文件的靜態(tài)加載器 不需要
backedcgc 允許指定內(nèi)存和寄存器支持的CGC二進(jìn)制文件靜態(tài)加載器 不需要
elfcore ELF核心轉(zhuǎn)儲文件的靜態(tài)加載器 不需要
ida 啟動ida來分析文件 需要
blob 按照平坦模式加載文件到內(nèi)存中 需要

關(guān)于表中提到的CGC,這個youtube視頻展示了什么是CGC,簡單來說就是一個簡化的操作系統(tǒng),這個系統(tǒng)構(gòu)建的目的主要是用于CTF比賽中供各隊伍使用自己的AI來自動化分析和尋找這個簡化的系統(tǒng)上運行的程序的漏洞,CGC比賽是CTF的另一種形式。

符號函數(shù)摘要集(Symbolic Function Summaries)

譯者注:這里的“摘要”不是指對符號函數(shù)的一個概括和總結(jié),而是符號執(zhí)行中的一個概念

默認(rèn)情況下,Project都會嘗試用SimProcedures這個符號摘要集(symbolic summaries)替換主程序的外部調(diào)用。SimProcedure使用
pyhton函數(shù)高效地模擬外部庫函數(shù)對state的影響。我們已經(jīng)在SimProcedure中實現(xiàn)了一個完整的函數(shù)集
。這些內(nèi)建過程(procedures)能夠在angr.SIM_PROCEDURES字典中獲得,這個字典是一個兩層結(jié)構(gòu),第一層的鍵是包名(libc,posix,win32,stubs),第二層的鍵是庫函數(shù)的名字。用SimProcedure替代實際庫函數(shù)的執(zhí)行雖然存在一些潛在的不準(zhǔn)確性,但是可以讓你的分析更加可控,

當(dāng)找不到某個函數(shù)的摘要時:

  • 如果auto_load_libs的值為True(默認(rèn)值),那么真正的庫函數(shù)就會被執(zhí)行。這可能是你想要的,也可能不是,取決于實際的函數(shù)是什么。比如說,一些libc函數(shù)十分復(fù)雜,難以分析,并且極有可能導(dǎo)致用于確定執(zhí)行的路徑的狀態(tài)數(shù)爆炸。

  • 如果auto_load_libsFalse,那么外部函數(shù)就是“未解析”的狀態(tài),并且Project對象將會將它們解析為叫做ReturnUnconstrained的通用“stub” SimProdurce。就如它的名字所描述的:每次這個符號被調(diào)用,它都會將一個唯一的無約束符號作為返回值。

  • 如果use_sim_procedures(這是angr.Project的參數(shù),不是cle.loader的參數(shù))是False(默認(rèn)是True),那么只有外部對象提供的符號才會被SimProcedures替代,并且他們將會被一個ReturnUnconstrainedstub替代。

  • 你可以給angr.Project傳以下參數(shù)來指定一個不想被SimProcedure替代的符號:
    exclude_sim_procedures_listexclude_sim_procedures_func。

  • 查看angr.Project._register_object的源碼來獲取精確的算法。

鉤子(Hooking)

angr使用python函數(shù)摘要替換庫函數(shù)代碼的機制叫做Hooking,而且你也可以這么做!在執(zhí)行一次模擬(simulation)時,每一步執(zhí)行angr都會檢查當(dāng)前地址是否被下了鉤子(hooked),并且如果檢查到鉤子,就會執(zhí)行鉤子函數(shù),而不是那個地址里的二進(jìn)制碼。使用APIproj.hook(addr,hook)可以完成hook,這里參數(shù)中的hook是一個SimProcedure實例。你可以用.is_hooked,.unhook.hook_by屬性來管理你project中的鉤子,這些屬性的含義就如字面的意思,這里就不解釋了。

通過把proj.hook(addr)作為一個函數(shù)裝飾器(function decorator)。,你可以指定你自己的函數(shù)作為hook函數(shù)。如果你這么做了,你還可以指定一個可選的關(guān)鍵詞參數(shù)length來決定在你的hook函數(shù)執(zhí)行結(jié)束之后,程序跳過多少字節(jié)的機器碼再繼續(xù)執(zhí)行。

markdown-img-paste-20180117201920962.png

此外,你可以使用proj.hook_symbol(name,hook),提供一個符號名稱作為第一個參數(shù),這樣第二個參數(shù)指定的鉤子函數(shù)會被下到這個符號被調(diào)用的每個地址中。它的一個很重要的用途是用來擴展angr的內(nèi)建庫SimProcedure的行為。因為這些庫函數(shù)僅僅是一些類,你可以寫它們的子類,重寫它們的方法,并且把這些子類使用在hook中。

譯者注:hook_symbol的使用方法如下

markdown-img-paste-20180117214311252.png

So far so good!!

到目前為止,你應(yīng)該在CLE加載器和angr Project的級別上對如何控制你分析時的環(huán)境有了一個理性的認(rèn)識。你應(yīng)該還理解了angr采用了一個合理的方式來簡化它的分析:通過hook復(fù)雜的庫函數(shù),用SimProcedure這樣的只在總體上表現(xiàn)庫函數(shù)產(chǎn)生的影響的對象替代它們。

為了弄清使用CLE加載器和它的后臺能做的所有事情,你可以查閱CLE的API文檔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容