so加載—relocate篇
https://xrefandroid.com/android-10.0.0_r47/xref/bionic/linker/linker.cpp
relocate分析只保留relocate中與arm64有關的部份,刪除了其他架構&tls相關的東西。
relocate做了以下事情:
調用soinfo_do_lookup獲取類型為ElfW(Sym)的s。
將s傳入resolve_symbol_address函數,它會返回對應符號的地址sym_addr。
最後會根據不同的重定向類型來進行重定向,主要分為3類R_GENERIC_JUMP_SLOT、R_GENERIC_GLOB_DAT、R_GENERIC_RELATIVE。
reloc指向待重定向的地址,根據不同的重定向類型,修改為不同的值。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 ...
【N1CTF2024】ezapk
前言久違的看看安卓題,順便水一篇文章,有任何問題歡迎指出!
分析java層拉入jadx,很容易可以定位到關鍵邏輯,經典的加密對比。
加密函數enc在native層,而且加載了2個so。
嘗試分別將2個so都拉入ida,但都未發現enc,顯然是動態注冊的。
網上抄的一個frida腳本,用來hook動態注冊的native函數
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849// com.n1ctf2024.ezapkfunction find_RegisterNatives(params) { let symbols = Module.enumerateSymbolsSync("libart.so"); let addrRegisterNatives = null; for (let i = 0; i < symbols.length; i++) { let symbol = s ...
淺談Cocos2djs逆向
前言簡單聊一下cocos2djs手遊的逆向,有任何相關想法歡迎和我討論^^
一些概念列出一些個人認為比較有用的概念:
Cocos遊戲的兩大開發工具分別是CocosCreator和CocosStudio,區別是前者是cocos2djs專用的開發工具,後者則是cocos2d-lua、cocos2d-cpp那些。
使用Cocos Creator 2開發的手遊,生成的關鍵so默認名稱是libcocos2djs.so
使用Cocos Creator 3開發的手遊,生成的關鍵so默認名稱是libcocos.so ( 入口函數非applicationDidFinishLaunching )
Cocos Creator在構建時可以選擇是否對.js腳本進行加密&壓縮,而加密算法固定是xxtea,還可以選擇是否使用Zip壓縮
libcocos2djs.so裡的AppDelegate::applicationDidFinishLaunching是入口函數,可以從這裡開始進行分析
Cocos2djs是Cocos2d-x的一個分支,因此https://github.com/cocos2d/co ...
自實現Linker加載so
前言前一陣子在研究so加固,發現其中涉及自實現的Linker加載so的技術,而我對此知之什少,因此只好先來學習下Linker的加載流程。
本文參考AOSP源碼和r0ysue大佬的文章( 不知為何文中給出的那個demo我一直跑不起來 )來實現一個簡單的自實現Linker Demo。
環境:Pixel1XL、AOSP - Oreo - 8.1.0_r81
Demo實現Linker在加載so時大致可以分成五步:
讀取so文件:讀取ehdr( Elf header )、phdr( Program header )等信息。
載入so:預留一片內存空間,隨後將相關信息加載進去,最後修正so。
預鏈接:主要處理.dynamic節的內容。
正式鏈接:處理重定位的信息。
調用.init、.init_array
Read利用open+mmap來將待加載的so文件映射到內存空間,存放在start_addr_中。然後調用Read函數來獲取ehdr、phdr等信息。
123456789101112int fd;struct stat sb;fd = open(path, O_RDONLY);fstat(fd ...
初窺ARM平坦化還原
前言上周在看DASCTF的題發現難得有一道安卓( 題目名:RealeazyRealeazy ),興致勃勃地打開IDA卻發現了這可悲的控制流平坦化,當場直接自閉…
之後分析了下發現這ollvm應該算是比較簡單的那類( 只有間接跳轉 + 最普通的平坦化,貌似沒有虛假分支/虛假塊 ),於是決定好好地學習下怎麼還原。
一開始是想按「使用unidbg还原标准ollvm的fla控制流程平坦化」一樣使用Unidbg來還原,後面發現分支的情況用Unidbg不太好處理。
最後還是決定用Unicorn的模擬執行來還原,具體思路&實現完全參考「[原创]ARM64 OLLVM反混淆」。
還原思路利用Unicorn來模擬執行,從而獲取程序的執行流程,主要有以下步驟:
識別&保存函數所有的真實塊,有兩種識別思路,要麼通過真實塊的特徵,要麼通過非真實塊的特徵,看哪種特徵比較明顯,對本例來說真實塊有個明顯的特徵就是mov pc, r0這樣的間接跳轉。
模擬執行並保存執行路徑,遇到分支時就手動修改寄存器的值來遍歷( 本例沒有虛假分支,不用考慮太多,直接2條分支都執行就可以 )。模擬執行過程中遇到bl ...
so加載流程分析
前言同樣是在研究360加固,對so加載的理解不夠深刻,特此分析記錄完整的so加載流程。
注:分析的AOSP版本是Oreo8.1.0_r33。
So加載流程System.loadLibrary與System.loadloadLibrary:傳入的是一個so的名稱,如libtest.so,這個so通常位於/data/app/<pkg>/lib/<arch>下。
load:傳入的是so的絕對地址。
兩者的執行流程其實沒有太大差異,最終都會調用Runtime_nativeLoad,本文以System.load作為起始點,一步一步分析下去。
1234567891011// libcore/ojluni/src/main/java/java/lang/System.java@CallerSensitivepublic static void loadLibrary(String libname) { Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);}@C ...
elf文件結構
前言在研究360加固時,發現自己對elf文件完全不理解,於是決定先好好學下elf文件結構。
本文以AOSP版本Oreo8.1.0_r33作為研究對象,由上到下逐漸解析一個so文件。
Elf Header32位elf文件的Elf Header的結構體是Elf32_Ehdr,64位基本一致,除了e_ident[4]。
同時也列出一些會用到的常量( 宏定義/枚舉值 )如下:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556/*=================== art/runtime/elf.h ===================*/struct Elf32_Ehdr { unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes Elf32_Half e_type; // Type of file (see ET_* below) ...
ollvm_bcf_anti
一、通過IDA Python Patch思路1:直接patch用到不透明謂詞的地方原理說明:
所謂不透明謂詞是指在跳轉前就已經確定的表達式,但IDA無法分析。
通過對不透明謂詞進行交叉引用會發現,沒有任何一處是賦值,全都是LDR,而且這些不透明謂詞通常會定義在.bss段,默認值為0。
下圖的x_70是一個不透名謂詞,通過上述分析可以知道它其實永遠都為0,但可惜IDA不知道。
因此patch的目標就是直接將其賦為0,讓IDA可以分析出來。
觀察匯編代碼可以發現,x_70最終通過LDR W9, [X9]賦給W9寄存器。
因此只需要將其修改成mov w9, 0即可
最後的問題就是如何從LDR W9, [X9] → mov w9, 0?
通過IDA的Keypatch插件不斷修改來發現機械碼的變化規律,如下所示:
12345678910111213# 40 B9 代表 ldr reg1, [reg2]# 第1、2字節要合起來用小端來看(記作num)# reg2 + 1 -> num += 0x20# reg1 + 1 -> num += 1LDR W0, [X0] -> ...
B站sign算法分析
Target目標是如下的sign參數,很多接口都需要這個參數,隨即找一個來分析就可以
關鍵點定位方法一:字符串搜索不能直接搜sign,因為會出現很多結果,難以肉眼看出。
要嘗試這樣搜索:"sign、sign"、sign=、&sign
最終可以定位到com.bilibili.nativelibrary.LibBili類的s函數,是一個native方法,在libbili.so中。
參數是自定義的類型SortedMap,其實傳入TreeMap就可以
方法二:hook HashMap這個方法是從這篇文章學來的 → https://blog.csdn.net/xmx_000/article/details/134123902
原理:
猜測sign值大機率是其餘參數的簽名,而且請求參數的鍵值對通常都會以HashMap( 其他Map都有可能? )來保存,因此hook HashMap再打印調用棧就能快速定位到指定位置。
這裡選擇用於判斷的鍵值是ad_extra而不是sign( ad_extra是接口其中一個請求參數 ),因為sign這個詞太常見,選擇一個較為少見的參數 ...
【Unity+lua手遊逆向】道友掛機嗎
分析查看lib目錄,發現libil2cpp.so、libunity.so、libtolua.so,由此可以判斷是Unity + lua的組合。
第一步必然是要將dump.cs搞下來,以下兩種方式都可以:
常規操作 ( 這樣方式可以獲得更多信息 )
frida-il2cpp-bridge ( 只能dump下來dump.cs )
配合dump.cs的信息嘗試trace libil2cpp.so的一些類和方法,但發現具體邏輯應該是調用lua腳本實現的。
嘗試尋找APK目錄下是否存在lua腳本,發現/assests/lua。
在assets目錄下有一些.assetbundle文件,這些是Unity的一些資源打包成assetbundle ( 簡稱ab包 )的形式。
.assetbundle文件開頭是"UnityFS"標誌。 ( 後面會用到這點 )
進入lua目錄,也有一堆.assetbundle文件,但是用010Editor來查看會發現與上述正常的.assetbundle文件完全不一致。
因此合理懷疑這些就是被加密打包後的lua腳本。
解密lua腳本思路一:ho ...