前言:
不知道大家学习逆向技术的时候.有没有听说过什么驱动过保护. 什么驱动读写xxx的.而今天就讲解一下其原理.
PS: 讲解原理还有简单的Demo. 请大家学习逆向技术.并做好信息安全. 而不是要求大家去做黑产.
PS: 只讲今天表中有用的结构体.不会每个成员都会介绍.
我们都知道 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寄存器中.
我们知道.FS 里面的内容.在0环中.是存放表的位置. 我们可以看下GDT表中存放的段地址是什么.
由此得出表的首地址是 ffdff000.
这个地址则是我们表的首地址.
我们获得了表的首地址.但是要对其做解析. dt命令就是解析的.
dt是解析结构体的.
例如:
dt xxx结构体. :那么结构体内容就会显示出来.偏移也会显示出来.
dt xxx结构体 地址 : 那么不光显示偏移.而且成员的地址也会列出来. 注意,地址在前.结构体在后也可以.
我们的GDT的段地址就是 _KPCR表.
我们对其解析一下看一下.
通过解析.我们得出了3个重要的地方.
1. 我们的位置保存了GDT表的值.和第二处是一样的.
3.重要结构体 _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的位置.我们解析一下看看.
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的位置. 我们看一下里面存放的是什么.
通过解析表中的内容.我们得出了外键. 也就是进程的信息.
_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. .线程的同理.
我们重新解析一下.
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 ''
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寄存器的原值
有了思路,我们就可以进行写代码的操作了.
读取指定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环开始测试.入口点调用这个.
实现:
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;
}
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