複製鏈接
請複製以下鏈接發送給好友

KeBugCheckEx

鎖定
KeBugCheckEx [1]  Windows執行崩潰的函數,使計算機藍屏,需要ring0級特權才能調用
外文名
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);
}

參考資料