关于Windows内核空间操作的一些说明

来源:互联网 发布:金洲软件 编辑:程序博客网 时间:2024/04/27 14:39
作者:ZwelL
http://www.donews.net/zwell

    首先对被我误导的人说声对不起了。我在论坛中发的那篇贴(用户态隐藏进程的通用版本)真是乱七八糟(-_-我也是受害者)。在XP和WINDOWS 2003中用那种方法都是行不通的,而且在20043中的偏移也是错的。这里我先把XPSP2和2003中的EPROCESS整理出来给大家看一下:

typedef struct _EPROCESS_2K3
{
   /*+0x000*/ KPROCESS_2K3         Pcb;
   /*+0x06c*/ EX_PUSH_LOCK         ProcessLock;
   /*+0x070*/ LARGE_INTEGER      CreateTime;
   /*+0x078*/ LARGE_INTEGER      ExitTime;
   /*+0x080*/ EX_RUNDOWN_REF      RundownProtect;
   /*+0x084*/ PVOID            UniqueProcessId;
   /*+0x088*/ LIST_ENTRY         ActiveProcessLinks;
   /*+0x090*/ ULONG            QuotaUsage[3];
   /*+0x09c*/ ULONG            QuotaPeak[3];
   /*+0x0a8*/ ULONG            CommitCharge;
   /*+0x0ac*/ ULONG            PeakVirtualSize;
   /*+0x0b0*/ ULONG            VirtualSize;
   /*+0x0b4*/ LIST_ENTRY         SessionProcessLinks;
   /*+0x0bc*/ PVOID            DebugPort;
   /*+0x0c0*/ PVOID            ExceptionPort;
   /*+0x0c4*/ PHANDLE_TABLE      ObjectTable;
   /*+0x0c8*/ EX_FAST_REF         Token;
   /*+0x0cc*/ ULONG            WorkingSetPage;
   /*+0x0d0*/ KGUARDED_MUTEX      AddressCreationLock;
   /*+0x0f0*/ KSPIN_LOCK         HyperSpaceLock;
   /*+0x0f4*/ PETHREAD_2K3         ForkInProgress;
   /*+0x0f8*/ ULONG            HardwareTrigger;
   /*+0x0fc*/ PMM_AVL_TABLE      PhysicalVadRoot;
   /*+0x100*/ PVOID            CloneRoot;
   /*+0x104*/ ULONG            NumberOfPrivatePages;
   /*+0x108*/ ULONG            NumberOfLockedPages;
   /*+0x10c*/ PVOID            Win32Process;
   /*+0x110*/ PEJOB            Job;
   /*+0x114*/ PSECTION_OBJECT      SectionObject;
   /*+0x118*/ PVOID            SectionBaseAddress;
   /*+0x11c*/ PEPROCESS_QUOTA_BLOCK   QuotaBlock;
   /*+0x120*/ PPAGEFAULT_HISTORY   WorkingSetWatch;
   /*+0x124*/ PVOID            Win32WindowStation;
   /*+0x128*/ PVOID            InheritedFromUniqueProcessId;
   /*+0x12c*/ PVOID            LdtInformation;
   /*+0x130*/ PVOID            VadFreeHint;
   /*+0x134*/ PVOID            VdmObjects;
   /*+0x138*/ PVOID            DeviceMap;
   /*+0x13c*/ PVOID            Spare0[3];
   union {
   /*+0x148*/HARDWARE_PTE                PageDirectoryPte;
   /*+0x148*/ULONGLONG                   Filler;
   };
   /*+0x150*/ PVOID            Session;
   /*+0x154*/ UCHAR            ImageFileName[16];
   /*+0x164*/ LIST_ENTRY         JobLinks;
   /*+0x16c*/ PVOID            LockedPagesList;
   /*+0x170*/ LIST_ENTRY         ThreadListHead;
   /*+0x178*/ PVOID            SecurityPort;
   /*+0x17c*/ PVOID            PaeTop;
   /*+0x180*/ ULONG            ActiveThreads;
   /*+0x184*/ ULONG            GrantedAccess;
   /*+0x188*/ ULONG            DefaultHardErrorProcessing;
   /*+0x18c*/ NTSTATUS            LastThreadExitStatus;
   /*+0x190*/ PPEB               Peb;
   /*+0x194*/ EX_FAST_REF         PrefetchTrace;
   /*+0x198*/ LARGE_INTEGER      ReadOperationCount;
   /*+0x1a0*/ LARGE_INTEGER      WriteOperationCount;
   /*+0x1a8*/ LARGE_INTEGER      OtherOperationCount;
   /*+0x1b0*/ LARGE_INTEGER      ReadTransferCount;
   /*+0x1b8*/ LARGE_INTEGER      WriteTransferCount;
   /*+0x1c0*/ LARGE_INTEGER      OtherTransferCount;
   /*+0x1c8*/ ULONG            CommitChargeLimit;
   /*+0x1cc*/ ULONG            CommitChargePeak;
   /*+0x1d0*/ PVOID            AweInfo;
   /*+0x1d4*/ SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo;
   /*+0x1d8*/ MMSUPPORT_2K3      Vm;
   /*+0x238*/ LIST_ENTRY         MmProcessLinks;
   /*+0x240*/ ULONG            ModifiedPageCount;
   /*+0x244*/ ULONG            JobStatus;   
   union{
   /*+0x248*/ ULONG            Flags;
      struct{
   /*+0x248*/ ULONG            CreateReported      : 1;
   /*+0x248*/ ULONG            NoDebugInherit      : 1;
   /*+0x248*/ ULONG            ProcessExiting      : 1;
   /*+0x248*/ ULONG            ProcessDelete      : 1;
   /*+0x248*/ ULONG            Wow64SplitPages      : 1;
   /*+0x248*/ ULONG            VmDeleted         : 1;
   /*+0x248*/ ULONG            OutswapEnabled      : 1;
   /*+0x248*/ ULONG            Outswapped         : 1;
   /*+0x248*/ ULONG            ForkFailed         : 1;
   /*+0x248*/ ULONG            Wow64VaSpace4Gb      : 1;
   /*+0x248*/ ULONG            AddressSpaceInitialized :2;
   /*+0x248*/ ULONG            SetTimerResolution   : 1;
   /*+0x248*/ ULONG            BreakOnTermination   : 1;
   /*+0x248*/ ULONG            SessionCreationUnderway :1;
   /*+0x248*/ ULONG            WriteWatch         : 1;
   /*+0x248*/ ULONG            ProcessInSession   : 1;
   /*+0x248*/ ULONG            OverrideAddressSpace   : 1;
   /*+0x248*/ ULONG            HasAddressSpace      : 1;
   /*+0x248*/ ULONG            LaunchPrefetched   : 1;
   /*+0x248*/ ULONG            InjectInpageErrors   : 1;
   /*+0x248*/ ULONG            VmTopDown         : 1;
   /*+0x248*/ ULONG            ImageNotifyDone      : 1;
   /*+0x248*/ ULONG            PdeUpdateNeeded      : 1;
   /*+0x248*/ ULONG            VdmAllowed         : 1;
   /*+0x248*/ ULONG            Unused            : 7;
      };
   };
   /*+0x24c*/ NTSTATUS            ExitStatus;
   /*+0x250*/ USHORT            NextPageColor;
   union   {
      struct   {
   /*+0x252*/      UCHAR                   SubSystemMinorVersion;
   /*+0x253*/      UCHAR                   SubSystemMajorVersion;
      };
   /*+0x252*/   USHORT                      SubSystemVersion;
   };

   /*+0x254*/ UCHAR            PriorityClass;
   /*+0x258*/ MM_AVL_TABLE         VadRoot;
} EPROCESS_2K3, *PEPROCESS_2K3;

typedef struct _EPROCESS_XP_SP2
{
   /*+0x000*/_KPROCESS_XP     Pcb;
   /*+0x06c*/_EX_PUSH_LOCK     ProcessLock;
   /*+0x070*/_LARGE_INTEGER     CreateTime;
   /*+0x078*/_LARGE_INTEGER     ExitTime;
   /*+0x080*/_EX_RUNDOWN_REF    RundownProtect;
   /*+0x084*/PVOID        UniqueProcessId;
   /*+0x088*/_LIST_ENTRY    ActiveProcessLinks;
   /*+0x090*/ULONG         QuotaUsage[3];
   /*+0x09c*/ULONG         QuotaPeak[3];
   /*+0x0a8*/ULONG         CommitCharge;
   /*+0x0ac*/ULONG         PeakVirtualSize;
   /*+0x0b0*/ULONG         VirtualSize;
   /*+0x0b4*/_LIST_ENTRY    SessionProcessLinks;
   /*+0x0bc*/PVOID        DebugPort;
   /*+0x0c0*/PVOID         ExceptionPort;
   /*+0x0c4*/PHANDLE_TABLE    ObjectTable;
   /*+0x0c8*/_EX_FAST_REF    Token;
   /*+0x0cc*/_FAST_MUTEX    WorkingSetLock;
   /*+0x0ec*/ULONG        WorkingSetPage;
   /*+0x0f0*/_FAST_MUTEX    AddressCreationLock;
   /*+0x110*/ULONG        HyperSpaceLock;
   /*+0x114*/PETHREAD        ForkInProgress;
   /*+0x118*/ULONG        HardwareTrigger;
   /*+0x11c*/PVOID        VadRoot;
   /*+0x120*/PVOID        VadHint;
   /*+0x124*/PVOID        CloneRoot;
   /*+0x128*/ULONG        NumberOfPrivatePages;
   /*+0x12c*/ULONG        NumberOfLockedPages;
   /*+0x130*/PVOID        Win32Process;
   /*+0x134*/PEJOB        Job;
   /*+0x138*/PVOID        SectionObject;
   /*+0x13c*/PVOID        SectionBaseAddress;
   /*+0x140*/PEPROCESS_QUOTA_BLOCK    QuotaBlock;
   /*+0x144*/PPAGEFAULT_HISTORY        WorkingSetWatch;
   /*+0x148*/PVOID        Win32WindowStation;
   /*+0x14c*/PVOID        InheritedFromUniqueProcessId;
   /*+0x150*/PVOID         LdtInformation;
   /*+0x154*/PVOID         VadFreeHint;
   /*+0x158*/PVOID         VdmObjects;
   /*+0x15c*/PVOID         DeviceMap;
   /*+0x160*/_LIST_ENTRY    PhysicalVadList;
   /*+0x168*/_HARDWARE_PTE    PageDirectoryPte;
   /*+0x168*/Uint8B        Filler;
   /*+0x170*/PVOID        Session;
   /*+0x174*/UChar         ImageFileName[16];
   /*+0x184*/_LIST_ENTRY    JobLinks;
   /*+0x18c*/PVOID         LockedPagesList;
   /*+0x190*/_LIST_ENTRY    ThreadListHead;
   /*+0x198*/PVOID        SecurityPort;
   /*+0x19c*/PVOID        PaeTop;
   /*+0x1a0*/ULONG        ActiveThreads;
   /*+0x1a4*/ULONG        GrantedAccess;
   /*+0x1a8*/ULONG        DefaultHardErrorProcessing;
   /*+0x1ac*/Int4B        LastThreadExitStatus;
   /*+0x1b0*/Ptr32 _PEB        Peb;
   /*+0x1b4*/_EX_FAST_REF    PrefetchTrace;
   /*+0x1b8*/_LARGE_INTEGER    ReadOperationCount;
   /*+0x1c0*/_LARGE_INTEGER    WriteOperationCount;
   /*+0x1c8*/_LARGE_INTEGER    OtherOperationCount;
   /*+0x1d0*/_LARGE_INTEGER    ReadTransferCount;
   /*+0x1d8*/_LARGE_INTEGER    WriteTransferCount;
   /*+0x1e0*/_LARGE_INTEGER    OtherTransferCount;
   /*+0x1e8*/ULONG        CommitChargeLimit;
   /*+0x1ec*/ULONG        CommitChargePeak;
   /*+0x1f0*/PVOID AweInfo;
   /*+0x1f4*/_SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo;
   /*+0x1f8*/_MMSUPPORT Vm;
   /*+0x238*/ULONG LastFaultCount;
   /*+0x23c*/ULONG ModifiedPageCount;
   /*+0x240*/ULONG NumberOfVads;
   /*+0x244*/ULONG JobStatus;
   /*+0x248*/ULONG Flags;
   /*+0x248*/ULONG CreateReported   : 1;
   /*+0x248*/ULONG NoDebugInherit   : 1;
   /*+0x248*/ULONG ProcessExiting   : 1;
   /*+0x248*/ULONG ProcessDelete    : 1;
   /*+0x248*/ULONG Wow64SplitPages  : 1;
   /*+0x248*/ULONG VmDeleted        : 1;
   /*+0x248*/ULONG OutswapEnabled   : 1;
   /*+0x248*/ULONG Outswapped       : 1;
   /*+0x248*/ULONG ForkFailed       : 1;
   /*+0x248*/ULONG HasPhysicalVad   : 1;
   /*+0x248*/ULONG AddressSpaceInitialized : 2;
   /*+0x248*/ULONG SetTimerResolution : 1;
   /*+0x248*/ULONG BreakOnTermination : 1;
   /*+0x248*/ULONG SessionCreationUnderway : 1;
   /*+0x248*/ULONG WriteWatch       : 1;
   /*+0x248*/ULONG ProcessInSession : 1;
   /*+0x248*/ULONG OverrideAddressSpace : 1;
   /*+0x248*/ULONG HasAddressSpace  : 1;
   /*+0x248*/ULONG LaunchPrefetched : 1;
   /*+0x248*/ULONG InjectInpageErrors : 1;
   /*+0x248*/ULONG VmTopDown        : 1;
   /*+0x248*/ULONG Unused3          : 1;
   /*+0x248*/ULONG Unused4          : 1;
   /*+0x248*/ULONG VdmAllowed       : 1;
   /*+0x248*/ULONG Unused           : 5;
   /*+0x248*/ULONG Unused1          : 1;
   /*+0x248*/ULONG Unused2          : 1;
   /*+0x24c*/Int4B ExitStatus;
   /*+0x250*/Uint2B NextPageColor;
   /*+0x252*/UChar SubSystemMinorVersion;
   /*+0x253*/UChar SubSystemMajorVersion;
   /*+0x252*/Uint2B SubSystemVersion;
   /*+0x254*/UChar PriorityClass;
   /*+0x255*/UChar WorkingSetAcquiredUnsafe;
   /*+0x258*/ULONG Cookie;
}EPROCESS_XP_SP2, *PEPROCESS_XP_SP2

关于如何在xp和2003中读写内核空间,TK大哥已经说的很清楚了,用ZwSystemDebugControl函数的8,9调用号就可以了。
这里给大家一个写的示例程序,大家改一下放到程序中,再做一下系统的判断就可以达到通用性了。

/*
Write data in kernel POC
Author:ZwelL
Idea from:TK
*/
#include <windows.h>
#include <Aclapi.h>
#include <stdio.h>

#define NT_SUCCESS(Status)      ((NTSTATUS)(Status) >= 0)
typedef LONG NTSTATUS;


typedef struct _MEMORY_CHUNKS {
    ULONG Address;
    PVOID Data;
    ULONG Length;
}MEMORY_CHUNKS, *PMEMORY_CHUNKS;

typedef NTSTATUS (NTAPI * PZwSystemDebugControl) (
    int ControlCode,
    PVOID InputBuffer,
    ULONG InputBufferLength,
    PVOID OutputBuffer,
    ULONG OutputBufferLength,
    PULONG ReturnLength
    );

HMODULE    g_hNtDLL = NULL;

PZwSystemDebugControl ZwSystemDebugControl = NULL;

BOOL InitNTDLL()
{
    g_hNtDLL = LoadLibrary( "ntdll.dll" );
    if ( !g_hNtDLL )
    {
        return FALSE;
    }

    ZwSystemDebugControl =
        (PZwSystemDebugControl)GetProcAddress (g_hNtDLL, "ZwSystemDebugControl");

    return TRUE;
}

VOID CloseNTDLL()
{
    if(g_hNtDLL != NULL)
    {
        FreeLibrary(g_hNtDLL);
    }
}

BOOL EnablePrivilege (PCSTR name)
{
    HANDLE hToken;
    BOOL rv;
    
    TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
    LookupPrivilegeValue (
        0,
        name,
        &priv.Privileges[0].Luid
    );
    
    OpenProcessToken(
        GetCurrentProcess (),
        TOKEN_ADJUST_PRIVILEGES,
        &hToken
    );
    
    AdjustTokenPrivileges (
        hToken,
        FALSE,
        &priv,
        sizeof priv,
        0,
        0
    );
    rv = GetLastError () == ERROR_SUCCESS;
    
    CloseHandle (hToken);
    return rv;
}


int main(int argc, char **argv)
{
    if (InitNTDLL())
    {
        EnablePrivilege(SE_DEBUG_NAME);
        MEMORY_CHUNKS QueryBuff;
        ULONG ReturnLength;
        char *Buff= "/x11/x11/x11/x11";

        QueryBuff.Address = (ULONG)0x804ed5cc; //在2003中是第一个服务调用号的函数指针,指向80592290
                            //大家可以改成链表的地址
        QueryBuff.Data = Buff;
        QueryBuff.Length = 0x4;
        ZwSystemDebugControl
        (
            0x9,
            &QueryBuff,
            sizeof(MEMORY_CHUNKS),  //必须是0x0C
            NULL,
            0,
            &ReturnLength
        );
        CloseNTDLL();
    }

    return 0;
}


这里我还对TK大哥在04峰会上讲的内容做了验证,发现SessionProcessLinks在XP和2003中都是可以用来权举进程的,但是在2000中都为0x00000000,
也就是说,在2000中不能通过它进行进程检查了,只能通过WorkingSetExpansionLinks来权举进程。这里TK大哥也没做说明,前面一直没怀疑过TK大哥的准确性,
花了很长时间去执行,都没成功,用WINDBG一看就出来了。哎,看来什么事还得自己验证一下啊。5555。。。下面是对TK大哥讲的内容的实现代码:

/*
用ring3代码枚举Windows进程的演示代码
Enum process in ring3 POC
Author:ZwelL
Idea from:TK
*/
#include <windows.h>
#include <Aclapi.h>
#include <stdio.h>

#define NT_SUCCESS(Status)      ((NTSTATUS)(Status) >= 0)
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
#define BASEADDRLEN 10

#define W2K_SESSION_LST_OFFSET    0X118
#define WXP_SESSION_LST_OFFSET    0X0b4
#define W2K3_SESSION_LST_OFFSET    0X0b4

#define W2K_ACTIVE_LST_OFFSET    0X0a0
#define WXP_ACTIVE_LST_OFFSET    0X088
#define W2K3_ACTIVE_LST_OFFSET    0X088

#define W2K_SESSION_TO_NAME_OFFSET    0X1fc-0x118
#define WXP_SESSION_TO_NAME_OFFSET    0X0C0
#define W2K3_SESSION_TO_NAME_OFFSET    0X154-0XB4

#define W2K_ACTIVE_LST_TO_NAME_OFFSET    W2K_SESSION_TO_NAME_OFFSET+W2K_SESSION_LST_OFFSET-W2K_ACTIVE_LST_OFFSET
#define WXP_ACTIVE_LST_TO_NAME_OFFSET    WXP_SESSION_TO_NAME_OFFSET+WXP_SESSION_LST_OFFSET-WXP_ACTIVE_LST_OFFSET
#define W2K3_ACTIVE_LST_TO_NAME_OFFSET    W2K3_SESSION_TO_NAME_OFFSET+W2K3_SESSION_LST_OFFSET-W2K3_ACTIVE_LST_OFFSET

#define W2K_WORK_LST_OFFSET 0X0f4
#define W2K_IMAGE_NAME_OFFSET 0X1fc

typedef LONG NTSTATUS;

typedef struct _UNICODE_STRING
{
    USHORT    Length;
    USHORT    MaximumLength;
    PWSTR    Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES
{
    ULONG    Length;
    HANDLE    RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG    Attributes;
    PVOID    SecurityDescriptor;
    PVOID    SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;  

typedef struct _SYSTEM_MODULE_INFORMATION
{
    ULONG Reserved[2];
    PVOID Base;
    ULONG Size;
    ULONG Flags;
    USHORT Index;
    USHORT Unknown;
    USHORT LoadCount;
    USHORT ModuleNameOffset;
    CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;


typedef struct _MEMORY_CHUNKS {
    ULONG Address;
    PVOID Data;
    ULONG Length;
}MEMORY_CHUNKS, *PMEMORY_CHUNKS;

typedef enum _SYSDBG_COMMAND {
//以下5个在Windows NT各个版本上都有
    SysDbgGetTraceInformation = 1,
    SysDbgSetInternalBreakpoint = 2,
    SysDbgSetSpecialCall = 3,
    SysDbgClearSpecialCalls = 4,
    SysDbgQuerySpecialCalls = 5,

// 以下是NT 5.1 新增的
    SysDbgDbgBreakPointWithStatus = 6,

    //获取KdVersionBlock
    SysDbgSysGetVersion = 7,

    //从内核空间拷贝到用户空间,或者从用户空间拷贝到用户空间
    //但是不能从用户空间拷贝到内核空间
    SysDbgCopyMemoryChunks_0 = 8,
  //SysDbgReadVirtualMemory = 8,

    //从用户空间拷贝到内核空间,或者从用户空间拷贝到用户空间
    //但是不能从内核空间拷贝到用户空间
    SysDbgCopyMemoryChunks_1 = 9,
  //SysDbgWriteVirtualMemory = 9,

    //从物理地址拷贝到用户空间,不能写到内核空间
    SysDbgCopyMemoryChunks_2 = 10,
  //SysDbgReadVirtualMemory = 10,

    //从用户空间拷贝到物理地址,不能读取内核空间
    SysDbgCopyMemoryChunks_3 = 11,
  //SysDbgWriteVirtualMemory = 11,

    //读写处理器相关控制块
    SysDbgSysReadControlSpace = 12,
    SysDbgSysWriteControlSpace = 13,

    //读写端口
    SysDbgSysReadIoSpace = 14,
    SysDbgSysWriteIoSpace = 15,

    //分别调用RDMSR@4和_WRMSR@12
    SysDbgSysReadMsr = 16,
    SysDbgSysWriteMsr = 17,

    //读写总线数据
    SysDbgSysReadBusData = 18,
    SysDbgSysWriteBusData = 19,

    SysDbgSysCheckLowMemory = 20,

// 以下是NT 5.2 新增的

    //分别调用_KdEnableDebugger@0和_KdDisableDebugger@0
    SysDbgEnableDebugger = 21,
    SysDbgDisableDebugger = 22,
    
    //获取和设置一些调试相关的变量
    SysDbgGetAutoEnableOnEvent = 23,
    SysDbgSetAutoEnableOnEvent = 24,
    SysDbgGetPitchDebugger = 25,
    SysDbgSetDbgPrintBufferSize = 26,
    SysDbgGetIgnoreUmExceptions = 27,
    SysDbgSetIgnoreUmExceptions = 28
} SYSDBG_COMMAND, *PSYSDBG_COMMAND;

typedef enum _SYSTEM_INFORMATION_CLASS
{
    SystemBasicInformation,
    SystemProcessorInformation,
    SystemPerformanceInformation,
    SystemTimeOfDayInformation,
    SystemNotImplemented1,
    SystemProcessesAndThreadsInformation,
    SystemCallCounts,
    SystemConfigurationInformation,
    SystemProcessorTimes,
    SystemGlobalFlag,
    SystemNotImplemented2,
    SystemModuleInformation,
    SystemLockInformation,
    SystemNotImplemented3,
    SystemNotImplemented4,
    SystemNotImplemented5,
    SystemHandleInformation,
    SystemObjectInformation,
    SystemPagefileInformation,
    SystemInstructionEmulationCounts,
    SystemInvalidInfoClass1,
    SystemCacheInformation,
    SystemPoolTagInformation,
    SystemProcessorStatistics,
    SystemDpcInformation,
    SystemNotImplemented6,
    SystemLoadImage,
    SystemUnloadImage,
    SystemTimeAdjustment,
    SystemNotImplemented7,
    SystemNotImplemented8,
    SystemNotImplemented9,
    SystemCrashDumpInformation,
    SystemExceptionInformation,
    SystemCrashDumpStateInformation,
    SystemKernelDebuggerInformation,
    SystemContextSwitchInformation,
    SystemRegistryQuotaInformation,
    SystemLoadAndCallImage,
    SystemPrioritySeparation,
    SystemNotImplemented10,
    SystemNotImplemented11,
    SystemInvalidInfoClass2,
    SystemInvalidInfoClass3,
    SystemTimeZoneInformation,
    SystemLookasideInformation,
    SystemSetTimeSlipEvent,
    SystemCreateSession,
    SystemDeleteSession,
    SystemInvalidInfoClass4,
    SystemRangeStartInformation,
    SystemVerifierInformation,
    SystemAddVerifier,
    SystemSessionProcessesInformation
} SYSTEM_INFORMATION_CLASS;

typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION )
(
 IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
 IN OUT PVOID SystemInformation,
 IN ULONG SystemInformationLength,
 OUT PULONG ReturnLength OPTIONAL
 );

typedef NTSTATUS (CALLBACK* ZWOPENSECTION)(
    OUT PHANDLE SectionHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes
    );

typedef VOID (CALLBACK* RTLINITUNICODESTRING)(        
    IN OUT PUNICODE_STRING DestinationString,
    IN PCWSTR SourceString
    );

typedef NTSTATUS (NTAPI * PZwSystemDebugControl) (
    SYSDBG_COMMAND ControlCode,
    PVOID InputBuffer,
    ULONG InputBufferLength,
    PVOID OutputBuffer,
    ULONG OutputBufferLength,
    PULONG ReturnLength
    );

ZWQUERYSYSTEMINFORMATION    ZwQuerySystemInformation = NULL;
RTLINITUNICODESTRING        RtlInitUnicodeString;
ZWOPENSECTION                ZwOpenSection;
HMODULE                        g_hNtDLL = NULL;
PVOID                        g_pMapPhysicalMemory = NULL;
HANDLE                        g_hMPM   = NULL;

PZwSystemDebugControl ZwSystemDebugControl = NULL;

BOOL InitNTDLL()
{
    g_hNtDLL = LoadLibrary( "ntdll.dll" );
    if ( !g_hNtDLL )
    {
        return FALSE;
    }

    RtlInitUnicodeString =
        (RTLINITUNICODESTRING)GetProcAddress( g_hNtDLL, "RtlInitUnicodeString");

    ZwOpenSection =
        (ZWOPENSECTION)GetProcAddress( g_hNtDLL, "ZwOpenSection");

    ZwQuerySystemInformation =
        ( ZWQUERYSYSTEMINFORMATION )GetProcAddress( g_hNtDLL, "ZwQuerySystemInformation" );

    ZwSystemDebugControl =
        (PZwSystemDebugControl)GetProcAddress (g_hNtDLL, "ZwSystemDebugControl");

    return TRUE;
}

VOID CloseNTDLL()
{
    if(g_hNtDLL != NULL)
    {
        FreeLibrary(g_hNtDLL);
    }
}

HANDLE OpenPhysicalMemory()
{
    NTSTATUS        status;
    UNICODE_STRING        physmemString;
    OBJECT_ATTRIBUTES    attributes;
    
    RtlInitUnicodeString( &physmemString, L"//Device//PhysicalMemory" );
    
    attributes.Length            = sizeof(OBJECT_ATTRIBUTES);
    attributes.RootDirectory        = NULL;
    attributes.ObjectName            = &physmemString;
    attributes.Attributes            = 0;
    attributes.SecurityDescriptor        = NULL;
    attributes.SecurityQualityOfService    = NULL;
    
    status = ZwOpenSection(&g_hMPM,SECTION_MAP_READ|SECTION_MAP_WRITE,&attributes);
    
    if(status == STATUS_ACCESS_DENIED){
        status = ZwOpenSection(&g_hMPM,READ_CONTROL|WRITE_DAC,&attributes);
        //SetPhyscialMemorySectionCanBeWrited(g_hMPM);
        CloseHandle(g_hMPM);
        status =ZwOpenSection(&g_hMPM,SECTION_MAP_READ|SECTION_MAP_WRITE,&attributes);
    }
    if( !NT_SUCCESS( status ))
    {
        return NULL;
    }
    
    g_pMapPhysicalMemory = MapViewOfFile(
        g_hMPM,
        4,
        0,
        0x30000,
        0x1000);
    if( g_pMapPhysicalMemory == NULL )
    {
        return NULL;
    }
    return g_hMPM;
}


PVOID LinearToPhys(PULONG BaseAddress,PVOID addr)
{
    ULONG VAddr=(ULONG)addr,PGDE,PTE,PAddr;
    if(VAddr>=0x80000000 && VAddr<0xa0000000)
    {
        PAddr=VAddr-0x80000000;
        return (PVOID)PAddr;
    }
    PGDE=BaseAddress[VAddr>>22];
    if ((PGDE&1)!=0)
    {
        ULONG tmp=PGDE&0x00000080;
        if (tmp!=0)
        {
            PAddr=(PGDE&0xFFC00000)+(VAddr&0x003FFFFF);
        }
        else
        {
            PGDE=(ULONG)MapViewOfFile(g_hMPM, FILE_MAP_ALL_ACCESS, 0, PGDE & 0xfffff000, 0x1000);
            PTE=((PULONG)PGDE)[(VAddr&0x003FF000)>>12];
            if ((PTE&1)!=0)
            {
                PAddr=(PTE&0xFFFFF000)+(VAddr&0x00000FFF);
                UnmapViewOfFile((PVOID)PGDE);
            }
            else return 0;
        }
    }
    else return 0;

    return (PVOID)PAddr;
}

BOOL EnablePrivilege (PCSTR name)
{
    HANDLE hToken;
    BOOL rv;
    
    TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
    LookupPrivilegeValue (
        0,
        name,
        &priv.Privileges[0].Luid
    );
    
    OpenProcessToken(
        GetCurrentProcess (),
        TOKEN_ADJUST_PRIVILEGES,
        &hToken
    );
    
    AdjustTokenPrivileges (
        hToken,
        FALSE,
        &priv,
        sizeof priv,
        0,
        0
    );
    rv = GetLastError () == ERROR_SUCCESS;
    
    CloseHandle (hToken);
    return rv;
}

void GetString(PVOID addr, char *returnstr)
{
    OSVERSIONINFO OSVersionInfo;
    PCHAR ret;

    OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
    GetVersionEx (&OSVersionInfo);
    if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
        OSVersionInfo.dwMajorVersion >= 5 &&
        OSVersionInfo.dwMinorVersion >= 1)    //Windows XP以上
    {    
        MEMORY_CHUNKS QueryBuff;
        ULONG ReturnLength;
        char Buff[0x30] = {0};

        QueryBuff.Address = (ULONG)addr;
        QueryBuff.Data = Buff;  //在此是读出缓冲
        QueryBuff.Length = sizeof(Buff);

        EnablePrivilege(SE_DEBUG_NAME);

        ZwSystemDebugControl
        (
            SysDbgCopyMemoryChunks_0,
            &QueryBuff,
            sizeof(MEMORY_CHUNKS),  //必须是0x0C
            NULL,
            0,
            &ReturnLength
        );

        strcpy(returnstr, Buff);
    }
    else
    {
        ULONG phys=(ULONG)LinearToPhys((PULONG)g_pMapPhysicalMemory,(PVOID)addr);
        PULONG tmp=(PULONG)MapViewOfFile(g_hMPM, FILE_MAP_ALL_ACCESS, 0, phys & 0xfffff000, 0x1000);
        if (tmp==0)
        {
            printf("getdata wrong/n");
            return;
        }
        strcpy(returnstr, (PCHAR)&tmp[(phys & 0xFFF)>>2]);
        UnmapViewOfFile(tmp);
    }
}

ULONG GetData(PVOID addr)
{
    OSVERSIONINFO OSVersionInfo;
    ULONG ret;

    OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
    GetVersionEx (&OSVersionInfo);
    if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
        OSVersionInfo.dwMajorVersion >= 5 &&
        OSVersionInfo.dwMinorVersion >= 1)    //Windows XP以上
    {    
        MEMORY_CHUNKS QueryBuff;
        ULONG ReturnLength;
        char Buff[0x300] = {0};

        QueryBuff.Address = (ULONG)addr;
        QueryBuff.Data = Buff;  //在此是读出缓冲
        QueryBuff.Length = sizeof(Buff);

        EnablePrivilege(SE_DEBUG_NAME);

        ZwSystemDebugControl
        (
            SysDbgCopyMemoryChunks_0,
            &QueryBuff,
            sizeof(MEMORY_CHUNKS),  //必须是0x0C
            NULL,
            0,
            &ReturnLength
        );
        ret = *(PULONG)Buff;
    }
    else
    {
        ULONG phys=(ULONG)LinearToPhys((PULONG)g_pMapPhysicalMemory,(PVOID)addr);
        PULONG tmp=(PULONG)MapViewOfFile(g_hMPM, FILE_MAP_ALL_ACCESS, 0, phys & 0xfffff000, 0x1000);
        if (tmp==0)
        {
            printf("getdata wrong/n");
            return 0;
        }
        ret=tmp[(phys & 0xFFF)>>2];
        UnmapViewOfFile(tmp);
    }
    return ret;
}

DWORD MyGetModuleBaseAddress( char * pModuleName)
{
    PSYSTEM_MODULE_INFORMATION    pSysModule;    

    ULONG            uReturn;
    ULONG            uCount;
    PCHAR            pBuffer = NULL;
    PCHAR            pName    = NULL;
    NTSTATUS        status;
    UINT            ui;

    CHAR            szBuffer[BASEADDRLEN];
    DWORD            pBaseAddress;

    status = ZwQuerySystemInformation( SystemModuleInformation, szBuffer, BASEADDRLEN, &uReturn );

    pBuffer = ( PCHAR )malloc(uReturn);

    if ( pBuffer )
    {
        status = ZwQuerySystemInformation( SystemModuleInformation, pBuffer, uReturn, &uReturn );

        if( NT_SUCCESS(status) )
        {
            uCount = ( ULONG )*( ( ULONG * )pBuffer );
            pSysModule = ( PSYSTEM_MODULE_INFORMATION )( pBuffer + sizeof( ULONG ) );

            if(pModuleName == NULL)
            {
                for ( ui = 0; ui < uCount; ui++ )
                {
                    printf("%s /n/tBase address: 0x%08x/n", pSysModule->ImageName, pSysModule->Base);

                    pSysModule ++;
                }
            }
            else
            {

                for ( ui = 0; ui < uCount; ui++ )
                {
                    pName = strstr( pSysModule->ImageName, pModuleName );

                    if( pName )
                    {
                        //printf("%s /n/tBase address: 0x%08x/n", pSysModule->ImageName, pSysModule->Base);
                        pBaseAddress = (DWORD)pSysModule->Base;
                        free( pBuffer );
                        return pBaseAddress;
                    }
                    pSysModule ++;
                }
            }
        }

        free( pBuffer );
    }

    return NULL;
}

int main(int argc, char **argv)
{
    int SESSION_TO_NAME_OFFSET=0;
    int SESSION_LST_OFFSET=0;
    int ACTIVE_LST_TO_NAME_OFFSET=0;
    int ACTIVE_LST_OFFSET=0;
    char imagename[0x30];
    OSVERSIONINFO OSVersionInfo;
    HMODULE hDll;
    LPVOID lpps;
    PVOID firstaddr;
    PVOID nowaddr;


    if (InitNTDLL())
    {
        OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
        GetVersionEx (&OSVersionInfo);

        if (OSVersionInfo.dwMajorVersion == 5)
        {
            if(OSVersionInfo.dwMinorVersion == 0)
            {
                    //SESSION_TO_NAME_OFFSET=W2K_SESSION_TO_NAME_OFFSET;
                    //SESSION_LST_OFFSET=W2K_SESSION_LST_OFFSET;
                    //ACTIVE_LST_TO_NAME_OFFSET=W2K_ACTIVE_LST_TO_NAME_OFFSET;
                    //ACTIVE_LST_OFFSET=W2K_ACTIVE_LST_OFFSET;
                    //如果用SESSIONLST的话,将会读到0x00000000
                    SESSION_TO_NAME_OFFSET=W2K_IMAGE_NAME_OFFSET-W2K_WORK_LST_OFFSET;
                    SESSION_LST_OFFSET=W2K_WORK_LST_OFFSET;
                    ACTIVE_LST_TO_NAME_OFFSET=W2K_ACTIVE_LST_TO_NAME_OFFSET;
                    ACTIVE_LST_OFFSET=W2K_ACTIVE_LST_OFFSET;

                    if (OpenPhysicalMemory()==0)
                    {
                        printf("OpenPhysicalMemory wrong/n");
                        return -1;
                    }
            }
            else if(OSVersionInfo.dwMinorVersion == 1)
            {
                    SESSION_TO_NAME_OFFSET=WXP_SESSION_TO_NAME_OFFSET;
                    SESSION_LST_OFFSET=WXP_SESSION_LST_OFFSET;
                    ACTIVE_LST_TO_NAME_OFFSET=WXP_ACTIVE_LST_TO_NAME_OFFSET;
                    ACTIVE_LST_OFFSET=WXP_ACTIVE_LST_OFFSET;
            }
            else if(OSVersionInfo.dwMinorVersion == 2)
            {
                    SESSION_TO_NAME_OFFSET=W2K3_SESSION_TO_NAME_OFFSET;
                    SESSION_LST_OFFSET=W2K3_SESSION_LST_OFFSET;
                    ACTIVE_LST_TO_NAME_OFFSET=W2K3_ACTIVE_LST_TO_NAME_OFFSET;
                    ACTIVE_LST_OFFSET=W2K3_ACTIVE_LST_OFFSET;
            }
        }
        else
        {
            printf("The OS version is not be supported.../n");
            return -1;
        }

        hDll = LoadLibrary("ntoskrnl.exe");
        lpps = GetProcAddress(hDll, "PsInitialSystemProcess");
        lpps=(LPVOID)(MyGetModuleBaseAddress("ntoskrnl.exe")+(DWORD)lpps-(DWORD)hDll);
        printf("PsInitialSystemProcess address : 0x%08X/n/n", lpps);
        FreeLibrary(hDll);

        printf("OS version: %1d.%1d/n", OSVersionInfo.dwMajorVersion, OSVersionInfo.dwMinorVersion);
        printf("ActiveProcessLinks Offset : 0x%03X/n", ACTIVE_LST_OFFSET);
        if(OSVersionInfo.dwMinorVersion == 0)
            printf("SessionProcessLinks Offset : 0x%03X/n", SESSION_LST_OFFSET);
        else
            printf("WorkingSetExpansionLinks Offset : 0x%03X/n", SESSION_LST_OFFSET);
        printf("ImageFileName Offset : 0x%03X/n/n", ACTIVE_LST_OFFSET+ACTIVE_LST_TO_NAME_OFFSET);
        
        firstaddr=(LPVOID)(GetData(lpps)+ACTIVE_LST_OFFSET);
        //GetString((PVOID)((DWORD)firstaddr+ACTIVE_LST_TO_NAME_OFFSET),imagename);
        //printf("EPROCESS : 0x%08X : %s/n", (DWORD)firstaddr-ACTIVE_LST_OFFSET, imagename);
        if(OSVersionInfo.dwMinorVersion == 0)
        {
            firstaddr=(LPVOID)((DWORD)firstaddr-ACTIVE_LST_OFFSET+SESSION_LST_OFFSET);
        }
        else
        {
            firstaddr=(LPVOID)(GetData(firstaddr));
            GetString((PVOID)((DWORD)firstaddr+ACTIVE_LST_TO_NAME_OFFSET),imagename);
            printf("EPROCESS : 0x%08X : %s/n", (DWORD)firstaddr-ACTIVE_LST_OFFSET, imagename);
            firstaddr=(LPVOID)(GetData(firstaddr));
            firstaddr=(LPVOID)((DWORD)firstaddr-ACTIVE_LST_OFFSET+SESSION_LST_OFFSET);
        }

        nowaddr=firstaddr;
        do
        {
            if((DWORD)nowaddr>0xffff0000)
                break;
            GetString((PVOID)((DWORD)nowaddr+SESSION_TO_NAME_OFFSET), imagename);
            printf("EPROCESS : 0x%08X : %s/n", (DWORD)nowaddr-SESSION_LST_OFFSET, imagename);
            nowaddr=(LPVOID)GetData(nowaddr);        
        }
        while(firstaddr!=nowaddr && nowaddr>0);
        getchar();
        UnmapViewOfFile(g_pMapPhysicalMemory);
        CloseHandle(g_hMPM);
        CloseNTDLL();
    }

    return 0;
}


参考资料:
1. 用ring3代码可靠地枚举Windows进程 -TK
    http://www.xfocus.net/projects/Xcon/2004/Xcon2004_tk.pdf