映像劫持“IFEO”(Image File Execution Options)詳解
“映像劫持”,也被稱為“IFEO”(Image File Execution Options,其實應該稱為“Image Hijack”,至少也應該稱為IFEO Hijack而不是只有“IFEO”自身!),它的存在自然有它的理由,在WindowsNT架構的系統裡,IFEO的本意是為一些在默認系統環境中運行時可能引發錯誤的程序執行體提供特殊的環境設定,系統廠商之所以會這麼做,是有一定歷史原因的,在Windows NT時代,系統使用一種早期的堆棧Heap,由應用程序管理的內存區域)管理機制,使得一些程序的運行機制與現在的不同,而後隨著系統更新換代,廠商修改了系統的堆棧管理機制,通過引入動態內存分配方案,讓程序對內存的占用更為減少,在安全上也保護程序不容易被溢出,但是這些改動卻導致了一些程序從此再也無法運作,為了兼顧這些出問題的程序,微軟以“從長計議”的態度專門設計了“IFEO”技術,它的原意根本不是“劫持”,而是“映像文件執行參數”!
IFEO 設定了一些與堆棧分配有關的參數,當一個可執行程序位於IFEO的控制中時,它的內存分配則根據該程序的參數來設定,那麼如何使一個可執行程序位於 IFEO 的控制中呢?答案很簡單,Windows NT架構的系統為用戶預留了一個交互接口,位於註冊表的“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options”內,使用與可執行程序文件名匹配的項目作為程序載入時的控制依據,最終得以設定一個程序的堆棧管理機制和一些輔助機制等,大概微軟考慮到加入路徑控制會造成判斷麻煩與操作不靈活的後果,也容易導致註冊表冗余,於是IFEO使用忽略路徑的方式來匹配它所要控制的程序文件名,例如IFEO指定了對一個名為“AAA.EXE”的可執行程序文件進行控制,那麼無論它在哪個目錄下,只要它名字還叫“AAA.EXE”,它就只能在IFEO的五指山裡打滾了。
說了半天都只是純粹的概念,那麼IFEO到底是怎麼樣發揮作用的呢?例如有一個程序文件名為“lk007.exe”,由於使用了舊的堆棧管理機制,它在新系統裡無法正常運行甚至出現非法操作,為了讓系統為其提供舊的堆棧管理機制,我們需要IFEO來介入,則需執行以下步驟:
1. 確保在管理員狀態下執行regedit.exe,定位到以下註冊表項:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
2. 在“Image File Execution Options”下建立一個子鍵,名為“lk007.exe”,不區分大小寫。現在確保位於HKEY_LOCAL_MACHINE\SOFTWARE\ Microsoft\Windows NT\CurrentVersion\Image File Execution Options\lk007.exe\下,建立一個字符串類型的註冊表項,名為“DisableHeapLookAside”,值為“1”
3. 再次運行lk007.exe查看運行情況,如果真的是由於堆棧管理機制引發的問題,則程序得以正常運行,否則該程序問題不屬於IFEO能夠干涉的範圍,或者需要嘗試搭配其他的參數使用。
目前已知的IFEO參數有:
ApplicationGoo
Debugger
PageHeapFlags
DisableHeapLookAside
DebugProcessHeapOnly
PageHeapSizeRangeStart
PageHeapSizeRangeEnd
PageHeapRandomProbability
PageHeapDllRangeStart
PageHeapDllRangeEnd
GlobalFlag
BreakOnDllLoad
ShutdownFlags
說白了,IFEO本質是系統廠商為某些可能以早期設計模式運行的軟件提供一種保全措施而設計出來的產物,並對其加以擴充形成了一套可用於調試程序的簡易方案,如“BreakOnDllLoad”參數可設定在載入某個DLL時設置斷點,便於程序員調試ISAPI接口;帶有“Range”字樣的幾個參數則用於限制堆的大小等。
而裡面有一個導致了今天這種局面的參數:Debugger。或許微軟當初的用意是便於程序員能夠通過雙擊某個設置了IFEO控制列表的執行體文件來直接調用調試器對其進行調試,而不用再通過繁瑣的打開調試器再進行文件載入來實現調試,提高了工作效率。
為了使得IFEO能夠影響到任何一個程序啟動請求,NT架構中將IFEO的優先權設置得很高,基本上,當用戶要求執行某個程序時,系統首先判斷該程序文件是否可執行體,然後就到IFEO的入口項進行文件名配對了,直到通過IFEO這一步後,進程才真正開始申請內存創建起來。
如果系統在IFEO程序列表裡匹配了當前運行的文件名,它就會讀取文件名下的參數,這些參數在未被人為設置之前均有個默認值,而且它們也具備優先權,“Debugger”的優先權是最高的,所以它是第一個被讀取的參數,如果該參數未被設置,則默認不作處理,如果設置了這個參數,情況就變得複雜了……
三. 罪魁禍首“Debugger”
前面大家應該都了解IFEO的本質了,從實際現象來說,把IFEO直接稱為“映像劫持”未免有點冤枉它了,因為裡面大部分參數並不會導致今天這種局面的發生,惹禍的參數只有一個,那就是“Debugger”,將IFEO視為映像劫持,大概是因為國內一些人直接套用了“Image File Execution Options”的縮寫罷,在相對規範的來自Sysinternals的專業術語裡,利用這個技術的設計漏洞進行非法活動的行為應該被稱為“Image Hijack”,這才是真正字面上的“映像劫持”!
Debugger參數,直接翻譯為“調試器”,它是IFEO裡第一個被處理的參數,其作用是屬於比較匪夷所思的,系統如果發現某個程序文件在IFEO列表中,它就會首先來讀取Debugger參數,如果該參數不為空,系統則會把Debugger參數裡指定的程序文件名作為用戶試圖啟動的程序執行請求來處理,而僅僅把用戶試圖啟動的程序作為Debugger參數裡指定的程序文件名的參數發送過去!光是這個概念大概就足夠一部分人無法理解了,所以我們放簡單點說,例如有兩個客人在一起吃自助餐,其中一個客人(用戶)委託另一個客人(系統)去拿食物時順便幫自己帶點食物回來(啟動程序的請求),可是系統在幫用戶裝了一盤子食物並打算回來時卻發現另一桌上有個客人(Debugger參數指定的程序文件)居然是自己小學裡的暗戀對象!於是系統直接端著原本要拿給用戶的食物放到那桌客人那裡共同回憶往事去了(將啟動程序請求的執行文件映像名和最初參數組合轉換成新的命令行參數……),最終吃到食物的自然就是Debugger客人(獲得命令行參數),至此系統就忙著執行Debugger客人的啟動程序請求而把發出最初始啟動程序請求的用戶和那盤食物(都送給Debugger客人做命令行參數了)給遺忘了。
在系統執行的邏輯裡,這就意味著,當一個設置了 IFEO項Debugger參數指定為“notepad.exe”的“iexplore.exe”被用戶以命令行參數“-nohome bbs.nettf.net”請求執行時,系統實際上到了IFEO那裡就跑去執行notepad.exe了,而原來收到的執行請求的文件名和參數則被轉化為整個命令行參數“C:\Program Files\Internet Explorer\IEXPLORE.EXE - nohome bbs.nettf.net”來提交給notepad.exe執行,所以最終執行的是“notepad.exe C:\Program Files\Internet Explorer\IEXPLORE.EXE - nohome bbs.nettf.net”,即用戶原來要執行的程序文件名iexplore.exe被替換為notepad.exe,而原來的整串命令行加上 iexplore.exe自身,都被作為新的命令行參數發送到notepad.exe去執行了,所以用戶最終看到的是記事本的界面,並可能出現兩種情況,一是記事本把整個iexplore.exe都作為文本讀了出來,二是記事本彈出錯誤信息報告“文件名不正確”,這取決於iexplore.exe原來是作為光桿司令狀態請求執行(無附帶運行命令行參數)的還是帶命令行參數執行的。
Debugger參數存在的本意是為了讓程序員能夠通過雙擊程序文件直接進入調試器裡調試自己的程序,曾經調試過程序的朋友也許會有一個疑問,既然程序啟動時都要經過IFEO這一步,那麼在調試器裡點擊啟動剛被 Debugger參數送進來的程序時豈不是又會因為這個法則的存在而導致再次產生一個調試器進程?微軟並不是傻子,他們理所當然的考慮到了這一點,因此一個程序啟動時是否會調用到IFEO規則取決於它是否“從命令行調用”的,那麼“從命令行調用”該怎麼理解呢?例如我們在命令提示符裡執行 taskmgr.exe,這就是一個典型的“從命令行調用”的執行請求,而我們在點擊桌面上、普通應用程序菜單裡的taskmgr.exe時,系統都會將其視為由外殼程序Explorer.exe傳遞過來的執行請求,這樣一來,它也屬於“從命令行調用”的範圍而觸發IFEO規則了。為了與用戶操作區分開來,系統自身加載的程序、調試器裡啟動的程序,它們就不屬於“從命令行調用”的範圍,從而繞開了IFEO,避免了這個加載過程無休止的循環下去。
從編程角度來說明“命令行調用”,那就是取決於啟動程序時CreateProcess是使用lpCommandLine(命令行)還是 lpApplicationName(程序文件名)來執行,默認情況下大部分程序員編寫的調用習慣是lpCommandLine——命令行調用
BOOL CreateProcess
(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes。
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
由於Debugger參數的這種特殊作用,它又被稱為“重定向”(Redirection),而利用它進行的攻擊,又被稱為“重定向劫持” (Redirection Hijack),它和“映像劫持”(Image Hijack,或IFEO Hijack)只是稱呼不同,實際上都是一樣的技術手段。
講解完Debugger參數的作用,現在我們來看看“映像劫持”到底是怎麼一回事,遭遇流行“映像劫持”病毒的系統表現為常見的殺毒軟件、防火墻、安全檢測工具等均提示“找不到文件”或執行了沒有反應,於是大部分用戶只能去重裝系統了,但是有經驗或者歪打正著的用戶將這個程序改了個名字,就發現它又能正常運行了,這是為什麼?答案就是IFEO被人為設置了針對這些流行工具的可執行文件名的列表了,而且Debugger參數指向不存在的文件甚至病毒本身!
以超級巡警的主要執行文件AST.exe為例,首先,有個文件名為kkk.exe 的惡意程序向IFEO列表裡寫入AST.exe項,並設置其Debugger指向kkk.exe,於是系統就會認為kkk.exe是AST.exe的調試器,這樣每次用戶點擊執行AST.exe時,系統執行的實際上是作為調試器身份的kkk.exe,至於本該被執行的AST.exe,此刻只能被當作 kkk.exe的執行參數來傳遞而已,而由於kkk.exe不是調試器性質的程序,甚至惡意程序作者都沒有編寫執行參數的處理代碼,所以被啟動的永遠只有 kkk.exe自己一個,用戶每次點擊那些“打不開”的安全工具,實際上就等於又執行了一次惡意程序本體!這個招數被廣大使用“映像劫持”技術的惡意軟件所青睞,隨著OSO這款超級U盤病毒與AV終結者(隨機數病毒、8位字母病毒)這兩個滅殺了大部分流行安全工具和殺毒軟件的惡意程序肆虐網絡以後,一時之間全國上下人心惶惶,其實它們最大改進的技術核心就是利用IFEO把自己設置為各種流行安全工具的調試器罷了,破解之道尤其簡單,只需要將安全工具的執行文件隨便改個名字,而這個安全工具又不在乎互斥量的存在,那麼它就能正常運行了,除非你運氣太好又改到另一個也處於黑名單內的文件名去了,例如把 AST.exe改為IceSword.exe。
小知識:互斥量
為了預防用戶簡單的更改一個文件名就使得大部分安全工具破籠而出,一些木馬還同時採用了一種被稱為“互斥量”的技術來徹底阻止安全工具運行。在系統裡,有一類特殊的系統對象被稱為“互斥量”(Mutex),它們的存在是為了減少系統開銷而設,例如一些工具在運行時會檢測是否已經有另一個自己的副本在運行,要做這種檢測最有效率的方法就是在第一次運行時創建一個互斥量,以後再運行時檢測即可,這實際上是很簡單的方法,因為系統會為我們保存已經創建的互斥量,直到程序請求銷毀互斥量,否則它將一直存在。這樣一來,問題又出現了,如果惡意程序掌握了一些安全工具的互斥量並偽造呢?這些安全工具就會因為檢測到“自身已經運行”而放棄繼續執行的權利,惡意程序就沒有剋星了。
而那些雙擊時明明程序文件就在眼前,系統卻報錯說“找不到文件”,又是什麼回事呢?這也是IFEO的另一種應用罷了,其秘訣是將Debugger參數指向一個不存在的文件位置,這樣系統就會因為找不到這個調試器而無法順利執行下去,如果系統老老實實報出“找不到調試器”的錯誤提示那倒還好了,但就不知道微軟是出於對IFEO這個東西存在的事實掩蓋還是什麼苦衷,卻死活不肯承認是Debugger指向的調試器不存在導致的錯誤,而是把已經被“變異”成為命令行參數無法進入系統創建進程機制的原執行請求作為“找不到的文件”給報了回去,於是未曾了解過IFEO的用戶只能莫名其妙的看著眼前就存在而系統“不承認” 的安全工具發愣了。
