SG Input 软件安全分析之逆向分析
前言
通過本文介紹怎么對一個 windows 程序進行安全分析。分析的軟件版本為 2018-10-9 , 所有相關文件的鏈接
鏈接:https://pan.baidu.com/s/1l6BuuL-HPFdkFsVNOLpjUQ 提取碼:erml逆向分析
定位核心代碼
拿到一個軟件首先需要進行攻擊面的探測,即找到盡可能多的可以與程序進行交互的入口點,有數據交互的地方就有可能會出現漏洞。首先對軟件的功能做一個大概的了解,發現搜狗輸入法能夠安裝用戶自定義的皮膚,這是一個比較好的入口點,于是下面分析分析處理皮膚文件的邏輯。
先從官網隨便下個皮膚,然后拿 010editor 簡單看看能不能拿到一些有用的信息。
使用 binwalk 也沒有識別出文件格式,于是猜測應該是輸入法自己實現的格式。
后來在對皮膚相關的功能進行瀏覽的時候發現有皮膚編輯器這個軟件
https://pinyin.sogou.com/skins/design.php下載下來隨便創建一個皮膚,發現此時的皮膚格式為 zip 格式,雙擊也能正常安裝。皮膚編輯器的最近更新在 13 年,估計輸入法是為了做兼容,同時支持兩種格式的皮膚文件。
下載下來的皮膚雙擊就可以安裝,這樣的安裝方式我們不好定位具體安裝皮膚的程序,這時我們可以使用 api montor 監控當雙擊皮膚文件時系統所執行的命令,以便進行下一步的分析。
打開 api monitor , 然后打開皮膚文件可以監控到搜狗輸入法處理皮膚文件執行的命令
"C:\Program Files (x86)\SogouInput\SogouExe\SogouExe.exe" "C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe"-line 0 -border --appid=skinreg -list "C:\Users\XinSai\Desktop\test.ssf"通過使用 Procmon.exe 分析,其實最后調用
"C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -line 0 -border --appid=skinreg -install -c "C:\Users\XinSai\Desktop\test.ssf" -q -ef通過執行這條命令就可以把皮膚安裝到輸入法內部。
下面把 SGTool.exe 拖到 IDA 里面, 使用命令行選項來搜索字符串的交叉引用去找到相關的處理代碼。通過對命令行參數的交叉引用逐步向上追溯,在 0x07A04D0 發現程序會根據 appid 參數的值,決定下一步進行處理的函數
然后調試發現一直斷不到這,于是用 drrun 看看程序到底走了哪些路徑
drrun.exe -t drcov -- "C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -line 0 -border --appid=skinreg -install -c "C:\Users\XinSai\Desktop\test.ssf" -q -ef發現直接點擊 ssf 文件還是沒有進入這個分支。
經過不斷的嘗試 + 使用一些監控軟件,發現在關閉所有搜狗輸入法相關進程的情況下,雙擊 .ssf 文件,會首先使用
"C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -daemon開啟一個類似于服務器的進程,然后在使用
"C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -line 0 -border --appid=skinreg -install -c "C:\Users\XinSai\Desktop\test.ssf" -q -ef另外再起一個 SGTool.exe 的進程向剛剛啟動服務進程發送消息,后續的皮膚處理在服務進程進行。猜測可能是使用了 windows 本地通信機制實現 C/S 架構
后續在瞎試的時候,將一個非皮膚文件命名成 .ssf 后綴,然后雙擊會出現報錯信息。
根據這些字符串在 od 里面找,可以找到一些信息,最后通過對
皮膚解壓失敗:skin.ini不存在交叉引用, 然后不斷回溯, 發現了一個有趣的函數 0x07A72D0
這個函數首先 調用 0x7A84F0檢測了某些參數。
從我們的參數進行對比,猜測這里校驗的應該是最后那兩個參數
然后猜測 -q 應該是安靜模式,于是刪掉 -q 試了一試
發現居然會有提示框,那這個提示框的代碼附件應該離處理 皮膚文件的代碼更加近了。
對字符串交叉引用,發現其實就是上面的那個代碼(0x007A75DC)
所以從這里開始,應該就開始對皮膚文件進行處理了。
分析皮膚處理相關的代碼
經過不斷的調試以及查看函數調用的參數,發現當我們點擊 確認 的時候,會調用位于0x914980 的函數。
這個函數傳入的參數是一個對象指針,對象內部有我們皮膚文件的路徑,這個函數會對傳入的 皮膚文件 進行第一次的判斷。
函數首先會打開文件, 然后取出開頭的4個字節作為文件類型,判斷是不是Skin。如果是的話就認為是最新的皮膚格式然后進入后續的操作。
如果不是就認為是第一代皮膚格式 ,即用zip格式打包的皮膚。
調試時,可以看到 type 的值。 下面是打開的官網下載的皮膚文件,所以 type 為 Skin.
當皮膚文件的type值不為Skin時,程序會進入decompress_skin_ini (0x063F340), 這個函數里面會調用ziplib.dll 里面的函數對皮膚文件進行解壓,提取并解析skin.ini文件。
總的來說,0x914980 函數其實只是校驗了皮膚文件的版本信息,對于 文件頭 不是 Skin 的文件,則認為是第一代皮膚格式文件,然后會使用 ziplib.dll 里面的函數提取 skin.ini 文件并嘗試解析它。
在進行完第一次的校驗后,會回到 0x7A72D0, 將文件拷貝到用戶的皮膚保存目錄,然后對皮膚文件進行解析,提取出里面的文件。
其中 0x7A6230 deal_skin 就是解析皮膚文件的入口,它會調用 0x63E3F0 完成具體文件解析流程。
這個函數首先判斷文件頭 , 如果是 Skin , 表示為最新格式的皮膚文件
則通過 decompress_skinv3 0x053B320 進行解析并提取出皮膚包里面包含的文件。否則就認為是第一代皮膚文件, 使用 ziplib 里面的函數, 把皮膚包里面的文件解壓出來。
for ( i = v25 - 3; v28 < v27; ++v28 ) { ........................................................................................................................................................................................................................................................................if ( decompress_file_from_zip(v46, v65, &path, target, &len, &buf) ){v47 = len;if ( len <= 0x80000000 && len ){len = target;(*v51)(&v51, &len, 0);v48 = buf;v54 = v47;v53 = buf;sub_53ACE0(obj1, &v50, 0);// 做一些析構操作sub_49F5C0(ziplib_obj, v65, v47, v48);}v24 = v62;}........................................................................................................................................................................................................................................................................}下面對decompress_skinv3(0x053B320)進行分析,以便理解最新皮膚包的格式
首先打開皮膚包,讀取文件內容到內存,然后把文件內容,大小傳給 handle_skinv3 0x0053A8C0 進行處理。
通過對這個函數的逆向,可以明白.ssf文件開頭 8個字節的結構為 4字節的 Skin 和 4 字節的 version 字段
校驗完版本信息后, 會對文件頭部后的數據使用程序自己實現的算法進行解碼,然后對解碼之后的數據使用zlib再次解碼。
zlib 解碼完成后,把解碼后的數據傳入 0x53bf50 (調試時確認)對文件進行提取
這個函數對傳入的數據進行解析,提取出相關的文件
// 調用者 0x53AAE1 unsigned int __thiscall skin_v3_step2(int this, unsigned int *buf, unsigned int size, int a4) {len = *buf; // 取出 buf 開始的 4 個字節, 表示數據的長度if ( *buf > size )return -1;new_size = size - 4;sizea = size - 4;if ( *buf ){if ( (**(this + 4))(this + 4, buf + 1, new_size, a4) < 0 )// 調用0x53c110L,第 2, 3個參數為 buf + 4, size-4// 就是忽略掉頭4個字節// 函數作用復制 zlib 解碼后的數據 0x8-0x40 到對象里面do // 循環的從 zlib 解壓過的文件里面提取出文件{offset = *(v12 + 4 * v9);if ( offset < data_len ){v17 = (**v15)(cur, sizea, a4); // 調用 0x923f70L, 提取文件名if ( v17 < 0 )goto LABEL_19;v18 = &cur[v17];v19 = (*v22[3])(v18, sizea - v17, a4);// 調用的是 0x53c1c0L, 提取文件內容}++v9;}while ( v9 < v11 );文件格式匯總
老版本的皮膚格式
其實就是一個 zip 包, 里面有配置文件和一些圖片。
新版本的皮膚格式
首先是 .ssf 文件
開頭 8個字節為 4字節的 Skin 和 4 字節的 version
- 然后調用 0x0639610 對 文件偏移 8開始進行解碼, 解碼后的數據 A 偏移 4 字節開始 為 zlib 壓縮的數據。
- 然后對 A + 4 使用 zlib 解碼,得到 zlib 解碼后的數據 B
- 然后把 B 和 B 的長度傳入 0x53bf50 繼續處理
B 的結構為
開頭4個字節為數據的總長度
然后根據 0x53C110 , 后面緊跟著的 4 個字節為文件映射表的長度,即 0x38 字節。每一個表項4個字節,代表表項指示其所表示的文件在整個文件中的偏移地址。
如圖所示, 第一個表項的值為 0x40, 所以第一個文件應該在 0x40 處。
經過一定的觀察發現一個文件的表示方式為
- 4字節: 文件名的長度
- 文件名( unicode 編碼)
- 4字節: 文件數據的長度
- 文件數據
發現漏洞
分析完整個皮膚處理的代碼后發現整個代碼的邏輯還是不怎么復雜的。于是可以直接讀反編譯的代碼來找找看是否存在什么漏洞。在讀代碼找漏洞時重點關注緩沖區的操作, 內存的分配大小以及對文件中表示長度的字段的使用是否合理。
經過一番仔細的走查發現在對皮膚文件第一步用自己實現的解密算法解密后的開始 4 個字節為 deocded_data_size , 之后會把它加上 8 然后去分配內存。
deocded_data_size 是從解密后的文件中取出的,當把 deocded_data_size 改成 0xffffffff 時,在分配內存時會整數溢出導致分配比較小的內存塊,然后后續的代碼在使用這個緩沖區時會造成一個堆溢出。漏洞已于3個月前提交并修復。
總結
在分析軟件功能實現時,可以采用一些監控軟件比如 api monitor 來輔助定位關鍵代碼。一些程序中的提示,報錯信息也可以用來定位。最重要的就是多調試,多調試。程序從文件內容中取 size 時要注意校驗。
轉載于:https://www.cnblogs.com/hac425/p/10772834.html
總結
以上是生活随笔為你收集整理的SG Input 软件安全分析之逆向分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cookie经典案例—实现显示用户上次服
- 下一篇: Python-获取法定节假日