【原創】對Rav 2005中HOOK的初步分析
分析了半天,準備放棄了。不過因為和驅動有關,而且分析過程也和RE掛鉤,所以放上來給兄弟們看看。有知道的討論一下,沒有懂NT核心的作個參考,算廢物利用吧。
廢話幾句,記得Xtreme是用驅動的……寒一個……
===================================================================
對Rav 2005中HOOK的初步分析
昨天升級了一下RAV2004。本以為很快就完,但升級程式卻拖了近一個小時。啟動後發現,RAV已經被升級到了2005。這事本應該就這麼完了,但恰巧我對各種軟體的記憶體佔用非常敏感,弄了個empty.exe放在bat裡,定期清理一下記憶體。執行了一遍bat卻發現empty報錯,說無法清理ravmond.exe!於是本能地覺得有名堂。趕緊分析了一下empty。
從出錯資訊入手,可以找到下面的程式碼(註釋是我加的):
.text:01001603 loc_1001603:
.text:01001603 call sub_1001D1B
.text:01001608 mov eax, dword_12D3180 ; EAX裡應該是PID
.text:0100160D test eax, eax
.text:0100160F jz short loc_100163D
.text:01001611 push eax
.text:01001612 call sub_1001F2C ; 清理記憶體
.text:01001617 test eax, eax
.text:01001619 jnz short loc_1001636
.text:0100161B push dword_12D3180
.text:01001621 push offset aCouldNotEmptyW ; "could not empty working set for process"...
.text:01001626 call ds:printf
.text:0100162C pop ecx
OK,到sub_1001F2C去看看:
.text:01001F2C push ebp
.text:01001F2D mov ebp, esp
.text:01001F2F push ecx
.text:01001F30 push esi
.text:01001F31 push edi
.text:01001F32 push [ebp+MaximumWorkingSetSize] ; dwProcessId
.text:01001F35 xor edi, edi
.text:01001F37 push edi ; bInheritHandle
.text:01001F38 push 1F0FFFh ; dwDesiredAccess
.text:01001F3D call ds:OpenProcess
.text:01001F43 mov esi, eax
.text:01001F45 cmp esi, edi
.text:01001F47 jnz short loc_1001F4D
.text:01001F49 xor eax, eax
.text:01001F4B jmp short loc_1001F77
首先是以PROCESS_ALL_ACCESS許可權呼叫OpenProcess。但就是在這裡,esi=edi,跳到出口loc_1001F77。
好,於是寫段呼叫OpenProcess的程式。結果發現,對ravmond的操作結果是返回ERROR_INVALID_PARAMETER??!!但是我的引數沒有寫錯啊!然後開始懷疑bInheritHandle引數,但改了還是一樣。那麼,換PID。換了SMSS的PID,說沒有許可權,很正常。換delphi32的PID,可以正常開啟。那麼,就是說,引數絕對是正確的,只是RAV玩了個花樣。那樣,按照系統給的PID去找就找不到了。
既然這樣,那就拿RAV開刀。先翻了一下RAV的目錄,有幾個驅動檔案引起了我的注意:
Hooksys.sys
hookbase.sys
HOOKREG.sys
HookCont.sys
HookApi.sys
難道是OpenProcess被HOOK了?於是先在HookApi裡查import,沒有可疑的API。hookbase?Hooksys?HookCont?都沒有。
還是寫程式看看……GetProcAddress卻報告說沒有異常。
沒辦法,查詢ravmond吧……HOOKREG里居然有ravmond的字樣!改之,重新啟動RAV的服務,bingo!在工作管理員裡k程式時顯示沒有許可權!那麼很明顯是被HOOK了。
以前玩過rootkit(只是玩而已,寫不來),本來是應該想到的……
那麼反彙編HOOKREG,查詢ravmond的xref……在00011BEF有一個push,向上找到函式入口,得到整個函式:
.text:00011B74 sub_11B74 proc near
.text:00011B74
.text:00011B74 var_2C = dword ptr -2Ch
.text:00011B74 var_28 = byte ptr -28h
.text:00011B74 var_9 = byte ptr -9
.text:00011B74 var_8 = dword ptr -8
.text:00011B74 var_4 = dword ptr -4
.text:00011B74 arg_0 = dword ptr 8
.text:00011B74
.text:00011B74 push ebp
.text:00011B75 mov ebp, esp
.text:00011B77 sub esp, 2Ch
.text:00011B7A mov [ebp+var_2C], 0
.text:00011B81 mov [ebp+var_28], 0
.text:00011B85 call ds:IoGetCurrentProcess
.text:00011B8B mov [ebp+var_8], eax
//指向當前程式開頭的指標
.text:00011B8E mov eax, [ebp+var_8]
.text:00011B91 add eax, dword_12F48
//dword_12F48的真實偏移
.text:00011B97 mov [ebp+var_4], eax
.text:00011B9A mov ecx, [ebp+var_4]
.text:00011B9D push ecx
.text:00011B9E lea edx, [ebp+var_28]
//緩衝的長度是$1F
.text:00011BA1 push edx
.text:00011BA2 call strcpy
.text:00011BA7 add esp, 8
//複製
.text:00011BAA mov [ebp+var_9], 0
.text:00011BAE lea eax, [ebp+var_28]
.text:00011BB1 push eax ; char *
.text:00011BB2 call ds:_strupr
.text:00011BB8 add esp, 4
//大寫
.text:00011BBB cmp [ebp+arg_0], 0
.text:00011BBF jz short loc_11BD1
//若引數是0就走
.text:00011BC1 lea ecx, [ebp+var_28]
//dword_12F48的復件
.text:00011BC4 push ecx
.text:00011BC5 mov edx, [ebp+arg_0]
.text:00011BC8 push edx
.text:00011BC9 call strcpy
.text:00011BCE add esp, 8
//這樣看,引數應該是PChar
//引數非0就給個dword_12F48的復件
.text:00011BD1 loc_11BD1:
.text:00011BD1 push offset dword_11B50
.text:00011BD6 lea eax, [ebp+var_28]
.text:00011BD9 push eax
.text:00011BDA call strcmp
.text:00011BDF add esp, 8
.text:00011BE2 test eax, eax
.text:00011BE4 jnz short loc_11BEF
//和dword_11B50比較(RAV.EXE),若不等就繼續,否則返回2
.text:00011BE6 mov [ebp+var_2C], 2
.text:00011BED jmp short loc_11C41
.text:00011BEF loc_11BEF:
.text:00011BEF push offset dword_11B58
.text:00011BF4 lea ecx, [ebp+var_28]
.text:00011BF7 push ecx
.text:00011BF8 call strcmp
.text:00011BFD add esp, 8
.text:00011C00 test eax, eax
.text:00011C02 jz short loc_11C19
//和dword_11B58比較(RAVMOND.EXE),若相等就返回3,否則繼續
.text:00011C04 push offset dword_11B64
.text:00011C09 lea edx, [ebp+var_28]
.text:00011C0C push edx
.text:00011C0D call strcmp
.text:00011C12 add esp, 8
.text:00011C15 test eax, eax
.text:00011C17 jnz short loc_11C22
//和dword_11B64比較(RAVMON.EXE),若相等就返回3,否則繼續
.text:00011C19 loc_11C19:
.text:00011C19 mov [ebp+var_2C], 3
.text:00011C20 jmp short loc_11C41
.text:00011C22 loc_11C22:
.text:00011C22 push 3 ; size_t
.text:00011C24 push offset aRav ; char *
.text:00011C29 lea eax, [ebp+var_28]
.text:00011C2C push eax ; char *
.text:00011C2D call ds:strncmp
.text:00011C33 add esp, 0Ch
.text:00011C36 test eax, eax
.text:00011C38 jnz short loc_11C41
//檢查var_28的頭3個字元是否RAV,是就返回4,不是就直接返回
.text:00011C3A mov [ebp+var_2C], 4
.text:00011C41 loc_11C41:
.text:00011C41 mov eax, [ebp+var_2C]
.text:00011C44 mov esp, ebp
.text:00011C46 pop ebp
.text:00011C47 retn 4
.text:00011C47 sub_11B74 endp
我們可以看到,這個東西有點象call/pop的手法。好處就是可以不要資料段(反正特徵字串是隻讀的)。
那麼,這只是一個判斷。判斷dword_12F48是否含有特定的字串,若是RAV的核心就返回3,主程式返回2,外圍程式返回4,其他返回0。
那麼來看看sub_11B74的xref,有三處:11D27、119E6、115E2,對應的sub分別是sub_11D00、sub_119D0、sub_115BC。
sub_115BC有4個xref,全部是code引用,sub_119D0只有1個data引用的xref,而11D00,有3個xref,data引用。
先看11D00,xref全在start裡:
.text:00010453 8B 45 08 mov eax, [ebp+DriverObject]
.text:00010456 C7 40 38 00 1D 01+ mov dword ptr [eax+38h], offset sub_11D00
.text:0001045D 8B 4D 08 mov ecx, [ebp+DriverObject]
.text:00010460 C7 41 40 00 1D 01+ mov dword ptr [ecx+40h], offset sub_11D00
.text:00010467 8B 55 08 mov edx, [ebp+DriverObject]
.text:0001046A C7 82 80 00 00 00+ mov dword ptr [edx+80h], offset sub_11D00
下面就dump一下和DriverObject有關的程式碼(eax,ecx,edx都是臨時使用的):
.text:00010308 ; int __stdcall start(PDRIVER_OBJECT DriverObject)
.text:00010308 public start
.text:00010308 start proc near
.text:00010308
.text:00010308 var_64 = dword ptr -64h
.text:00010308 var_60 = dword ptr -60h
.text:00010308 SymbolicLinkName= UNICODE_STRING ptr -5Ch
.text:00010308 DeviceObject = dword ptr -54h
.text:00010308 DeviceName = UNICODE_STRING ptr -50h
.text:00010308 SourceString = word ptr -48h
.text:00010308 var_28 = dword ptr -28h
.text:00010308 DriverObject = dword ptr 8
.text:00010308
.text:00010308 55 push ebp
.text:00010309 8B EC mov ebp, esp
.text:0001030B 83 EC 64 sub esp, 64h
.text:0001030E 56 push esi
.text:0001030F 57 push edi
.text:00010310 C7 45 AC 00 00 00+ mov [ebp+DeviceObject], 0
.....
.text:0001036A 8D 55 AC lea edx, [ebp+DeviceObject]
.text:0001036D 52 push edx ; DeviceObject
.text:0001036E 6A 00 push 0 ; Exclusive
.text:00010370 6A 00 push 0 ; DeviceCharacteristics
.text:00010372 68 00 84 00 00 push 8400h ; DeviceType
.text:00010377 8D 45 B0 lea eax, [ebp+DeviceName]
.text:0001037A 50 push eax ; DeviceName
.text:0001037B 6A 00 push 0 ; DeviceExtensionSize
.text:0001037D 8B 4D 08 mov ecx, [ebp+DriverObject]
.text:00010380 51 push ecx ; DriverObject
.text:00010381 FF 15 DC 26 01 00 call ds:IoCreateDevice
.....
.text:000103BD 8B 45 08 mov eax, [ebp+DriverObject]
.text:000103C0 8B 48 04 mov ecx, [eax+4]
.text:000103C3 51 push ecx ; DeviceObject
.text:000103C4 FF 15 D4 26 01 00 call ds:IoDeleteDevice
.text:000103CA 8B 45 9C mov eax, [ebp+var_64]
.....
.text:00010453 8B 45 08 mov eax, [ebp+DriverObject]
.text:00010456 C7 40 38 00 1D 01+ mov dword ptr [eax+38h], offset sub_11D00
.text:0001045D 8B 4D 08 mov ecx, [ebp+DriverObject]
.text:00010460 C7 41 40 00 1D 01+ mov dword ptr [ecx+40h], offset sub_11D00
.text:00010467 8B 55 08 mov edx, [ebp+DriverObject]
.text:0001046A C7 82 80 00 00 00+ mov dword ptr [edx+80h], offset sub_11D00
.text:00010474 8B 45 08 mov eax, [ebp+DriverObject]
.text:00010477 C7 40 70 BF 1D 01+ mov dword ptr [eax+70h], offset sub_11DBF
.text:0001047E 8B 4D 08 mov ecx, [ebp+DriverObject]
.text:00010481 C7 41 34 68 05 01+ mov dword ptr [ecx+34h], offset sub_10568
就是填充PDRIVER_OBJECT,其他沒有什麼。這裡的大概意思是建立一個核心Device,然後定義幾個Function。問題是,這個驅動的Type是自定義的,而我又不懂Driver……
不過還好,119D0的xref有點意思:
.text:00010CBA mov eax, ds:ZwSetValueKey
.text:00010CBF mov ecx, [eax+1]
.text:00010CC2 mov edx, ds:KeServiceDescriptorTable
.text:00010CC8 mov eax, [edx]
.text:00010CCA mov dword ptr [eax+ecx*4], offset sub_119D0
那麼,這裡是修改ServiceDescriptorTable裡ZwSetValueKey的入口。聯想一下,應該是不允許修改RAVMOND服務的Key。
最後看看115BC,xref對應的sub有111A0,112F0,11360和119D0。而它們都是隻有一個data的xref,應該是function了:
.text:00010CD1 mov ecx, ds:ZwCreateKey
.text:00010CD7 mov edx, [ecx+1]
.text:00010CDA mov eax, ds:KeServiceDescriptorTable
.text:00010CDF mov ecx, [eax]
.text:00010CE1 mov dword ptr [ecx+edx*4], offset sub_111A0
.text:00010CE8 mov edx, ds:ZwDeleteValueKey
.text:00010CEE mov eax, [edx+1]
.text:00010CF1 mov ecx, ds:KeServiceDescriptorTable
.text:00010CF7 mov edx, [ecx]
.text:00010CF9 mov dword ptr [edx+eax*4], offset sub_11360
.text:00010D00 mov eax, ds:ZwDeleteKey
.text:00010D05 mov ecx, [eax+1]
.text:00010D08 mov edx, ds:KeServiceDescriptorTable
.text:00010D0E mov eax, [edx]
.text:00010D10 mov dword ptr [eax+ecx*4], offset sub_112F0
沒有什麼,都是常規的Reg讀寫。失望ing……
回頭再找,居然在Hooksys裡看見了ravmond!看來下次要用Hex editer了……用BIEW雖然方便,但很容易看漏的。而且,還犯了輕信IDA的錯誤……
OK,再看Hooksys!有了剛才的經驗,這次應該很簡單了。
很快發現字串'RAV.EXE'在11D70處。判斷子程式是sub_11ED4。但是居然沒有使用KeServiceDescriptorTable!而且驅動的Type是8300h,自定義。
下面就沒有什麼進展了。在網上搜了搜,發現有人問過類似的問題。不過他要知道的是如何完美地對檔案系統Hook。
不過可以肯定的是,RAV沒有使用常規的方法來Hook。有可能是透過FileSystem或自己直接計算記憶體地址來實現Hook的。
PS:在小四的站看了篇Hume的文章,講透過SEH獲取Ker32基址的。在IDA裡搜了搜,發現有
.text:00012CD9 mov eax, large fs:4
.text:00012CDF mov [ebp+VirtualAddress], eax
很可能就是這個了……暴力搜尋,然後改cr0,直接修改實體地址,完美Hook……猜測而已……
TMD簡直跟rootkit沒什麼區別了。隱蔽得一塌糊塗,拿來做rootkit連import也不要,想k的話就乖乖地從頭做逆向工程吧……不過做一遍也有好處,現在起碼對驅動有點了解了。以前?覺得象天書……
相關文章
- 標
題:avserve病毒初步分析!【原創】2004-05-02
- [原創]■■易格式初步研究筆記■■2004-11-01筆記
- [原創]Adobe reader 漏洞CVE-2009-4324初步分析2010-01-10
- 【原創】面試對白2011-10-24面試
- [原創]解讀天書----漏洞利用中級技巧的分析2014-02-19
- [原創]SQL Server 2005 映象構建手冊2010-12-03SQLServer
- MOM 2005 安裝設定初步2017-11-15
- [舊帖] [原創]檢測SSDT獲得hook rootkit驅動模組資訊2010-02-11Hook
- 原創:解決xp下安裝jbuider 2005的錯誤2005-03-15UIIDE
- [原創] KCP 原始碼分析(上)2024-03-15原始碼
- [原創] Linux 中的 nohup 與 &2018-11-29Linux
- [原創]流行防毒軟體對惡意PDF文件檢測的概括性分析2011-02-22防毒
- 對函式的初步瞭解2018-12-06函式
- [原創]破解-分析Crackme演算法2009-06-13演算法
- 【原創】需求分析之用例規模2010-01-13
- seo技術中的原創內容對搜尋引擎一定好嗎?2020-08-06
- asp.net中形式的用法(原創)2013-11-15ASP.NET
- Hollis原創|深入分析Java的編譯原理2019-05-14Java編譯原理
- react中的 Hook 使用規則2024-09-10ReactHook
- Dart中的Stream初步研究2021-09-02Dart
- 對於加密解密的初步瞭解2017-12-06加密解密
- Statspack初步學和用第三篇 分析初步2007-09-24
- 【原創】Oracle RAC故障分析與處理2013-07-18Oracle
- Alex-protect外殼完全分析【原創】2004-12-07
- [原創]程式設計師對私密聊天的亂想2020-09-03程式設計師
- 【原創】InnoDB 和TokuDB的讀寫分析與比較2021-09-09
- 【原創】Linux中斷子系統(一)-中斷控制器及驅動分析2020-05-31Linux
- 對於HOOK函式的一點認識2007-11-26Hook函式
- [原創] Mysql中 Desc tables 中MUl解釋2009-02-05MySql
- Oracle中Hint深入理解(原創)2018-11-23Oracle
- 【原創】中華通訊錄
pj教程2015-11-15
- FCKeditor原始碼分析(一)—–fckeditor.js的中文註釋分析(原創)薦2010-04-20原始碼JS
- [絕對原創] SAP Get User data by User ID2015-04-01
- 一個外行對ERP的問題的思考方式=原創2007-12-05
- [原創] Linux ptrace詳細分析系列(一)2021-02-02Linux
- 【原創】Linux PCI驅動框架分析(一)2020-12-20Linux框架
- 【原創】Linux PCI驅動框架分析(二)2020-12-29Linux框架
- 原創:oracle data block 內部結構分析2011-09-27OracleBloC