• 内核知识第十讲,内核结构体简介.以及自己实现内存读写功能.


                内核知识第十讲,内核结构体简介.以及自己实现内存读写功能.

    前言:

      不知道大家学习逆向技术的时候.有没有听说过什么驱动过保护. 什么驱动读写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 "); } 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 ", i++, dwCurPID, pszImageName);
      if (dwCurPID == dwPID) //判断我们的ID.和遍历的进程ID是否相等.
       {
        
    *pDirBase = (*(DWORD*)((char*)CurProcess + 0x018));//DirectoryTableBase = KPROCESS 0x18 //获得PDE的值.给我们的参数复制.
        dprintf("[MyReadProcessMemory] Find PID=%d DirBase:%p ", 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 "); }
      
    return STATUS_UNSUCCESSFUL;
    }
  • 相关阅读:
    核心动画-关键帧动画易混淆属性记录
    CALayer的隐式动画
    const位置上的不同代表哪些不同的意义
    又是一年国庆假期最后一天
    你做微商赚到钱了吗?
    为什么你不看好家教O2O
    【算法】基数排序
    【算法】快速排序/数组第K小的元素
    【算法】归并排序
    【算法】插入排序/冒泡排序/选择排序
  • 原文地址:https://www.cnblogs.com/iBinary/p/8321736.html
Copyright © 2020-2023  润新知