內核知識第十講,內核結構體簡介.以及自己實現內存讀寫功能.


 

            內核知識第十講,內核結構體簡介.以及自己實現內存讀寫功能.

前言:

  不知道大家學習逆向技術的時候.有沒有聽說過什么驅動過保護. 什么驅動讀寫xxx的.而今天就講解一下其原理. 

  PS: 講解原理還有簡單的Demo. 請大家學習逆向技術.並做好信息安全. 而不是要求大家去做黑產.

  PS: 只講今天表中有用的結構體.不會每個成員都會介紹.

一丶ReadProcessMemory 和WriteProcessMemory 的小知識.

 

我們都知道 Ring3讀寫別人進程的內存.都是用這兩個API進行操作的.  但是游戲為了保護自己.對這兩個API進行了HOOK. 進而使自己的游戲進程不會被更改.

但是我們有沒有想過. 我們是否可以自己實現這個API.

首先隨便找一個API. 看看作用.

BOOL ReadProcessMemory(
  HANDLE hProcess,              // handle to the process
  LPCVOID lpBaseAddress,        // base of memory area
  LPVOID lpBuffer,              // data buffer
  SIZE_T nSize,                 // number of bytes to read
  SIZE_T * lpNumberOfBytesRead  // number of bytes read
);

可以看到.第一個參數是一個句柄.  而OpenProcess獲取句柄的API.也肯定被HOOK了.那我們可以不通過句柄來獲取嗎?

答案是可以的:

  我們進了Ring0了. 我們也知道了這些API的本質就是查表. windows對進程管理肯定有一張表格存放這. 那么我們怎么查看.

通過調試虛擬機的XP系統. 查看內核中0環的API.

這里需要介紹一下X指令

x nt!*Read*Mmmory*  

*代表通配符. 代表的是我想查找一個API. 前邊我不知道.但是中間我知道.

x指令的作用就是 查找所有有關的API.

其中.有個API.是nt!ZwReadVirtualMemory

我們查看反匯編

發現內部調用一個Call,繼續跟進去

發現操作了fs段寄存器.所以得出結論.fs段寄存器中保存了表首地址.

 

而這個表.在32位系統下.存放在了FS寄存器中.  

二丶通過GDT獲取表內容.

我們知道.FS 里面的內容.在0環中.是存放表的位置. 我們可以看下GDT表中存放的段地址是什么.

由此得出表的首地址是  ffdff000.

這個地址則是我們表的首地址.

DT命令的使用.

我們獲得了表的首地址.但是要對其做解析.  dt命令就是解析的.

dt是解析結構體的.

例如:

  dt  xxx結構體.         :那么結構體內容就會顯示出來.偏移也會顯示出來.

  dt  xxx結構體  地址 : 那么不光顯示偏移.而且成員的地址也會列出來.   注意,地址在前.結構體在后也可以.

 

三丶_KPCR表.

我們的GDT的段地址就是 _KPCR表.

我們對其解析一下看一下.

 

通過解析.我們得出了3個重要的地方.  

1. 我們的位置保存了GDT表的值.和第二處是一樣的.

3.重要結構體 _KPRCB

四丶_KPRCB表.

通過上圖,我們得出了__KPRCB表.我們在對其解析一下看看.

這個結構體內容比較多.我直接COPY下來了.

kd> dt _KPRCB 0xffdff120 
nt!_KPRCB
   +0x000 MinorVersion     : 1
   +0x002 MajorVersion     : 1
   +0x004 CurrentThread    : 0x8055a9c0 _KTHREAD    //當前的線程.
   +0x008 NextThread       : (null) 
   +0x00c IdleThread       : 0x8055a9c0 _KTHREAD
   +0x010 Number           : 0 ''
   +0x011 Reserved         : 0 ''
   +0x012 BuildType        : 2
   +0x014 SetMember        : 1
   +0x018 CpuType          : 6 ''
   +0x019 CpuID            : 1 ''
   +0x01a CpuStep          : 0x5e03
   +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   : 0
   +0x4a8 KernelTime       : 0
   +0x4ac UserTime         : 0
   +0x4b0 DpcTime          : 0
   +0x4b4 DebugDpcTime     : 0
   +0x4b8 InterruptTime    : 0
   +0x4bc AdjustDpcThreshold : 0x14
   +0x4c0 PageColor        : 0
   +0x4c4 SkipTick         : 0
   +0x4c8 MultiThreadSetBusy : 0 ''
   +0x4c9 Spare2           : [3]  ""
   +0x4cc ParentNode       : 0x8055b080 _KNODE
   +0x4d0 MultiThreadProcessorSet : 1
   +0x4d4 MultiThreadSetMaster : (null) 
   +0x4d8 ThreadStartCount : [2] 0
   +0x4e0 CcFastReadNoWait : 0
   +0x4e4 CcFastReadWait   : 0
   +0x4e8 CcFastReadNotPossible : 0
   +0x4ec CcCopyReadNoWait : 0
   +0x4f0 CcCopyReadWait   : 0
   +0x4f4 CcCopyReadNoWaitMiss : 0
   +0x4f8 KeAlignmentFixupCount : 0
   +0x4fc KeContextSwitches : 0
   +0x500 KeDcacheFlushCount : 0
   +0x504 KeExceptionDispatchCount : 0x1f
   +0x508 KeFirstLevelTbFills : 0
   +0x50c KeFloatingEmulationCount : 0
   +0x510 KeIcacheFlushCount : 0
   +0x514 KeSecondLevelTbFills : 0
   +0x518 KeSystemCalls    : 0
   +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     : 0
   +0x7a8 IpiFrame         : (null) 
   +0x7ac PrcbPad2         : [52]  ""
   +0x7e0 CurrentPacket    : [3] (null) 
   +0x7ec TargetSet        : 0
   +0x7f0 WorkerRoutine    : (null) 
   +0x7f4 IpiFrozen        : 0
   +0x7f8 PrcbPad3         : [40]  ""
   +0x820 RequestSummary   : 0
   +0x824 SignalDone       : (null) 
   +0x828 PrcbPad4         : [56]  ""
   +0x860 DpcListHead      : _LIST_ENTRY [ 0xffdff980 - 0xffdff980 ]
   +0x868 DpcStack         : 0x8054f200 Void
   +0x86c DpcCount         : 0
   +0x870 DpcQueueDepth    : 0
   +0x874 DpcRoutineActive : 0
   +0x878 DpcInterruptRequested : 0
   +0x87c DpcLastCount     : 0
   +0x880 DpcRequestRate   : 0
   +0x884 MaximumDpcQueueDepth : 4
   +0x888 MinimumDpcRate   : 3
   +0x88c QuantumEnd       : 0
   +0x890 PrcbPad5         : [16]  ""
   +0x8a0 DpcLock          : 0
   +0x8a4 PrcbPad6         : [28]  ""
   +0x8c0 CallDpc          : _KDPC
   +0x8e0 ChainedInterruptList : (null) 
   +0x8e4 LookasideIrpFloat : 0n0
   +0x8e8 SpareFields0     : [6] 0
   +0x900 VendorString     : [13]  "GenuineIntel"
   +0x90d InitialApicId    : 0 ''
   +0x90e LogicalProcessorsPerPhysicalProcessor : 0x1 ''
   +0x910 MHz              : 0
   +0x914 FeatureBits      : 0xa0013fff
   +0x918 UpdateSignature  : _LARGE_INTEGER 0x6a`00000000
   +0x920 NpxSaveArea      : _FX_SAVE_AREA
   +0xb30 PowerState       : _PROCESSOR_POWER_STATE //電源狀態.

這個表中重要的結構體就是

_KTHREAD結構體.保存了當前線程的信息.

五丶了解進程和線程的數據關系.

 

我們知道.一個進程可以有多個線程.  一對多的關系.

而一個線程只屬於一個進程.

所以   進程做外鍵.放到線程表中.

那么得出了數據關系.我們在看_KThread結構體里面是否這樣做.

PS: 也就是說我們通過線程信息.能得到進程信息.

例如圖示:

  

線程_KThread

進程

Xxx線程

A進程

Xxx線程

A進程

六丶_KTHREAD 結構體中的內容.

通過上面解析.我們得出_KThread的位置.我們解析一下看看.

PS結構體也是很多.copy過來.

nt!_KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListHead   : _LIST_ENTRY [ 0x8055a9d0 - 0x8055a9d0 ]
   +0x018 InitialStack     : 0x80552200 Void
   +0x01c StackLimit       : 0x8054f200 Void
   +0x020 Teb              : (null) 
   +0x024 TlsArray         : (null) 
   +0x028 KernelStack      : 0x80551fd4 Void
   +0x02c DebugActive      : 0 ''
   +0x02d State            : 0x2 ''
   +0x02e Alerted          : [2]  ""
   +0x030 Iopl             : 0 ''
   +0x031 NpxState         : 0xa ''
   +0x032 Saturation       : 0 ''
   +0x033 Priority         : 31 ''
   +0x034 ApcState         : _KAPC_STATE      //APC狀態.
   +0x04c ContextSwitches  : 0
   +0x050 IdleSwapBlock    : 0 ''
   +0x051 Spare0           : [3]  ""
   +0x054 WaitStatus       : 0n0
   +0x058 WaitIrql         : 0x2 ''
   +0x059 WaitMode         : 0 ''
   +0x05a WaitNext         : 0 ''
   +0x05b WaitReason       : 0 ''
   +0x05c WaitBlockList    : (null) 
   +0x060 WaitListEntry    : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x060 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x068 WaitTime         : 0
   +0x06c BasePriority     : 0 ''
   +0x06d DecrementCount   : 0 ''
   +0x06e PriorityDecrement : 0 ''
   +0x06f Quantum          : 127 ''
   +0x070 WaitBlock        : [4] _KWAIT_BLOCK
   +0x0d0 LegoData         : (null) 
   +0x0d4 KernelApcDisable : 0
   +0x0d8 UserAffinity     : 0xffffffff
   +0x0dc SystemAffinityActive : 0 ''
   +0x0dd PowerState       : 0 ''
   +0x0de NpxIrql          : 0 ''
   +0x0df InitialNode      : 0 ''
   +0x0e0 ServiceTable     : 0x8055b220 Void
   +0x0e4 Queue            : (null) 
   +0x0e8 ApcQueueLock     : 0
   +0x0f0 Timer            : _KTIMER
   +0x118 QueueListEntry   : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x120 SoftAffinity     : 1
   +0x124 Affinity         : 1
   +0x128 Preempted        : 0 ''
   +0x129 ProcessReadyQueue : 0 ''
   +0x12a KernelStackResident : 0x1 ''
   +0x12b NextProcessor    : 0 ''
   +0x12c CallbackStack    : (null) 
   +0x130 Win32Thread      : (null) 
   +0x134 TrapFrame        : (null) 
   +0x138 ApcStatePointer  : [2] 0x8055a9f4 _KAPC_STATE
   +0x140 PreviousMode     : 0 ''
   +0x141 EnableStackSwap  : 0x1 ''
   +0x142 LargeStack       : 0 ''
   +0x143 ResourceIndex    : 0 ''
   +0x144 KernelTime       : 0
   +0x148 UserTime         : 0
   +0x14c SavedApcState    : _KAPC_STATE
   +0x164 Alertable        : 0 ''
   +0x165 ApcStateIndex    : 0 ''
   +0x166 ApcQueueable     : 0x1 ''
   +0x167 AutoAlignment    : 0 ''
   +0x168 StackBase        : 0x80552200 Void
   +0x16c SuspendApc       : _KAPC
   +0x19c SuspendSemaphore : _KSEMAPHORE
   +0x1b0 ThreadListEntry  : _LIST_ENTRY [ 0x8055ac70 - 0x8055ac70 ]
   +0x1b8 FreezeCount      : 0 ''
   +0x1b9 SuspendCount     : 0 ''
   +0x1ba IdealProcessor   : 0 ''
   +0x1bb DisableBoost     : 0 ''

我們當前所講重要的成員有一個 

_KAPC_STATE, 也就是當前地址+ 0x34的位置. 我們看一下里面存放的是什么.

七丶解析 _KAPC_STATE表的內容.

通過解析表中的內容.我們得出了外鍵. 也就是進程的信息.

_KPROCESS

現在我們解析_KPROCESS

八丶解析_KPROCESS表中的內容

命令:

  dt 0x8055ac20 _KPROCESS

其中重要的成員有一個 CR3,也就是我們所說的PDE. 里面保存了當前進程PDE

 

九丶微軟的隱藏.核心的知識.

通過上面幾張表.我們最終找到了PDE的位置.那么最后我們修改PDE.然后對其讀取內存.則可以自己實現ReadProcessMemory

但是現在微軟對我們隱藏了.也就是說我們的 _KTHREA 和 _KPROCESS 結構體其實都是一小部分.

 

其實真正的結構體是

_ETHREAD 和_EPROCESS

而_KTHREAD 和_ETHREAD都是這兩個結構體中的第一項成員.

例如:

  

struct _EPROCESS
{
    _KPROCESS * m_Kprocess       
}

struct _ETHREAD
{
    _KTHREAD * m_KTHREAD     
}

也就是說.同一個 地址,可以解析為_KPROCESS.也可以解析成_EPROCESS.  .線程的同理.

我們重新解析一下.

解析_ETHREAD

 PS: 表項太多.直接拷貝

kd> dt 0x8055a9c0  _ETHREAD
nt!_ETHREAD
   +0x000 Tcb              : _KTHREAD            //第一個成員果然是_KTHREAD
   +0x1c0 CreateTime       : _LARGE_INTEGER 0x0
   +0x1c0 NestedFaultCount : 0y00
   +0x1c0 ApcNeeded        : 0y0
   +0x1c8 ExitTime         : _LARGE_INTEGER 0x0
   +0x1c8 LpcReplyChain    : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x1c8 KeyedWaitChain   : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x1d0 ExitStatus       : 0n0
   +0x1d0 OfsChain         : (null) 
   +0x1d4 PostBlockList    : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x1dc TerminationPort  : (null) 
   +0x1dc ReaperLink       : (null) 
   +0x1dc KeyedWaitValue   : (null) 
   +0x1e0 ActiveTimerListLock : 0
   +0x1e4 ActiveTimerListHead : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x1ec Cid              : _CLIENT_ID
   +0x1f4 LpcReplySemaphore : _KSEMAPHORE
   +0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
   +0x208 LpcReplyMessage  : (null) 
   +0x208 LpcWaitingOnPort : (null) 
   +0x20c ImpersonationInfo : (null) 
   +0x210 IrpList          : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x218 TopLevelIrp      : 0
   +0x21c DeviceToVerify   : (null) 
   +0x220 ThreadsProcess   : (null) 
   +0x224 StartAddress     : (null) 
   +0x228 Win32StartAddress : (null) 
   +0x228 LpcReceivedMessageId : 0
   +0x22c ThreadListEntry  : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x234 RundownProtect   : _EX_RUNDOWN_REF
   +0x238 ThreadLock       : _EX_PUSH_LOCK
   +0x23c LpcReplyMessageId : 0
   +0x240 ReadClusterSize  : 0
   +0x244 GrantedAccess    : 0
   +0x248 CrossThreadFlags : 0
   +0x248 Terminated       : 0y0
   +0x248 DeadThread       : 0y0
   +0x248 HideFromDebugger : 0y0
   +0x248 ActiveImpersonationInfo : 0y0
   +0x248 SystemThread     : 0y0
   +0x248 HardErrorsAreDisabled : 0y0
   +0x248 BreakOnTermination : 0y0
   +0x248 SkipCreationMsg  : 0y0
   +0x248 SkipTerminationMsg : 0y0
   +0x24c SameThreadPassiveFlags : 0
   +0x24c ActiveExWorker   : 0y0
   +0x24c ExWorkerCanWaitUser : 0y0
   +0x24c MemoryMaker      : 0y0
   +0x250 SameThreadApcFlags : 0
   +0x250 LpcReceivedMsgIdValid : 0y0
   +0x250 LpcExitThreadCalled : 0y0
   +0x250 AddressSpaceOwner : 0y0
   +0x254 ForwardClusterOnly : 0 ''
   +0x255 DisablePageFaultClustering : 0 ''

解析_EPROCESS

kd> dt _ePROCESS 0x8055ac20
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS        //第一個也是_KPROCESS
   +0x06c ProcessLock      : _EX_PUSH_LOCK
   +0x070 CreateTime       : _LARGE_INTEGER 0x0
   +0x078 ExitTime         : _LARGE_INTEGER 0x0
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : (null)           //進程的ID
   +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]//雙向鏈表.其中指向了下一個_EPROCESS 鏈表的位置. 也就是+0x88的位置. 我們需要-0x88才到首地址.
   +0x090 QuotaUsage       : [3] 0
   +0x09c QuotaPeak        : [3] 0
   +0x0a8 CommitCharge     : 0
   +0x0ac PeakVirtualSize  : 0
   +0x0b0 VirtualSize      : 0
   +0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x0bc DebugPort        : (null)             //調試事件.我們的進程如果把這個給空.那么任何調試器都會死.什么調試都不管用.
   +0x0c0 ExceptionPort    : (null) 
   +0x0c4 ObjectTable      : (null) 
   +0x0c8 Token            : _EX_FAST_REF          //令牌權限. 可以讓我們的ring3程序變為 system級別的進程.最高級別.比管理員級別還高.但是你ring0.弄這個就意義不大了.除非有特殊需求.而且這個也是病毒作者常用的.
   +0x0cc WorkingSetLock   : _FAST_MUTEX
   +0x0ec WorkingSetPage   : 0xbff80
   +0x0f0 AddressCreationLock : _FAST_MUTEX
   +0x110 HyperSpaceLock   : 0
   +0x114 ForkInProgress   : (null) 
   +0x118 HardwareTrigger  : 0
   +0x11c VadRoot          : (null) 
   +0x120 VadHint          : (null) 
   +0x124 CloneRoot        : (null) 
   +0x128 NumberOfPrivatePages : 0
   +0x12c NumberOfLockedPages : 0
   +0x130 Win32Process     : (null) 
   +0x134 Job              : (null) 
   +0x138 SectionObject    : (null) 
   +0x13c SectionBaseAddress : (null) 
   +0x140 QuotaBlock       : (null) 
   +0x144 WorkingSetWatch  : (null) 
   +0x148 Win32WindowStation : (null) 
   +0x14c InheritedFromUniqueProcessId : (null) 
   +0x150 LdtInformation   : (null) 
   +0x154 VadFreeHint      : (null) 
   +0x158 VdmObjects       : (null) 
   +0x15c DeviceMap        : (null) 
   +0x160 PhysicalVadList  : _LIST_ENTRY [ 0x8055ad80 - 0x8055ad80 ]
   +0x168 PageDirectoryPte : _HARDWARE_PTE
   +0x168 Filler           : 0
   +0x170 Session          : (null) 
   +0x174 ImageFileName    : [16]  ""              //進程名稱
   +0x184 JobLinks         : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x18c LockedPagesList  : (null) 
   +0x190 ThreadListHead   : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x198 SecurityPort     : (null) 
   +0x19c PaeTop           : (null) 
   +0x1a0 ActiveThreads    : 0
   +0x1a4 GrantedAccess    : 0
   +0x1a8 DefaultHardErrorProcessing : 0
   +0x1ac LastThreadExitStatus : 0n0
   +0x1b0 Peb              : (null) 
   +0x1b4 PrefetchTrace    : _EX_FAST_REF
   +0x1b8 ReadOperationCount : _LARGE_INTEGER 0x0
   +0x1c0 WriteOperationCount : _LARGE_INTEGER 0x0
   +0x1c8 OtherOperationCount : _LARGE_INTEGER 0x0
   +0x1d0 ReadTransferCount : _LARGE_INTEGER 0x0
   +0x1d8 WriteTransferCount : _LARGE_INTEGER 0x0
   +0x1e0 OtherTransferCount : _LARGE_INTEGER 0x0
   +0x1e8 CommitChargeLimit : 0
   +0x1ec CommitChargePeak : 0
   +0x1f0 AweInfo          : (null) 
   +0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x1f8 Vm               : _MMSUPPORT
   +0x238 LastFaultCount   : 0
   +0x23c ModifiedPageCount : 0
   +0x240 NumberOfVads     : 0
   +0x244 JobStatus        : 0
   +0x248 Flags            : 0x800
   +0x248 CreateReported   : 0y0
   +0x248 NoDebugInherit   : 0y0
   +0x248 ProcessExiting   : 0y0
   +0x248 ProcessDelete    : 0y0
   +0x248 Wow64SplitPages  : 0y0
   +0x248 VmDeleted        : 0y0
   +0x248 OutswapEnabled   : 0y0
   +0x248 Outswapped       : 0y0
   +0x248 ForkFailed       : 0y0
   +0x248 HasPhysicalVad   : 0y0
   +0x248 AddressSpaceInitialized : 0y10
   +0x248 SetTimerResolution : 0y0
   +0x248 BreakOnTermination : 0y0
   +0x248 SessionCreationUnderway : 0y0
   +0x248 WriteWatch       : 0y0
   +0x248 ProcessInSession : 0y0
   +0x248 OverrideAddressSpace : 0y0
   +0x248 HasAddressSpace  : 0y0
   +0x248 LaunchPrefetched : 0y0
   +0x248 InjectInpageErrors : 0y0
   +0x248 VmTopDown        : 0y0
   +0x248 Unused3          : 0y0
   +0x248 Unused4          : 0y0
   +0x248 VdmAllowed       : 0y0
   +0x248 Unused           : 0y00000 (0)
   +0x248 Unused1          : 0y0
   +0x248 Unused2          : 0y0
   +0x24c ExitStatus       : 0n0
   +0x250 NextPageColor    : 0
   +0x252 SubSystemMinorVersion : 0 ''
   +0x253 SubSystemMajorVersion : 0 ''
   +0x252 SubSystemVersion : 0
   +0x254 PriorityClass    : 0 ''
   +0x255 WorkingSetAcquiredUnsafe : 0 ''
   +0x258 Cookie           : 0

至此.我們的表項就寫完了.下面可以通過這些表項.來寫我們自己的ReadProcessMemory了.

十丶實現自己的進程內存讀寫

現在我們要自己對進程的虛擬內存進行讀寫了.

PS: 我們要對CR3進行操作.如果不懂.可以查看前幾篇博客. 內存的分頁管理.進行了解CR3 分頁管理,點擊即可.

思路:

  1.遍歷_EPROCESS. 遍歷進程.

  2.通過PID.獲取指定進程的CR3. 我們知道.每個進程的CR3不一樣.倘若我們獲取了我們想操作進程的CR3.對其操作.其實就是操作指定進程的物理內存.

  3.找到之后對CR3進行操作.

    3.1 保存CR3寄存器的原值

    3.2 關閉CR0的內存保護屬性,如果寫WriteProcessMemory的是否需要用到

    3.3 修改CR3寄存器的原值

    3.4寫你的核心代碼.比如給定一個虛擬內存.進行讀寫.

    3.5 恢復CR3寄存器的原值

 有了思路,我們就可以進行寫代碼的操作了.

1.內核驅動提供公共的接口.

讀取指定PID進程的物理內存:

NTSTATUS MyReadProcessMemory(DWORD dwPID,      //指定進程的PID
                             DWORD dwAdddress,    //指定進程的虛擬內存
                             DWORD dwSize,      //指定進程虛擬內存的大小
                  PVOID lpBuff,      //讀取內容的緩沖區 DWORD dwBufSize) //緩沖區的大小.

獲得指定進程PID的PDE

NTSTATUS GetProcessDirBase(DWORD dwPID,       //指定進程的PID
                 PDWORD pDirBase);    //傳入傳出參數.指定進程的PDE

 

沒有寫和三環進行通訊的代碼.只是0環開始測試.入口點調用這個.

MyReadProcessMemory的實現.

實現:

NTSTATUS MyReadProcessMemory(DWORD dwPID, DWORD dwAdddress, 
                             DWORD dwSize, PVOID lpBuff, 
                             DWORD dwBufSize)
{
  DWORD dwDirBase;
  NTSTATUS status;
  DWORD dwOldDirBase;

  KdBreakPoint();

  __try
  {
    status = GetProcessDirBase(dwPID, &dwDirBase);
    if (status != STATUS_SUCCESS)
      return status;

 
    __asm
    {
      cli                    //屏蔽中斷防止線程切換
      mov eax, cr0                //關閉內存保護
      and eax, not 10000h      
      mov cr0, eax

      mov eax, cr3          // 保存CR3寄存器原來的值        
      mov dwOldDirBase, eax
      
      //切換CR3
      mov eax, dwDirBase      //切換CR3的值. CR3的值是我們獲取指定進程的PDE得出的
      mov cr3, eax
    }

    //讀取內存
    //ProbeForRead(dwAdddress, dwSize, 4);

    if ( dwSize > dwBufSize)   //簡單的判斷
      dwSize = dwBufSize;

    RtlCopyMemory(lpBuff, dwAdddress, dwSize);//讀取內存.拷貝到我們的緩沖區中. 因為CR3被更改了.所以說讀取的內存就是指定進程的內存.
__asm { mov eax, dwOldDirBase mov cr3, eax                //恢復CR3 mov eax, cr0
//恢復內存保護 or eax, 10000h mov cr0, eax sti //恢復中斷 } } __except(EXCEPTION_EXECUTE_HANDLER ) { dprintf("[MyReadProcessMemory] MyReadProcessMemory __except \r\n"); } return STATUS_SUCCESS; }

GetProcessDirBase的實現.獲取PDE

 

NTSTATUS GetProcessDirBase(DWORD dwPID, PDWORD pDirBase)
{
  PEPROCESS Process;
  PEPROCESS CurProcess;
  CHAR  *pszImageName;
  DWORD dwCurPID;
  DWORD i;

  __try
  {
    //遍歷EPROCESS
    __asm 
    {
      mov eax, fs:[124h]  //ETHREAD // 首先 GDT首地址 + 0x120 獲取_KPCR的成員 PrcbData,而這個成員是_KPRCB結構體. 對其取內容加偏移0x4獲得CurrentThread
     mov eax, [eax+44h] //EPROCESS    *currentHREAD + 0x34 = APCSTATE 首地址*(APCSTATE) + 0X10 = eprocess ,找到外鍵_Eprocess.(也可以解釋為_KPROCESS)
      mov Process, eax 
   }
CurProcess
= Process;
i
= 0;

do
  {
  pszImageName
= (char*)CurProcess + 0x174; // dt 0x89d14020 _EPROCESS EPROCESS +0x174 = ImageFileName ,通過查表.得出EPROCESS + 0X174得出進程名
   dwCurPID = (*(DWORD*)((char*)CurProcess + 0x084));// UniqueProcessId 進程ID, 的除了進程ID
   dprintf("[MyReadProcessMemory] {%d} PID=%d ImageName:%s \r\n", i++, dwCurPID, pszImageName);
  if (dwCurPID == dwPID) //判斷我們的ID.和遍歷的進程ID是否相等.
   {
    
*pDirBase = (*(DWORD*)((char*)CurProcess + 0x018));//DirectoryTableBase = KPROCESS 0x18 //獲得PDE的值.給我們的參數復制.
    dprintf("[MyReadProcessMemory] Find PID=%d DirBase:%p\r\n", dwCurPID, pDirBase);
   
return STATUS_SUCCESS;
   }
   CurProcess
= (*(DWORD*)((char*)CurProcess + 0x088)) - 0x88; //下一個繼續循環. -0x88上面也說了.主要是鏈表位置的偏移在0x88,而_EPROCESS是在0位置.所以-0x88得出_EPROCESS的位置.
  }
while (CurProcess != Process);
}
__except(EXCEPTION_EXECUTE_HANDLER )
{
  dprintf(
"[MyReadProcessMemory] GetProcessDirBase __except \r\n"); }
  
return STATUS_UNSUCCESSFUL;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM