IDA故障排除過程記錄
由于IDA閉源,又加上其十分無效的官方文檔(指和代碼無異,代碼也沒有注釋,文檔也沒有注釋)。因此如果出現任何錯誤,都需要進行分析和查錯,這一過程很麻煩。于是我在這里給出逆向IDA錯誤代碼的方法。本文可以作為部分錯誤的索引,也可以作為逆向一個大型軟件的初學者教程。
也算是久病成醫了,眾所周知越是容易發生的故障在要緊的時候越會發生。上次ciscn邊逆邊修ida,這次打完了,我就要看看ida到底抽什么瘋。
情景再現
你遇到了下述故障:

是的,這個故障沒有給出其他的信息。像這樣的“一刀砍死”的故障還有很多。


IDA的霸王條款是告訴你要么生成一個dump,然后關閉IDA,要么直接退出。于是你生成了dump文件。

按下確定之后,IDA就隨風而逝了。你氣急敗壞的不斷導入文件,但是IDA就是屹然不動。欸,錯誤修復了嗎?如修!
觀察故障的表和log,也沒有任何反饋。于是你開始去搜索。搜索的結果就是,沒有任何幫助。于是你來到了一片沒有知識的荒原。于是只好干回老本行,用逆向手段觀察這個錯誤是什么。簡稱,用IDA調試IDA。

安全模式
借鑒Windows的災難修復過程,程序的“安全模式”指的是關閉其他一切插件、附件,以最初的配置啟動IDA。因為你很明確在你第一次啟動IDA的時候這個程序運行是正常的,只是有一天你心血來潮看到了IDA的某個插件,于是你裝了第一個插件。于是你接著裝了第二個,第三個,直到今天這個可怕的錯誤爆發。
首先你要禁用所有plugin。將你的plugin文件夾按照日期排序,從新到舊移除你以前安裝的插件。

最終你發現,如果裝上紅框里的插件,這個錯誤就會出現。于是你鎖定了這個插件,修復這個插件就可以了。
修復的參考步驟將放在后文技術節。
未知bug
可是你沒有安裝任何插件,或者說這個bug如影隨形,根本不是插件引起的。于是我們進入Exception Analysis階段。
使用WinDBG打開導出的dump文件:

windbg大名鼎鼎,其威名必不用說。載入后,你會看到紅框部分的提示。
For analysis of this file, run !analyze -v
windbg的語法在此不表,雖然諸位不開發驅動或者硬件,但是windbg是推薦學一學的。根據上面的提示,我們按下這個超鏈接(或者鍵入指令)
!analyze -v
經過windbg的一頓操作,下面的輸出多了不少:

我們繼續向下翻:

在這里,記錄了發生錯誤的進程名稱和錯誤代碼。一般而言,根據規范引發的錯誤,尤其是經由RaiseException的錯誤,大多都應該返回一個有效的錯誤碼。這一點在Windows的藍屏分析上尤其重要。使用WinDBG分析BSOD錯誤也是這個思路,根據PROCESS NAME就可以分析錯誤應用,并由此大概可以猜測到底是什么故障了。
我們本寄希望于錯誤代碼能告訴我們就行發生了什么錯誤,但是奈何這個錯誤代碼0xe0424242根本狗屁不通。于是我們只好接著向下看。注意到接下來出現STACK TEXT。這里代表棧追蹤,用于指示程序在執行過程中發生異常或錯誤時的調用堆棧信息。系統的代碼調用路徑就顯示在堆棧跟蹤上。

堆棧跟蹤中顯示,調用鏈如下:
ida64_exe+0x17b002 -> ida64!init_database+0xe2d -> ida64!user2bin+0x4200 -> ida64!user2bin+0x681f -> ida64!interr+0x37 -> ida64!print_fpval+0x5bc2 -> ida64!verror+0x25 -> ida64_exe+0x53bd4 -> ida64_exe+0x57bf7 -> ida64_exe+0x58282 -> ida64_exe+0x56f16 -> KERNELBASE!RaiseException+0x69
那么回溯上去,我們可以從內存地址ida64!init_database+0xe2d開始看。打開IDA,注意到此時的被調用方為ida64,代表dll。載入dll,根據導出表找到init_database的基址。

計算init_database+0xe2d,追蹤到對應的內存位置。

由于棧底保留的是返回指針,即函數ret之后應該執行的下一條指令的位置,于是我們知道異常的發生應該在函數sub_101CA560內。

注意user2bin+0x4200位置的代碼,在往下追蹤之前,我們先看看這是干什么的。

根據提示字符串,這是在加載插件時出現故障了。
追蹤到sub_101CBC60函數內查看:

注意到這里發生錯誤(interr的條件為!v44 && *((char *)v40 + 144) < 0),很明顯v40是一個結構體。動態調試一下看:

分析過程不表,因為已經可以用動態調試的方法獲得參數,在這里給出函數的原型:
__int64 **__fastcall sub_5755BC60(__int64 a1, __int64 a2, char *file_path, int a4, unsigned __int16 a5, int a6, unsigned int a7)
其第三個參數file_path為加載的dll等一眾插件的地址。這里會對插件進行初始化。

其中參數v44為當前插件的代碼入口。

而v40+144我猜測是鏈表的next項。如果插件出現未卸載或者什么別的后卸載故障(例如內存未回收等),那么這里的代碼入口和下一表項可能出現為空、為負數的故障,因此引發錯誤,錯誤編號1827。
部分故障碼分析結果
有了上面的分析基礎,又加上ida本身并不進行反調試,因此可以搜索interr的函數調用,分析上下文,給出錯誤原因。
1491
IDA 7.0故障,已經在后續版本中被修復了。
這個故障由 IDA Pro 中的winbase_debmod.cpp( Windows 調試器模塊)引發。這段代碼的目的是向ntdll_vec_t類型的容器中添加一個新的ntdll_range_t元素。
// winbase_debmod.cpp
// Line 388
// ......
bool ntdll_vec_t::add(eanat_t addr, size_t sz, HANDLE h)
{
if ( has(addr) )
return false;
// max number of ntdlls: ntdll32.dll and ntdll.dll
//QASSERT(1491, size() < 2);
ntdll_range_t &r = push_back();
r.start = addr;
r.end = addr + sz;
r.handle = h;
return true;
}
reference
該函數ntdll_vec_t::add()在調試器模塊中用于添加對應的 ntdll(NT DLL)庫的信息。這段代碼包含了一個斷言(assertion)QASSERT(1491, size() < 2),它的作用是確保容器中的元素數量不超過 2。如果當前容器中的元素數量已經達到或超過 2,那么這個斷言將會觸發一個錯誤(error)編號為 1491。
根據提供的信息,為了解決在 Windows 10 的版本大于 16xxx 下使用 IDA Pro 7.0 時的問題,建議注釋掉這個斷言或者通過修復二進制文件來禁用這個檢查。
40343
此故障屬于Qt界面方面的故障,根據調試信息:

這里會進入選擇架構框:

根據網上的教程,引發此錯誤的原因應該是由于路徑中出現寬字符(例如中文),導致qword_7ff755247b70對應的參數(即支持的架構數量)歸零,然后選中的架構又高于0,于是引發了40341錯誤。
1203
來源:origin
由于版本是6.8,已經老舊到近10年了,這個報錯很可能已經被消除了,因此在此不表。如果確實有大哥2024年還在用2014年的工具....升級一下ida吧
40178
BUGFIX: debugger: using instant debugger for debugging a 32bit MacOSX application could cause internal error 40178
IDA: What's new in 6.4 (hex-rays.com),早在6.4版本就修復了MACOSX的故障。
520
BUGFIX: Leaving a mark, and then right-clicking on the address of an instruction could cause IDA to INTERR with the code 520
IDA: What's new in 6.9 (hex-rays.com),雖然聽上去520,但是這是一個bug,已經在6.9版本修復了。
1827
分析過程不表,插件出現故障。修復的方法是修改插件的加載flag。(目前不確定是否100%有效,Use at your own risk)。

這里插播一個小知識:
◆PLUGIN_MOD (0x0001): 表示插件可以修改IDA的狀態或行為。◆PLUGIN_DRAW (0x0002): 表示插件可以在IDA的圖形界面上進行繪圖或顯示自定義圖形。◆PLUGIN_SEG (0x0004): 該標志在IDA 7.0之前使用,現在已被棄用,不再使用。◆PLUGIN_UNL (0x0008): 該標志在IDA 7.0之前使用,現在已被棄用,不再使用。◆PLUGIN_HIDE (0x0010): 表示插件應該隱藏其界面,以便在加載時不顯示插件的任何用戶界面元素。◆PLUGIN_DBG (0x0020): 表示插件是一個調試器插件,用于與調試器交互。◆PLUGIN_PROC (0x0040): 表示插件是一個處理器模塊(Processor Module),用于支持特定的處理器架構。◆PLUGIN_FIX (0x0080): 表示插件是一個修復插件,用于修復IDA中的一些問題或提供額外的修復功能。◆PLUGIN_MULTI (0x0100): 表示插件是一個多實例插件,允許同時存在多個實例。◆PLUGIN_SKIP: 表示插件在初始化期間被跳過。◆PLUGIN_OK: 表示插件初始化成功。◆PLUGIN_KEEP: 表示插件在IDA關閉時保持加載狀態。這些常量用于設置插件的標志屬性,并根據插件的需求來定義其行為和特性。插件開發者可以根據需要選擇適當的標志來定義插件的行為。
PLUGIN_KEEP是一個IDA插件的常量,用于定義插件的行為和生命周期。具體來說,它指定了插件在IDA關閉時是否保持加載狀態。當插件被設置為PLUGIN_KEEP時,它將保持加載狀態,即使用戶關閉了IDA。這意味著,在下次啟動IDA時,插件將繼續保持加載狀態,并自動運行。插件保持加載狀態的好處是,它可以在IDA重新啟動時無縫地恢復之前的狀態和設置。例如,如果插件負責維護一些用戶自定義的配置或數據,那么通過設置PLUGIN_KEEP,它可以確保這些數據在IDA關閉和重新打開后仍然可用。值得注意的是,插件的保持加載狀態并不意味著它會一直運行。插件的運行仍然取決于其初始化函數的調用時機和其他條件。
來源:ChatGPT
2028
遇到過一次,原因是在文件加載之前就調用了Strings窗口。

可能是出于安全性設計,因此修復方案也很簡單,別調用就行,這個也是插件故障。

聚銘網絡
中國信息安全
中國信息安全
信息安全與通信保密雜志社
商密君
一顆小胡椒
安全圈
安全圈
黑客技術和網絡安全
零零信安
看雪學苑
信息安全與通信保密雜志社