程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> VC驅動監控進程的創建

VC驅動監控進程的創建

編輯:vc教程

下面這個驅動程序的作用:監控准備運行的可執行文件。(由用戶決定是不是讓它運行)所以我們要做以下工作:

首先是修改(NtCreateSection)SSDT索引號,(索引號從用戶程序中得到)HOOK NtCreateSection()這個函數,然後通過文件句柄獲得文件名,判斷它是不是可執行文件,檢測其屬性與判斷用戶是否允許它執行,如果允許就運行原來NtCreateSection這個函數,否則返回STATUS_Access_DENIED。

如果我們截獲一個NtCreateSection()的請求,該請求要求映射可執行文件作為SEC_IMAGE屬性,通過結合頁保護屬性,我們能夠知道進程將要執行了,因此我們在這個時候作出決定:是否讓其執行。如果不想讓它執行,EAX 返回值為STATUS_Access_DENIED。

因為調用是從ntdll. dll 以一條 MOV EAX, ServiceIndex五字節指令開始的,第一個字節是MOV EAX,後四字節是索引號,所以我們可以得到索引號(後四字節)然後將它進行修改成我們自己的函數索引。當然在修改之前要將原服務函數地址保存在全局變量中。


if(loc->Parameters.DeviceIoControl.IoControlCode==1000)
{
buff=(UCHAR*)Irp->AssociatedIrp.SystemBuffer;

// hook service dispatch table
memmove(&Index,buff,4);//所有的調用都是從ntdll.dll以一條五字節指令MOV EAX, ServiceIndex開始,四字節是索引號
a=4*Index+(ULONG)KeServiceDescriptorTable->ServiceTable;//從用戶程序中得到索引號,a指向服務函數地址

base=(ULONG)MmMapiOSpace(MmGetPhysicalAddress((void*)a),4,0);//將物理地址映射到非分頁池,因此可以進行讀寫,減少讀寫服務表保護屬性的麻煩
a=(ULONG)&Proxy;//a指向Proxy函數的地址

_asm
{
mov eax,base

mov ebx,dWord ptr[eax]

mov RealCallee,ebx//將原服務函數地址保存在全局變量中
mov ebx,a

mov dWord ptr[eax],ebx//Proxy函數地址寫進服務函數表中
}

memmove(&a,&buff[4],4);
output=(char*)MmMapiOSpace(MmGetPhysicalAddress((void*)a),256,0);
}


下面是我們自己函數的實現:
//這個函數決定是否 NtCreateSection() 被成功調用
ULONG __stdcall check(PULONG arg)//獲得指向服務參數指針
{

  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;//檢測標志
if((arg[5]&0x01000000)==0)return 1;//檢測屬性

//通過文件句柄獲得文件名
hand=(HANDLE)arg[6];//獲得執行文件句柄

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)//通過循環判斷是不是有". "標志
{
 
if(buff[a]=='.')
{a++;break;}

  a--;

}
ObDereferenceObject(file);

if(_stricmp(&buff[a],"exe")){RtlFreeAnsiString(&str);return 1;}//判斷是否為可執行文件
 
KeWaitForSingleObject(&event,Executive,KernelMode,0,0);//將當前線程置於等待狀態知道信號態

strcpy(&output[8],buff);//將string復制進buff
RtlFreeAnsiString(&str);

a=1;//用戶的決定通過a的制來反映
memmove(&output[0],&a,4);
while(1)
{
KeDelayExecutionThread(KernelMode,0,&li);//在一個固定時間間隔內當前線程處於等待狀態
memmove(&a,&output[0],4);
if(!a)break;
}
memmove(&a,&output[4],4);

KeSetEvent(&event,0,0);

return a;
}

//保存執行文件上下文,調用check()函數
_declspec(naked) Proxy()
{

_asm{

pushfd
pushad
mov ebx,esp

add ebx,40
push ebx

call check

cmp eax,1//由check()的返回值判斷是否讓可執行文件繼續執行
jne block


popad
popfd
jmp RealCallee//通過,調用ntcreatesection


block:popad
mov ebx, dWord ptr[esp+8]

mov dWord ptr[ebx],0
mov eax,0xC0000022L//不讓其通過,返回STATUS_Access_DENIED
popfd
ret 32

}
}

到此,驅動程序的工作基本完成,所以在用戶程序中用到一個線程來等待驅動的判斷結果。
 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);

        //讓驅動繼續
        a=0;
        memmove(&outputbuff[0],&a,4);
}}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved