页表HOOK

hook一个内核函数,不修改API对应的物理页,而是把与API相关的物理页拷贝一份(PTE,PDE,PPE,PXE四个页),然后修改目标进程的页表映射到拷贝的物理页,使目标进程对此API的操作与其他进程分离,让对此API的hook不会影响到其他进程
结构体

enum
{
    PhyPage,
    PT,
    PDT,
    PPT,
    PXT,
};
typedef struct _PAGE_INFO
{
    UINT64 PteBase;//页表基址
    UINT32 PXEIndex;//线性地址所属的PXE存储在PXT位置的索引
    UINT64 Pxe;//线性地址所属的PXE的值
    PVOID pPageArray[5];//物理页,PT,PDT,PPT,PXT
}PAGE_INFO,* PPAGE_INFO;

函数

UINT64 GetPTEBase();
UINT64 GetXXXAddress(UINT64 VirtualAddress, UINT64 PTEBase);
VOID CopyPhysicalPage(PVOID DestPage, UINT64 SourcePagePTE);
BOOLEAN InitHookPage(UINT64 VirtualAddress, PPAGE_INFO pPageInfo,CHAR ShellCode[],UINT32 Length);
VOID  SetHookPage(UINT64 DirectoryTableBase, PAGE_INFO pPageInfo);
VOID LinkPhysicalPages(PVOID ChildPage, PVOID ParentPage, UINT32 Index, UINT64 Attribute);

详情
驱动加载时调用InitHookPage()初始化hook页,然后在目标进程创建时(PsSetCreateProcessNotifyRoutine),将此hook页替换到目标进程中

//==================================================================
//内部函数
//函数名:GetPTEBase
//功能:获取页表基址
//返回值:UINT64,返回页表的基址
//==================================================================
UINT64 GetPTEBase()
{
    PUCHAR BaseAddr = (PUCHAR)MmGetVirtualForPhysical;
    return *(PUINT64)(BaseAddr + 0x22);
}
//==================================================================
//内部函数
//函数参数1 UINT64,一个虚拟地址
//函数参数2 UINT64,页表基址,由GetPTEBase()获取
//函数名:GetXXXAddress
//功能:获取一个虚拟地址所属的PTE,PDE,PPE,PXE之一的虚拟地址
//返回值:UINT64,返回PTE,PDE,PPE,PXE之一的虚拟地址
//==================================================================
UINT64 GetXXXAddress(UINT64 VirtualAddress, UINT64 PTEBase)
{
    //VA+PTEBase->PTE
    //PTE+PTEBase->PDE
    //PDE+PTEBase->PPE
    //PPE+PTEBase->PXE
    return  ((VirtualAddress & 0x0000FFFFFFFFF000) >> 12) * 8 + PTEBase;
}
//==================================================================
//内部函数
//函数名:CopyPhysicalPage
//函数参数1 PVOID 指向目标物理页的虚拟地址
//函数参数2 UINT64 原物理页的物理地址
//功能:拷贝原物理页的内容到目标物理页
//返回值:VOID
//==================================================================
VOID CopyPhysicalPage(PVOID DestPage, UINT64 SourcePagePhyAddr)
{
    PHYSICAL_ADDRESS Low = { 0 };
    PHYSICAL_ADDRESS High = { MAXULONG64 };
    PVOID TempPage = MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached);
 
    UINT64 PTEAddress = GetXXXAddress((UINT64)TempPage, GetPTEBase());
    UINT64 OldPTE = *(PUINT64)PTEAddress;
    *(PULONG64)PTEAddress = SourcePagePhyAddr;
    RtlCopyMemory(DestPage, TempPage, PAGE_SIZE);
    *(PUINT64)PTEAddress = OldPTE;
    MmFreeContiguousMemory(TempPage);
}
//==================================================================
//内部函数
//函数名:LinkPhysicalPages
//函数参数1  PVOID 子物理页的虚拟地址
//函数参数2  PVOID 父物理页的虚拟地址
//函数参数3  UINT32 子物理页插入到父物理页位置的索引
//函数参数4  UINT64 子物理页的属性
//功能:连接两个物理页
//返回值:VOID
//==================================================================
VOID LinkPhysicalPages(PVOID ChildPage,PVOID ParentPage,UINT32 Index ,UINT64 Attribute)
{
    UINT64 ChildPagePhyAddr = *(PUINT64)(GetXXXAddress((UINT64)ChildPage, GetPTEBase()));
    *(PUINT64)((UINT64)ParentPage+ (UINT64)Index * 8) = ((UINT64)ChildPagePhyAddr & 0xFFFFFFFFF000) | (Attribute & ~(0xFFFFFFFFF000));
}
//==================================================================
//函数名:InitHookPage
//函数参数1 UINT64,一个要hook的函数的虚拟地址
//函数参数2 OUT PPAGE_INFO结构体,供SetHookPage使用
//函数参数3 CHAR[] 要替换的二进制代码数组
//函数参数4 UINT32 数组长度
//功能:初始化hook页
//返回值:BOOLEAN,安装成功返回TRUE,失败返回FALSE
//==================================================================
BOOLEAN InitHookPage(UINT64 VirtualAddress,PPAGE_INFO pPageInfo,CHAR ShellCode[],UINT32 Length)
{
    //按9-9-9-9-12拆分VirtualAddres这个线性地址
    pPageInfo->PXEIndex = (VirtualAddress >> 0x27) & 0x1FF; //PXEIndex
    UINT32 PPEIndex = (VirtualAddress >> 0x1E) & 0x1FF;     //PPEIndex
    UINT32 PDEIndex = (VirtualAddress >> 0x15) & 0x1FF;     //PDEIndex
    UINT32 PTEIndex = (VirtualAddress >> 0xC) & 0x1FF;      //PTEIndex
    UINT32 FuncOffset = VirtualAddress & 0xFFF;
    //获得VirtualAddress对应的Pte Pde Ppe Pxe的值
    pPageInfo->PteBase = GetPTEBase();
    UINT64 PteAddr = GetXXXAddress(VirtualAddress, pPageInfo->PteBase);     //VirtualAddress所属的物理页的PTE的指针
    UINT64 PdeAddr = GetXXXAddress(PteAddr, pPageInfo->PteBase);            //VirtualAddress所属的物理页的PDE的指针
    UINT64 PpeAddr = GetXXXAddress(PdeAddr, pPageInfo->PteBase);            //VirtualAddress所属的物理页的PPE的指针
    UINT64 PxeAddr = GetXXXAddress(PpeAddr, pPageInfo->PteBase);            //VirtualAddress所属的物理页的PXE的指针
    UINT64 Pte = *(PUINT64)PteAddr;
    UINT64 Pde = *(PUINT64)PdeAddr;
    UINT64 Ppe= *(PUINT64)PpeAddr;
    pPageInfo->Pxe = *(PUINT64)PxeAddr;
    //分配一块物理页并初始化
    PHYSICAL_ADDRESS Low = { 0 };
    PHYSICAL_ADDRESS High = { MAXULONG64 };
    for (int i = 0; i < 5; i++)
    {
        //成功返回虚拟地址,失败返回NULL
        pPageInfo->pPageArray[i] = MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached);
        if (!pPageInfo->pPageArray[i])
        {
            DbgPrint("物理页分配失败\n");
            return FALSE;
        }
        RtlZeroMemory(pPageInfo->pPageArray[i], PAGE_SIZE);
    }
    //拷贝VirtualAddress所属的PhyPage,PT,PDT,PPT
    CopyPhysicalPage(pPageInfo->pPageArray[PhyPage], Pte);
    CopyPhysicalPage(pPageInfo->pPageArray[PT], Pde);
    CopyPhysicalPage(pPageInfo->pPageArray[PDT], Ppe);
    CopyPhysicalPage(pPageInfo->pPageArray[PPT], pPageInfo->Pxe);
    //连接PhyPage,PT,PDT,PPT
    LinkPhysicalPages(pPageInfo->pPageArray[PhyPage], pPageInfo->pPageArray[PT], PTEIndex, Pte);
    LinkPhysicalPages(pPageInfo->pPageArray[PT], pPageInfo->pPageArray[PDT], PDEIndex, Pde);
    LinkPhysicalPages(pPageInfo->pPageArray[PDT], pPageInfo->pPageArray[PPT], PPEIndex, Ppe);

    if (ShellCode == NULL||Length == 0)
    {
        return TRUE; 
    }
    //__debugbreak();
    //UINT64 aaaaaaa = (UINT64)pPageInfo->pPageArray[PhyPage] + FuncOffset + 0XB;
    for (UINT32 i = 0; i < Length; i++)
    {
        *(PCHAR)((UINT64)pPageInfo->pPageArray[PhyPage] + FuncOffset+ i) = ShellCode[i];
    }
    return TRUE;
}
//==================================================================
//函数名:SetHookPage
//函数参数1 UINT64,目标进程的cr3
//函数参数2 PAGE_INFO 结构体,PAGE_INFO由InitHookPage获得
//功能:安装hook页
//返回值:VOID
//==================================================================

VOID  SetHookPage(UINT64 DirectoryTableBase, PAGE_INFO PageInfo)
{
    DirectoryTableBase = DirectoryTableBase & (~0xFFF) | 0x063;
    UINT64 PtePXTAddress = GetXXXAddress((UINT64)PageInfo.pPageArray[PXT], PageInfo.PteBase);
    UINT64 PtePXT = *(PUINT64)PtePXTAddress;
    //修改了映射
    *(PUINT64)PtePXTAddress = DirectoryTableBase;
    LinkPhysicalPages(PageInfo.pPageArray[PPT],PageInfo.pPageArray[PXT], PageInfo.PXEIndex, PageInfo.Pxe);
    *(PUINT64)PtePXTAddress = PtePXT;
    DbgPrint("HOOK 成功\n");
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
页表是操作系统中用来记录虚拟内存地址与物理内存地址映射关系的数据结构,其实现方式因操作系统不同而异。以下是一个简单的页表代码实现示例,供参考: ```c #define PAGE_SIZE 4096 // 页大小为 4KB #define PAGE_NUM 1024 // 页表项数为 1024 struct page_table_entry { unsigned int present : 1; // 页是否存在 unsigned int writeable : 1; // 页是否可写 unsigned int user_access : 1; // 用户是否有访问权限 unsigned int write_through : 1; // 是否写直达 unsigned int cache_disabled : 1; // 是否禁用缓存 unsigned int accessed : 1; // 是否被访问过 unsigned int dirty : 1; // 是否被修改过 unsigned int zero : 1; // 保留位 unsigned int global : 1; // 全局页标志位 unsigned int available : 3; // 空闲可用位 unsigned int page_frame : 20; // 物理页框号 }; struct page_table_entry page_table[PAGE_NUM]; // 初始化页表 // 将虚拟地址映射到物理地址 void map_virtual_to_physical(unsigned int virtual_address, unsigned int physical_address) { unsigned int page_index = virtual_address / PAGE_SIZE; // 计算页号 page_table[page_index].present = 1; // 设置页存在 page_table[page_index].writeable = 1; // 设置页可写 page_table[page_index].user_access = 1; // 设置用户可访问 page_table[page_index].write_through = 0; // 不写直达 page_table[page_index].cache_disabled = 0; // 不禁用缓存 page_table[page_index].accessed = 0; // 未被访问过 page_table[page_index].dirty = 0; // 未被修改过 page_table[page_index].zero = 0; // 保留位清零 page_table[page_index].global = 0; // 非全局页 page_table[page_index].available = 0; // 空闲可用位清零 page_table[page_index].page_frame = physical_address / PAGE_SIZE; // 计算页框号 } ``` 以上代码实现了将虚拟地址映射到物理地址的功能,具体实现方式可能会因操作系统的不同而有所差异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值