首页
社区
课程
招聘
[原创] 某盾so加固與修復
发表于: 4天前 5202

[原创] 某盾so加固與修復

4天前
5202

packagename:Y29tLmhlcm8uc20uYW5kcm9pZC5oZXJv
聲明:本文內容僅供學習交流之用

很久之前看過乐佬的那篇「误入虎穴,喜得虎子——记一次手游加固的脱壳与修复」,寫得實在太好,奈何當時水平有限,看得兩眼一黑。

最近重溫經典時發現兩眼不再發黑,於是打算好好復現一下,這才有了這篇文章。

libil2cpp.so拉入IDA,直接報了一個錯,這時大概就可以知道這個so被動了手腳。

ctrl+s沒有發現.init_array,改為用readelf工具,發現.init_array位於0x5953a50

但發現0x5953a50根本無法被解析被函數,像是被加密的樣子。

理論上來說第一個.init_array函數是無法被加密,因此這種情況大概率是IDA分析出了錯。

將shdr table置0,這樣IDA就會根據.dynamic來解析。

再次拉入IDA,這次init_array終於被正確解析了。

直接動調會發現一直觸發SIGCHILD信號,然後crash。

解決方案是直接忽略SIGCHILD信號:Debugger → Debugger options → Edit exceptions

注:每個init_array函數裡都有一堆花指令( junk_codeX ),可能會造成堆棧不平衡、無法F5的情況,使用IDA9.0可以無視這種情況,低版本( 7.7 )在動調1次後同樣可以無視這情況。

.init_array的第1個函數主要在初始化一些全局變量,以及打開/proc/self/maps做了一些檢查。

init_some_global_var實現如下,全是一些賦值操作:

接著看看open_maps_and_do_some_check

一開始是一些字符串解密操作,解密後會得到"/proc/self/maps"

隨後便是fopen + fgets + sscanf來遍歷/proc/self/maps,整體邏輯大概只是在檢查libc.so是否有執行權限。

看到/proc/self/maps本以為是一個檢測點,但實際上應該只是一些普通的安全檢查,防止程序崩潰之類的?

接下來分析.init_array的第2個函數。

一開始調用了do_something1,動調後發現它會先解密一段代碼,然後調用這段代碼( 同樣是一些全局變量的賦值操作 ),之後會把這段代碼加密回去。

然後調用get_dynamic獲取.dynamic段,為後面prelink_imagedecrypt_str_sym做準備。

看看get_dynamic的實現方式。

一開始的while循環並不會走,也看不懂在干什麼 ( 不重要 )

然後是解析elf header,獲取了e_phnum、phdr table( 段表 )的起始位置等信息。

注:在分析時最好是動調配合010來看,能更好地弄清楚每個變量的含義。

然後會遍歷phdr table,*(_DWORD *)phdr獲取的是phdr的p_type成員,1代表PT_LOAD ( 可加載的段 )。

這裡是在遍歷所有Loadable Segment,記錄第1個Loadable Segment的起始位置( 通常是0 )和最後一個Loadable Segment的結束位置。

最後才是獲取.dyncmic段的邏輯,同樣是遍歷phdr table,但這次的目標是PT_DYNAMIC(2),保存在res[6]中。

獲取完.dynamic後,會調用prelink_image

進入prelink_image後,會看到一大段switch…case語句,看過Android源碼的會發現這與/bionic/linker/linker.cpp裡的prelink_image十分相似,做的事情也差不多,都是利用.dynamic的信息來初始化si ( soinfo結構,用於表示一個內存中的so )。

這個加固的soinfo結構是魔改的,嘗試直接導入oacia大佬這篇文章的soinfo結構會發現完全對不上,需要手動調整,下圖是我手動調整soinfo結構後的結果,雖然無法完全還原,但也勉強能用,看起來也方便一點。

最後的while循環是在處理依據庫的部份,沒有仔細看,處理邏輯大概也與Android源碼差不多,會對每個依賴庫調用prelink_image

init_array_func2最後會調用decrypt_str_sym來解密字符串表和部份的符號表。

簡單分析後可以反推出decrypt_str_sym每個參數的含義:

然後可以選擇將解密後的數據dump下來回填到so中,或者手寫解密腳本進行解密。

這時再將解密後的so拉入IDA就能看到一些符號了,不再是一堆奇怪的字符串。

接下來分析.init_array的第3個函數,它也調用了do_something1,但進去沒走兩步就返回了。重點關注do_something2

do_something2函數可以分成3大部份:

接下來重點看看第1部份加載子so的邏輯。

加載子so的第一步是先解密子so的一些數據,在decrypt_phdr_loadable_seg中分別調用了2次解密函數解密兩段不同的密文。

第1次調用解密函數解密出來的信息包含子so的phdr table、符號表、重定向表、dynamic表。而第2次調用解密函數解密出來的數據不太確定有什麼用,可能會跟後面提到的loadable_data1有關。下面來具體看看這整個過程。

進入decrypt_phdr_loadable_seg後,忽略一些不重要的部份,之後第一個遇到的函數是decrypt_something2,這就是上面提到的解密函數。

進入decrypt_something2可以看到明顯的RC4的特徵,而且是魔改過的RC4。具體的算法細節我沒有細看,我關注的是解密後的結果,因此選擇直接將解密後的數據dump下來。

args[0]是密文、args[2]用來存放解密後的明文、args[3]args[2]的長度,將dump下來的文件名記為dec_data1

注:IDA Python dump memory script

dump出來的dec_data1如下:

一開始無法直接知道dec_data1每部份的含義,我是由後續的分析反推出dec_data1分成4個部份的。

調用decrypt_phdr_loadable_seg解密完子so所需的數據後,會調用load_realso_PTLOAD來加載子so的所有loadable段。

一開始會先保存殼so的phdr,然後獲取殼so的大小。

繼續向下看,看到56這個數字可以大概猜到是在遍歷phdr table( 子so的phdr table ),而1代表PT_LOAD,因此這裡是在遍歷所有loadable的段,並計算段的映射地址和大小。

子so的phdr如下,複製前3行然後在dec_data1裡搜,會發現與dec_data1的前3行一樣,由此可知dec_data1的第1部份是子so的phdr信息。

然後會調用mmapfd的內容映射到子so的loadable段的內存起始地址,基址是殼so的起始地址,fd是殼so的句柄。即最終是在殼so的基礎上進行修正,將殼so的某些位置修正為子so的代碼段和數據段。

然後調用mprotect設置段的權限,調用memset將段置為0xBB

之後調用的memcpy才會真正將解密後子so的loadable段數據複製到對應的位置,然後會將多餘的內存空間置0

子so第1個loadable段如下,dump下來,記為loadable_data1

( loadable_data1的頭4個字節7F B2 B3 0F其實是代表子so的魔數,前0x40字節是elf_header區域,接著的0x188個字節是殼的phdr table區域,這兩部份數據沒有用,直接刪掉,後面提到的loadabe_data1均不包含這兩部份 )

子so第2個loadable段如下,記為loadable_data2

子so總共只有這兩個loadable段,一個是代碼段、一個是數據段,可從子so的phdr table來區分哪個是代碼段或數據段。

注:殼so的第1個loadable段的p_memsz特意設置得很大,就是為了讓子so的loadable_data2裝載於此。

最後會再調用一次mprotect將段設置回原本的權限。

調用完load_realso_PTLOAD裝載子so的loadable段後,會進行兩次的prelink_image。

第一次prelink_image用的.dynamic數據是殼so的,這是因為子so的一些基礎信息是依賴於殼so的。具體獲取.dynamic和prelink_image的過程在上面已經分析了,就不再重複。

第二次調用prelink_image用的.dynamic數據才是子so的。

複製第一行然後在dec_data1裡搜,發現dec_data1最後一部份就是子so的.dynamic。

子so完成兩次prelink_image後,會調用maybe_init_somethingdecrypt_something3,調了好幾遍都沒搞清楚這2個函數具體在干什麼,猜測大概與後面的do_relocate有關。

接著調用do_relocate進行重定向。

do_relocate會根據relaplt_rela的信息調用relocate進行重定向,本例沒有plt_rela,只需關注rela即可。

在調用relocate前先將rela dump下來,為後續修復so做準備。

注:dump下來的rela同樣可以在dec_data1中搜到,起始位置為0x1700

簡單分析relocate後會發現,它與Android源碼的relocate其實大同小異。

簡單解釋下so重定向的原理。

重定向表每個元素都是如下結構,r_info的高4位代表sym( 符號表索引 )、低4位代表type( 重定向類型 )。

個人總結出重定向大致可以分為2種情況:

下面藍框是一組真實數據:

最終重定向過程表現為:

下面藍框是一組真實數據:

最終重定向過程表現為:

relocate中查找符號地址的過程如下:

symtab_如下,同樣可以在dec_data1中找到,這代表子so有自己的符號表( 這樣說是因為字符串表用的是殼so的 )。

至此可以總結出dec_data1的分佈如下:

通過上述分析可以知道,子so的phdr table、符號表、重定向表、dynamic等信息只有在使用時才會從其他地方讀取來使用,因此整體dump so變得沒有太大意義。

而子so與殼so會共用一些基礎信息,因此不能單單重建子so,而是要在殼so的基礎上修正成子so。

注:使用解密字符串表、符號表後的殼so作為外殼,該外殼記為libil2cpp_str_sym.so

以下提取的數據也是從libil2cpp_str_sym.so中提取。

提取libil2cpp_str_sym.so的符號表,記為orig_sym


[注意]APP应用上架合规检测服务,协助应用顺利上架!

收藏
免费 17
支持
分享
最新回复 (13)
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
大佬,感谢更新,实力杠杆的
4天前
0
雪    币: 1904
活跃值: (1505)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
mb_ldbucrik 大佬,感谢更新,实力杠杆的[em_065]
4天前
0
雪    币: 162
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
佬app占坑了IDA附加不上去咋辦
3天前
0
雪    币: 1904
活跃值: (1505)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
北袅 佬app占坑了IDA附加不上去咋辦[em_064]
不知道, 試試patch掉它占坑的邏輯吧
3天前
0
雪    币: 270
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
厉害 大佬对so结构的掌握简直是登峰造极啊 现在大厂的so基本都是这么保护处理的 自己实现linker 父子so 共用section 父子so相互依赖 dump确实没有意义 只能解密修复符号信息 合并处理 但很多人都是没有实现 没想到大佬竟然成功了 牛逼  
3天前
0
雪    币: 270
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
期待大佬对大厂签名校验的分析!哈哈
3天前
0
雪    币: 1904
活跃值: (1505)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
软件君子 厉害 大佬对so结构的掌握简直是登峰造极啊 现在大厂的so基本都是这么保护处理的 自己实现linker 父子so 共用section 父子so相互依赖 dump确实没有意义 只能解密修复符号信息 合并 ...
主要還是乐佬的那篇文章寫得好, 跟著復現罷了, 最後的so修復也只能算半成功而已
3天前
0
雪    币: 102
活跃值: (2230)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
这是啥游戏啊,找遍了那个包名都没找到啊,创造XXX?
3天前
0
雪    币: 1904
活跃值: (1505)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
koflfy 这是啥游戏啊,找遍了那个包名都没找到啊,创造XXX?
3天前
0
雪    币: 103
活跃值: (2043)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
有毅力,有恒心,牛!大佬能否录制个视频复现一下,让我们这些小白能更直观的跟一遍整个流程
2天前
0
雪    币: 1904
活跃值: (1505)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
azd放 有毅力,有恒心,牛!大佬能否录制个视频复现一下,让我们这些小白能更直观的跟一遍整个流程
錄視頻就算了, 有什麼問題大家一起討論下就好了
2天前
0
雪    币: 1794
活跃值: (3011)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
13
2天前
0
雪    币: 38
活跃值: (1975)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
大佬牛的
1天前
0
游客
登录 | 注册 方可回帖
返回
// // 统计代码