-
KeBugCheckEx
鎖定
- 外文名
- KeBugCheckEx
- 函數類型
- Windows系統執行藍屏時調用的函數
- 調用等級
- ring0級特權
- 返回類型
- VOID
KeBugCheckEx簡介
KeBugCheckEx是Windows執行崩潰的函數
返回類型:VOID
參數列表:(DWORD, UINT, UINT, UINT, UINT)
該函數接受一個錯誤檢查代碼(bug check code),以及四個根據停止代碼來解釋的參數。KeBugCheckEx屏蔽了該系統處理器上的所有中斷後,將顯示器切換到低分辨率的VGA圖形模式下,繪製一個藍色背景,然後顯示此停止代碼,幾乎WINDOWS支持的所有視頻卡都實現了這種模式。
第一個錯誤檢查代碼是一個8位16進制數,後4個是整型數參數,將出現在藍屏中以幫助管理員瞭解錯誤細節。
此函數為KeBugCheck在WINNT以上的擴充版本。
KeBugCheckEx計算程序
如果想使用此函數,必須申請RING0級特權,示例代碼如下:
#include<Windows.h> #include<Ntsecapi.h> #include<Aclapi.h> #pragmacomment(lib,"ntdll.lib") //CopyFromDDK #pragmacomment(lib,"Kernel32.lib") #pragmacomment(lib,"Advapi32.lib") //------------------數據類型聲明開始--------------------// typedefstruct_SYSTEM_MODULE_INFORMATION{ ULONGReserved[2]; PVOIDBase; ULONGSize; ULONGFlags; USHORTIndex; USHORTUnknown; USHORTLoadCount; USHORTModuleNameOffset; CHARImageName[256]; }SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION; typedefstruct_OBJECT_ATTRIBUTES{ ULONGLength; HANDLERootDirectory; PUNICODE_STRINGObjectName; ULONGAttributes; PVOIDSecurityDescriptor; PVOIDSecurityQualityOfService; }OBJECT_ATTRIBUTES,*POBJECT_ATTRIBUTES; typedefenum_SECTION_INHERIT{ ViewShare=1, ViewUnmap=2 }SECTION_INHERIT; typedefstruct_MY_PROCESS_INFO{ ULONGPID; ULONGKPEB; ULONGCR3; CHARName[16]; ULONGReserved; }MY_PROCESS_INFO,*PMY_PROCESS_INFO; typedeflongNTSTATUS; //------------------數據類型聲明結束--------------------// //---------------------預定義開始-----------------------// #defineNT_SUCCESS(Status)((NTSTATUS)(Status)>=0) #defineSTATUS_SUCCESS 0x00000000 #defineSTATUS_UNSUCCESSFUL 0xC0000001 #defineSTATUS_NOT_IMPLEMENTED 0xC0000002 #defineSTATUS_INFO_LENGTH_MISMATCH0xC0000004 #defineSTATUS_INVALID_PARAMETER 0xC000000D #defineSTATUS_ACCESS_DENIED 0xC0000022 #defineSTATUS_BUFFER_TOO_SMALL 0xC0000023 #defineOBJ_KERNEL_HANDLE 0x00000200 #defineSystemModuleInformation 11 #defineInitializeObjectAttributes(p,n,a,r,s){\ /*注意,由於php標籤過濾,以下6行缺少續行符\*/ (p)->Length=sizeof(OBJECT_ATTRIBUTES); (p)->RootDirectory=r; (p)->Attributes=a; (p)->ObjectName=n; (p)->SecurityDescriptor=s; (p)->SecurityQualityOfService=NULL; } //---------------------預定義結束-----------------------// //------------------NativeAPI聲明開始------------------// NTSYSAPI VOID NTAPI RtlInitUnicodeString( PUNICODE_STRINGDestinationString, PCWSTRSourceString ); NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation( ULONGSystemInformationClass, PVOIDSystemInformation, ULONGSystemInformationLength, PULONGReturnLength ); NTSYSAPI NTSTATUS NTAPI ZwOpenSection( OUTPHANDLESectionHandle, INACCESS_MASKDesiredAccess, INPOBJECT_ATTRIBUTESObjectAttributes ); NTSYSAPI NTSTATUS NTAPI ZwMapViewOfSection( INHANDLESectionHandle, INHANDLEProcessHandle, INOUTPVOID*BaseAddress, INULONGZeroBits, INULONGCommitSize, INOUTPLARGE_INTEGERSectionOffsetOPTIONAL, INOUTPULONGViewSize, INSECTION_INHERITInheritDisposition, INULONGAllocationType, INULONGProtect ); NTSYSAPI NTSTATUS NTAPI ZwUnmapViewOfSection( INHANDLEProcessHandle, INPVOIDBaseAddress ); NTSYSAPI NTSTATUS NTAPI ZwClose( INHANDLEHandle ); NTSYSAPI NTSTATUS NTAPI NtVdmControl( INULONGControlCode, INPVOIDControlData ); //------------------NativeAPI聲明結束------------------// //------------------全局變量定義開始--------------------// NTSTATUS (NTAPI*pfnNtVdmControl)( INULONGControlCode, INPVOIDControlData ); BOOLEAN (NTAPI*pfnPsGetVersion)( PULONGMajorVersionOPTIONAL, PULONGMinorVersionOPTIONAL, PULONGBuildNumberOPTIONAL, PUNICODE_STRINGCSDVersionOPTIONAL ); HANDLE (NTAPI*pfnPsGetCurrentProcessId)( ); PVOID (NTAPI*pfnMemcpy)( INVOIDUNALIGNED*Destination, INCONSTVOIDUNALIGNED*Source, INSIZE_TLength ); ULONG (_cdecl*pfnDbgPrint)( INPCHARFormat, ... ); ULONG*pPsInitialSystemProcess; //------------------全局變量定義結束--------------------// //獲取指定模塊的基址 PVOIDGetModuleBase(PCSTRname) { NTSTATUSstatus; PVOIDpBuffer,pModule; ULONGnRetSize,i,n; PSYSTEM_MODULE_INFORMATIONpmi; pBuffer=LocalAlloc(LPTR,0x1000); if(NULL==pBuffer) { printf("LocalAlloc[0]Failed:%d\n",GetLastError()); returnNULL; } 0x1000,&nRetSize); if(STATUS_INFO_LENGTH_MISMATCH==status) { //緩衝區太小,重新分配 LocalFree(pBuffer); pBuffer=LocalAlloc(LPTR,nRetSize); if(NULL==pBuffer) { printf("LocalAlloc[1]Failed:%d\n",GetLastError()); returnNULL; } nRetSize,&nRetSize); } if(!NT_SUCCESS(status)) { printf("ZwQuerySystemInformationFailed:%d\n",LsaNtStatusToWinError(status)); LocalFree(pBuffer); returnNULL; } pmi=(PSYSTEM_MODULE_INFORMATION)((ULONG)pBuffer+4); n=*(ULONG*)pBuffer; pModule=NULL; //搜索指定的模塊名,獲取基址 for(i=0;i<n;i++) { if(!_stricmp(pmi->ImageName+pmi->ModuleNameOffset,name)) { pModule=pmi->Base; break; } pmi++; } LocalFree(pBuffer); returnpModule; } //獲取\Device\PhysicalMemory的可讀寫句柄 HANDLEOpenPhysicalMemory() { DWORDdwRet; NTSTATUSstatus; UNICODE_STRINGname; OBJECT_ATTRIBUTESoa; EXPLICIT_ACCESSea; PSECURITY_DESCRIPTORpSD; PACLpDacl=NULL; PACLpNewDacl=NULL; HANDLEhSection=NULL; HANDLEhSectionRet=NULL; RtlInitUnicodeString(&name,L"\\Device\\PhysicalMemory"); InitializeObjectAttributes(&oa,&name,OBJ_KERNEL_HANDLE,NULL,NULL); //以可讀寫Section權限打開PhysicalMemory status=ZwOpenSection(&hSectionRet,SECTION_MAP_READ|SECTION_MAP_WRITE,&oa); if(NT_SUCCESS(status))gotoFreeAndExit;//打開成功,直接返回 if(status!=STATUS_ACCESS_DENIED) { //錯誤,但非權限不足,打開失敗 printf("ZwOpenSection[0]Failed:%d\n",LsaNtStatusToWinError(status)); hSectionRet=NULL; gotoFreeAndExit; } //以可讀寫ACL權限打開PhysicalMemory status=ZwOpenSection(&hSection,READ_CONTROL|WRITE_DAC,&oa); if(!NT_SUCCESS(status)) { printf("ZwOpenSection[1]Failed:%d\n",LsaNtStatusToWinError(status)); gotoFreeAndExit; } //獲取PhysicalMemory的DACL dwRet=GetSecurityInfo(hSection NULL,NULL,&pDacl,NULL,&pSD); if(dwRet!=ERROR_SUCCESS) { printf("GetSecurityInfoFailed:%d\n",dwRet); gotoFreeAndExit; } //創建一個ACE,允許當前用户讀寫PhysicalMemory ZeroMemory(&ea,sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions=SECTION_MAP_READ|SECTION_MAP_WRITE; ea.grfAccessMode=GRANT_ACCESS; ea.grfInheritance=NO_INHERITANCE; ea.Trustee.TrusteeForm=TRUSTEE_IS_NAME; ea.Trustee.TrusteeType=TRUSTEE_IS_USER; ea.Trustee.ptstrName="CURRENT_USER"; //將新的ACE加入DACL dwRet=SetEntriesInAcl(1,&ea,pDacl,&pNewDacl); if(dwRet!=ERROR_SUCCESS) { printf("SetEntriesInAclFailed:%d\n",dwRet); gotoFreeAndExit; } //更新PhysicalMemory的DACL dwRet=SetSecurityInfo(hSection, NULL,NULL,pNewDacl,NULL); if(dwRet!=ERROR_SUCCESS) { printf("SetSecurityInfoFailed:%d\n",dwRet); gotoFreeAndExit; } //再次以可讀寫權限打開PhysicalMemory status=ZwOpenSection(&hSectionRet,SECTION_MAP_READ|SECTION_MAP_WRITE,&oa); if(!NT_SUCCESS(status)) { printf("ZwOpenSection[2]Failed:%d\n",LsaNtStatusToWinError(status)); gotoFreeAndExit; } FreeAndExit: if(pSD)LocalFree(pSD); if(pNewDacl)LocalFree(pNewDacl); if(hSection)ZwClose(hSection); returnhSectionRet; } //將物理內存映射到當前進程的用户空間 PVOIDMapPhysicalMemory(HANDLEhSection,//物理內存的Section句柄 ULONGOffset, //映射起始偏移量,相對於物理內存的0地址 ULONGCommitSize//映射範圍 ) { NTSTATUSstatus; PVOIDBaseAddress=NULL; LARGE_INTEGERPhysicalAddress={Offset,0}; SIZE_TViewSize=CommitSize; status=ZwMapViewOfSection(hSection,(HANDLE)-1,&BaseAddress,0, CommitSize,&PhysicalAddress,&ViewSize,ViewShare,0,PAGE_READWRITE); if(!NT_SUCCESS(status)) { printf("ZwMapViewOfSectionFailed:%d\n",LsaNtStatusToWinError(status)); returnNULL; } returnBaseAddress; } //在Ring0執行的代碼。這裏演示如何獲取每個進程的PID、KPEB、CR3和ImageName NTSTATUSRing0Code(ULONGsize, //緩衝區大小 PULONGbuffer) //緩衝區指針,指向調用者分配的緩存 //參數個數與NtVdmControl一致,以平衡堆棧 { ULONGBuildNumber; ULONGListOffset; ULONGPIDOffset; ULONGNameOffset; PLIST_ENTRYListHead,ListPtr; PMY_PROCESS_INFOmypi; pfnDbgPrint("RuninRing0!\n");//輸出調試信息 pfnPsGetVersion(NULL,NULL,&BuildNumber,NULL); pfnDbgPrint("BuildNumber=%d\n",BuildNumber); switch(BuildNumber) //各版本OS的KPEB結構不同 { case2195: //Win2000 ListOffset=0xa0; PIDOffset=0x9c; NameOffset=0x1fc; break; case2600: //WinXP ListOffset=0x88; PIDOffset=0x84; NameOffset=0x174; break; case3790: //Win2003 ListOffset=0x88; PIDOffset=0x84; NameOffset=0x154; break; default: returnSTATUS_NOT_IMPLEMENTED; } if(size<4)returnSTATUS_BUFFER_TOO_SMALL; size-=4; if(NULL==buffer)returnSTATUS_INVALID_PARAMETER; *buffer=0L; //緩存的第一個ULONG用於保存進程總數 mypi=(PMY_PROCESS_INFO)(buffer+1); //歷遍ActiveProcessLinks ListHead=ListPtr=(PLIST_ENTRY)(*pPsInitialSystemProcess+ListOffset); while(ListPtr->Flink!=ListHead) { if(size<sizeof(MY_PROCESS_INFO))returnSTATUS_BUFFER_TOO_SMALL; mypi->KPEB=(ULONG)ListPtr-ListOffset; mypi->PID=*(ULONG*)(mypi->KPEB+PIDOffset); mypi->CR3=*(ULONG*)(mypi->KPEB+0x18); pfnMemcpy(mypi->Name,(PVOID)(mypi->KPEB+NameOffset),16); (*buffer)++; mypi++; size-=sizeof(MY_PROCESS_INFO); ListPtr=ListPtr->Flink; } returnSTATUS_SUCCESS; } //顯示進程信息 voidListProcessInfo(PULONGbuffer) { ULONGi,n=*buffer; PMY_PROCESS_INFOmypi=(PMY_PROCESS_INFO)(buffer+1); printf("PID KPEB CR3 Name\n" "---- -------- -------- ----\n"); for(i=0;i<n;i++) { printf("%-4d %08x %08x %s\n", mypi->PID,mypi->KPEB,mypi->CR3,mypi->Name); mypi++; } } voidmain() { char*Kernel="ntoskrnl.exe"; PVOIDpKernel=NULL; HMODULEhKernel=NULL; HANDLEhSection=NULL; char*mapping=NULL; PVOIDbuffer=NULL; ULONGoffset; NTSTATUSstatus; charOrigCode[24],HookCode[24]= "\xE8\xFF\xFF\xFF\xFF" //call0xffffffff ;nt!PsGetCurrentProcessId "\x3D\xEE\xEE\xEE\xEE" //cmpeax,0xeeeeeeee ;自己的PID "\x75\x05" //jne$Content$5 "\xE9\xDD\xDD\xDD\xDD" //jmp0xdddddddd ;Ring0Code "\xB8\x01\x00\x00\xC0" //moveax,0xc0000001 ;STATUS_UNSUCCESSFUL "\xC3"; //ret printf("\n-=<RunRing0CodeWithoutDriverDemo>=-\n\n"); //獲取系統核心模塊ntoskrnl.exe的基址 pKernel=GetModuleBase(Kernel); if(NULL==pKernel)return; if((ULONG)pKernel<0x80000000||(ULONG)pKernel>0x9FFFFFFF) { //模塊基址超出直接內存映射範圍 printf("Error:Kernelmodulebase(%08x)isoutofrange.\n",pKernel); return; } //在用户態加載一份ntoskrnl.exe hKernel=LoadLibrary(Kernel); if(NULL==hKernel) { printf("LoadLibraryFailed:%d\n",GetLastError()); return; } //獲取內核例程/變量在用户態的相對位置 if((pfnMemcpy=(PVOID)GetProcAddress(hKernel,"memcpy"))&& (pfnDbgPrint=(PVOID)GetProcAddress(hKernel,"DbgPrint"))&& (pfnNtVdmControl=(PVOID)GetProcAddress(hKernel,"NtVdmControl"))&& (pfnPsGetVersion=(PVOID)GetProcAddress(hKernel,"PsGetVersion"))&& (pfnPsGetCurrentProcessId=(PVOID)GetProcAddress(hKernel,"PsGetCurrentProcessId"))&& (pPsInitialSystemProcess=(PVOID)GetProcAddress(hKernel,"PsInitialSystemProcess"))); else { printf("GetProcAddressFailed:%d\n",GetLastError()); gotoFreeAndExit; } //計算內核例程/變量的實際地址 offset=(ULONG)pKernel-(ULONG)hKernel; (ULONG)pfnMemcpy+=offset; (ULONG)pfnDbgPrint+=offset; (ULONG)pfnNtVdmControl+=offset; (ULONG)pfnPsGetVersion+=offset; (ULONG)pfnPsGetCurrentProcessId+=offset; (ULONG)pPsInitialSystemProcess+=offset; //設置HookCode *(ULONG*)(HookCode+1)=(ULONG)pfnPsGetCurrentProcessId-(ULONG)pfnNtVdmControl-5; *(ULONG*)(HookCode+6)=GetCurrentProcessId(); *(ULONG*)(HookCode+13)=(ULONG)Ring0Code-(ULONG)pfnNtVdmControl-17; //打開物理內存Section hSection=OpenPhysicalMemory(); if(NULL==hSection)gotoFreeAndExit; //映射NtVdmControl入口附近的內存 offset=(ULONG)pfnNtVdmControl&0x1FFFF000; //轉換到物理內存頁地址 mapping=MapPhysicalMemory(hSection,offset,0x2000); if(NULL==mapping)gotoFreeAndExit; //保存NtVdmControl入口代碼 offset=(ULONG)pfnNtVdmControl&0x00000FFF; //頁內偏移 memcpy(OrigCode,mapping+offset,24); buffer=LocalAlloc(LPTR,0x1000); if(NULL==buffer) { printf("LocalAllocFailed:%d\n",GetLastError()); gotoFreeAndExit; } memcpy(mapping+offset,HookCode,24); //掛鈎NtVdmControl status=NtVdmControl(0x1000,buffer); //調用NtVdmControl,進入Ring0 memcpy(mapping+offset,OrigCode,24); //還原NtVdmControl入口 if(!NT_SUCCESS(status)) { printf("NtVdmControlFailed:%d\n",LsaNtStatusToWinError(status)); gotoFreeAndExit; } ListProcessInfo(buffer); FreeAndExit: if(buffer!=NULL)LocalFree(buffer); if(mapping!=NULL)ZwUnmapViewOfSection(hSection,mapping); if(hSection!=NULL)ZwClose(hSection); if(hKernel!=NULL)FreeLibrary(hKernel); }
- 參考資料
-
- 1. KeBugCheckEx routine .技術雲[引用日期2014-12-28]