2014年8月22日星期五

编程获取某个CPU的PCR/PRCB

#include <ntifs.h>
#include <windef.h>
//#include <wdbgexts.h> //明明有这个文件为啥说找不到呢?这里包含DBGKD_GET_VERSION64和DBGKD_DEBUG_DATA_HEADER64,KDDEBUGGER_DATA64等结构。


/*
文件名:KeGetPcr.c
功能:获取某个CPU的PCR/PRCB。

以前感觉eprocess/kprocess和_ethread/_kthread就很厉害了。
其实还有比他们更加底层的,这就是_kpcr和_kprcb。
更多的还有blos,PCI等硬件信息。

以前觉得这太底层,不敢触及。
其实这是必须接触,接触到有很多的好处。
本文没有用汇编语法实现的X86和X64的编程。其实也是变相的汇编,由编译器实现而已。
看来搞系统,不但知道系统的知识,还要知道编译环境的信息,会更好。

软件再智能,再高级也是借助于硬件实现的。
没用硬件,连空虚的灵魂都没有。

本文参考:WDK和MSDN。

made by correy
made at 2014.08.22
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/


//这是X64的定义。
//这里用代码实现,这个函数肯定没有导出。
//__forceinline
//PKPCR
//KeGetPcr (
//    VOID
//    )
//
//{
//    return (PKPCR)(ULONG_PTR)KIPCR();
//}


//这是X64的定义。
//__forceinline
//PKPCR
//KeGetPcr (
//    VOID
//    )
//
//{
//    return (PKPCR)__readgsqword(FIELD_OFFSET(KPCR, Self));
//}


/*
仿照系统的写的64位的KeGetPcr,
自己写一个X86的。
*/
#ifdef _X86_
__forceinline
PKPCR
KeGetPcr (
    VOID
    )
{
    return (PKPCR)__readfsdword(FIELD_OFFSET(KPCR, SelfPcr));
}
#endif
//另一种思路是:直接汇编。
//__asm {  
//    movzx eax, _PCR
//        mov pkpcr,eax
//}
//注意:这一行.
//#define _PCR   fs:[0]  


struct _KPRCB * KeGetPrcb (PKPCR pkpcr)
    /*
    _KPRCB结构没有公开。
    WRK和WINDBG肯定有。
    而且有32和64之分。
    wrk\WindowsResearchKernel-WRK\WRK-v1.2\base\ntos\inc\i386.h
    wrk\WindowsResearchKernel-WRK\WRK-v1.2\base\ntos\inc\amd64.h
    */
{
#ifdef _X86_
    return pkpcr->Prcb;
#endif

#if !defined(MIDL_PASS) && defined(_M_AMD64)
    return pkpcr->CurrentPrcb;
#endif
}


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{   
    
}


#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PKPCR pkpcr;
    struct _KPRCB *Prcb;
    //DBGKD_GET_VERSION64 * pdgv;
    //PKDDEBUGGER_DATA64 pkdd;
    //char * p;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload; 

    KeSetSystemAffinityThread(1);
    pkpcr = KeGetPcr ();
    KeRevertToUserAffinityThread();

    Prcb = KeGetPrcb(pkpcr);

    ////下面打印获取一些没有导出的重要的信息,如诸多变量。
    //参考了:http://www.cnblogs.com/unixstudio/archive/2012/11/05/2755356.html。
    //pdgv = pkpcr->KdVersionBlock;//在X64下这个等于零。

    ////pkdd = (PKDDEBUGGER_DATA64)((char *)pkpcr + sizeof(DBGKD_GET_VERSION64));
    //p = (char *)pdgv;
    //p += sizeof(DBGKD_GET_VERSION64);
    //pkdd = (PKDDEBUGGER_DATA64)p;     

    return Status;
} 


/*
X86的验证:
0: kd> !pcr 
KPCR for Processor 0 at ffdff000:
    Major 1 Minor 1
	NtTib.ExceptionList: f88f6578
	    NtTib.StackBase: f88f6df0
	   NtTib.StackLimit: f88f4000
	 NtTib.SubSystemTib: 00000000
	      NtTib.Version: 00000000
	  NtTib.UserPointer: 00000000
	      NtTib.SelfTib: 00000000

	            SelfPcr: ffdff000
	               Prcb: ffdff120
	               Irql: 00000000
	                IRR: 00000000
	                IDR: ffffffff
	      InterruptMode: 00000000
	                IDT: 8003f400
	                GDT: 8003f000
	                TSS: 80042000

	      CurrentThread: 8234c8a0
	         NextThread: 00000000
	         IdleThread: 8055ce60

	          DpcQueue: 
0: kd> !pcr 0
KPCR for Processor 0 at ffdff000:
    Major 1 Minor 1
	NtTib.ExceptionList: f88f6578
	    NtTib.StackBase: f88f6df0
	   NtTib.StackLimit: f88f4000
	 NtTib.SubSystemTib: 00000000
	      NtTib.Version: 00000000
	  NtTib.UserPointer: 00000000
	      NtTib.SelfTib: 00000000

	            SelfPcr: ffdff000
	               Prcb: ffdff120
	               Irql: 00000000
	                IRR: 00000000
	                IDR: ffffffff
	      InterruptMode: 00000000
	                IDT: 8003f400
	                GDT: 8003f000
	                TSS: 80042000

	      CurrentThread: 8234c8a0
	         NextThread: 00000000
	         IdleThread: 8055ce60

	          DpcQueue: 
0: kd> dt nt!_kpcr ffdff000
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : 0xffdff000 _KPCR
   +0x020 Prcb             : 0xffdff120 _KPRCB
   +0x024 Irql             : 0 ''
   +0x028 IRR              : 0
   +0x02c IrrActive        : 0
   +0x030 IDR              : 0xffffffff
   +0x034 KdVersionBlock   : 0x8054e2b8 Void
   +0x038 IDT              : 0x8003f400 _KIDTENTRY
   +0x03c GDT              : 0x8003f000 _KGDTENTRY
   +0x040 TSS              : 0x80042000 _KTSS
   +0x044 MajorVersion     : 1
   +0x046 MinorVersion     : 1
   +0x048 SetMember        : 1
   +0x04c StallScaleFactor : 0xd40
   +0x050 DebugActive      : 0 ''
   +0x051 Number           : 0 ''
   +0x052 Spare0           : 0 ''
   +0x053 SecondLevelCacheAssociativity : 0 ''
   +0x054 VdmAlert         : 0
   +0x058 KernelReserved   : [14] 0
   +0x090 SecondLevelCacheSize : 0
   +0x094 HalReserved      : [16] 0
   +0x0d4 InterruptMode    : 0      注意:从这里开始这里的在结构的定义里面是没有的。也就是说WINDBG命令显示的比结构定义的成员多四个。
   +0x0d8 Spare1           : 0 ''
   +0x0dc KernelReserved2  : [17] 0
   +0x120 PrcbData         : _KPRCB
0: kd> dt nt!_kpcr ffdff000 -b
   ...
   这命令太长就不显示了,有几千行。
0: kd> dt nt!_kprcb 0xffdff120 
   +0x000 MinorVersion     : 1
   +0x002 MajorVersion     : 1
   +0x004 CurrentThread    : 0x8234c8a0 _KTHREAD
   +0x008 NextThread       : (null) 
   +0x00c IdleThread       : 0x8055ce60 _KTHREAD
   +0x010 Number           : 0 ''
   +0x011 Reserved         : 0 ''
   +0x012 BuildType        : 0
   +0x014 SetMember        : 1
   +0x018 CpuType          : 6 ''
   +0x019 CpuID            : 1 ''
   +0x01a CpuStep          : 0x3a09
   +0x01c ProcessorState   : _KPROCESSOR_STATE
   +0x33c KernelReserved   : [16] 0
   +0x37c HalReserved      : [16] 0
   +0x3bc PrcbPad0         : [92]  ""
   +0x418 LockQueue        : [16] _KSPIN_LOCK_QUEUE
   +0x498 PrcbPad1         : [8]  ""
   +0x4a0 NpxThread        : (null) 
   +0x4a4 InterruptCount   : 0x87e0
   +0x4a8 KernelTime       : 0x50b7
   +0x4ac UserTime         : 0x89
   +0x4b0 DpcTime          : 0x47
   +0x4b4 DebugDpcTime     : 0
   +0x4b8 InterruptTime    : 0x33b
   +0x4bc AdjustDpcThreshold : 0x14
   +0x4c0 PageColor        : 0x14a14
   +0x4c4 SkipTick         : 1
   +0x4c8 MultiThreadSetBusy : 0x1 ''
   +0x4c9 Spare2           : [3]  ""
   +0x4cc ParentNode       : 0x8055d560 _KNODE
   +0x4d0 MultiThreadProcessorSet : 3
   +0x4d4 MultiThreadSetMaster : 0xffdff120 _KPRCB
   +0x4d8 ThreadStartCount : [2] 0
   +0x4e0 CcFastReadNoWait : 0
   +0x4e4 CcFastReadWait   : 0x27f
   +0x4e8 CcFastReadNotPossible : 0
   +0x4ec CcCopyReadNoWait : 6
   +0x4f0 CcCopyReadWait   : 0x344
   +0x4f4 CcCopyReadNoWaitMiss : 1
   +0x4f8 KeAlignmentFixupCount : 0
   +0x4fc KeContextSwitches : 0x2c332
   +0x500 KeDcacheFlushCount : 0
   +0x504 KeExceptionDispatchCount : 0xc4
   +0x508 KeFirstLevelTbFills : 0
   +0x50c KeFloatingEmulationCount : 0
   +0x510 KeIcacheFlushCount : 0
   +0x514 KeSecondLevelTbFills : 0
   +0x518 KeSystemCalls    : 0xd1c9d
   +0x51c SpareCounter0    : [1] 0
   +0x520 PPLookasideList  : [16] _PP_LOOKASIDE_LIST
   +0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x7a0 PacketBarrier    : 0
   +0x7a4 ReverseStall     : 0xce
   +0x7a8 IpiFrame         : 0xf871ea9c Void
   +0x7ac PrcbPad2         : [52]  ""
   +0x7e0 CurrentPacket    : [3] 0x00000001 Void
   +0x7ec TargetSet        : 0
   +0x7f0 WorkerRoutine    : 0x804fc26a     void  nt!KiFlushTargetMultipleTb+0
   +0x7f4 IpiFrozen        : 0x24
   +0x7f8 PrcbPad3         : [40]  ""
   +0x820 RequestSummary   : 0
   +0x824 SignalDone       : (null) 
   +0x828 PrcbPad4         : [56]  ""
   +0x860 DpcListHead      : _LIST_ENTRY [ 0xffdff980 - 0xffdff980 ]
   +0x868 DpcStack         : 0xf88c7000 Void
   +0x86c DpcCount         : 0x29e6
   +0x870 DpcQueueDepth    : 0
   +0x874 DpcRoutineActive : 0
   +0x878 DpcInterruptRequested : 0
   +0x87c DpcLastCount     : 0x29e6
   +0x880 DpcRequestRate   : 0
   +0x884 MaximumDpcQueueDepth : 1
   +0x888 MinimumDpcRate   : 3
   +0x88c QuantumEnd       : 0
   +0x890 PrcbPad5         : [16]  ""
   +0x8a0 DpcLock          : 0
   +0x8a4 PrcbPad6         : [28]  ""
   +0x8c0 CallDpc          : _KDPC
   +0x8e0 ChainedInterruptList : (null) 
   +0x8e4 LookasideIrpFloat : 0n768
   +0x8e8 SpareFields0     : [6] 0
   +0x900 VendorString     : [13]  "GenuineIntel"
   +0x90d InitialApicId    : 0 ''
   +0x90e LogicalProcessorsPerPhysicalProcessor : 0x2 ''
   +0x910 MHz              : 0xd40
   +0x914 FeatureBits      : 0xa0033fff
   +0x918 UpdateSignature  : _LARGE_INTEGER 0x00000017`00000000
   +0x920 NpxSaveArea      : _FX_SAVE_AREA
   +0xb30 PowerState       : _PROCESSOR_POWER_STATE
0: kd> dt nt!_kpcr poi(pkpcr) 这是编程获取的,可以和前面的对比。
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : 0xffdff000 _KPCR
   +0x020 Prcb             : 0xffdff120 _KPRCB
   +0x024 Irql             : 0 ''
   +0x028 IRR              : 0
   +0x02c IrrActive        : 0
   +0x030 IDR              : 0xffffffff
   +0x034 KdVersionBlock   : 0x8054e2b8 Void
   +0x038 IDT              : 0x8003f400 _KIDTENTRY
   +0x03c GDT              : 0x8003f000 _KGDTENTRY
   +0x040 TSS              : 0x80042000 _KTSS
   +0x044 MajorVersion     : 1
   +0x046 MinorVersion     : 1
   +0x048 SetMember        : 1
   +0x04c StallScaleFactor : 0xd40
   +0x050 DebugActive      : 0 ''
   +0x051 Number           : 0 ''
   +0x052 Spare0           : 0 ''
   +0x053 SecondLevelCacheAssociativity : 0 ''
   +0x054 VdmAlert         : 0
   +0x058 KernelReserved   : [14] 0
   +0x090 SecondLevelCacheSize : 0
   +0x094 HalReserved      : [16] 0
   +0x0d4 InterruptMode    : 0
   +0x0d8 Spare1           : 0 ''
   +0x0dc KernelReserved2  : [17] 0
   +0x120 PrcbData         : _KPRCB
*/


/*
X64的验证:
0: kd> !pcr 
KPCR for Processor 0 at fffff800019f9d00:
    Major 1 Minor 1
	NtTib.ExceptionList: fffff80001753000
	    NtTib.StackBase: fffff80001754080
	   NtTib.StackLimit: 000000000008e2e8
	 NtTib.SubSystemTib: fffff800019f9d00
	      NtTib.Version: 00000000019f9e80
	  NtTib.UserPointer: fffff800019fa4f0
	      NtTib.SelfTib: 000007fffff9e000

	            SelfPcr: 0000000000000000
	               Prcb: fffff800019f9e80
	               Irql: 0000000000000000
	                IRR: 0000000000000000
	                IDR: 0000000000000000
	      InterruptMode: 0000000000000000
	                IDT: 0000000000000000
	                GDT: 0000000000000000
	                TSS: 0000000000000000

	      CurrentThread: fffffa8018df6680
	         NextThread: 0000000000000000
	         IdleThread: fffff80001a07cc0

	          DpcQueue: 
0: kd> !pcr 0
KPCR for Processor 0 at fffff800019f9d00:
    Major 1 Minor 1
	NtTib.ExceptionList: fffff80001753000
	    NtTib.StackBase: fffff80001754080
	   NtTib.StackLimit: 000000000008e2e8
	 NtTib.SubSystemTib: fffff800019f9d00
	      NtTib.Version: 00000000019f9e80
	  NtTib.UserPointer: fffff800019fa4f0
	      NtTib.SelfTib: 000007fffff9e000

	            SelfPcr: 0000000000000000
	               Prcb: fffff800019f9e80
	               Irql: 0000000000000000
	                IRR: 0000000000000000
	                IDR: 0000000000000000
	      InterruptMode: 0000000000000000
	                IDT: 0000000000000000
	                GDT: 0000000000000000
	                TSS: 0000000000000000

	      CurrentThread: fffffa8018df6680
	         NextThread: 0000000000000000
	         IdleThread: fffff80001a07cc0

	          DpcQueue: 
0: kd> dt nt!_kpcr fffff800019f9d00
   +0x000 NtTib            : _NT_TIB
   +0x000 GdtBase          : 0xfffff800`01753000 _KGDTENTRY64
   +0x008 TssBase          : 0xfffff800`01754080 _KTSS64
   +0x010 UserRsp          : 0x8e2e8
   +0x018 Self             : 0xfffff800`019f9d00 _KPCR
   +0x020 CurrentPrcb      : 0xfffff800`019f9e80 _KPRCB
   +0x028 LockArray        : 0xfffff800`019fa4f0 _KSPIN_LOCK_QUEUE
   +0x030 Used_Self        : 0x000007ff`fff9e000 Void
   +0x038 IdtBase          : 0xfffff800`01753080 _KIDTENTRY64
   +0x040 Unused           : [2] 0
   +0x050 Irql             : 0 ''
   +0x051 SecondLevelCacheAssociativity : 0xc ''
   +0x052 ObsoleteNumber   : 0 ''
   +0x053 Fill0            : 0 ''
   +0x054 Unused0          : [3] 0
   +0x060 MajorVersion     : 1
   +0x062 MinorVersion     : 1
   +0x064 StallScaleFactor : 0xd40
   +0x068 Unused1          : [3] (null) 
   +0x080 KernelReserved   : [15] 0
   +0x0bc SecondLevelCacheSize : 0x300000
   +0x0c0 HalReserved      : [16] 0xca332730
   +0x100 Unused2          : 0
   +0x108 KdVersionBlock   : (null) 
   +0x110 Unused3          : (null) 
   +0x118 PcrAlign1        : [24] 0
   +0x180 Prcb             : _KPRCB 注意:从这里开始这里的在结构的定义里面是没有的。也就是说WINDBG命令显示的比结构定义的成员多四个。
0: kd> dt nt!_kprcb fffff800019f9e80
   +0x000 MxCsr            : 0x1f80
   +0x004 LegacyNumber     : 0 ''
   +0x005 ReservedMustBeZero : 0 ''
   +0x006 InterruptRequest : 0 ''
   +0x007 IdleHalt         : 0 ''
   +0x008 CurrentThread    : 0xfffffa80`18df6680 _KTHREAD
   +0x010 NextThread       : (null) 
   +0x018 IdleThread       : 0xfffff800`01a07cc0 _KTHREAD
   +0x020 NestingLevel     : 0 ''
   +0x021 PrcbPad00        : [3]  ""
   +0x024 Number           : 0
   +0x028 RspBase          : 0xfffff880`0231dc70
   +0x030 PrcbLock         : 0
   +0x038 PrcbPad01        : 0
   +0x040 ProcessorState   : _KPROCESSOR_STATE
   +0x5f0 CpuType          : 6 ''
   +0x5f1 CpuID            : 1 ''
   +0x5f2 CpuStep          : 0x3a09
   +0x5f2 CpuStepping      : 0x9 ''
   +0x5f3 CpuModel         : 0x3a ':'
   +0x5f4 MHz              : 0xd40
   +0x5f8 HalReserved      : [8] 0
   +0x638 MinorVersion     : 1
   +0x63a MajorVersion     : 1
   +0x63c BuildType        : 0 ''
   +0x63d CpuVendor        : 0x2 ''
   +0x63e CoresPerPhysicalProcessor : 0x2 ''
   +0x63f LogicalProcessorsPerCore : 0x1 ''
   +0x640 ApicMask         : 0xfffffffe
   +0x644 CFlushSize       : 0x40
   +0x648 AcpiReserved     : (null) 
   +0x650 InitialApicId    : 0
   +0x654 Stride           : 2
   +0x658 Group            : 0
   +0x660 GroupSetMember   : 1
   +0x668 GroupIndex       : 0 ''
   +0x670 LockQueue        : [17] _KSPIN_LOCK_QUEUE
   +0x780 PPLookasideList  : [16] _PP_LOOKASIDE_LIST
   +0x880 PPNPagedLookasideList : [32] _GENERAL_LOOKASIDE_POOL
   +0x1480 PPPagedLookasideList : [32] _GENERAL_LOOKASIDE_POOL
   +0x2080 PacketBarrier    : 0n0
   +0x2088 DeferredReadyListHead : _SINGLE_LIST_ENTRY
   +0x2090 MmPageFaultCount : 0n152708
   +0x2094 MmCopyOnWriteCount : 0n3321
   +0x2098 MmTransitionCount : 0n64413
   +0x209c MmDemandZeroCount : 0n64284
   +0x20a0 MmPageReadCount  : 0n46114
   +0x20a4 MmPageReadIoCount : 0n8302
   +0x20a8 MmDirtyPagesWriteCount : 0n0
   +0x20ac MmDirtyWriteIoCount : 0n0
   +0x20b0 MmMappedPagesWriteCount : 0n1
   +0x20b4 MmMappedWriteIoCount : 0n1
   +0x20b8 KeSystemCalls    : 0x1fd8c5
   +0x20bc KeContextSwitches : 0x219d2
   +0x20c0 CcFastReadNoWait : 0
   +0x20c4 CcFastReadWait   : 0x1648
   +0x20c8 CcFastReadNotPossible : 0
   +0x20cc CcCopyReadNoWait : 0
   +0x20d0 CcCopyReadWait   : 0x1865
   +0x20d4 CcCopyReadNoWaitMiss : 0
   +0x20d8 LookasideIrpFloat : 0n2147483647
   +0x20dc IoReadOperationCount : 0n7516
   +0x20e0 IoWriteOperationCount : 0n1741
   +0x20e4 IoOtherOperationCount : 0n70676
   +0x20e8 IoReadTransferCount : _LARGE_INTEGER 0x51033c0
   +0x20f0 IoWriteTransferCount : _LARGE_INTEGER 0x1786f65
   +0x20f8 IoOtherTransferCount : _LARGE_INTEGER 0x1feec4
   +0x2100 TargetCount      : 0n0
   +0x2104 IpiFrozen        : 0x24
   +0x2180 DpcData          : [2] _KDPC_DATA
   +0x21c0 DpcStack         : 0xfffff800`01760fb0 Void
   +0x21c8 MaximumDpcQueueDepth : 0n4
   +0x21cc DpcRequestRate   : 0
   +0x21d0 MinimumDpcRate   : 3
   +0x21d4 DpcLastCount     : 0x55dc
   +0x21d8 ThreadDpcEnable  : 0x1 ''
   +0x21d9 QuantumEnd       : 0 ''
   +0x21da DpcRoutineActive : 0 ''
   +0x21db IdleSchedule     : 0 ''
   +0x21dc DpcRequestSummary : 0n0
   +0x21dc DpcRequestSlot   : [2] 0n0
   +0x21dc NormalDpcState   : 0n0
   +0x21de DpcThreadActive  : 0y0
   +0x21de ThreadDpcState   : 0n0
   +0x21e0 TimerHand        : 0x2eac
   +0x21e4 MasterOffset     : 0n8675
   +0x21e8 LastTick         : 0x2eac
   +0x21ec UnusedPad        : 0
   +0x21f0 PrcbPad50        : [2] 0
   +0x2200 TimerTable       : _KTIMER_TABLE
   +0x4400 DpcGate          : _KGATE
   +0x4418 PrcbPad52        : (null) 
   +0x4420 CallDpc          : _KDPC
   +0x4460 ClockKeepAlive   : 0n1
   +0x4464 ClockCheckSlot   : 0x1 ''
   +0x4465 ClockPollCycle   : 0x53 'S'
   +0x4466 NmiActive        : 0
   +0x4468 DpcWatchdogPeriod : 0n1924
   +0x446c DpcWatchdogCount : 0n1741
   +0x4470 TickOffset       : 0x23f7e
   +0x4478 KeSpinLockOrdering : 0n0
   +0x447c PrcbPad70        : 0
   +0x4480 WaitListHead     : _LIST_ENTRY [ 0xfffffa80`1a996c00 - 0xfffffa80`18df70e0 ]
   +0x4490 WaitLock         : 0
   +0x4498 ReadySummary     : 0x1500
   +0x449c QueueIndex       : 1
   +0x44a0 TimerExpirationDpc : _KDPC
   +0x44e0 PrcbPad72        : [4] 0
   +0x4500 DispatcherReadyListHead : [32] _LIST_ENTRY [ 0xfffff800`019fe380 - 0xfffff800`019fe380 ]
   +0x4700 InterruptCount   : 0x11edc
   +0x4704 KernelTime       : 0x2d4b
   +0x4708 UserTime         : 0x161
   +0x470c DpcTime          : 0x55
   +0x4710 InterruptTime    : 0x213
   +0x4714 AdjustDpcThreshold : 0xc
   +0x4718 DebuggerSavedIRQL : 0 ''
   +0x4719 PrcbPad80        : [7]  ""
   +0x4720 DpcTimeCount     : 0
   +0x4724 DpcTimeLimit     : 0x282
   +0x4728 PeriodicCount    : 0
   +0x472c PeriodicBias     : 0
   +0x4730 AvailableTime    : 0x73
   +0x4734 KeExceptionDispatchCount : 0x58c0
   +0x4738 ParentNode       : 0xfffff800`01a07c00 _KNODE
   +0x4740 StartCycles      : 0x00000096`d20559b7
   +0x4748 PrcbPad82        : [3] 0
   +0x4760 MmSpinLockOrdering : 0n0
   +0x4764 PageColor        : 0x3abb
   +0x4768 NodeColor        : 0
   +0x476c NodeShiftedColor : 0
   +0x4770 SecondaryColorMask : 0x3f
   +0x4774 PrcbPad83        : 0
   +0x4778 CycleTime        : 0x00000015`c0c9fe04
   +0x4780 CcFastMdlReadNoWait : 0
   +0x4784 CcFastMdlReadWait : 0
   +0x4788 CcFastMdlReadNotPossible : 0
   +0x478c CcMapDataNoWait  : 0
   +0x4790 CcMapDataWait    : 0x5ce8
   +0x4794 CcPinMappedDataCount : 0x573
   +0x4798 CcPinReadNoWait  : 0
   +0x479c CcPinReadWait    : 0x160
   +0x47a0 CcMdlReadNoWait  : 0
   +0x47a4 CcMdlReadWait    : 0
   +0x47a8 CcLazyWriteHotSpots : 0x18
   +0x47ac CcLazyWriteIos   : 0xdb
   +0x47b0 CcLazyWritePages : 0x1cb3
   +0x47b4 CcDataFlushes    : 0x1e3
   +0x47b8 CcDataPages      : 0x1ad7
   +0x47bc CcLostDelayedWrites : 0
   +0x47c0 CcFastReadResourceMiss : 0
   +0x47c4 CcCopyReadWaitMiss : 0xc4b
   +0x47c8 CcFastMdlReadResourceMiss : 0
   +0x47cc CcMapDataNoWaitMiss : 0
   +0x47d0 CcMapDataWaitMiss : 0x63e
   +0x47d4 CcPinReadNoWaitMiss : 0
   +0x47d8 CcPinReadWaitMiss : 0x1a
   +0x47dc CcMdlReadNoWaitMiss : 0
   +0x47e0 CcMdlReadWaitMiss : 0
   +0x47e4 CcReadAheadIos   : 0x1ea3
   +0x47e8 MmCacheTransitionCount : 0n0
   +0x47ec MmCacheReadCount : 0n0
   +0x47f0 MmCacheIoCount   : 0n0
   +0x47f4 PrcbPad91        : [1] 0
   +0x47f8 RuntimeAccumulation : 0x6f1b1aaa
   +0x4800 PowerState       : _PROCESSOR_POWER_STATE
   +0x4900 PrcbPad92        : [16]  ""
   +0x4910 KeAlignmentFixupCount : 0
   +0x4918 DpcWatchdogDpc   : _KDPC
   +0x4958 DpcWatchdogTimer : _KTIMER
   +0x4998 Cache            : [5] _CACHE_DESCRIPTOR
   +0x49d4 CacheCount       : 4
   +0x49d8 CachedCommit     : 0x86
   +0x49dc CachedResidentAvailable : 0xf6
   +0x49e0 HyperPte         : 0xfffff880`00800006 Void
   +0x49e8 WheaInfo         : 0xfffffa80`18e31960 Void
   +0x49f0 EtwSupport       : 0xfffffa80`18e4c010 Void
   +0x4a00 InterruptObjectPool : _SLIST_HEADER
   +0x4a10 HypercallPageList : _SLIST_HEADER
   +0x4a20 HypercallPageVirtual : 0xfffff880`02d53000 Void
   +0x4a28 VirtualApicAssist : 0xfffff880`02d51000 Void
   +0x4a30 StatisticsPage   : 0xfffff880`02d52000  -> 0x00900001`00000002
   +0x4a38 RateControl      : (null) 
   +0x4a40 CacheProcessorMask : [5] 3
   +0x4a68 PackageProcessorSet : _KAFFINITY_EX
   +0x4a90 CoreProcessorSet : 1
   +0x4a98 PebsIndexAddress : 0xfffff800`019fe918 Void
   +0x4aa0 PrcbPad93        : [12] 0
   +0x4b00 SpinLockAcquireCount : 0x5310d6
   +0x4b04 SpinLockContentionCount : 0xa1e
   +0x4b08 SpinLockSpinCount : 0x392b847a
   +0x4b0c IpiSendRequestBroadcastCount : 0x21e2
   +0x4b10 IpiSendRequestRoutineCount : 0x21f
   +0x4b14 IpiSendSoftwareInterruptCount : 0x5f77
   +0x4b18 ExInitializeResourceCount : 0x3497
   +0x4b1c ExReInitializeResourceCount : 0x47c
   +0x4b20 ExDeleteResourceCount : 0x2843
   +0x4b24 ExecutiveResourceAcquiresCount : 0x1861cb
   +0x4b28 ExecutiveResourceContentionsCount : 0x66e
   +0x4b2c ExecutiveResourceReleaseExclusiveCount : 0x367ca
   +0x4b30 ExecutiveResourceReleaseSharedCount : 0x14fa15
   +0x4b34 ExecutiveResourceConvertsCount : 0x305
   +0x4b38 ExAcqResExclusiveAttempts : 0x35d51
   +0x4b3c ExAcqResExclusiveAcquiresExclusive : 0x30a5d
   +0x4b40 ExAcqResExclusiveAcquiresExclusiveRecursive : 0x52d2
   +0x4b44 ExAcqResExclusiveWaits : 0x5b6
   +0x4b48 ExAcqResExclusiveNotAcquires : 0x22
   +0x4b4c ExAcqResSharedAttempts : 0x143531
   +0x4b50 ExAcqResSharedAcquiresExclusive : 0x1008
   +0x4b54 ExAcqResSharedAcquiresShared : 0x13f9db
   +0x4b58 ExAcqResSharedAcquiresSharedRecursive : 0x2b4b
   +0x4b5c ExAcqResSharedWaits : 0xb8
   +0x4b60 ExAcqResSharedNotAcquires : 3
   +0x4b64 ExAcqResSharedStarveExclusiveAttempts : 0xcf6f
   +0x4b68 ExAcqResSharedStarveExclusiveAcquiresExclusive : 1
   +0x4b6c ExAcqResSharedStarveExclusiveAcquiresShared : 0xceff
   +0x4b70 ExAcqResSharedStarveExclusiveAcquiresSharedRecursive : 0x6f
   +0x4b74 ExAcqResSharedStarveExclusiveWaits : 0
   +0x4b78 ExAcqResSharedStarveExclusiveNotAcquires : 0
   +0x4b7c ExAcqResSharedWaitForExclusiveAttempts : 0
   +0x4b80 ExAcqResSharedWaitForExclusiveAcquiresExclusive : 0
   +0x4b84 ExAcqResSharedWaitForExclusiveAcquiresShared : 0
   +0x4b88 ExAcqResSharedWaitForExclusiveAcquiresSharedRecursive : 0
   +0x4b8c ExAcqResSharedWaitForExclusiveWaits : 0
   +0x4b90 ExAcqResSharedWaitForExclusiveNotAcquires : 0
   +0x4b94 ExSetResOwnerPointerExclusive : 0
   +0x4b98 ExSetResOwnerPointerSharedNew : 0x298
   +0x4b9c ExSetResOwnerPointerSharedOld : 0xba
   +0x4ba0 ExTryToAcqExclusiveAttempts : 0
   +0x4ba4 ExTryToAcqExclusiveAcquires : 0
   +0x4ba8 ExBoostExclusiveOwner : 0xe
   +0x4bac ExBoostSharedOwners : 0
   +0x4bb0 ExEtwSynchTrackingNotificationsCount : 0
   +0x4bb4 ExEtwSynchTrackingNotificationsAccountedCount : 0
   +0x4bb8 VendorString     : [13]  "GenuineIntel"
   +0x4bc5 PrcbPad10        : [3]  ""
   +0x4bc8 FeatureBits      : 0x21193dfe
   +0x4bd0 UpdateSignature  : _LARGE_INTEGER 0x00000017`00000000
   +0x4bd8 Context          : 0xfffff880`009c6340 _CONTEXT
   +0x4be0 ContextFlags     : 0x10004b
   +0x4be8 ExtendedState    : 0xfffff880`009c6000 _XSAVE_AREA
   +0x4c00 Mailbox          : (null) 
   +0x4c80 RequestMailbox   : [1] _REQUEST_MAILBOX
0: kd> dt nt!_kpcr poi(pkpcr) 这是编程获取的,可以和前面的对比。
   +0x000 NtTib            : _NT_TIB
   +0x000 GdtBase          : 0xfffff800`01753000 _KGDTENTRY64
   +0x008 TssBase          : 0xfffff800`01754080 _KTSS64
   +0x010 UserRsp          : 0x8e2e8
   +0x018 Self             : 0xfffff800`019f9d00 _KPCR
   +0x020 CurrentPrcb      : 0xfffff800`019f9e80 _KPRCB
   +0x028 LockArray        : 0xfffff800`019fa4f0 _KSPIN_LOCK_QUEUE
   +0x030 Used_Self        : 0x000007ff`fff9e000 Void
   +0x038 IdtBase          : 0xfffff800`01753080 _KIDTENTRY64
   +0x040 Unused           : [2] 0
   +0x050 Irql             : 0 ''
   +0x051 SecondLevelCacheAssociativity : 0xc ''
   +0x052 ObsoleteNumber   : 0 ''
   +0x053 Fill0            : 0 ''
   +0x054 Unused0          : [3] 0
   +0x060 MajorVersion     : 1
   +0x062 MinorVersion     : 1
   +0x064 StallScaleFactor : 0xd40
   +0x068 Unused1          : [3] (null) 
   +0x080 KernelReserved   : [15] 0
   +0x0bc SecondLevelCacheSize : 0x300000
   +0x0c0 HalReserved      : [16] 0xca332730
   +0x100 Unused2          : 0
   +0x108 KdVersionBlock   : (null) 
   +0x110 Unused3          : (null) 
   +0x118 PcrAlign1        : [24] 0
   +0x180 Prcb             : _KPRCB
*/

2014年8月20日星期三

内核中的CPUID

#include <ntifs.h>
#include <windef.h>
#include <intrin.h> //VS2012编译。
//#include <mmintrin.h> //WDK 编译。
//#include <emmintrin.h>//WDK 编译。
//#include <xmmintrin.h>//WDK 编译。


/*
标题:内核中的CPUID。

CPUID这个指令很有用,如查看:CPU微码,虚拟化等。
注意很旧的CPU不支持:http://correy.webs.com/articles/computer/asm/cpu_microcode.asm.txt
如此重要的指令,微软岂能不支持。
尽管X64不支持内联汇编,但也有替代的办法对付此特别有用的指令。
如:http://msdn.microsoft.com/en-us/library/26td21ds.aspx

本文参考:http://msdn.microsoft.com/zh-cn/library/hskdteyh(v=vs.110).aspx
在X86和X64的Windows系统上测试通过。

made by correy
made at 2014.08.20
homepage:http://correy.webs.com
*/


//自己添加。
#define bool BOOL 
#define false FALSE 
#define printf_s DbgPrint


const char* szFeatures[] =
{
    "x87 FPU On Chip",
    "Virtual-8086 Mode Enhancement",
    "Debugging Extensions",
    "Page Size Extensions",
    "Time Stamp Counter",
    "RDMSR and WRMSR Support",
    "Physical Address Extensions",
    "Machine Check Exception",
    "CMPXCHG8B Instruction",
    "APIC On Chip",
    "Unknown1",
    "SYSENTER and SYSEXIT",
    "Memory Type Range Registers",
    "PTE Global Bit",
    "Machine Check Architecture",
    "Conditional Move/Compare Instruction",
    "Page Attribute Table",
    "36-bit Page Size Extension",
    "Processor Serial Number",
    "CFLUSH Extension",
    "Unknown2",
    "Debug Store",
    "Thermal Monitor and Clock Ctrl",
    "MMX Technology",
    "FXSAVE/FXRSTOR",
    "SSE Extensions",
    "SSE2 Extensions",
    "Self Snoop",
    "Multithreading Technology",
    "Thermal Monitor",
    "Unknown4",
    "Pending Break Enable"
};


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;  

    char CPUString[0x20];
    char CPUBrandString[0x40];
    int CPUInfo[4] = {-1};
    int nSteppingID = 0;
    int nModel = 0;
    int nFamily = 0;
    int nProcessorType = 0;
    int nExtendedmodel = 0;
    int nExtendedfamily = 0;
    int nBrandIndex = 0;
    int nCLFLUSHcachelinesize = 0;
    int nLogicalProcessors = 0;
    int nAPICPhysicalID = 0;
    int nFeatureInfo = 0;
    int nCacheLineSize = 0;
    int nL2Associativity = 0;
    int nCacheSizeK = 0;
    int nPhysicalAddress = 0;
    int nVirtualAddress = 0;
    int nRet = 0;

    int nCores = 0;
    int nCacheType = 0;
    int nCacheLevel = 0;
    int nMaxThread = 0;
    int nSysLineSize = 0;
    int nPhysicalLinePartitions = 0;
    int nWaysAssociativity = 0;
    int nNumberSets = 0;

    unsigned    nIds, nExIds, i;

    bool    bSSE3Instructions = false;
    bool    bMONITOR_MWAIT = false;
    bool    bCPLQualifiedDebugStore = false;
    bool    bVirtualMachineExtensions = false;
    bool    bEnhancedIntelSpeedStepTechnology = false;
    bool    bThermalMonitor2 = false;
    bool    bSupplementalSSE3 = false;
    bool    bL1ContextID = false;
    bool    bCMPXCHG16B = false;
    bool    bxTPRUpdateControl = false;
    bool    bPerfDebugCapabilityMSR = false;
    bool    bSSE41Extensions = false;
    bool    bSSE42Extensions = false;
    bool    bPOPCNT = false;

    bool    bMultithreading = false;

    bool    bLAHF_SAHFAvailable = false;
    bool    bCmpLegacy = false;
    bool    bSVM = false;
    bool    bExtApicSpace = false;
    bool    bAltMovCr8 = false;
    bool    bLZCNT = false;
    bool    bSSE4A = false;
    bool    bMisalignedSSE = false;
    bool    bPREFETCH = false;
    bool    bSKINITandDEV = false;
    bool    bSYSCALL_SYSRETAvailable = false;
    bool    bExecuteDisableBitAvailable = false;
    bool    bMMXExtensions = false;
    bool    bFFXSR = false;
    bool    b1GBSupport = false;
    bool    bRDTSCP = false;
    bool    b64Available = false;
    bool    b3DNowExt = false;
    bool    b3DNow = false;
    bool    bNestedPaging = false;
    bool    bLBRVisualization = false;
    bool    bFP128 = false;
    bool    bMOVOptimization = false;

    bool    bSelfInit = false;
    bool    bFullyAssociative = false;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;

    // __cpuid with an InfoType argument of 0 returns the number of valid Ids in CPUInfo[0] and the CPU identification string in the other three array elements.
    // The CPU identification string is not in linear order. The code below arranges the information in a human readable form.

    /*
    这行指令对应的汇编代码为:
    X86:
    180 test.c               f88902e5 8d758c          lea     esi,[ebp-74h]
    180 test.c               f88902e8 33c0            xor     eax,eax
    180 test.c               f88902ea 33c9            xor     ecx,ecx
    180 test.c               f88902ec 0fa2            cpuid
    180 test.c               f88902ee 8906            mov     dword ptr [esi],eax
    180 test.c               f88902f0 895e04          mov     dword ptr [esi+4],ebx
    180 test.c               f88902f3 894e08          mov     dword ptr [esi+8],ecx
    180 test.c               f88902f6 89560c          mov     dword ptr [esi+0Ch],edx

    X64:
    167 test.c               fffff880`06b79300 33c0            xor     eax,eax
    167 test.c               fffff880`06b79302 33c9            xor     ecx,ecx
    167 test.c               fffff880`06b79304 0fa2            cpuid
    167 test.c               fffff880`06b79306 488dbc24d0010000 lea     rdi,[rsp+1D0h]
    167 test.c               fffff880`06b7930e 8907            mov     dword ptr [rdi],eax
    167 test.c               fffff880`06b79310 895f04          mov     dword ptr [rdi+4],ebx
    167 test.c               fffff880`06b79313 894f08          mov     dword ptr [rdi+8],ecx
    167 test.c               fffff880`06b79316 89570c          mov     dword ptr [rdi+0Ch],edx
    */
    __cpuid(CPUInfo, 0);
    nIds = CPUInfo[0];
    memset(CPUString, 0, sizeof(CPUString));
    *((int*)CPUString) = CPUInfo[1];
    *((int*)(CPUString+4)) = CPUInfo[3];
    *((int*)(CPUString+8)) = CPUInfo[2];

    // Get the information associated with each valid Id
    for (i=0; i<=nIds; ++i)
    {
        __cpuid(CPUInfo, i);
        printf_s("\nFor InfoType %d\n", i); 
        printf_s("CPUInfo[0] = 0x%x\n", CPUInfo[0]);
        printf_s("CPUInfo[1] = 0x%x\n", CPUInfo[1]);
        printf_s("CPUInfo[2] = 0x%x\n", CPUInfo[2]);
        printf_s("CPUInfo[3] = 0x%x\n", CPUInfo[3]);

        // Interpret CPU feature information.
        if  (i == 1)
        {
            nSteppingID = CPUInfo[0] & 0xf;
            nModel = (CPUInfo[0] >> 4) & 0xf;
            nFamily = (CPUInfo[0] >> 8) & 0xf;
            nProcessorType = (CPUInfo[0] >> 12) & 0x3;
            nExtendedmodel = (CPUInfo[0] >> 16) & 0xf;
            nExtendedfamily = (CPUInfo[0] >> 20) & 0xff;
            nBrandIndex = CPUInfo[1] & 0xff;
            nCLFLUSHcachelinesize = ((CPUInfo[1] >> 8) & 0xff) * 8;
            nLogicalProcessors = ((CPUInfo[1] >> 16) & 0xff);
            nAPICPhysicalID = (CPUInfo[1] >> 24) & 0xff;
            bSSE3Instructions = (CPUInfo[2] & 0x1) || false;
            bMONITOR_MWAIT = (CPUInfo[2] & 0x8) || false;
            bCPLQualifiedDebugStore = (CPUInfo[2] & 0x10) || false;
            bVirtualMachineExtensions = (CPUInfo[2] & 0x20) || false;
            bEnhancedIntelSpeedStepTechnology = (CPUInfo[2] & 0x80) || false;
            bThermalMonitor2 = (CPUInfo[2] & 0x100) || false;
            bSupplementalSSE3 = (CPUInfo[2] & 0x200) || false;
            bL1ContextID = (CPUInfo[2] & 0x300) || false;
            bCMPXCHG16B= (CPUInfo[2] & 0x2000) || false;
            bxTPRUpdateControl = (CPUInfo[2] & 0x4000) || false;
            bPerfDebugCapabilityMSR = (CPUInfo[2] & 0x8000) || false;
            bSSE41Extensions = (CPUInfo[2] & 0x80000) || false;
            bSSE42Extensions = (CPUInfo[2] & 0x100000) || false;
            bPOPCNT= (CPUInfo[2] & 0x800000) || false;
            nFeatureInfo = CPUInfo[3];
            bMultithreading = (nFeatureInfo & (1 << 28)) || false;
        }
    }

    // Calling __cpuid with 0x80000000 as the InfoType argument
    // gets the number of valid extended IDs.
    __cpuid(CPUInfo, 0x80000000);
    nExIds = CPUInfo[0];
    memset(CPUBrandString, 0, sizeof(CPUBrandString));

    // Get the information associated with each extended ID.
    for (i=0x80000000; i<=nExIds; ++i)
    {
        __cpuid(CPUInfo, i);
        printf_s("\nFor InfoType %x\n", i); 
        printf_s("CPUInfo[0] = 0x%x\n", CPUInfo[0]);
        printf_s("CPUInfo[1] = 0x%x\n", CPUInfo[1]);
        printf_s("CPUInfo[2] = 0x%x\n", CPUInfo[2]);
        printf_s("CPUInfo[3] = 0x%x\n", CPUInfo[3]);

        if  (i == 0x80000001)
        {
            bLAHF_SAHFAvailable = (CPUInfo[2] & 0x1) || false;
            bCmpLegacy = (CPUInfo[2] & 0x2) || false;
            bSVM = (CPUInfo[2] & 0x4) || false;
            bExtApicSpace = (CPUInfo[2] & 0x8) || false;
            bAltMovCr8 = (CPUInfo[2] & 0x10) || false;
            bLZCNT = (CPUInfo[2] & 0x20) || false;
            bSSE4A = (CPUInfo[2] & 0x40) || false;
            bMisalignedSSE = (CPUInfo[2] & 0x80) || false;
            bPREFETCH = (CPUInfo[2] & 0x100) || false;
            bSKINITandDEV = (CPUInfo[2] & 0x1000) || false;
            bSYSCALL_SYSRETAvailable = (CPUInfo[3] & 0x800) || false;
            bExecuteDisableBitAvailable = (CPUInfo[3] & 0x10000) || false;
            bMMXExtensions = (CPUInfo[3] & 0x40000) || false;
            bFFXSR = (CPUInfo[3] & 0x200000) || false;
            b1GBSupport = (CPUInfo[3] & 0x400000) || false;
            bRDTSCP = (CPUInfo[3] & 0x8000000) || false;
            b64Available = (CPUInfo[3] & 0x20000000) || false;
            b3DNowExt = (CPUInfo[3] & 0x40000000) || false;
            b3DNow = (CPUInfo[3] & 0x80000000) || false;
        }

        // Interpret CPU brand string and cache information.
        if  (i == 0x80000002)
            memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
        else if  (i == 0x80000003)
            memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
        else if  (i == 0x80000004)
            memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
        else if  (i == 0x80000006)
        {
            nCacheLineSize = CPUInfo[2] & 0xff;
            nL2Associativity = (CPUInfo[2] >> 12) & 0xf;
            nCacheSizeK = (CPUInfo[2] >> 16) & 0xffff;
        }
        else if  (i == 0x80000008)
        {
           nPhysicalAddress = CPUInfo[0] & 0xff;
           nVirtualAddress = (CPUInfo[0] >> 8) & 0xff;
        }
        else if  (i == 0x8000000A)
        {
            bNestedPaging = (CPUInfo[3] & 0x1) || false;
            bLBRVisualization = (CPUInfo[3] & 0x2) || false;
        }
        else if  (i == 0x8000001A)
        {
            bFP128 = (CPUInfo[0] & 0x1) || false;
            bMOVOptimization = (CPUInfo[0] & 0x2) || false;
        }
    }

    // Display all the information in user-friendly format.

    printf_s("\n\nCPU String: %s\n", CPUString);

    if  (nIds >= 1)
    {
        if  (nSteppingID)
            printf_s("Stepping ID = %d\n", nSteppingID);
        if  (nModel)
            printf_s("Model = %d\n", nModel);
        if  (nFamily)
            printf_s("Family = %d\n", nFamily);
        if  (nProcessorType)
            printf_s("Processor Type = %d\n", nProcessorType);
        if  (nExtendedmodel)
            printf_s("Extended model = %d\n", nExtendedmodel);
        if  (nExtendedfamily)
            printf_s("Extended family = %d\n", nExtendedfamily);
        if  (nBrandIndex)
            printf_s("Brand Index = %d\n", nBrandIndex);
        if  (nCLFLUSHcachelinesize)
            printf_s("CLFLUSH cache line size = %d\n", nCLFLUSHcachelinesize);
        if (bMultithreading && (nLogicalProcessors > 0))
           printf_s("Logical Processor Count = %d\n", nLogicalProcessors);
        if  (nAPICPhysicalID)
            printf_s("APIC Physical ID = %d\n", nAPICPhysicalID);

        if  (nFeatureInfo || bSSE3Instructions ||
             bMONITOR_MWAIT || bCPLQualifiedDebugStore ||
             bVirtualMachineExtensions || bEnhancedIntelSpeedStepTechnology ||
             bThermalMonitor2 || bSupplementalSSE3 || bL1ContextID || 
             bCMPXCHG16B || bxTPRUpdateControl || bPerfDebugCapabilityMSR || 
             bSSE41Extensions || bSSE42Extensions || bPOPCNT || 
             bLAHF_SAHFAvailable || bCmpLegacy || bSVM ||
             bExtApicSpace || bAltMovCr8 ||
             bLZCNT || bSSE4A || bMisalignedSSE ||
             bPREFETCH || bSKINITandDEV || bSYSCALL_SYSRETAvailable || 
             bExecuteDisableBitAvailable || bMMXExtensions || bFFXSR || b1GBSupport ||
             bRDTSCP || b64Available || b3DNowExt || b3DNow || bNestedPaging || 
             bLBRVisualization || bFP128 || bMOVOptimization )
        {
            printf_s("\nThe following features are supported:\n");

            if  (bSSE3Instructions)
                printf_s("\tSSE3\n");
            if  (bMONITOR_MWAIT)
                printf_s("\tMONITOR/MWAIT\n");
            if  (bCPLQualifiedDebugStore)
                printf_s("\tCPL Qualified Debug Store\n");
            if  (bVirtualMachineExtensions)
                printf_s("\tVirtual Machine Extensions\n");
            if  (bEnhancedIntelSpeedStepTechnology)
                printf_s("\tEnhanced Intel SpeedStep Technology\n");
            if  (bThermalMonitor2)
                printf_s("\tThermal Monitor 2\n");
            if  (bSupplementalSSE3)
                printf_s("\tSupplemental Streaming SIMD Extensions 3\n");
            if  (bL1ContextID)
                printf_s("\tL1 Context ID\n");
            if  (bCMPXCHG16B)
                printf_s("\tCMPXCHG16B Instruction\n");
            if  (bxTPRUpdateControl)
                printf_s("\txTPR Update Control\n");
            if  (bPerfDebugCapabilityMSR)
                printf_s("\tPerf\\Debug Capability MSR\n");
            if  (bSSE41Extensions)
                printf_s("\tSSE4.1 Extensions\n");
            if  (bSSE42Extensions)
                printf_s("\tSSE4.2 Extensions\n");
            if  (bPOPCNT)
                printf_s("\tPPOPCNT Instruction\n");

            i = 0;
            nIds = 1;
            while (i < (sizeof(szFeatures)/sizeof(const char*)))
            {
                if  (nFeatureInfo & nIds)
                {
                    printf_s("\t");
                    printf_s(szFeatures[i]);
                    printf_s("\n");
                }

                nIds <<= 1;
                ++i;
            }
            if (bLAHF_SAHFAvailable)
                printf_s("\tLAHF/SAHF in 64-bit mode\n");
            if (bCmpLegacy)
                printf_s("\tCore multi-processing legacy mode\n");
            if (bSVM)
                printf_s("\tSecure Virtual Machine\n");
            if (bExtApicSpace)
                printf_s("\tExtended APIC Register Space\n");
            if (bAltMovCr8)
                printf_s("\tAltMovCr8\n");
            if (bLZCNT)
                printf_s("\tLZCNT instruction\n");
            if (bSSE4A)
                printf_s("\tSSE4A (EXTRQ, INSERTQ, MOVNTSD, MOVNTSS)\n");
            if (bMisalignedSSE)
                printf_s("\tMisaligned SSE mode\n");
            if (bPREFETCH)
                printf_s("\tPREFETCH and PREFETCHW Instructions\n");
            if (bSKINITandDEV)
                printf_s("\tSKINIT and DEV support\n");
            if (bSYSCALL_SYSRETAvailable)
                printf_s("\tSYSCALL/SYSRET in 64-bit mode\n");
            if (bExecuteDisableBitAvailable)
                printf_s("\tExecute Disable Bit\n");
            if (bMMXExtensions)
                printf_s("\tExtensions to MMX Instructions\n");
            if (bFFXSR)
                printf_s("\tFFXSR\n");
            if (b1GBSupport)
                printf_s("\t1GB page support\n");
            if (bRDTSCP)
                printf_s("\tRDTSCP instruction\n");
            if (b64Available)
                printf_s("\t64 bit Technology\n");
            if (b3DNowExt)
                printf_s("\t3Dnow Ext\n");
            if (b3DNow)
                printf_s("\t3Dnow! instructions\n");
            if (bNestedPaging)
                printf_s("\tNested Paging\n");
            if (bLBRVisualization)
                printf_s("\tLBR Visualization\n");
            if (bFP128)
                printf_s("\tFP128 optimization\n");
            if (bMOVOptimization)
                printf_s("\tMOVU Optimization\n");
        }
    }

    if  (nExIds >= 0x80000004)
        printf_s("\nCPU Brand String: %s\n", CPUBrandString);

    if  (nExIds >= 0x80000006)
    {
        printf_s("Cache Line Size = %d\n", nCacheLineSize);
        printf_s("L2 Associativity = %d\n", nL2Associativity);
        printf_s("Cache Size = %dK\n", nCacheSizeK);
    }


    for (i=0;;i++)
    {
        __cpuidex(CPUInfo, 0x4, i);
        if(!(CPUInfo[0] & 0xf0)) break;

        if(i == 0)
        {
            nCores = CPUInfo[0] >> 26;
            printf_s("\n\nNumber of Cores = %d\n", nCores + 1);
        }

        nCacheType = (CPUInfo[0] & 0x1f);
        nCacheLevel = (CPUInfo[0] & 0xe0) >> 5;
        bSelfInit = (CPUInfo[0] & 0x100) >> 8;
        bFullyAssociative = (CPUInfo[0] & 0x200) >> 9;
        nMaxThread = (CPUInfo[0] & 0x03ffc000) >> 14;
        nSysLineSize = (CPUInfo[1] & 0x0fff);
        nPhysicalLinePartitions = (CPUInfo[1] & 0x03ff000) >> 12;
        nWaysAssociativity = (CPUInfo[1]) >> 22;
        nNumberSets = CPUInfo[2];

        printf_s("\n");

        printf_s("ECX Index %d\n", i);
        switch (nCacheType)
        {
            case 0:
                printf_s("   Type: Null\n");
                break;
            case 1:
                printf_s("   Type: Data Cache\n");
                break;
            case 2:
                printf_s("   Type: Instruction Cache\n");
                break;
            case 3:
                printf_s("   Type: Unified Cache\n");
                break;
            default:
                 printf_s("   Type: Unknown\n");
        }

        printf_s("   Level = %d\n", nCacheLevel + 1); 
        if (bSelfInit)
        {
            printf_s("   Self Initializing\n");
        }
        else
        {
            printf_s("   Not Self Initializing\n");
        }
        if (bFullyAssociative)
        {
            printf_s("   Is Fully Associatve\n");
        }
        else
        {
            printf_s("   Is Not Fully Associatve\n");
        }
        printf_s("   Max Threads = %d\n", nMaxThread+1);
        printf_s("   System Line Size = %d\n", nSysLineSize+1);
        printf_s("   Physical Line Partions = %d\n", nPhysicalLinePartitions+1);
        printf_s("   Ways of Associativity = %d\n", nWaysAssociativity+1);
        printf_s("   Number of Sets = %d\n", nNumberSets+1);
    }    

    return status;    
} 

2014年8月18日星期一

内核中的GetProcAddress

#include <ntifs.h>
#include <windef.h>


/*
文件名:MiFindExportedRoutineByName.c

写作目的:
MmGetSystemRoutineAddress这个函数有如下的限制:
It can only be used for routines exported by the kernel or HAL, not for any driver-defined routine. 

有时候获取别的内核模块的函数的地址是一个解决问题的办法,如:WINHV.sys。
有人为此还专门写了函数,当然是解析PE32/PE32+了。

其实系统已经提供了一些函数,只不过导出而没有公开而已。

看WRK知道:MmGetSystemRoutineAddress是通过MiFindExportedRoutineByName实现的。
可是:MiFindExportedRoutineByName没有导出,定位又没有好的稳定的办法。
所以自己实现,还好RtlImageDirectoryEntryToData(RtlImageNtHeader)已经导出。

本文的一些信息摘自:WRK。
不过这也是源码,加入驱动也是可以使用的。

made by correy
made at 2014.08.18
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/


#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory


/*
这个应该兼容PE32+也就是64位的系统。
有待看PE32规范。
*/
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


PVOID RtlImageDirectoryEntryToData (IN PVOID Base, IN BOOLEAN MappedAsImage, IN USHORT DirectoryEntry, OUT PULONG Size);
/*++
Routine Description:
    This function locates a Directory Entry within the image header and returns either the virtual address or seek address of the data the Directory describes.
Arguments:
    Base - Supplies the base of the image or data file.
    MappedAsImage - FALSE if the file is mapped as a data file.
                  - TRUE if the file is mapped as an image.
    DirectoryEntry - Supplies the directory entry to locate.
    Size - Return the size of the directory.
Return Value:
    NULL - The file does not contain data for the specified directory entry.
    NON-NULL - Returns the address of the raw data the directory describes.
--*/
//{
//    PIMAGE_NT_HEADERS NtHeaders;
//
//    if (LDR_IS_DATAFILE(Base)) {
//        Base = LDR_DATAFILE_TO_VIEW(Base);
//        MappedAsImage = FALSE;
//    }
//
//    NtHeaders = RtlImageNtHeader(Base);
//
//    if (!NtHeaders)
//        return NULL;
//
//    if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//        return (RtlpImageDirectoryEntryToData32(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS32)NtHeaders));
//    } else if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
//        return (RtlpImageDirectoryEntryToData64(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS64)NtHeaders));
//    } else {
//        return (NULL);
//    }
//}


PVOID MiFindExportedRoutineByName (IN PVOID DllBase, IN PANSI_STRING AnsiImageRoutineName)
/*++
Routine Description:
    This function searches the argument module looking for the requested exported function name.
Arguments:
    DllBase - Supplies the base address of the requested module.
    AnsiImageRoutineName - Supplies the ANSI routine name being searched for.
Return Value:
    The virtual address of the requested routine or NULL if not found.
--*/
{
    USHORT OrdinalNumber;
    PULONG NameTableBase;
    PUSHORT NameOrdinalTableBase;
    PULONG Addr;
    LONG High;
    LONG Low;
    LONG Middle;
    LONG Result;
    ULONG ExportSize;
    PVOID FunctionAddress;
    PIMAGE_EXPORT_DIRECTORY ExportDirectory;

    PAGED_CODE();

    ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData (DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize);
    if (ExportDirectory == NULL) {
        return NULL;
    }
    
    NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);// Initialize the pointer to the array of RVA-based ansi export strings.    
    NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);// Initialize the pointer to the array of USHORT ordinal numbers.    
    Low = 0;
    Middle = 0;
    High = ExportDirectory->NumberOfNames - 1;

    while (High >= Low) // Lookup the desired name in the name table using a binary search.
    {        
        Middle = (Low + High) >> 1;// Compute the next probe index and compare the import name with the export name entry.
        Result = strcmp (AnsiImageRoutineName->Buffer, (PCHAR)DllBase + NameTableBase[Middle]);
        if (Result < 0) {
            High = Middle - 1;
        } else if (Result > 0) {
            Low = Middle + 1;
        } else {
            break;
        }
    }

    // If the high index is less than the low index, then a matching table entry was not found.
    // Otherwise, get the ordinal number from the ordinal table.
    if (High < Low) {
        return NULL;
    }

    OrdinalNumber = NameOrdinalTableBase[Middle];

    // If the OrdinalNumber is not within the Export Address Table,then this image does not implement the function.
    // Return not found.
    if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {
        return NULL;
    }

    // Index into the array of RVA export addresses by ordinal number.
    Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
    FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);

    // Forwarders are not used by the kernel and HAL to each other.
    ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) || (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize)));

    return FunctionAddress;
}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;    

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;    

    //测试的代码就不写了。

    return status;    
} 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#include <ntifs.h>
#include <windef.h>
#include <Aux_klib.h> //source里面要有TARGETLIBS=$(DDK_LIB_PATH)\Aux_klib.lib


/*
made by correy
made at 2014.08.19
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/


#define TAG  'tset' //test

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


PVOID RtlImageDirectoryEntryToData (IN PVOID Base, IN BOOLEAN MappedAsImage, IN USHORT DirectoryEntry, OUT PULONG Size);
/*++
Routine Description:
    This function locates a Directory Entry within the image header and returns either the virtual address or seek address of the data the Directory describes.
Arguments:
    Base - Supplies the base of the image or data file.
    MappedAsImage - FALSE if the file is mapped as a data file.
                  - TRUE if the file is mapped as an image.
    DirectoryEntry - Supplies the directory entry to locate.
    Size - Return the size of the directory.
Return Value:
    NULL - The file does not contain data for the specified directory entry.
    NON-NULL - Returns the address of the raw data the directory describes.
--*/
//{
//    PIMAGE_NT_HEADERS NtHeaders;
//
//    if (LDR_IS_DATAFILE(Base)) {
//        Base = LDR_DATAFILE_TO_VIEW(Base);
//        MappedAsImage = FALSE;
//    }
//
//    NtHeaders = RtlImageNtHeader(Base);
//
//    if (!NtHeaders)
//        return NULL;
//
//    if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//        return (RtlpImageDirectoryEntryToData32(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS32)NtHeaders));
//    } else if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
//        return (RtlpImageDirectoryEntryToData64(Base, MappedAsImage, DirectoryEntry, Size, (PIMAGE_NT_HEADERS64)NtHeaders));
//    } else {
//        return (NULL);
//    }
//}


PVOID MiFindExportedRoutineByName (IN PVOID DllBase, IN PANSI_STRING AnsiImageRoutineName)
/*++
Routine Description:
    This function searches the argument module looking for the requested exported function name.
Arguments:
    DllBase - Supplies the base address of the requested module.
    AnsiImageRoutineName - Supplies the ANSI routine name being searched for.
Return Value:
    The virtual address of the requested routine or NULL if not found.
--*/
{
    USHORT OrdinalNumber;
    PULONG NameTableBase;
    PUSHORT NameOrdinalTableBase;
    PULONG Addr;
    LONG High;
    LONG Low;
    LONG Middle;
    LONG Result;
    ULONG ExportSize;
    PVOID FunctionAddress = 0;
    PIMAGE_EXPORT_DIRECTORY ExportDirectory;

    PAGED_CODE();

    __try
    {
        FunctionAddress = *(PVOID *)DllBase;
        FunctionAddress = 0;
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        return FunctionAddress;
    }  

    //确保DllBase可以访问。否则蓝屏。
    ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData (DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize);
    if (ExportDirectory == NULL) {
        return NULL;
    }
    
    NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);// Initialize the pointer to the array of RVA-based ansi export strings.    
    NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);// Initialize the pointer to the array of USHORT ordinal numbers.    
    Low = 0;
    Middle = 0;
    High = ExportDirectory->NumberOfNames - 1;

    while (High >= Low) // Lookup the desired name in the name table using a binary search.
    {        
        Middle = (Low + High) >> 1;// Compute the next probe index and compare the import name with the export name entry.
        Result = strcmp (AnsiImageRoutineName->Buffer, (PCHAR)DllBase + NameTableBase[Middle]);
        if (Result < 0) {
            High = Middle - 1;
        } else if (Result > 0) {
            Low = Middle + 1;
        } else {
            break;
        }
    }

    // If the high index is less than the low index, then a matching table entry was not found.
    // Otherwise, get the ordinal number from the ordinal table.
    if (High < Low) {
        return NULL;
    }

    OrdinalNumber = NameOrdinalTableBase[Middle];

    // If the OrdinalNumber is not within the Export Address Table,then this image does not implement the function.
    // Return not found.
    if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {
        return NULL;
    }

    // Index into the array of RVA export addresses by ordinal number.
    Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
    FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);

    // Forwarders are not used by the kernel and HAL to each other.
    ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) || (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize)));

    return FunctionAddress;
}


PVOID get_module_image_base(__in UCHAR * name)
{
    NTSTATUS status = 0;
    ULONG  modulesSize;
    AUX_MODULE_EXTENDED_INFO * modules;
    ULONG  numberOfModules;
    ULONG i;
    PIMAGE_EXPORT_DIRECTORY pied = 0;
    PVOID ImageBase = 0;

    status = AuxKlibInitialize();
    if (!NT_SUCCESS( status )) 
    {
        KdPrint(( "AuxKlibInitialize fail %d\n", status));
        return ImageBase;
    }    
    
    status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL);// Get the required array size.
    if (!NT_SUCCESS(status) || modulesSize == 0) {
        return ImageBase;
    }
    
    numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO);// Calculate the number of modules.
        
    modules = (AUX_MODULE_EXTENDED_INFO*) ExAllocatePoolWithTag(PagedPool, modulesSize, TAG);// Allocate memory to receive data.
    if (modules == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        return ImageBase;
    }
    RtlZeroMemory(modules, modulesSize);
    
    status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), modules);// Obtain the module information.
    if (!NT_SUCCESS(status)) {
        ExFreePoolWithTag(modules,TAG);
        return ImageBase;
    }

    for (i = 0;i<numberOfModules;i++)
    {
        UCHAR * pfilename = modules[i].FullPathName + modules[i].FileNameOffset;

        if (_stricmp(pfilename, name) == 0)
        {
            ImageBase = modules[i].BasicInfo.ImageBase;
            break;
        }
    }

    ExFreePoolWithTag(modules,TAG);

    return ImageBase;
} 


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;  
    PVOID ImageBase = 0;
    PVOID FunctionAddress;
    //ANSI_STRING EngCreateBitmap  = RTL_CONSTANT_STRING("EngCreateBitmap");//NT开头的函数竟然一个也没有导出。
    ANSI_STRING EngCreateBitmap  = RTL_CONSTANT_STRING("ArcFilterDprIndicateReceive");

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;    

    //ImageBase = get_module_image_base("WIN32k.sys");//注意这个的环境:有的线程不可以访问。不然地址不可访问。
    ImageBase = get_module_image_base("ndis.sys");
    if (ImageBase == 0)
    {
        return status; 
    }

    FunctionAddress = MiFindExportedRoutineByName (ImageBase, &EngCreateBitmap);
    if (FunctionAddress == 0)
    {
        return status; 
    }

    /*
    验证下:
    1: kd> dd FunctionAddress L1
    f88f6c78  ba5552cd
    1: kd> u ba5552cd
    NDIS!ArcFilterDprIndicateReceive:
    ba5552cd 8bff            mov     edi,edi
    ba5552cf 55              push    ebp
    ba5552d0 8bec            mov     ebp,esp
    ba5552d2 83ec24          sub     esp,24h
    ba5552d5 a11c6353ba      mov     eax,dword ptr [NDIS!__security_cookie (ba53631c)]
    ba5552da 53              push    ebx
    ba5552db 8b5d10          mov     ebx,dword ptr [ebp+10h]
    ba5552de 56              push    esi
    */

    return status;    
} 

2014年8月15日星期五

WINDBG条件断点

Setting a Conditional Breakpoint

Conditional breakpoints can be very useful when you are trying to find bugs in your code. 
They cause a break to occur only if a specific condition is satisfied.

正如文章所说:很有用。
同时,这也是通向WINDBG脚本的好途径。

本文收集本人常用的条件断点:


1.不是条件断点的高级断点:发生操作时不断下来而是打印个信息。
bu nt!zwcreatefile ".echo zwcreatefile is called;g"
bu ntdll!ntcreatefile ".echo ntcreatefile is called;g"
bu kernel32!CreateFileA "poi(eso + 4)"
bu kernel32!CreateFileW "poi(eso + 4)"


2.不算是条件断点的基于进程/线程的断点,主要用于内核模式的调试:
bu /p 81cf3540 test!PreOPeration
bu /p 81cf3540 test!PreOPeration+0x1af
bu1 /p 81e7f368 @@masm(`test!e:\code\driver\test0\test.c:422+`);
线程的不再说了,因为CID都是全局的。
这也省了编写这些识别条件的代码了。

2014年8月9日星期六

编写内核DLL

#include <ntifs.h>
#include <windef.h>


/*
汇编也可以写内核的DLL,包括64位的。
这里也就不说了。

VS2012和VS2013应该也可以,好像应该有示例的工程。

这里是WDK的内核的DLL的示例。

参考:
http://msdn.microsoft.com/zh-cn/library/windows/hardware/ff542891(v=vs.85).aspx
http://msdn.microsoft.com/zh-cn/library/windows/hardware/dn613893(v=vs.85).aspx
http://www.wd-3.com/archive/KernelDlls.htm

注意事项:
1.Unlike a standard driver, however, an export driver does not receive IRPs or occupy a place in the driver stack, nor is it considered to be a system service.
2.(Even if you use DECLSPEC_EXPORT, your .def file must contain at least DllInitialize and DllUnload so you can mark these functions as PRIVATE.)
3.You can build any standard driver as an export driver—it will operate as a standard driver when loaded in the usual way, and also export functions that other drivers can call. 

made by correy
made at 2014.08.09
homepage:http://correy.webs.com
*/


//DECLSPEC_IMPORT 
//DECLSPEC_EXPORT
 __declspec(dllexport) int test ()
{
    int Status = STATUS_SUCCESS;

    KdPrint(("内核DLL的test\n"));

    return Status;
}


NTSTATUS DllUnload(void)
{
    NTSTATUS Status = STATUS_SUCCESS;

    KdPrint(("内核DLL的DllUnload\n"));

    return Status;
}


NTSTATUS DllInitialize(_In_  PUNICODE_STRING RegistryPath)
{
    NTSTATUS Status = STATUS_SUCCESS;

    KdPrint(("内核DLL的DllInitialize\n"));

    return Status;
}


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{   
    KdPrint(("内核DLL的Unload\n"));
}


/*
 At a minimum, an export driver must have a DriverEntry routine; 
 this can be an empty stub to satisfy build scripts--the export driver's DriverEntry is never called by Plug and Play.
*/
#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    NTSTATUS Status = STATUS_SUCCESS;
    KdBreakPoint();

    DriverObject->DriverUnload = Unload; 

    KdPrint(("内核DLL的入口\n"));

    return Status;
} 

source文件如下:

TARGETNAME=KernelDLL #The .sys file is your kernel-mode DLL.

TARGETTYPE=EXPORT_DRIVER #这也可能决定了别的程序对这个文件的调用方式(静态链接和只有函数的信息)。DRIVER_LIBRARY可能就是静态链接的。以及生成的文件大小等。

SOURCES=KernelDLL.C 

DLLDEF=def.def #这个文件没有使用。这是另一个办法。

TARGETPATH=obj

/////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <ntifs.h>
#include <windef.h>


DECLSPEC_IMPORT int test (); 


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{   
    
}


#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    NTSTATUS Status = STATUS_SUCCESS;
    KdBreakPoint();

    DriverObject->DriverUnload = Unload; 

    test();

    return Status;
} 

source文件如下:

TARGETNAME=test

TARGETTYPE=DRIVER

SOURCES=test.C 

TARGETPATH=obj 

TARGETLIBS=KernelDLL.lib #要把这个文件复制到相应的位置。好像还有静态链接和动态链接之别。

/////////////////////////////////////////////////////////////////////////////////////////////////////////

测试:
1.Export drivers must be installed in the %Windir%\System32\Drivers directory.
2.Install the export driver .sys file in the %windir%\system32\drivers directory. 
  It will be loaded the first time any other driver calls into it.
  先加载KernelDLL.sys.
  不然test.sys加载失败。
  开始觉得这不可思议,不像DLL。
  又一想系统的SYS也都是这样的。如ntos*.exe NDIS.SYS。
  所以此功能用处不大。
3.加载test.sys.
  效果就不说了。
  

2014年8月5日星期二

打印栈帧的一点信息

#include <ntifs.h>

LARGE_INTEGER  Cookie;


/*
功能:打印到现在为止的函数调用的栈帧的信息(栈回溯),而不是最终的函数调用栈帧的信息。

记得以前有个函数,可以打印函数调用堆栈的信息,如果有符号文件还可以显示更多的信息。
当时觉得没有用,一心想解析符号文件的信息。

现在想来,即使没有符号文件及相关的信息,有这些调用堆栈的信息,对开发这和解决问题也是有用的。
不能光想着符号文件。没有符号文件分析程序更加锻炼人的能力。

此文收集并简单测试一些信息。

更多的API如下:
IoGetStackLimits
IoGetInitialStack 
IoGetRemainingStackSize 
IoWithinStackLimits
KeExpandKernelStackAndCallout 
KeSetKernelStackSwapEnable

http://www.cnblogs.com/welfear/archive/2010/11/16/1878503.html
http://blog.csdn.net/cosmoslife/article/details/7818841
http://blogs.msdn.com/b/vcblog/archive/2014/01/23/examining-stack-traces-of-objects-using-visual-studio-2013.aspx
CaptureStackBackTrace 
RtlCaptureStackBackTrace 
RtlCaptureStackContext
RtlGetCallerAddress XP 已经导出。
RtlWalkFrameChain http://msdn.microsoft.com/zh-cn/office/ff563638(v=vs.100).aspx
KeExpandKernelStackAndCallout

made by correy
made at 2014.08.05
homepage:http://correy.webs.com
*/


void get_open_information_from_stack_in_32()
    /*
    相信也可以处理64位系统的,尽管它的参数的调用方式特殊,但参数也是存在栈上的。
    */
{
    /*
    The RtlCaptureStackBackTrace routine captures a stack back trace by walking up the stack and recording the information for each frame.
    Important  This is an exported function that MUST probe the ability to take page faults.
    所以:IRQL: <= DISPATCH_LEVEL

    Requirements
    Versions: Available in Windows XP and later versions of the Windows operating systems.
    */

    /*
    此时栈的信息类似如下:
    3: kd> k
    ChildEBP RetAddr  
    efaf6964 f8870132 test!get_open_information_from_stack_in_32+0x8 [e:\code\driver\test\test.c @ 20]
    efaf6970 f887005d test!post_open_key+0x12 [e:\code\driver\test\test.c @ 58]
    efaf6980 8056bdd4 test!RegistryCallback+0x1d [e:\code\driver\test\test.c @ 74]
    efaf69b4 806312bd nt!CmpCallCallBacks+0x50
    efaf6b88 805c0099 nt!CmpParseKey+0x7b9
    efaf6c00 805bca48 nt!ObpLookupObjectName+0x119
    efaf6c54 80626810 nt!ObOpenObjectByName+0xea
    efaf6d50 805427e8 nt!NtOpenKey+0x1c8
    efaf6d50 7c92e514 nt!KiSystemServicePostCall
    0168f700 7c92d5da ntdll!KiFastSystemCallRet
    0168f7e8 7c93019b ntdll!ZwOpenKey+0xc
    0168fa14 00000000 ntdll!RtlAllocateHeap+0x1c2
    在这种情况下是一定能找到:nt!NtOpenKey函数的地址的。
    */

    PVOID pbacts = IoGetInitialStack();//returns the base address of the current thread's stack.
    /*
    上面一行运行的结果如下:
    3: kd> r
    eax=efaf7000 ebx=8055b3a0 ecx=efaf6b44 edx=e1a02d90 esi=e1a02d88 edi=e1cf5508
    eip=f88700b1 esp=efaf6948 ebp=efaf6964 iopl=0         nv up ei ng nz ac pe nc
    cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000296
    test!get_open_information_from_stack_in_32+0x11:
    f88700b1 33c0            xor     eax,eax
    3: kd> dd efaf6948
    efaf6948  efaf7000 00000001 805f2501 80630424
    efaf6958  00000000 e16d2518 e1d1ab98 efaf6970
    efaf6968  f8870132 00000000 efaf6980 f887005d
    efaf6978  efaf6b44 0000000d efaf69b4 8056bdd4
    efaf6988  00000000 0000000d efaf6b44 00000000
    efaf6998  e16d2518 e1d1ab98 e1a02d90 e1a02d90
    efaf69a8  81ed9da0 8055b214 00000000 efaf6b88
    efaf69b8  806312bd 0000000d efaf6b44 e1bb5558
    3: kd> dd pbacts
    efaf6948  efaf7000 00000001 805f2501 80630424
    efaf6958  00000000 e16d2518 e1d1ab98 efaf6970
    efaf6968  f8870132 00000000 efaf6980 f887005d
    efaf6978  efaf6b44 0000000d efaf69b4 8056bdd4
    efaf6988  00000000 0000000d efaf6b44 00000000
    efaf6998  e16d2518 e1d1ab98 e1a02d90 e1a02d90
    efaf69a8  81ed9da0 8055b214 00000000 efaf6b88
    efaf69b8  806312bd 0000000d efaf6b44 e1bb5558
    可见IoGetInitialStack的内容和栈指针(这里是ESP)的内容的内容是一样的。
    */
    
    USHORT ncf = 0;//The number of captured frames
    USHORT i = 0;

    //In Windows XP and Windows Server 2003, the sum of the FramesToSkip and FramesToCapture parameters must be less than 63.
    ULONG FramesToSkip = 0;//The number of frames to skip from the start of the back trace. 
    ULONG FramesToCapture = 62;//The number of frames to be captured. 
    
    PVOID  * BackTrace = 0;//An array of pointers captured from the current stack trace. 
    PVOID  * pBackTrace = 0;

    /*An optional value that can be used to organize hash tables. 
    If this parameter is NULL, no hash value is computed.
    This value is calculated based on the values of the pointers returned in the BackTrace array.
    Two identical stack traces will generate identical hash values.
    */
    ULONG BackTraceHash = 0;

    /*
    http://msdn.microsoft.com/zh-cn/office/ff563638(v=vs.100).aspx
    RtlGetCallersAddress. Use the intrinsic _ReturnAddress instead.
    就是本函数的返回地址,也就是调用本函数的下一个指令的地址。
    在调试器里面就是Retaddr。
    */
    PVOID CallersAddress = _ReturnAddress();

    //http://msdn.microsoft.com/zh-cn/library/windows/hardware/Dn613940(v=vs.85).aspx
    int stacklength = 32 * 1024;//取X86/X64/IA64的栈的最大值。

    UNICODE_STRING NtOpenKey = RTL_CONSTANT_STRING(L"NtOpenKey");
    PVOID p_NtOpenKey = MmGetSystemRoutineAddress(&NtOpenKey);//此函数没有导出。获取的值恒为0.

    ULONG_PTR  LowLimit = 0;//Pointer to a caller-supplied variable in which this routine returns the lower offset of the current thread's stack frame. 
    ULONG_PTR  HighLimit = 0;//Pointer to a caller-supplied variable in which this routine returns the higher offset of the current thread's stack frame.
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //下面开始代码。

    IoGetStackLimits(&LowLimit, &HighLimit);

    BackTrace = (PVOID  *)ExAllocatePool(NonPagedPool, stacklength); 
    if (BackTrace == NULL)
    {
        return ;
    }
    RtlZeroMemory(BackTrace, stacklength);
    /*
    BackTrace的地址一定在LowLimit和HighLimit之间,这是废话。
    */

    ncf = RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture, BackTrace, &BackTraceHash);     
    /*
    这行代码运行后的效果类似为:
    3: kd> dps esp
    efaf6948  efaf7000
    efaf694c  00000000
    efaf6950  0000003e
    efaf6954  ebbd2e00
    efaf6958  00009000
    efaf695c  82161000
    efaf6960  e1d10009
    efaf6964  efaf6970
    efaf6968  f8870132 test!post_open_key+0x12 [e:\code\driver\test\test.c @ 58]
    efaf696c  00000000
    efaf6970  efaf6980
    efaf6974  f887005d test!RegistryCallback+0x1d [e:\code\driver\test\test.c @ 74]
    efaf6978  efaf6b44
    efaf697c  0000000d
    efaf6980  efaf69b4
    efaf6984  8056bdd4 nt!CmpCallCallBacks+0x50
    efaf6988  00000000
    efaf698c  0000000d
    efaf6990  efaf6b44
    efaf6994  00000000
    efaf6998  e16d2518
    efaf699c  e1d1ab98
    efaf69a0  e1a02d90
    efaf69a4  e1a02d90
    efaf69a8  81ed9da0
    efaf69ac  8055b214 nt!CmpRegistryLock+0x34
    efaf69b0  00000000
    efaf69b4  efaf6b88
    efaf69b8  806312bd nt!CmpParseKey+0x7b9
    efaf69bc  0000000d
    efaf69c0  efaf6b44
    efaf69c4  e1bb5558
    3: kd> dps BackTrace
    efaf695c  82161000
    efaf6960  e1d10009
    efaf6964  efaf6970
    efaf6968  f8870132 test!post_open_key+0x12 [e:\code\driver\test\test.c @ 58]
    efaf696c  00000000
    efaf6970  efaf6980
    efaf6974  f887005d test!RegistryCallback+0x1d [e:\code\driver\test\test.c @ 74]
    efaf6978  efaf6b44
    efaf697c  0000000d
    efaf6980  efaf69b4
    efaf6984  8056bdd4 nt!CmpCallCallBacks+0x50
    efaf6988  00000000
    efaf698c  0000000d
    efaf6990  efaf6b44
    efaf6994  00000000
    efaf6998  e16d2518
    efaf699c  e1d1ab98
    efaf69a0  e1a02d90
    efaf69a4  e1a02d90
    efaf69a8  81ed9da0
    efaf69ac  8055b214 nt!CmpRegistryLock+0x34
    efaf69b0  00000000
    efaf69b4  efaf6b88
    efaf69b8  806312bd nt!CmpParseKey+0x7b9
    efaf69bc  0000000d
    efaf69c0  efaf6b44
    efaf69c4  e1bb5558
    efaf69c8  00000000
    efaf69cc  efaf6c40
    efaf69d0  e63561d1
    efaf69d4  81220010
    efaf69d8  e1b9fb18
    可见这个函数的栈顶少几个,但是不影响查找以前的函数和参数。
    多几个的原因可能是又调用函数了或者局部变量的初始化。

    BackTrace的这段内容就是函数的调用关系。
    */

    /*
    这里打印的信息类似于WINDBG的K命令,但是信息不多。
    */
    for (pBackTrace = BackTrace;i < ncf;pBackTrace++,i++ )
    {
        //if (*pBackTrace == p_NtOpenKey)//ZwOpenKey可以直接使用。
        //{
        //    break;
        //}
        KdPrint(("%d: %p \n", i, *pBackTrace));
    }

    /*
    要想获取某个函数的参数信息
    还得用IoGetStackLimits(&LowLimit, &HighLimit)的两个参数的值。
    在那个范围内搜索。
    */

    /*
    RtlWalkFrameChain和RtlCaptureStackBackTrace功能相似。
    RtlCaptureStackBackTrace封装了RtlWalkFrameChain(见WDK)。
    只不过:
    1.RtlWalkFrameChain导出(且头文件有函数申明)但是没有公开。
    2.RtlWalkFrameChain还可以获取包括(加上)用户态栈帧的数目。
    3.#pragma optimize( "y", off ) // disable FPO
    */
    //ncf = (USHORT)RtlWalkFrameChain (BackTrace, FramesToCapture, 0);  
    //ncf = (USHORT)RtlWalkFrameChain (BackTrace, FramesToCapture, 1); 

    ExFreePool(BackTrace);
}


NTSTATUS post_open_key(__in_opt PVOID  Argument2)
{
    unsigned int status = STATUS_SUCCESS;

    get_open_information_from_stack_in_32();

    return status;
}


EX_CALLBACK_FUNCTION RegistryCallback;
NTSTATUS RegistryCallback(__in PVOID  CallbackContext, __in_opt PVOID  Argument1, __in_opt PVOID  Argument2)
{
    switch((int)Argument1)
    {  
    case RegNtPostOpenKey:// == 13 仅仅XP收到此消息.
        post_open_key(Argument2);
        break;
    default:
        break;
    }

    return STATUS_SUCCESS;
}


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{   
    CmUnRegisterCallback(Cookie);
}


#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    KdBreakPoint();

    DriverObject->DriverUnload = Unload; 

    return CmRegisterCallback(RegistryCallback, NULL, &Cookie);
}