首页
社区
课程
招聘
[原创]实现简易ARK工具(3) 遍历进程和内核模块
发表于: 2025-7-16 02:20 6192

[原创]实现简易ARK工具(3) 遍历进程和内核模块

2025-7-16 02:20
6192

​ 大家好,本文讨论了ARK工具在XP/WIN7 32位在内核通过ActiveProcessLinks手动遍历进程的方法,文末贴了遍历进程和内核模块的代码。在下新手,不足之处多多包涵~

在进行进程附加读写操作之前,我们首先需要找到目标进程,传进程PID给读写函数。遍历系统中的所有进程是ARK工具的基础功能之一,用于:

下面看看遍历进程的方法,看雪上有些相关文章:

[原创]简单利用_CSR_PROCESS结构枚举出进程-软件逆向-看雪-安全社区|安全招聘|kanxue.com

[原创]驱动遍历系统进程-软件逆向-看雪-安全社区|安全招聘|kanxue.com

本文讲通过ActiveProcessLinks获取进程链表的方法

在Windows内核中,每个进程都对应一个EPROCESS结构体,所有活跃进程通过ActiveProcessLinks字段形成一个双向循环链表。

EPROCESS结构简化示意:

要遍历进程,我们需要:

找到入口点:获取当前进程的EPROCESS结构

遍历链表:通过ActiveProcessLinks访问其他进程,只要拿到当前进程在ActiveProcessLinks中的节点,我们就可以遍历列表拿到数据。

循环检测:当回到起始进程的节点时停止遍历

获取EPROCESS涉及了大量的结构体

硬件层面:
FS寄存器 → 指向当前处理器的KPCR

内核层面:
KPCR (处理器控制区域)
├── PrcbData → KPRCB (处理器控制块)
└── CurrentThread → ETHREAD (当前执行线程)

线程层面:
ETHREAD (执行线程)
├── ApcState → KAPC_STATE (APC状态)
│ └── Process → EPROCESS (所属进程)
└── ThreadsProcess → EPROCESS (直接指向所属进程)

进程层面:
EPROCESS (执行进程)
├── Pcb → KPROCESS (内核进程块)
├── ActiveProcessLinks → LIST_ENTRY (进程链表)
├── UniqueProcessId → 进程ID
├── InheritedFromUniqueProcessId → 父进程ID
├── ImageFileName[16] → 进程名
└── 其他进程相关信息

关注这条路径:FS → KPCR → KPRCB → ETHREAD → EPROCESS → 找链表遍历其他进程的EPROCESS

由于影响观感,截取了部分XP下的结构体贴在文末,建议在windbg中查看这些结构体进行学习,命令:

要拿EPROCESS就得计算这些结构体的偏移,然而windows各个版本的结构体是不同的,工作量不小,这里有几种方法:

1.人肉计算结构体偏移量,在驱动启动时RtlGetVersion(&versionInfo)获得当前windows版本然后设置对应的偏移量。我刚开始也是这样干的,文末有使用这种方式的代码

2.特征API: PsGetCuurentProcessIdPsGetNextProcess直接拿链表头。缺陷:如果API被hook需要考虑被改jmp的情况,且如果需要的函数没有导出,定位不到函数入口点,需要利用api调用层级进行逐级特征定位。(真有人这么干吗0.0

看这个偏移[eax+0x1EC],Cid 可以拿到UniqueProcessUniqueThread的指针

这里可以特征到链表头PsActiveProcessHead

3.解析pdb:下载pdb,写工具代码解析pdp获取偏移量。解析pdb很累?其实可以调用symsrv.dlldbghelp.dll的导出函数解析,也可以使用VS目录下自带的DIA2dump,以及它已经编译好的dll。Dia2dump 示例 - Visual Studio (Windows) | Microsoft Learn

有相关文章介绍DIA2DUMP[原创]通过pdb解析SSDT表地址-编程技术-看雪-安全社区|安全招聘|kanxue.com

cmd输入regsvr32 msdia140.dll之后就可以在工程里下断点调试?

4.调API,哎谁爱解析谁解析,我先调了=。=

NtQuerySystemInformation 函数 (winternl.h) - Win32 apps | Microsoft Learn)在文档中找到SYSTEM_PROCESS_INFORMATION

SYSTEM_PROCESS_INFORMATION 算是半公开的结构体,直接查微软文档他会有一些保留字段显示Reserved,可以使用SourceInsight查看WRK1.2的源码观察他。

SourceInsight官网: 202K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2K6L8%4g2J5j5$3g2A6L8Y4y4A6k6$3S2@1i4K6u0W2j5$3!0E0i4K6u0r3N6s2u0A6j5h3I4Q4x3V1j5`.

WRK1.2下载: 4c3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6S2P5i4W2#2j5$3g2V1k6h3#2A6M7X3u0S2M7#2)9J5c8W2N6A6L8X3c8G2N6%4y4Q4x3X3c8d9k6i4y4W2j5i4u0U0K9q4)9J5k6p5E0W2M7X3&6W2L8q4)9J5k6q4N6d9d9#2)9J5k6l9`.`.

看一下这个结构体,想要什么自己说(狗头

微软自己也会使用这些API,所以直接抄他代码就行。WRK1.2中搜索PerInfoProcessRundownPerfInfoSysModuleRunDown文末代码中遍历模块使用了这些API

注意
高版本看NT开头的函数

都是第一次获取数量,申请缓冲区,第二次获取数据。你直接申请巨大缓冲区也行。

这里没有处理头节点? 有个空的
图片描述
遍历模块列表,看到了一堆sys
图片描述

遍历进程的代码 检测Windows版本手动设置偏移量 然后遍历ActiveProcessLinks拿进程信息

遍历模块的代码 直接调用API

img

img

img

img

挖坑,后续补充一下ARK集成DIA2dump解析PDB的方法~

typedef struct _EPROCESS {
    // ...
    LIST_ENTRY ActiveProcessLinks;     // 用于链接所有进程 偏移: 0x088 (XP)
    HANDLE UniqueProcessId;            // 进程ID 
    CHAR ImageFileName[16];            // 进程名(最多15字符)
    // ... 其他字段
} EPROCESS, *PEPROCESS;
 
具体结构在文末
typedef struct _EPROCESS {
    // ...
    LIST_ENTRY ActiveProcessLinks;     // 用于链接所有进程 偏移: 0x088 (XP)
    HANDLE UniqueProcessId;            // 进程ID 
    CHAR ImageFileName[16];            // 进程名(最多15字符)
    // ... 其他字段
} EPROCESS, *PEPROCESS;
 
具体结构在文末
dt!_KPCR      
dt!_KPRCB     
dt!_ETHREAD   
dt!_EPROCESS  
dt!_KAPC_STATE
dt!_LIST_ENTRY 
 
!pcr                    ; 查看当前处理器的KPCR
!prcb                   ; 查看当前处理器的KPRCB
!thread                 ; 查看当前线程的ETHREAD
!process                ; 查看当前进程的EPROCESS
!process 0 0            ; 列出所有进程
 
; 查看ActiveProcessLinks链表
dt _EPROCESS nt!PsInitialSystemProcess ActiveProcessLinks
dt!_KPCR      
dt!_KPRCB     
dt!_ETHREAD   
dt!_EPROCESS  
dt!_KAPC_STATE
dt!_LIST_ENTRY 
 
!pcr                    ; 查看当前处理器的KPCR
!prcb                   ; 查看当前处理器的KPRCB
!thread                 ; 查看当前线程的ETHREAD
!process                ; 查看当前进程的EPROCESS
!process 0 0            ; 列出所有进程
 
; 查看ActiveProcessLinks链表
dt _EPROCESS nt!PsInitialSystemProcess ActiveProcessLinks
DriverEntry启动时:
├─ DetectWindowsVersion() 检测系统版本
├─ InitProcessOffsets() 根据版本设置偏移量
 
FS寄存器到ETHREAD:
├─ FS:[0x124] → 当前ETHREAD指针
└─ 这个0x124是KPCR结构中CurrentThread字段的偏移
 
WinXP偏移量:
├─ ProcessId: 0x84          // EPROCESS + 0x84 → UniqueProcessId字段
├─ ActiveProcessLinks: 0x88 // EPROCESS + 0x88 → ActiveProcessLinks字段
├─ ParentProcessId: 0x14C   // EPROCESS + 0x14C → InheritedFromUniqueProcessId字段
├─ ImageFileName: 0x174     // EPROCESS + 0x174 → ImageFileName[16]字段
└─ DirectoryTableBase: 0x18 // EPROCESS + 0x18 → DirectoryTableBase字段
 
Win7偏移量: 
├─ ProcessId: 0xB4          // EPROCESS + 0xB4 → UniqueProcessId字段
├─ ActiveProcessLinks: 0xB8 // EPROCESS + 0xB8 → ActiveProcessLinks字段 
├─ ParentProcessId: 0x140   // EPROCESS + 0x140 → InheritedFromUniqueProcessId字段
├─ ImageFileName: 0x16C     // EPROCESS + 0x16C → ImageFileName[16]字段
└─ DirectoryTableBase: 0x18 // EPROCESS + 0x18 → DirectoryTableBase字段 (两个版本相同)
DriverEntry启动时:
├─ DetectWindowsVersion() 检测系统版本
├─ InitProcessOffsets() 根据版本设置偏移量
 
FS寄存器到ETHREAD:
├─ FS:[0x124] → 当前ETHREAD指针
└─ 这个0x124是KPCR结构中CurrentThread字段的偏移
 
WinXP偏移量:
├─ ProcessId: 0x84          // EPROCESS + 0x84 → UniqueProcessId字段
├─ ActiveProcessLinks: 0x88 // EPROCESS + 0x88 → ActiveProcessLinks字段
├─ ParentProcessId: 0x14C   // EPROCESS + 0x14C → InheritedFromUniqueProcessId字段
├─ ImageFileName: 0x174     // EPROCESS + 0x174 → ImageFileName[16]字段
└─ DirectoryTableBase: 0x18 // EPROCESS + 0x18 → DirectoryTableBase字段
 
Win7偏移量: 
├─ ProcessId: 0xB4          // EPROCESS + 0xB4 → UniqueProcessId字段
├─ ActiveProcessLinks: 0xB8 // EPROCESS + 0xB8 → ActiveProcessLinks字段 
├─ ParentProcessId: 0x140   // EPROCESS + 0x140 → InheritedFromUniqueProcessId字段
├─ ImageFileName: 0x16C     // EPROCESS + 0x16C → ImageFileName[16]字段
└─ DirectoryTableBase: 0x18 // EPROCESS + 0x18 → DirectoryTableBase字段 (两个版本相同)
进程遍历流程
R3                          R0
│                           │
├─1. UI响应             ─────┤
├─2. ProcessGetCount()调用──┤
├─3. DeviceIoControl────────►│
│   [CTL_ENUM_PROCESS_COUNT] ├─4. EnumProcessEx第一次调用
│                           │   ├─ GetCurrentEprocess()获取起始进程
│                           │   │   ├─ mov eax, fs:[0x124] 获取ETHREAD
│                           │   │   └─ mov eax, [eax + 0x44/0x150] 获取EPROCESS
│                           │   ├─ 遍历ActiveProcessLinks双向链表
│                           │   │   ├─ 只统计进程数量,不提取数据
│                           │   │   ├─ 获取Flink指针: *(CurrentProcess + 0x88/0xB8)
│                           │   │   └─ 计算下一个EPROCESS: Flink - 0x88/0xB8
│                           │   └─ 返回进程总数
│◄─5. 返回[进程数量]────────┤
├─6. ProcessGetVec()调用────┤
├─7. DeviceIoControl────────►│
│   [CTL_ENUM_PROCESS]       ├─8. 分配PROCESS_INFO数组缓冲区
│                           ├─9. EnumProcessEx第二次调用
│                           │   ├─ 参数: (buffer, false, &processCount)
│                           │   ├─ 重复相同的链表遍历过程
│                           │   ├─ 但这次提取并填充进程信息:
│                           │   │   ├─ ProcessId: *(EPROCESS + 0x84/0xB4)
│                           │   │   ├─ ParentProcessId: *(EPROCESS + 0x14C/0x140)
│                           │   │   ├─ DirectoryTableBase: *(EPROCESS + 0x18)
│                           │   │   ├─ ImageFileName: RtlCopyMemory(EPROCESS + 0x174/0x16C)
│                           │   │   └─ EprocessAddr: EPROCESS指针本身
│                           │   └─ 将数据复制到SystemBuffer
│                           ├─10. 转换为PROCESS_INFO格式
│◄─11. 返回[PROCESS_INFO数组]┤
进程遍历流程
R3                          R0
│                           │
├─1. UI响应             ─────┤
├─2. ProcessGetCount()调用──┤
├─3. DeviceIoControl────────►│
│   [CTL_ENUM_PROCESS_COUNT] ├─4. EnumProcessEx第一次调用
│                           │   ├─ GetCurrentEprocess()获取起始进程
│                           │   │   ├─ mov eax, fs:[0x124] 获取ETHREAD
│                           │   │   └─ mov eax, [eax + 0x44/0x150] 获取EPROCESS
│                           │   ├─ 遍历ActiveProcessLinks双向链表
│                           │   │   ├─ 只统计进程数量,不提取数据
│                           │   │   ├─ 获取Flink指针: *(CurrentProcess + 0x88/0xB8)
│                           │   │   └─ 计算下一个EPROCESS: Flink - 0x88/0xB8
│                           │   └─ 返回进程总数
│◄─5. 返回[进程数量]────────┤
├─6. ProcessGetVec()调用────┤
├─7. DeviceIoControl────────►│
│   [CTL_ENUM_PROCESS]       ├─8. 分配PROCESS_INFO数组缓冲区
│                           ├─9. EnumProcessEx第二次调用
│                           │   ├─ 参数: (buffer, false, &processCount)
│                           │   ├─ 重复相同的链表遍历过程
│                           │   ├─ 但这次提取并填充进程信息:
│                           │   │   ├─ ProcessId: *(EPROCESS + 0x84/0xB4)
│                           │   │   ├─ ParentProcessId: *(EPROCESS + 0x14C/0x140)
│                           │   │   ├─ DirectoryTableBase: *(EPROCESS + 0x18)
│                           │   │   ├─ ImageFileName: RtlCopyMemory(EPROCESS + 0x174/0x16C)
│                           │   │   └─ EprocessAddr: EPROCESS指针本身
│                           │   └─ 将数据复制到SystemBuffer
│                           ├─10. 转换为PROCESS_INFO格式
│◄─11. 返回[PROCESS_INFO数组]┤
内核模块遍历流程
R3                          R0
│                           │
├─1. UI响应             ─────┤
├─2. ModuleGetCount()调用───┤
├─3. DeviceIoControl────────►│
│   [CTL_ENUM_MODULE_COUNT]  ├─4. ZwQuerySystemInformation第一次调用
│                           │   ├─ SystemInformationClass = SystemModuleInformation
│◄─5. 返回[模块数量]────────┤
├─6. ModuleGetVec()调用─────┤
├─7. DeviceIoControl────────►│
│   [CTL_ENUM_MODULE]       ├─8. 分配足够大小的缓冲区
│                           ├─9. ZwQuerySystemInformation第二次调用
│                           │   ├─ 传入充足的缓冲区
│                           │   ├─ 获取SYSTEM_MODULE_INFORMATION数组
│                           │   └─ 解析每个模块信息:
│                           │       ├─ ImageBase (模块基址)
│                           │       ├─ ImageSize (模块大小) 
│                           │       ├─ FullPathName (完整路径)
│                           │       └─ 提取模块名 (路径最后部分)
│                           ├─10. 转换为MODULE_INFO格式
│◄─11. 返回[MODULE_INFO数组]─┤
内核模块遍历流程
R3                          R0
│                           │
├─1. UI响应             ─────┤
├─2. ModuleGetCount()调用───┤
├─3. DeviceIoControl────────►│
│   [CTL_ENUM_MODULE_COUNT]  ├─4. ZwQuerySystemInformation第一次调用
│                           │   ├─ SystemInformationClass = SystemModuleInformation
│◄─5. 返回[模块数量]────────┤
├─6. ModuleGetVec()调用─────┤
├─7. DeviceIoControl────────►│
│   [CTL_ENUM_MODULE]       ├─8. 分配足够大小的缓冲区
│                           ├─9. ZwQuerySystemInformation第二次调用
│                           │   ├─ 传入充足的缓冲区
│                           │   ├─ 获取SYSTEM_MODULE_INFORMATION数组
│                           │   └─ 解析每个模块信息:
│                           │       ├─ ImageBase (模块基址)
│                           │       ├─ ImageSize (模块大小) 
│                           │       ├─ FullPathName (完整路径)
│                           │       └─ 提取模块名 (路径最后部分)
│                           ├─10. 转换为MODULE_INFO格式
│◄─11. 返回[MODULE_INFO数组]─┤
//R0的
 
ULONG g_WindowsVersion = 0;  //windows版本
ENUM_PROCESS_OFFSETS g_ProcessOffsets;
 
enum WindowsVersion
{
    WinXP,
    Win7,
    Other
};
 
//检测windows版本 设置到全局变量
NTSTATUS DetectWindowsVersion()
{
    RTL_OSVERSIONINFOW versionInfo = { 0 };
    versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
    NTSTATUS status = RtlGetVersion(&versionInfo);
    if (!NT_SUCCESS(status)) {
        return status;
    }
 
    if (versionInfo.dwMajorVersion == 5) {
        g_WindowsVersion = WinXP;
        KdPrint(("[test] Version: WinXP\n"));
    }
    else if (versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion == 1) {
        g_WindowsVersion = Win7;
        KdPrint(("[test] Version: Win7\n"));
    }
    else {
        KdPrint(("[test] Version: Other\n"));
        return STATUS_NOT_SUPPORTED;
    }
 
    return STATUS_SUCCESS;
}
 
// 解析进程需要的偏移量
typedef struct ENUM_PROCESS_OFFSETS {
    ULONG EThreadToProcess;     // ETHREAD -> EPROCESS 偏移
    ULONG ProcessId;           // UniqueProcessId 偏移
    ULONG ActiveProcessLinks;  // ActiveProcessLinks 偏移 
    ULONG ParentProcessId;     // InheritedFromUniqueProcessId 偏移
    ULONG ImageFileName;       // ImageFileName 偏移
    ULONG DirectoryTableBase;  // CR3 偏移
}*PENUM_PROCESS_OFFSETS;
 
// 这里可以看下各个版本的偏移
NTSTATUS InitProcessOffsets() {
    if (g_WindowsVersion == WinXP) {
        g_ProcessOffsets.EThreadToProcess = 0x44;
 
        g_ProcessOffsets.ProcessId = 0x84;
        g_ProcessOffsets.ActiveProcessLinks = 0x88;
        g_ProcessOffsets.ParentProcessId = 0x14C;
        g_ProcessOffsets.ImageFileName = 0x174;
        g_ProcessOffsets.DirectoryTableBase = 0x18;
    }
    else if (g_WindowsVersion == Win7) {
        g_ProcessOffsets.EThreadToProcess = 0x150;
 
        g_ProcessOffsets.ProcessId = 0xB4;
        g_ProcessOffsets.ActiveProcessLinks = 0xB8;
        g_ProcessOffsets.ParentProcessId = 0x140;
        g_ProcessOffsets.ImageFileName = 0x16C;
        g_ProcessOffsets.DirectoryTableBase = 0x18;
    }
 
    return STATUS_SUCCESS;
}
 
PEPROCESS GetCurrentEprocess() {
    PEPROCESS Process = NULL;
 
    __asm {
        mov eax, fs: [0x124]                    //ETHREAD
        mov ebx, g_ProcessOffsets.EThreadToProcess     // 0x44  或 0x150
        mov eax, [eax + ebx]                    // ETHREAD.ThreadsProcess
        mov Process, eax
    }
 
    return Process;
}
 
//onlyGetCount判断 获取进程数量还是遍历进程数据。
//如果只需要判断数量,我会传processBuffer为NULL。
NTSTATUS EnumProcessEx(PPROCESS_INFO processBuffer, bool onlyGetCount, PULONG processCount) {
    PEPROCESS CurrentProcess = NULL;
    PEPROCESS StartProcess = NULL;//记录开始的进程避免循环 双向链表
    ULONG Counter = 0;
 
    __try {
        StartProcess = GetCurrentEprocess();
        CurrentProcess = StartProcess;
 
        KdPrint(("[test] 开始遍历进程,起始EPROCESS: %p\n", CurrentProcess));
 
        do {
            // 如果需要拿进程数据
            if (!onlyGetCount&& processBuffer!=NULL) {
                PPROCESS_INFO pInfo = &processBuffer[Counter];
                RtlZeroMemory(pInfo, sizeof(PROCESS_INFO));
 
                // 提取进程信息
                pInfo->ProcessId = *(PULONG)((PUCHAR)CurrentProcess + g_ProcessOffsets.ProcessId);
                pInfo->ParentProcessId = *(PULONG)((PUCHAR)CurrentProcess + g_ProcessOffsets.ParentProcessId);
                pInfo->EprocessAddr = CurrentProcess;
                pInfo->DirectoryTableBase = *(PULONG)((PUCHAR)CurrentProcess + g_ProcessOffsets.DirectoryTableBase);
 
                // 复制进程名
                PUCHAR ImageFileName = (PUCHAR)CurrentProcess + g_ProcessOffsets.ImageFileName;
                RtlCopyMemory(pInfo->ImageFileName, ImageFileName, 16);
                pInfo->ImageFileName[15] = '\0';
 
                KdPrint(("[test] 进程[%d]: PID=%d, Name=%s, EPROCESS=%p\n",
                    Counter, pInfo->ProcessId, pInfo->ImageFileName, CurrentProcess));
            }
 
            Counter++;
 
            //下一个进程
            PULONG ActiveProcessLinksPtr = (PULONG)((PUCHAR)CurrentProcess + g_ProcessOffsets.ActiveProcessLinks);
            ULONG NextLinkAddress = *ActiveProcessLinksPtr;  // 获取Flink
            CurrentProcess = (PEPROCESS)(NextLinkAddress - g_ProcessOffsets.ActiveProcessLinks);  // 减去偏移得到EPROCESS地址
 
        } while (CurrentProcess != StartProcess && Counter < 1000);//怕无限循环
 
        *processCount = Counter;
        KdPrint(("[test] 遍历完成,总共找到 %d 个进程\n", Counter));
 
        return STATUS_SUCCESS;
 
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        KdPrint(("[test] err EnumerateProcessCount \n"));
        return STATUS_UNSUCCESSFUL;
    }
}
 
//DispatchDeviceControl中
    case CTL_ENUM_PROCESS_COUNT:
    {
        ULONG processCount = 0;
        status = EnumProcessEx(NULL, true, &processCount);
        if (NT_SUCCESS(status)) {
            *(PULONG)Irp->AssociatedIrp.SystemBuffer = processCount;
            info = sizeof(ULONG);
            KdPrint(("[test] CTL_ENUM_PROCESS_COUNT: %d 个进程\n", processCount));
        }
    }
    break;
    case CTL_ENUM_PROCESS:
    {
        ULONG processCount = 0;
        status = EnumProcessEx((PPROCESS_INFO)Irp->AssociatedIrp.SystemBuffer,
            false, &processCount);
        if (NT_SUCCESS(status)) {
            info = processCount * sizeof(PROCESS_INFO);
            KdPrint(("[test] CTL_ENUM_PROCESS: 返回 %d 个进程信息\n", processCount));
        }
    }
    break;
//R0的
 
ULONG g_WindowsVersion = 0;  //windows版本
ENUM_PROCESS_OFFSETS g_ProcessOffsets;
 
enum WindowsVersion
{
    WinXP,
    Win7,
    Other
};
 
//检测windows版本 设置到全局变量
NTSTATUS DetectWindowsVersion()
{
    RTL_OSVERSIONINFOW versionInfo = { 0 };
    versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
    NTSTATUS status = RtlGetVersion(&versionInfo);
    if (!NT_SUCCESS(status)) {
        return status;
    }
 
    if (versionInfo.dwMajorVersion == 5) {
        g_WindowsVersion = WinXP;
        KdPrint(("[test] Version: WinXP\n"));
    }
    else if (versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion == 1) {
        g_WindowsVersion = Win7;
        KdPrint(("[test] Version: Win7\n"));
    }
    else {
        KdPrint(("[test] Version: Other\n"));
        return STATUS_NOT_SUPPORTED;
    }
 
    return STATUS_SUCCESS;
}
 
// 解析进程需要的偏移量
typedef struct ENUM_PROCESS_OFFSETS {
    ULONG EThreadToProcess;     // ETHREAD -> EPROCESS 偏移
    ULONG ProcessId;           // UniqueProcessId 偏移
    ULONG ActiveProcessLinks;  // ActiveProcessLinks 偏移 
    ULONG ParentProcessId;     // InheritedFromUniqueProcessId 偏移
    ULONG ImageFileName;       // ImageFileName 偏移
    ULONG DirectoryTableBase;  // CR3 偏移
}*PENUM_PROCESS_OFFSETS;
 
// 这里可以看下各个版本的偏移
NTSTATUS InitProcessOffsets() {
    if (g_WindowsVersion == WinXP) {
        g_ProcessOffsets.EThreadToProcess = 0x44;
 
        g_ProcessOffsets.ProcessId = 0x84;
        g_ProcessOffsets.ActiveProcessLinks = 0x88;
        g_ProcessOffsets.ParentProcessId = 0x14C;
        g_ProcessOffsets.ImageFileName = 0x174;
        g_ProcessOffsets.DirectoryTableBase = 0x18;
    }
    else if (g_WindowsVersion == Win7) {
        g_ProcessOffsets.EThreadToProcess = 0x150;
 
        g_ProcessOffsets.ProcessId = 0xB4;
        g_ProcessOffsets.ActiveProcessLinks = 0xB8;
        g_ProcessOffsets.ParentProcessId = 0x140;
        g_ProcessOffsets.ImageFileName = 0x16C;
        g_ProcessOffsets.DirectoryTableBase = 0x18;
    }
 
    return STATUS_SUCCESS;
}
 
PEPROCESS GetCurrentEprocess() {
    PEPROCESS Process = NULL;
 
    __asm {
        mov eax, fs: [0x124]                    //ETHREAD
        mov ebx, g_ProcessOffsets.EThreadToProcess     // 0x44  或 0x150
        mov eax, [eax + ebx]                    // ETHREAD.ThreadsProcess
        mov Process, eax
    }
 
    return Process;
}
 
//onlyGetCount判断 获取进程数量还是遍历进程数据。
//如果只需要判断数量,我会传processBuffer为NULL。
NTSTATUS EnumProcessEx(PPROCESS_INFO processBuffer, bool onlyGetCount, PULONG processCount) {
    PEPROCESS CurrentProcess = NULL;
    PEPROCESS StartProcess = NULL;//记录开始的进程避免循环 双向链表
    ULONG Counter = 0;
 
    __try {
        StartProcess = GetCurrentEprocess();
        CurrentProcess = StartProcess;
 
        KdPrint(("[test] 开始遍历进程,起始EPROCESS: %p\n", CurrentProcess));
 
        do {
            // 如果需要拿进程数据
            if (!onlyGetCount&& processBuffer!=NULL) {
                PPROCESS_INFO pInfo = &processBuffer[Counter];
                RtlZeroMemory(pInfo, sizeof(PROCESS_INFO));
 
                // 提取进程信息
                pInfo->ProcessId = *(PULONG)((PUCHAR)CurrentProcess + g_ProcessOffsets.ProcessId);
                pInfo->ParentProcessId = *(PULONG)((PUCHAR)CurrentProcess + g_ProcessOffsets.ParentProcessId);
                pInfo->EprocessAddr = CurrentProcess;
                pInfo->DirectoryTableBase = *(PULONG)((PUCHAR)CurrentProcess + g_ProcessOffsets.DirectoryTableBase);
 
                // 复制进程名
                PUCHAR ImageFileName = (PUCHAR)CurrentProcess + g_ProcessOffsets.ImageFileName;
                RtlCopyMemory(pInfo->ImageFileName, ImageFileName, 16);
                pInfo->ImageFileName[15] = '\0';
 
                KdPrint(("[test] 进程[%d]: PID=%d, Name=%s, EPROCESS=%p\n",
                    Counter, pInfo->ProcessId, pInfo->ImageFileName, CurrentProcess));
            }
 
            Counter++;
 
            //下一个进程
            PULONG ActiveProcessLinksPtr = (PULONG)((PUCHAR)CurrentProcess + g_ProcessOffsets.ActiveProcessLinks);
            ULONG NextLinkAddress = *ActiveProcessLinksPtr;  // 获取Flink
            CurrentProcess = (PEPROCESS)(NextLinkAddress - g_ProcessOffsets.ActiveProcessLinks);  // 减去偏移得到EPROCESS地址
 
        } while (CurrentProcess != StartProcess && Counter < 1000);//怕无限循环
 
        *processCount = Counter;
        KdPrint(("[test] 遍历完成,总共找到 %d 个进程\n", Counter));
 
        return STATUS_SUCCESS;
 
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        KdPrint(("[test] err EnumerateProcessCount \n"));
        return STATUS_UNSUCCESSFUL;
    }
}
 
//DispatchDeviceControl中
    case CTL_ENUM_PROCESS_COUNT:
    {
        ULONG processCount = 0;
        status = EnumProcessEx(NULL, true, &processCount);
        if (NT_SUCCESS(status)) {
            *(PULONG)Irp->AssociatedIrp.SystemBuffer = processCount;
            info = sizeof(ULONG);
            KdPrint(("[test] CTL_ENUM_PROCESS_COUNT: %d 个进程\n", processCount));
        }
    }
    break;
    case CTL_ENUM_PROCESS:
    {
        ULONG processCount = 0;
        status = EnumProcessEx((PPROCESS_INFO)Irp->AssociatedIrp.SystemBuffer,
            false, &processCount);
        if (NT_SUCCESS(status)) {
            info = processCount * sizeof(PROCESS_INFO);
            KdPrint(("[test] CTL_ENUM_PROCESS: 返回 %d 个进程信息\n", processCount));
        }
    }
    break;
//R3的
 
DWORD ArkR3::ProcessGetCount()
{
    DWORD dwBytes;
    DWORD dwEntryNum = NULL;
 
    DeviceIoControl(m_hDriver, CTL_ENUM_PROCESS_COUNT, NULL, NULL, &dwEntryNum, sizeof(DWORD), &dwBytes, NULL);
 
    return dwEntryNum;
}
 
 
std::vector<PROCESS_INFO> ArkR3::ProcessGetVec(DWORD processCount)
{
    DWORD dwRetBytes;
    DWORD dwBufferSize = sizeof(PROCESS_INFO) * processCount;
    PPROCESS_INFO pEntryInfo = (PPROCESS_INFO)malloc(dwBufferSize);
    BOOL bResult = DeviceIoControl(m_hDriver, CTL_ENUM_PROCESS, NULL, NULL, pEntryInfo, dwBufferSize, &dwRetBytes, NULL);
 
    ProcVec_.clear();
     
    DWORD Count = 0;
    if (bResult) {
        Count = dwRetBytes / sizeof(PROCESS_INFO);
        for (DWORD i = 0; i < Count; i++) {
            PROCESS_INFO pInfo = pEntryInfo[i];    
            ProcVec_.emplace_back(pInfo);          
 
            Log("ProcessGetVec 进程[%d]: PID=%d, 父PID=%d, 名称=%s, EPROCESS=%p\n",
                i, pInfo.ProcessId, pInfo.ParentProcessId,
                pInfo.ImageFileName, pInfo.EprocessAddr);
        }
    }
     
    free(pEntryInfo);
 
    return ProcVec_;
}
//R3的
 
DWORD ArkR3::ProcessGetCount()
{
    DWORD dwBytes;
    DWORD dwEntryNum = NULL;
 
    DeviceIoControl(m_hDriver, CTL_ENUM_PROCESS_COUNT, NULL, NULL, &dwEntryNum, sizeof(DWORD), &dwBytes, NULL);
 
    return dwEntryNum;
}
 
 
std::vector<PROCESS_INFO> ArkR3::ProcessGetVec(DWORD processCount)
{
    DWORD dwRetBytes;
    DWORD dwBufferSize = sizeof(PROCESS_INFO) * processCount;
    PPROCESS_INFO pEntryInfo = (PPROCESS_INFO)malloc(dwBufferSize);
    BOOL bResult = DeviceIoControl(m_hDriver, CTL_ENUM_PROCESS, NULL, NULL, pEntryInfo, dwBufferSize, &dwRetBytes, NULL);
 
    ProcVec_.clear();
     
    DWORD Count = 0;

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2025-7-16 14:56 被X66iaM编辑 ,原因:
收藏
免费 26
支持
分享
最新回复 (18)
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
有偿咨询,怎么联系,给个联系方式
2025-7-16 14:18
0
雪    币: 0
活跃值: (738)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2025-7-16 20:56
0
雪    币: 74
活跃值: (1123)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2025-7-17 10:09
0
雪    币: 10
活跃值: (1364)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2025-7-17 12:05
0
雪    币: 0
活跃值: (320)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
看下思路
2025-7-17 18:02
0
雪    币: 2839
活跃值: (12132)
能力值: (RANK:385 )
在线值:
发帖
回帖
粉丝
7

如果不做ark 简单的做个系统信息查看工具的话. 目前使用 PsLookupProcessByProcessId 去拿信息就行 或者说现在使用这个也算是最优解. 因为隐藏进程断链等骚操作在目前PG状态下.都凉凉. 当然一山还有一山高.对抗无止境. 能满足日常80%的需求也可以 除非特别需要20%. 但这20%会付出更多. 比如上面的 我需要找系统特征码来定位.(更好的是解析pdb)

最后于 2025-7-18 09:51 被TkBinary编辑 ,原因: 错别字
2025-7-18 09:50
0
雪    币: 8671
活跃值: (5866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢分享
2025-7-18 10:27
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
牛逼
2025-7-18 13:51
0
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
very good
2025-7-20 17:42
0
雪    币: 34
活跃值: (601)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
11
感谢分享
2025-7-31 16:14
0
雪    币: 468
活跃值: (350)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
感谢分享
2025-8-3 11:12
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
mark
2025-8-26 18:27
0
雪    币: 239
活跃值: (248)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
感谢分享
2025-8-28 18:53
0
雪    币: 2703
活跃值: (7346)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
谢谢分享
2025-9-19 07:50
0
雪    币: 201
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
123
2025-10-5 13:08
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
感谢分享
2025-10-18 17:33
0
雪    币: 205
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
谢谢分享
2025-12-24 18:50
0
雪    币: 1
活跃值: (227)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
666
2026-1-5 04:56
0
游客
登录 | 注册 方可回帖
返回