«

»

30

EPROCESS劫持

昨天见群里有人提起,今天就随便写了一下。把PspCidTable中指定进程的Object改成一个自己构造的Object,从而使RING3的各种句 柄操作无效。一开始还没明白跟直接修改EPROCESS有什么区别,后来发现劫持EPROCESS更有针对性,而且比DKOM更稳定一些。很老很简单的技 术,没啥亮点。其实主要还是为了研究一下PspCidTable的稀疏数组结构,以前掌握很多理论但一直没写码遍历过这个表,今天总算是给弄明白了~之后 再看页表的结构应该也更容易理解了。代码贴上来做个记录。
 

[代码如下]
//===================头文件===================//
#include "stdafx.h"

 

//===================结构体声明===================//
typedef struct _HANDLE_TABLE_ENTRY {
    union {
        VOID* Object;
        ULONG32 ObAttributes;
        struct _HANDLE_TABLE_ENTRY_INFO* InfoTable;
        ULONG32 Value;
    };
    union {
        ULONG32 GrantedAccess;
        struct {
            UINT16 GrantedAccessIndex;
            UINT16 CreatorBackTraceIndex;
        };
        LONG32 NextFreeTableEntry;
    };
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;

typedef struct _HANDLE_TABLE {
    ULONG32 TableCode;
    struct _EPROCESS* QuotaProcess;
    VOID* UniqueProcessId;
    EX_PUSH_LOCK HandleTableLock[4];
    LIST_ENTRY HandleTableList;
    EX_PUSH_LOCK HandleContentionEvent;
    struct _HANDLE_TRACE_DEBUG_INFO* DebugInfo;
    LONG32 ExtraInfoPages;
    ULONG32 FirstFree;
    ULONG32 LastFree;
    ULONG32 NextHandleNeedingPool;
    LONG32 HandleCount;
    union {
        ULONG32 Flags;
        UINT8 StrictFIFO : 1;
    };
} HANDLE_TABLE, *PHANDLE_TABLE;

//===================函数原型===================//
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING  RegistryPath);
void DriverUnload(IN PDRIVER_OBJECT DriverObject);
BOOLEAN HijackProcess(ULONG pid);
PHANDLE_TABLE_ENTRY LookupHandleTableEntry(ULONG pid);
PHANDLE_TABLE GetPspCidTable();
void WPOFF();
void WPON();
BOOLEAN MmIsAddressRangeValid(PVOID Address, ULONG Length);

//===================全局变量===================//
ULONG EPROCESS_Size;
PVOID gpFakeProcess;

//===================驱动例程===================//
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING  RegistryPath)
{
    DriverObject->DriverUnload = DriverUnload;

    EPROCESS_Size = 0x260;   // XP SP3: sizeof(struct _EPROCESS)

    // 对进程进行EPROCESS劫持
    HijackProcess(476);

    return STATUS_SUCCESS;
}

void DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
    return;
}

//===================Hijack关键函数===================//
BOOLEAN HijackProcess(ULONG pid)
{
    // 取得进程在PspCidTable中的位置
    PHANDLE_TABLE_ENTRY TableEntry = LookupHandleTableEntry(pid);  
    if (!MmIsAddressRangeValid(TableEntry, sizeof(HANDLE_TABLE_ENTRY)))
        return FALSE;

    // TODO: 验证EPROCESS的有效性

    ULONG ProcessMask = (ULONG)TableEntry->Object & 7;              // 取得Mask
    PVOID Process = (PVOID)((ULONG)TableEntry->Object & (~3));      // 取得EPROCESS地址
    if (!MmIsAddressRangeValid(Process, EPROCESS_Size))
        return FALSE;

    KdPrint(("[%d] EPROCESS: %X   Mask: %d", pid, Process, ProcessMask));

    // 构造自己的EPROCESS
    gpFakeProcess = ExAllocatePool(NonPagedPool, EPROCESS_Size);
    if (!MmIsAddressRangeValid(gpFakeProcess, EPROCESS_Size))
        return FALSE;
    RtlCopyMemory(gpFakeProcess, Process, EPROCESS_Size);

    // 还原Mask
    Process = (PVOID)((ULONG)gpFakeProcess + ProcessMask);
    // 修改PspCidTable中进程的Object为伪造的EPROCESS
    WPOFF();
    InterlockedExchange((LONG*)&TableEntry->Object, (LONG)Process);
    WPON();

    return TRUE;
}

//===================查找指定PID的进程在PspCidTable中的位置===================//
PHANDLE_TABLE_ENTRY LookupHandleTableEntry(ULONG pid)
{
    PHANDLE_TABLE PspCidTable;
    PspCidTable = GetPspCidTable();   // 取得PspCidTable
    if (!MmIsAddressRangeValid(PspCidTable, 4))
        return NULL;

    KdPrint(("PspCidTable: %X", PspCidTable));

    if (pid >= PspCidTable->NextHandleNeedingPool)
        return NULL;

    ULONG TableLevel;
    TableLevel = PspCidTable->TableCode & 3;   // TableCode后两位表明句柄表级数
    KdPrint(("TableLevel: %d", TableLevel));

    PHANDLE_TABLE_ENTRY Table1;
    PHANDLE_TABLE_ENTRY *Table2;
    PHANDLE_TABLE_ENTRY **Table3;
    int i, j, k;   // 表索引
    PHANDLE_TABLE_ENTRY pReturn;

    switch (TableLevel) {
    case 0x0:   // 1级表
        Table1 = (PHANDLE_TABLE_ENTRY)((PspCidTable->TableCode >> 2) << 2);   // 表项数组

        i = pid / 4;
        pReturn = &Table1[i];

        break;
    case 0x1:   // 2级表
        Table2 = (PHANDLE_TABLE_ENTRY*)((PspCidTable->TableCode >> 2) << 2);   // 一级表数组

        j = pid / 0x800;   // 根据pid确定表索引
        Table1 = Table2[j];
        i = (pid % 0x800) / 4;
        pReturn = &Table1[i];

        break;
    case 0x2:   // 3级表
        Table3 = (PHANDLE_TABLE_ENTRY**)((PspCidTable->TableCode >> 2) << 2);   // 二级表数组

        k = pid / 0x1000;
        Table2 = Table3[k];
        j = (pid % 0x1000) / 0x800;
        Table1 = Table2[j];
        i = (pid % 0x1000) % 0x800;
        pReturn = &Table1[i];

        break;
    default:
        pReturn = NULL;
    }

    return pReturn;
}

//===================获取PspCidTable===================//
PHANDLE_TABLE GetPspCidTable()
{
    PHANDLE_TABLE PspCidTable;
    KeSetSystemAffinityThread(1);   // 使当前线程运行在第一个处理器上,否则fs:[0x34]内容可能不正确
    __asm {  
        push eax  
        mov eax,fs:[0x34]        ;得到KdVersionBlock的地址  
        add eax,80h              ;保存PspCidTable变量的偏移: KdVersionBlock + 80h
        mov eax,[eax]            ;得到PspCidTable的指针
        mov eax,[eax]            ;得到PspCidTable
        mov PspCidTable,eax
        pop eax
    }  
    KeRevertToUserAffinityThread();   // 恢复线程运行的处理器
    return PspCidTable;
}

//===================检查一个内存段是否有效===================//
BOOLEAN MmIsAddressRangeValid(PVOID Address, ULONG Length)
{
    ULONG i;
    for (i = 0; i < Length; i++) {
        if (!MmIsAddressValid((PCHAR)Address + i)) return FALSE;
    }
    return TRUE;
}

//===================关/开 内存写保护===================//
void WPOFF()
{
    __asm {
        cli
        mov eax, CR0
        and eax, NOT 10000h  //disable WP bit
        mov CR0, eax
    }
}

void WPON()
{
    __asm {
        mov eax, CR0
        or eax, 10000h  //disable WP bit
        mov CR0, eax
        sti
    }
}
//==================================================================//

发表评论

电子邮件地址不会被公开。 必填项已用*标注

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>