在ring0調用Ring3的代碼

做者:VXK/CVC.GB
時間:2005-02-05
每次上driverdevelop總看到有人問怎麼在Ring0下調用Ring3的代碼——
Ring3使用Ring0已是地球人全知道的事情了,可是ring0下使用ring3的代碼
恐怕不多有人知道,Ratter和Benny這兩個高人以及Elzc的做者Elzcor各自提出
過一種方法。總結起來就是三種方法,Zombie在2004年也提出過一個方法看起
來像是Ratter和Elzcor的方法結合而成~
固然說其本質都是一種思想把ring3代碼搞到ring3的空間去執行,聽起來
你們也好像有所明白了吧,Benny的方法是在Ring0的向Ring3進程插入代碼執行,
Ratter則是Hook KAPIZ等待用戶層調用發生把ring3代碼放回Ring3空間,利用
KeUserModeCallBack來執行,Elzcor則是本身創建一個進程把代碼內存感染到
進程執行。Zombie取兩家之長搞的~。
今天我來向你們介紹的更像是Ratter和Benny的方法結合,對於Benny的方法,
我不徹底採用,我採用的思想仍然是代碼放回Ring3空間~
首先不管如何咱們都要有一個進程~
習習~Windows提供強大的kernel函數幫咱們虐待用戶~
PsSetCreateProcessNotifyRoutine攝定好NotifyRoutine在建立進程時咱們就
能夠yy進程了~
經過DDK文檔MSDN的大叔的幫助,這個函數
PsSetCreateProcessNotifyRoutine有兩個參數
返回值是NTSTATUS型,第一個參數是回調函數NotifyRoutine,第二個參數是Bool型的
若是第二個參數爲False表示設定NotifyRoutine,爲True就是取消~
NotifyRoutine的形式以下
NotifyRoutine proc dwParentId:DWORD, dwProcessId:DWORD, bCreate:BOOL
這樣咱們就能夠得到一個進程了~~xixi~~
咱們的NotifyRoutine只處理dwProcessId和dwProcessId,對bCreate不用理,經過使用ps
函數PsLookupProcessByProcessId獲得PEPROCESS結構(得不到結構的不處理),再取進程Name
若是是Explore且插入標識無就開始咱們的插入~(選Explore的緣由我就不用說了吧?)
插入時我採用Ratter的方法,因而乎就要用KeAttachProcess,Attach到進程而後開始
工做~~呵呵~~
插完了就用回調CallBackUserMode~~而後DetachProcess...
KeUserModeCallBack的參數
NTSTATUS KeUserModeCallback (
IN ULONG ApiNumber,
IN PVOID InputBuffer,
IN ULONG InputLength,
OUT PVOID *OutputBuffer,
IN PULONG OutputLength
)
可能看不出來怎麼使它返回UserMode執行任意代碼,可是若是你看看win2ksrc/private/ntos/ke/i386/
下的callback.c和callout.asm就會發現世界真奇妙~~~竟然KiCallUserMode回調的是~~~~~xixi~~~~
我不說了,你們應該本身研究一下吧~
另外我提一下參數傳遞的問題,這裏使用KeUserModeCallBack必需要用有效的InputBuffer和OutputBuffer
當KeUserModeCallBack發生時,調用咱們的Ring3代碼參數傳入的方式好像是PUSH進來的
KiCallUserMode中回調USER的時KiServiceExit回自動的飛向咱們的代碼~
相似發生下面的事情~
(
;這些代碼並不是真的在KiCallUserMode裏存在~
;只是我我的的猜想,由於softice跟到最後處處是[ebx+xxx],[esi+xxx]這樣的東西~
;實在難說~作後使用jmp _KiServiceExit返回ring3的代碼更是頭大~
;不過度析的說多是棧傳入參數~
;若是看ntos/ke/i386/下的分析,估計會更頭大~它的棧傳遞和stack變換等等搞的很暈~~
;不過能夠確定的說,就是已經到了ring3了,咱們本身作個檢測不就好了?
;hehe~具體究竟是怎麼傳遞的呢?你們作個檢測吧,我不說了~
;正確的函數傳遞方式:Kernel是怎麼運行咱們的函數的~
push Outlength
push lpOutBuffer
push Inlength
push lpInBuffer
push API_NUMBER
call KeUserCallBackDispatch
KeUserCallBackDispatch:
add esp,4
pop edx ;edx=Api_Number
mov eax,fs:[PcTeb]
mov eax,[eax].TebPeb
mov eax,[eax].PebKernelCallbackTable
call [eax+edx*4] ;Real Call To [EAX+EDX*4],hehe~~
;咱們計算的api_number被還原了~~~xixi~~~下面的代碼裏有那個計算~~呵呵~~api

)函數

雖然是這樣的,可是我仍是勸各位不要用KeUserModeCallBack來傳遞參數給咱們的Ring3代碼,要傳遞也應
該使用其它方法——好比Ratter把參數Copy到Ring3代碼後面,而後再代碼裏重定位到地方取參數~
返回參數EAX是KeUserModeCallBack的,於是要想要返回參數就要傳遞outsize爲strlen(lpoutbuf)就好了~~
若是非要傳遞,應該當心一些~由於可能藍屏~我也不知道爲何~呵呵~ui

我還有一種方法就是覆蓋KeUserCallbackDispatcher爲咱們Ring3代碼的地址----大多數狀況下會藍,而後
用KeUserModeCallBack執行,這樣咱們就能夠經過一個常見systemcall_number來執行咱們代碼,另外經過分析ntos/ps/psinit.c
我發現KeUserCallbackDispathcer就是NTDLL裏的KiUserCallbackDispatcher~~~習習~~~
那樣避免藍屏要用在進程空間改寫KiUserCallBackDispatch和插入代碼~
內核空間改寫的話,要指向內核地址,ring3代碼要插入內核的NTDLL空間中~
記得不論在哪裏改寫都要最後調用原函數~~~!!!!!!!!!~~~~
......(這種方法是我最z發現的阿阿----實際上是聽erx大哥講的一個思路~)
再多說就成了教唆犯罪了~spa

在ring0調用Ring3的代碼的續
 
  利用創建新的APC方法回調代碼——原創者不詳~
  這種方法通常應用用戶層和內核驅動之間有交互——KeUserModeCallBack的是插入回調,
  Infect是感染進程~
  可是創建新APC的方法更溫柔一些,呵呵~~
所用到的函數是兩個undoc的函數,具體的原始形態實在是簡單——感謝Open Source Windows~~~線程

VOID
KeInitializeApc (
   IN PRKAPC Apc,//咱們要本身初始化這個OurApc=ExAllocatePool(NonPagedPool, sizeof(struct _KAPC));
   IN PRKTHREAD Thread,//目標線程——用戶層交互的話,直接KeGetCurrentThread()好了
   IN KAPC_ENVIRONMENT Environment,//應該添0,就是CurrentApcEnvironment
   IN PKKERNEL_ROUTINE KernelRoutine,//咱們的APC處理函數MyApcRoutine,在APC_LEVEL上運行,很恐怖的高級,kernel mode apc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,//添NULL,
   IN PKNORMAL_ROUTINE NormalRoutine OPTIONAL,//添入咱們的ring3層的Ring3App代碼線性地址,實際上是user mode 的APC處理Routine,~~~privalige很是嚇人~~~
   IN KPROCESSOR_MODE ApcMode OPTIONAL,//1,使用NormRoutine
   IN PVOID NormalContext OPTIONAL//第一個參數~~~咱們ring3層代碼的,習習
   )orm

完成APC初始化後,咱們要插入咱們的APC了
BOOLEAN
KeInsertQueueApc (
   IN PRKAPC Apc,//OurApc
   IN PVOID SystemArgument1,//Ring3App的第二個參數arg2
   IN PVOID SystemArgument2,//Ring3App的第三個參數arg3
   IN KPRIORITY Increment//0
   )進程

Ring3層代碼的樣子::    
void Ring3App(ulong arg1,ulong arg2,ulong arg3);內存

咱們在kernel mode 的APC
//咱們也能夠在這作點什麼,不過APC_LEVEL這個高級別東西,咱們最好仍是不要作什麼大動做~
void MyApcRoutine(struct _KAPC *Apc,//Apc結構不說了吧?
              PKNORMAL_ROUTINE norm_routine,//咱們的Ring3App地址
              void *context,//arg1
              void *SysArg1,//arg2
              void *SysArg2)//arg3
{
   ExFreePool(Apc);
   return;
}rem


總體的思想的代碼:
//in kernel mode
PKAPC OurApc;
void SendApc(ulong addr,ulong arg1,ulong arg2,ulong arg3)
{
     PKTHREAD thread=KeGetCurrentThread();
    OurApc=ExAllocatePool(NonPagedPool, sizeof(struct _KAPC));文檔

   KeInitializeApc(OurApc, thread, 0,       (PKKERNEL_ROUTINE)&MyApcRoutine, 0,    (PKNORMAL_ROUTINE)addr, 1, (PVOID)arg1);    KeInsertQueueApc(OurApc, (PVOID)arg2, (PVOID)arg3, 0);    *((unsigned char *)thread+0x4a)=1;//這句代碼強制線程發生APC調用~    //kthread+0x4a的地方是KTHREAD->ApcState(kthread+0x34)->UserApcPending(ApcState+0x16)~~~    //xixi~~~    return ; } //in user mode void Ring3App(ulong arg1,ulong arg2,ulong arg3) { .... }     void SendQp(..) {  ....  SendBuf = BuildUpIrp(IRP_XXX_YYYY);  SendBuf->BackAddr=(ULONG)Ring3App;  ....  ReturnBuf = SendIrp(hDevice,SendBuf,sizeof(SendBuf));  ....  ....  

相關文章
相關標籤/搜索