驅(qū)動監(jiān)控進(jìn)程創(chuàng)建
Posted on 2009-09-20 22:25 S.l.e!ep.¢% 閱讀(579) 評論(0) 編輯 收藏 引用 所屬分類: 系統(tǒng)低層2008-05-31 12:48
這是我在http://www.codeproject.com .學(xué)習(xí)時看到的一個驅(qū)動程序,學(xué)習(xí)后對其整理的筆記
下面這個驅(qū)動程序的作用:監(jiān)控準(zhǔn)備運(yùn)行的可執(zhí)行文件。(由用戶決定是不是讓它運(yùn)行)所以我們要做以下工作: 首先是修改(NtCreateSection)SSDT索引號,(索引號從用戶程序中得到)HOOK NtCreateSection()這個函數(shù),然后通過文件句柄獲得文件名,判斷它是不是可執(zhí)行文件,檢測其屬性與判斷用戶是否允許它執(zhí)行,如果允許就運(yùn)行原來NtCreateSection這個函數(shù),否則返回STATUS_ACCESS_DENIED。 如果我們截獲一個NtCreateSection()的請求,該請求要求映射可執(zhí)行文件作為SEC_IMAGE屬性,通過結(jié)合頁保護(hù)屬性,我們能夠知道進(jìn)程將要執(zhí)行了,因此我們在這個時候作出決定:是否讓其執(zhí)行。如果不想讓它執(zhí)行,EAX 返回值為STATUS_ACCESS_DENIED。 因?yàn)檎{(diào)用是從ntdll. dll 以一條 MOV EAX, ServiceIndex五字節(jié)指令開始的,第一個字節(jié)是MOV EAX,后四字節(jié)是索引號,所以我們可以得到索引號(后四字節(jié))然后將它進(jìn)行修改成我們自己的函數(shù)索引。當(dāng)然在修改之前要將原服務(wù)函數(shù)地址保存在全局變量中。 if(loc->Parameters.DeviceIoControl.IoControlCode==1000) { buff=(UCHAR*)Irp->AssociatedIrp.SystemBuffer; // hook service dispatch table memmove(&Index,buff,4);//所有的調(diào)用都是從ntdll.dll以一條五字節(jié)指令MOV EAX, ServiceIndex開始,四字節(jié)是索引號 a=4*Index+(ULONG)KeServiceDescriptorTable->ServiceTable;//從用戶程序中得到索引號,a指向服務(wù)函數(shù)地址 base=(ULONG)MmMapIoSpace(MmGetPhysicalAddress((void*)a),4,0);//將物理地址映射到非分頁池,因此可以進(jìn)行讀寫,減少讀寫服務(wù)表保護(hù)屬性的麻煩 a=(ULONG)&Proxy;//a指向Proxy函數(shù)的地址 _asm { mov eax,base mov ebx,dword ptr[eax] mov RealCallee,ebx//將原服務(wù)函數(shù)地址保存在全局變量中 mov ebx,a mov dword ptr[eax],ebx//Proxy函數(shù)地址寫進(jìn)服務(wù)函數(shù)表中 } memmove(&a,&buff[4],4); output=(char*)MmMapIoSpace(MmGetPhysicalAddress((void*)a),256,0); } 下面是我們自己函數(shù)的實(shí)現(xiàn): //這個函數(shù)決定是否 NtCreateSection() 被成功調(diào)用 ULONG __stdcall check(PULONG arg)//獲得指向服務(wù)參數(shù)指針 { ?? HANDLE hand=0;PFILE_OBJECT file=0; ?? POBJECT_HANDLE_INFORMATION info=0;ULONG a;char*buff; ?? ANSI_STRING str; LARGE_INTEGER li;li.QuadPart=-10000; if((arg[4]&0xf0)==0)return 1;//檢測標(biāo)志 if((arg[5]&0x01000000)==0)return 1;//檢測屬性 //通過文件句柄獲得文件名 hand=(HANDLE)arg[6];//獲得執(zhí)行文件句柄 ObReferenceObjectByHandle(hand,0,0,KernelMode,&file,info);//&file獲得對象體指針 if(!file)return 1; RtlUnicodeStringToAnsiString(&str,&file->FileName,1); a=str.Length;buff=str.Buffer; while(1)//通過循環(huán)判斷是不是有". "標(biāo)志 { ?? if(buff[a]=='.') {a++;break;} ?? a--; } ObDereferenceObject(file); if(_stricmp(&buff[a],"exe")){RtlFreeAnsiString(&str);return 1;}//判斷是否為可執(zhí)行文件 KeWaitForSingleObject(&event,Executive,KernelMode,0,0);//將當(dāng)前線程置于等待狀態(tài)知道信號態(tài) strcpy(&output[8],buff);//將string復(fù)制進(jìn)buff RtlFreeAnsiString(&str); a=1;//用戶的決定通過a的制來反映 memmove(&output[0],&a,4); while(1) { KeDelayExecutionThread(KernelMode,0,&li);//在一個固定時間間隔內(nèi)當(dāng)前線程處于等待狀態(tài) memmove(&a,&output[0],4); if(!a)break; } memmove(&a,&output[4],4); KeSetEvent(&event,0,0); return a; } //保存執(zhí)行文件上下文,調(diào)用check()函數(shù) _declspec(naked) Proxy() { _asm{ pushfd pushad mov ebx,esp add ebx,40 push ebx call check cmp eax,1//由check()的返回值判斷是否讓可執(zhí)行文件繼續(xù)執(zhí)行 jne block popad popfd jmp RealCallee//通過,調(diào)用ntcreatesection block:popad mov ebx, dword ptr[esp+8] mov dword ptr[ebx],0 mov eax,0xC0000022L//不讓其通過,返回STATUS_ACCESS_DENIED popfd ret 32 } } 到此,驅(qū)動程序的工作基本完成,所以在用戶程序中用到一個線程來等待驅(qū)動的判斷結(jié)果。 char*name=(char*)&outputbuff[8]; ???????? for(x=0;x<stringcount;x++) ???????? { ???????????? if(!stricmp(name,strings[x])){a=1;goto skip;} ???????? } ???????? strcpy(msgbuff, "Do you want to run "); ???????? strcat(msgbuff,&outputbuff[8]); ???????? ???????? if(IDYES==MessageBox(0, msgbuff,"WARNING", ??????????? MB_YESNO|MB_ICONQUESTION|0x00200000L)) ???????? {a=1; strings[stringcount]=_strdup(name);stringcount++;} ???????? else a=0; ???? ???????? // write response to the buffer, and driver will get it ???????? skip:memmove(&outputbuff[4],&a,4); ???????? //讓驅(qū)動繼續(xù) ???????? a=0; ???????? memmove(&outputbuff[0],&a,4); |