Download as pdf or txt
Download as pdf or txt
You are on page 1of 88

Winows内核高级篇

0.系统时间通信
X64上,修改IRQL,靠 __writecr8(8) 来修改。
自定义回调的IRQL 一般是2(DPC等级) 不能使用绝大部分函数
靠PEB 传结构体指针通信。    

1.确定回调对象的目录

2.打开指定回调对象

PCALLBACK_OBJECT timeCallback = NULL;//回调对象的地址

OBJECT_ATTRIBUTES objAttr = { 0 };
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"\\CallBack\\SetSystemTime");
InitializeObjectAttributes(&objAttr, &name, OBJ_CASE_INSENSITIVE, NULL,
NULL);

NTSTATUS sta = ExCreateCallback(&timeCallback, &objAttr, TRUE, TRUE);//有则打


开,无则创建
if (!NT_SUCCESS(sta)) return FALSE;

3.注册回调

G_Callback_HANLE=ExRegisterCallback(timeCallback, callbackTime, NULL);


if (!G_Callback_HANLE) return FALSE;

4.卸载回调
VOID UnRegisterCommunicate()
{
if (G_Callback_HANLE)
{
ExUnregisterCallback(G_Callback_HANLE);
G_Callback_HANLE = NULL;
}
}

1.X64物理地址拆分
kd> dq fffff800`03f81c50
fffff800`03f81c50  4c000ca8`09358b48 3b49000c`a802258d

1111 1000 0
000 0000 00
00 0011 111
1 1000 0001
1100 0101 0000

PXE=*(CR3+1F0*8)
PPE=*(PXE+0*8)    
PDE=*(PPE+1F*8)
PTE=*(PDE+181*8)
c50

kd> !dq 6d6cc000+1F0*8


#6d6ccf80 00000000`00199063 00000000`7be84863

kd> !dq 00000000`00199000+0*8


# 199000 00000000`00198063 00000000`00000000

kd> !dq 00000000`00198000+1F*8


# 1980f8 00000000`001e3063 00000000`001e4063

kd> !dq 00000000`001e3000+181*8


# 1e3c08 00000000`03f81121 00000000`03f82121

kd> !db 00000000`03f81000+C50


# 3f81c50 48 8b 35 09 a8 0c 00 4c-8d 25 02 a8 0c 00 49 3b H.5....L.%....I;
# 3f81c60 f4 0f 84 57 04 00 00 48-8d 5e f8 48 8d 4b 48 e8 ...W...H.^.H.KH.

kd> !pte fffff800`03f81c50


                                          VA fffff80003f81c50
PXE at FFFFF6FB7DBEDF80    PPE at FFFFF6FB7DBF0000    PDE at FFFFF6FB7E0000F8  
 PTE at FFFFF6FC0001FC08
contains 0000000000199063  contains 0000000000198063  contains 00000000001E3063
 contains 0000000003F81121
pfn 199       ---DA--KWEV  pfn 198       ---DA--KWEV  pfn 1e3       ---DA--KWEV
 pfn 3f81      -G--A--KREV
//一一对应
kd> .process /i fffffa80023e2630

kd> dq FFFFF6FC0001FC08
fffff6fc`0001fc08  00000000`03f81121 00000000`03f82121
fffff6fc`0001fc18  00000000`03f83121 00000000`03f84121
fffff6fc`0001fc28  00000000`03f85121 00000000`03f86121
fffff6fc`0001fc38  00000000`03f87121 00000000`03f88121
fffff6fc`0001fc48  00000000`03f89121 00000000`03f8a121
fffff6fc`0001fc58  00000000`03f8b121 00000000`03f8c121
fffff6fc`0001fc68  00000000`03f8d121 00000000`03f8e121
fffff6fc`0001fc78  00000000`03f8f121 00000000`03f90121
   

1.VAD
1.WINDOWS内存管理
<windows内核原理与实现>潘爱民c

1.1内存管理概述

物理地址:内存存储器的索引。32位或36位无符号整数。
逻辑地址:段+偏移。
虚拟地址:懂得都懂
   
内存换出:进程中的数据或代码保存到磁盘
内存换入:磁盘中的数据或代码读到内存中    

/*
页式内存管理
物理内存按 页 管理,Trap Frame 结构。

*/

1.普通寻址

注意CR3是物理地址。
2.PAE寻址

32位虚拟地址 36位物理地址

1.3内存管理算法

为了满足动态内存申请,随机地不规则地申请内存,操作系统使用了堆内存。

位图标记法

把大小N字节的内存 按粒度M字节 分成 K块。

每块有个标志位,0未使用,1已使用。

N=M*K

空闲链表法

每个结点都是一块内存

1.4管理概述

PFN database数据库,描述了物理内存各个页面的状态。

PFN数据库实际是一个结构数组,每个页面对应一个一个PFN项,维护了该页面的使用情况。

操作系统还维护了一组链表,来管理不同类型的页表。
1.物理内存数据库
1.System Address Space Layout
2.Working Set
工作集用来管理进程的虚拟地址的物理页。(用户区域

除了每个进程都有一个工作集以外,系统也有一个工作集。

ZwVirtualLock 就是把虚拟地址和对应物理页放到工作集中。(锁的很死

MDL的MmProbeAndLockPages 是使用异常访问函数,访问页的头部地址。(锁地不严

3.MMPfndatabase
dt _MMPFN 有8种状态,但是使用的只有六种

1.结构

kd> dq MMpfndatabase
fffff800`04106220  fffffa80`00000000 000001f4`00000040
fffff800`04106230  0002ffff`00000250 00000003`00000000
fffff800`04106240  00000000`00000000 00080000`00000001
fffff800`04106250  00000001`ffffffff fffffa80`019e1000
fffff800`04106260  01d714e0`07a4bd3e fffffa80`018f4600
fffff800`04106270  fffffa80`01932830 00000000`00004840
fffff800`04106280  00000000`5c7fe000 fffffa80`018d1c10
fffff800`04106290  00000000`00000001 fffffa80`018eb570
 
kd> !pfn 0
   PFN 00000000 at address FFFFFA8000000000
   flink       00000000  blink / share count 00000000  pteaddress 00000000
   reference count 0000    used entry count  0000      NonCached color 0  
Priority 0
   restore pte 00000000  containing page 000000  Zeroed            
                   
kd> !pfn 1
   PFN 00000001 at address FFFFFA8000000030
   flink       00000000  blink / share count 00000001  pteaddress
FFFFF6FFFFFFE840
   reference count 0001    used entry count  0000      Cached    color 0  
Priority 0
   restore pte 00000000  containing page 0001F2  Active            
                   
kd> dt _MMPFN -v
nt!_MMPFN
struct _MMPFN, 13 elements, 0x30 bytes //数组每项大小0x30字节
  +0x000 u1               : union <unnamed-tag>, 7 elements, 0x8 bytes
  ********
  ********
  +0x028 u4               : union <unnamed-tag>, 6 elements, 0x8 bytes

2.查询

kd> dq MmIsAddressValid
fffff800`03f81c50  90fff871`c9e9d233 90909090`90909090
fffff800`03f81c60  6c894808`245c8948 57182474`89481024
fffff800`03f81c70  57415641`55415441 482a8b4c`20ec8348
fffff800`03f81c80  000000b9`4808428b 348d4c00`00058000
fffff800`03f81c90  8b4d006d`5c8d4b40 e6c14904`e3c148f9
fffff800`03f81ca0  4cd92b48`e08b4d04 ea8b48c9`8b49f12b
fffff800`03f81cb0  85ffff40`99e8ff33 33000000`bf840fc0
fffff800`03f81cc0  f1032aeb`014f8df6 17750018`45fe3585
   
//contains 代表对应的物理页(物理地址)的意思。    
kd> !pte fffff800`03f81c50
                                          VA fffff80003f81c50
PXE at FFFFF6FB7DBEDF80    PPE at FFFFF6FB7DBF0000    PDE at FFFFF6FB7E0000F8  
 PTE at FFFFF6FC0001FC08
contains 0000000000199063  contains 0000000000198063  contains 00000000001E3063
// contains 0000000003F81121
pfn 199       ---DA--KWEV  pfn 198       ---DA--KWEV  pfn 1e3       ---DA--KWEV
 /*pfn 3f81 */     -G--A--KREV

//0000000003F81121 右移12位 3F81 对应上面的pfn 3f81。


kd> !pfn 0
   PFN 00000000 at address FFFFFA8000000000
   
//kd> dt _MMPFN FFFFFA8000000000+3f81*0x30 -r1 计算
nt!_MMPFN
  +0x000 u1               : <unnamed-tag>
     +0x000 Flink           : 0
     +0x000 WsIndex         : 0
     +0x000 Event           : (null)
     +0x000 Next             : (null)
     +0x000 VolatileNext     : (null)
     +0x000 KernelStackOwner : (null)
     +0x000 NextStackPfn     : _SINGLE_LIST_ENTRY
  +0x008 u2               : <unnamed-tag>
     +0x000 Blink           : 1
     +0x000 ImageProtoPte   : 0x00000000`00000001 _MMPTE
     +0x000 ShareCount       : 1//分享次数,目前是独占使用。映射一次,次数就加1。
  +0x010 PteAddress       : 0xfffff6fc`0001fc08 _MMPTE//记录线性地址PTE的位置
     +0x000 u               : <unnamed-tag>
  +0x010 VolatilePteAddress : 0xfffff6fc`0001fc08 Void
  +0x010 Lock             : 0n130056
  +0x010 PteLong         : 0xfffff6fc`0001fc08
  +0x018 u3               : <unnamed-tag>
     +0x000 ReferenceCount   : 1//目前只被一个人引用
     +0x002 e1               : _MMPFNENTRY
     +0x000 e2               : <unnamed-tag>
  +0x01c UsedPageTableEntries : 0
  +0x01e VaType           : 0 ''
  +0x01f ViewCount       : 0 ''
  +0x020 OriginalPte     : _MMPTE
     +0x000 u               : <unnamed-tag>
  +0x020 AweReferenceCount : 0n96
  +0x028 u4               : <unnamed-tag>
     +0x000 PteFrame         :
0y0000000000000000000000000000000000000000000111100011 (0x1e3)//记录PDE的位置
     +0x000 Unused           : 0y000
     +0x000 PfnImageVerified : 0y0
     +0x000 AweAllocation   : 0y0
     +0x000 PrototypePte     : 0y0
     +0x000 PageColor       : 0y000000 (0)

kd> dt _MMPFN FFFFFA8000000000+3f81*0x30 -r2


nt!_MMPFN
  +0x000 u1               : <unnamed-tag>
     +0x000 Flink           : 0
     +0x000 WsIndex         : 0
     +0x000 Event           : (null)
     +0x000 Next             : (null)
     +0x000 VolatileNext     : (null)
     +0x000 KernelStackOwner : (null)
     +0x000 NextStackPfn     : _SINGLE_LIST_ENTRY
        +0x000 Next             : (null)
  +0x008 u2               : <unnamed-tag>
     +0x000 Blink           : 1
     +0x000 ImageProtoPte   : 0x00000000`00000001 _MMPTE
        +0x000 u               : <unnamed-tag>
     +0x000 ShareCount       : 1
  +0x010 PteAddress       : 0xfffff6fc`0001fc08 _MMPTE
     +0x000 u               : <unnamed-tag>
        +0x000 Long             : 0x3f81121
        +0x000 VolatileLong     : 0x3f81121
        +0x000 Hard             : _MMPTE_HARDWARE
        +0x000 Flush           : _HARDWARE_PTE
        +0x000 Proto           : _MMPTE_PROTOTYPE
        +0x000 Soft             : _MMPTE_SOFTWARE
        +0x000 TimeStamp       : _MMPTE_TIMESTAMP
        +0x000 Trans           : _MMPTE_TRANSITION
        +0x000 Subsect         : _MMPTE_SUBSECTION
        +0x000 List             : _MMPTE_LIST
  +0x010 VolatilePteAddress : 0xfffff6fc`0001fc08 Void
  +0x010 Lock             : 0n130056
  +0x010 PteLong         : 0xfffff6fc`0001fc08
  +0x018 u3               : <unnamed-tag>
     +0x000 ReferenceCount   : 1//大于1,就是ACTIVE
     +0x002 e1               : _MMPFNENTRY
        +0x000 PageLocation     :
0y110////////////////////////////MmPageLocationList 六个链表
        +0x000 WriteInProgress : 0y0//换入换出
        +0x000 Modified         : 0y1
        +0x000 ReadInProgress   : 0y0//换入换出
        +0x000 CacheAttribute   : 0y01
        +0x001 Priority         : 0y000
        +0x001 Rom             : 0y0
        +0x001 InPageError     : 0y0
        +0x001 KernelStack     : 0y0
        +0x001 RemovalRequested : 0y0
        +0x001 ParityError     : 0y0
     +0x000 e2               : <unnamed-tag>
        +0x000 ReferenceCount   : 1
        +0x000 VolatileReferenceCount : 0n1
        +0x002 ShortFlags       : 0x56
  +0x01c UsedPageTableEntries : 0
  +0x01e VaType           : 0 ''
  +0x01f ViewCount       : 0 ''
  +0x020 OriginalPte     : _MMPTE
     +0x000 u               : <unnamed-tag>
        +0x000 Long             : 0x60
        +0x000 VolatileLong     : 0x60
        +0x000 Hard             : _MMPTE_HARDWARE
        +0x000 Flush           : _HARDWARE_PTE
        +0x000 Proto           : _MMPTE_PROTOTYPE
        +0x000 Soft             : _MMPTE_SOFTWARE
        +0x000 TimeStamp       : _MMPTE_TIMESTAMP
        +0x000 Trans           : _MMPTE_TRANSITION
        +0x000 Subsect         : _MMPTE_SUBSECTION
        +0x000 List             : _MMPTE_LIST
  +0x020 AweReferenceCount : 0n96
  +0x028 u4               : <unnamed-tag>
     +0x000 PteFrame         :
0y0000000000000000000000000000000000000000000111100011 (0x1e3)
     +0x000 Unused           : 0y000
     +0x000 PfnImageVerified : 0y0
     +0x000 AweAllocation   : 0y0
     +0x000 PrototypePte     : 0y0
     +0x000 PageColor       : 0y000000 (0)
3.MmPageLocationList

/*

dt _MMPFN 有8种状态,但是使用的只有六种

PMMPFNLIST MmPageLocationList[NUMBER_OF_PAGE_LISTS] = {
                                     &MmZeroedPageListHead,
                                     &MmFreePageListHead,
                                     &MmStandbyPageListHead,
                                     &MmModifiedPageListHead,
                                     &MmModifiedNoWritePageListHead,
                                     &MmBadPageListHead,
                                     NULL,//未使用
                                     NULL //未使用};
*/    

MmZeroedPageListHead,
MmFreePageListHead,
MmStandbyPageListHead,
MmModifiedPageListHead,
MmModifiedNoWritePageListHead,
MmBadPageListHead, //MmMarkPhysicalMemoryAsBad(StartAddress,size)

4.Active Page

kd> dt _MMPFN -r1


nt!_MMPFN
  +0x000 u1               : <unnamed-tag>
     +0x000 WsIndex         : Uint4B//页面在工作集的索引
  +0x008 u2               : <unnamed-tag>
     +0x000 ShareCount       : Uint8B//映射次数,大于1则是Mapped内存,1就是私有内存。
大于0就不能从内存中换出。
  +0x010 PteAddress       : Ptr64 _MMPTE//虚拟PTE
     +0x000 u               : <unnamed-tag>
  +0x010 VolatilePteAddress : Ptr64 Void
  +0x010 Lock             : Int4B
  +0x010 PteLong         : Uint8B
  +0x018 u3               : <unnamed-tag>
     +0x000 ReferenceCount   : Uint2B//引用次数,判断是否该回收页面。当ShareCount=0,
ReferenceCount=0,则移动到备用链表,空闲链表。
     +0x002 e1               : _MMPFNENTRY
     +0x000 e2               : <unnamed-tag>
  +0x01c UsedPageTableEntries : Uint2B
  +0x01e VaType           : UChar
  +0x01f ViewCount       : UChar
  +0x020 OriginalPte     : _MMPTE//
     +0x000 u               : <unnamed-tag>
  +0x020 AweReferenceCount : Int4B
  +0x028 u4               : <unnamed-tag>
     +0x000 PteFrame         : Pos 0, 52 Bits
     +0x000 Unused           : Pos 52, 3 Bits
     +0x000 PfnImageVerified : Pos 55, 1 Bit
     +0x000 AweAllocation   : Pos 56, 1 Bit
     +0x000 PrototypePte     : Pos 57, 1 Bit
     +0x000 PageColor       : Pos 58, 6 Bits
5.u3 e1 _MMPFNENTRY

  +0x018 u3               : <unnamed-tag>
     +0x000 ReferenceCount   : 0
     +0x002 e1               : _MMPFNENTRY
        +0x000 PageLocation     : 0y000//当前页面状态的类型。
        +0x000 WriteInProgress : 0y0//读
        +0x000 Modified         : 0y0//页面已修改状态。如果要将页面移除内存,需要换出数
据。
        +0x000 ReadInProgress   : 0y0//写
        +0x000 CacheAttribute   : 0y01
        +0x001 Priority         : 0y000
        +0x001 Rom             : 0y0
        +0x001 InPageError     : 0y0
        +0x001 KernelStack     : 0y0
        +0x001 RemovalRequested : 0y0
        +0x001 ParityError     : 0y0

6.u4

  +0x028 u4               : <unnamed-tag>
     +0x000 PteFrame         :
0y1111111111111111111111111111111111111111111111111101 (0xffffffffffffd)
         //指向该页面的PTE所在页表的页帧编号。
     +0x000 Unused           : 0y000
     +0x000 PfnImageVerified : 0y0
     +0x000 AweAllocation   : 0y0
     +0x000 PrototypePte     : 0y0
     +0x000 PageColor       : 0y000000 (0)

7.MmZeroedPageListHead

kd> dt _MMPFN -r1


nt!_MMPFN
  +0x000 u1               : <unnamed-tag>
     +0x000 Flink           : Uint8B//下一个
  +0x008 u2               : <unnamed-tag>
     +0x000 Blink           : Uint8B//后一个
  +0x010 PteAddress       : Ptr64 _MMPTE//虚拟PTE地址
     +0x000 u               : <unnamed-tag>
  +0x010 VolatilePteAddress : Ptr64 Void
  +0x010 Lock             : Int4B
  +0x010 PteLong         : Uint8B
  +0x018 u3               : <unnamed-tag>
     +0x000 ReferenceCount   : Uint2B
     +0x002 e1               : _MMPFNENTRY
         //+0x000 PageLocation     : 0y000 为0
     +0x000 e2               : <unnamed-tag>
  +0x01c UsedPageTableEntries : Uint2B
  +0x01e VaType           : UChar
  +0x01f ViewCount       : UChar
  +0x020 OriginalPte     : _MMPTE//
     +0x000 u               : <unnamed-tag>
  +0x020 AweReferenceCount : Int4B
  +0x028 u4               : <unnamed-tag>
     +0x000 PteFrame         : Pos 0, 52 Bits
     +0x000 Unused           : Pos 52, 3 Bits
     +0x000 PfnImageVerified : Pos 55, 1 Bit
     +0x000 AweAllocation   : Pos 56, 1 Bit
     +0x000 PrototypePte     : Pos 57, 1 Bit
     +0x000 PageColor       : Pos 58, 6 Bits

kd>// dq MmZeroedPageListHead
fffff800`04108400  00000000`00058599 00000000`00000000
fffff800`04108410  ffffffff`ffffffff ffffffff`ffffffff
fffff800`04108420  00000000`00000000 00000000`00000000
fffff800`04108430  00000000`00000000 00000000`00000000
fffff800`04108440  00000000`00000000 00000000`00000000
fffff800`04108450  00000000`00000000 00000000`00000000
fffff800`04108460  00000000`00000000 00000000`00000000
fffff800`04108470  00000000`00000000 00000000`00000000
kd>// dq MMPFNDATABASE
fffff800`04106220  fffffa80`00000000 000001f4`00000040
fffff800`04106230  0002ffff`00000250 00000003`00000000
fffff800`04106240  00000000`00000000 00080000`00000001
fffff800`04106250  00000001`ffffffff fffffa80`019e1000
fffff800`04106260  01d714e0`07a4bd3e fffffa80`018f4600
fffff800`04106270  fffffa80`01932830 00000000`00004840
fffff800`04106280  00000000`5c7fe000 fffffa80`018d1c10
fffff800`04106290  00000000`00000001 fffffa80`018eb570
kd>// dt _MMPFN fffffa80`00000000+58599*0x30 -r1
nt!_MMPFN
  +0x000 u1               : <unnamed-tag>
  //   +0x000 Flink           : 0x58559
     +0x000 WsIndex         : 0x58559
     +0x000 Event           : 0x00000000`00058559 _KEVENT
     +0x000 Next             : 0x00000000`00058559 Void
     +0x000 VolatileNext     : 0x00000000`00058559 Void
     +0x000 KernelStackOwner : 0x00000000`00058559 _KTHREAD
     +0x000 NextStackPfn     : _SINGLE_LIST_ENTRY
  +0x008 u2               : <unnamed-tag>
   // +0x000 Blink           : 0x585d9
     +0x000 ImageProtoPte   : 0x00000000`000585d9 _MMPTE
     +0x000 ShareCount       : 0x585d9
  +0x010 PteAddress       : 0xfffff680`00000002 _MMPTE
     +0x000 u               : <unnamed-tag>
  +0x010 VolatilePteAddress : 0xfffff680`00000002 Void
  +0x010 Lock             : 0n2
  +0x010 PteLong         : 0xfffff680`00000002
  +0x018 u3               : <unnamed-tag>
     +0x000 ReferenceCount   : 0
     +0x002 e1               : _MMPFNENTRY
     +0x000 e2               : <unnamed-tag>
  +0x01c UsedPageTableEntries : 0
  +0x01e VaType           : 0 ''
  +0x01f ViewCount       : 0 ''
  +0x020 OriginalPte     : _MMPTE
     +0x000 u               : <unnamed-tag>
  +0x020 AweReferenceCount : 0n128
  +0x028 u4               : <unnamed-tag>
     +0x000 PteFrame         :
0y1111111111111111111111111111111111111111111111111101 (0xffffffffffffd)
     +0x000 Unused           : 0y000
     +0x000 PfnImageVerified : 0y0
     +0x000 AweAllocation   : 0y0
     +0x000 PrototypePte     : 0y0
     +0x000 PageColor       : 0y000000 (0)

8.MmFreePageListHead

9.MmStandbyPageListHead

10.MmBadPageListHead

2.VAD解析
申请的非分页内存,无需初始化,就挂上了物理页。

申请的分页内存,需要立即初始化挂上物理页,否则PTE无效,需要错误处理例程修复(异常)。

硬件PTE:有效,直接指向物理内存。

原型PTE:无效,可能换出,可能需要请求

typedef struct _MMPTE_PROTOTYPE {


   ULONG Valid : 1;
   ULONG ProtoAddressLow : 7;
   ULONG ReadOnly : 1;  // if set allow read only access.
   ULONG WhichPool : 1;
   ULONG Prototype : 1;
   ULONG ProtoAddressHigh : 21;
} MMPTE_PROTOTYPE;

typedef struct _MMPTE {


   union {
       ULONG Long;
       HARDWARE_PTE Flush;
       MMPTE_HARDWARE Hard;
       MMPTE_PROTOTYPE Proto;
       MMPTE_SOFTWARE Soft;
       MMPTE_TRANSITION Trans;
       MMPTE_SUBSECTION Subsect;
       MMPTE_LIST List;
      } u;
} MMPTE;
1.PTE标志位。

U位:当前核心的物理页,被别的核心访问,置1。

2.无效PTE
1.页面文件

PFN* 代表物理页换出到磁盘中的磁盘编号。从0开始。

换入时,CreateFileMapping映射的文件句柄,加上 页面文件偏移,就是换出的数据的地址。

判断流程,先判断P位有效位,再判断10 11位。

页面文件 取决于 NtCreateSection 有没有填入文件句柄。


2.要求零页面

私有内存:

映射内存:

3.页面正在转移

不能判断换入还是换出

4.原型PTE

当PTE的P位=0时,如果是共享内存,则查询Section->ProtoPte。
2.拿物理页小技巧

BOOL AllocateUserPhysicalPages(
 HANDLE     hProcess,
 PULONG_PTR NumberOfPages,
 PULONG_PTR PageArray
);

NTSTATUS
NtAllocateUserPhysicalPages(
   __in HANDLE ProcessHandle,
   __inout PULONG_PTR NumberOfPages,
   __out_ecount(*NumberOfPages) PULONG_PTR UserPfnArray
  )
   
//这样拿到的物理页,可以挂内核和用户地址,不在VAD内,但是不可执行。

3.VAD
VAD:一般用于管理用户地址,内核地址不用VAD。

4.修改Start和End

//上个VAD的end 修改成下个VAD的end
87e3a378  7      8b10      8b11      2 Private      READWRITE          
87e3af68  8      8b20      8b21      2 Private      READWRITE
//修改后
87e3a378  7      8b10      /*8b21*/  2 Private      READWRITE          
87e3af68  8      8b20      8b21      2 Private      READWRITE
   
//效果就是R3.API遍历内存,遍历不到    

3.VAD映射
私有内存是short类型 映射内存是long类型

win7以后 :dt _MMVAD_short

win7以后:dt _MMVAD_long

StatringVpn EndingVpn算法
ZwQueryMemory就是遍历VAD。

1.实验

int main()
{
system("pause");
PVOID mem=VirtualAlloc(0,0x1,MEM_RESERVE,PAGE_NOACCESS);
printf("地址:%x\n", mem);
system("pause");
mem=VirtualAlloc(0, 0x1,MEM_COMMIT,PAGE_NOACCESS);
printf("地址:%x\n", mem);
system("pause");
return 0;
}

//未申请前
1: kd> !vad 8665a3a8+0x278
VAD   Level     Start       End Commit
8665a620  0         0         0   4613 Mapped       NO_ACCESS          Pagefile
section, shared commit 0
86ad7380  5        10        1f      0 Mapped       READWRITE          Pagefile
section, shared commit 0x10
880a7718  4        20        2f      0 Mapped       READWRITE          Pagefile
section, shared commit 0x10
86662178  5        30        33      0 Mapped       READONLY           Pagefile
section, shared commit 0x4
883c18a8  3        40        40      0 Mapped       READONLY           Pagefile
section, shared commit 0x1
88241268  4        50        50      1 Private      READWRITE          
87f8e510  5        60        c6      0 Mapped       READONLY          
\Windows\System32\locale.nls
8667d838  2        d0       1fd     84 Mapped  Exe  EXECUTE_WRITECOPY
 \Users\TalShang\Desktop\38.VAD映射.exe
87f77b28  4       2d0       3cf      4 Private      READWRITE          
86470918  3       430       52f     30 Private      READWRITE          
86675588  5     75950     7599b      4 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\apphelp.dll
866471b8  4     75d00     75d49      3 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\KernelBase.dll
883905f0  5     77110     771e3      2 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\kernel32.dll
866576e0  1     77900     77a3b      9 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\ntdll.dll
8826a090  3     77b40     77b40      0 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\apisetschema.dll
882a5510  4     7f6f0     7f7ef      0 Mapped       READONLY           Pagefile
section, shared commit 0x5
86f3c860  2     7ffa0     7ffd2      0 Mapped       READONLY           Pagefile
section, shared commit 0x33
86597d60  3     7ffd6     7ffd6      1 Private      READWRITE          
86675538  4     7ffdf     7ffdf      1 Private      READWRITE          

Total VADs: 19, average level: 4, maximum depth: 5


Total private commit: 0x1290 pages (19008 KB)
Total shared commit:  0x5d pages (372 KB)
//第一次申请后
0: kd> !vad 8665a3a8+0x278
VAD   Level(结点的层级)     Start       End   Commit(是否提交过物理页)
8665a620  0         0         0   4869 Mapped       NO_ACCESS          Pagefile
section, shared commit 0
86ad7380  5        10        1f      0 Mapped       READWRITE          Pagefile
section, shared commit 0x10
880a7718  4        20        2f      0 Mapped       READWRITE          Pagefile
section, shared commit 0x10
86662178  5        30        33      0 Mapped       READONLY           Pagefile
section, shared commit 0x4
883c18a8  3        40        40      0 Mapped       READONLY           Pagefile
section, shared commit 0x1
88241268  4        50        50      1 Private      READWRITE          
87f8e510  5        60        c6      0 Mapped       READONLY          
\Windows\System32\locale.nls
8667d838  2        d0       1fd     84 Mapped  Exe  EXECUTE_WRITECOPY
 \Users\TalShang\Desktop\38.VAD映射.exe
//8830ae18 5       200       200     0 Private     NO_ACCESS        
//在这里申请到内存
//Start代表起始地址,大小为一个物理页0x1000,这里Start的真正地址为0x200*0x1000=0x200000,
结束地址同理:0x200000    
87f77b28  4       2d0       3cf      4 Private      READWRITE          
86470918  3       430       52f     32 Private      READWRITE          
86675588  5     75950     7599b      4 Mapped  Exe(EXE代表是PE文件)
 EXECUTE_WRITECOPY  \Windows\System32\apphelp.dll
866471b8  4     75d00     75d49      3 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\KernelBase.dll
883905f0  5     77110     771e3      2 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\kernel32.dll
866576e0  1     77900     77a3b      9 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\ntdll.dll
8826a090  3     77b40     77b40      0 Mapped  Exe  EXECUTE_WRITECOPY
 \Windows\System32\apisetschema.dll
882a5510  4     7f6f0     7f7ef      0 Mapped       READONLY           Pagefile
section, shared commit 0x5
86f3c860  2     7ffa0     7ffd2      0 Mapped       READONLY           Pagefile
section, shared commit 0x33
86597d60  3     7ffd6     7ffd6      1 Private      READWRITE          
86675538  4     7ffdf     7ffdf      1 Private      READWRITE          

Total VADs: 20, average level: 4, maximum depth: 5


Total private commit: 0x1392 pages (20040 KB)
Total shared commit:  0x5d pages (372 KB)

0: kd> dt _MMVAD 8830ae18


nt!_MMVAD
  +0x000 u1               : <unnamed-tag>
  +0x004 LeftChild       : (null)
  +0x008 RightChild       : (null)
  +0x00c StartingVpn     : 0x200
  +0x010 EndingVpn       : 0x200
  +0x014 u               : <unnamed-tag>
  +0x018 PushLock         : _EX_PUSH_LOCK
  +0x01c u5               : <unnamed-tag>
  +0x020 u2               : <unnamed-tag>
  //Private用__MMVAD结构,显示的是错误的。在WIN7里,Private应该用_MMVAD_SHORT,Mapped
用_MMVAD    
  +0x024 Subsection       : 0x7866744e _SUBSECTION
  +0x024 MappedSubsection : 0x7866744e _MSUBSECTION
  +0x028 FirstPrototypePte : 0x00840745 _MMPTE
  +0x02c LastContiguousPte : 0x00000001 _MMPTE
  +0x030 ViewLinks       : _LIST_ENTRY [ 0x0 - 0x0 ]
  +0x038 VadsProcess     : 0x00040001 _EPROCESS
//_MMVAD_SHORT      
0: kd> dt _MMVAD_SHORT 8830ae18
nt!_MMVAD_SHORT
  +0x000 u1               : <unnamed-tag> //父节点
  +0x004 LeftChild       : (null)
  +0x008 RightChild       : (null)
  +0x00c StartingVpn     : 0x200
  +0x010 EndingVpn       : 0x200
  +0x014 u               : <unnamed-tag>//_VAD_FLAGS
  +0x018 PushLock         : _EX_PUSH_LOCK
  +0x01c u5               : <unnamed-tag>
0: kd> dt _MMVAD_SHORT 8830ae18 -r1
nt!_MMVAD_SHORT
  +0x000 u1               : <unnamed-tag>
     +0x000 Balance         : 0y00
     +0x000 Parent           : 0x87f77b28 _MMVAD//父结点
  +0x004 LeftChild       : (null)
  +0x008 RightChild       : (null)
  +0x00c StartingVpn     : 0x200
  +0x010 EndingVpn       : 0x200
  +0x014 u               : <unnamed-tag>
     +0x000 LongFlags       : 0x98000000
     +0x000 VadFlags         : _MMVAD_FLAGS
  +0x018 PushLock         : _EX_PUSH_LOCK
     +0x000 Locked           : 0y0
     +0x000 Waiting         : 0y0
     +0x000 Waking           : 0y0
     +0x000 MultipleShared   : 0y0
     +0x000 Shared           : 0y0000000000000000000000000000 (0)
     +0x000 Value           : 0
     +0x000 Ptr             : (null)
  +0x01c u5               : <unnamed-tag>
     +0x000 LongFlags3       : 0
     +0x000 VadFlags3       : _MMVAD_FLAGS3
//_MMVAD_FLAGS        
0: kd> dt _MMVAD_FLAGS 8830ae18+0x014
nt!_MMVAD_FLAGS
  +0x000 CommitCharge     : 0y0000000000000000000 (0) //提交物理页的数量
  +0x000 NoChange         : 0y0 //是否允许改变线性地址的属性,这是一把锁
  +0x000 VadType         : 0y000//VAD类型,来确定线性地址是否为EXE。
  +0x000 MemCommit       : 0y0//是否挂上了物理页
  +0x000 Protection       : 0y11000 (0x18)//线性地址的属性,0x18代表NO_ACCESS,这只是
创建时候的属性,ProtectVirtualMemory后这里不变。
  +0x000 Spare           : 0y00
  +0x000 PrivateMemory   : 0y1//是否私有内存
//Protection
#define PAGE_NOACCESS           0x01
NtProtectVirtualMemory(
   __in HANDLE ProcessHandle,
   __inout PVOID *BaseAddress,
   __inout PSIZE_T RegionSize,
   __in WIN32_PROTECTION_MASK NewProtectWin32,
   __out PULONG OldProtect
  )
{
// ProtectionMask = MiMakeProtectionMask (NewProtectWin32); //NewProtectWin32是
线性地址的属性。
}
MiMakeProtectionMask (
   IN WIN32_PROTECTION_MASK Win32Protect
  )
{
   Field1 = Win32Protect & 0xF;//取后四位
   Field2 = (Win32Protect >> 4) & 0xF;//取前四位
      if (Field1 == 0) {
       if (Field2 == 0) {

           //
           // Both fields are zero, return failure.
           //

           return MM_INVALID_PROTECTION;
      }
       ProtectCode = MmUserProtectionToMask2[Field2];
  }
   else {
       if (Field2 != 0) {
           //
           // Both fields are non-zero, return failure.
           //

           return MM_INVALID_PROTECTION;
      }
       ProtectCode = MmUserProtectionToMask1[Field1];
}
CCHAR MmUserProtectionToMask1[16] = {
                                0,
                                MM_NOACCESS,//这个是0x18
                                MM_READONLY,
                                -1,
                                MM_READWRITE,
                                -1,
                                -1,
                                -1,
                                MM_WRITECOPY,
                                -1,
                                -1,
                                -1,
                                -1,
                                -1,
                                -1,
                                -1 };
CCHAR MmUserProtectionToMask2[16] = {
                                0,
                                MM_EXECUTE,
                                MM_EXECUTE_READ,
                                -1,
                                MM_EXECUTE_READWRITE,
                                -1,
                                -1,
                                -1,
                                MM_EXECUTE_WRITECOPY,
                                -1,
                                -1,
                                -1,
                                -1,
                                -1,
                                -1,
                                -1 };
#define MM_ZERO_ACCESS         0  // this value is not used.
#define MM_READONLY           1
#define MM_EXECUTE             2
#define MM_EXECUTE_READ       3
#define MM_READWRITE           4  // bit 2 is set if this is writable.
#define MM_WRITECOPY           5
#define MM_EXECUTE_READWRITE   6
#define MM_EXECUTE_WRITECOPY   7

#define MM_NOCACHE           0x8


#define MM_GUARD_PAGE         0x10
#define MM_DECOMMIT           0x10   // NO_ACCESS, Guard page
//#define MM_NOACCESS           0x18   // NO_ACCESS, Guard_page, nocache.
#define MM_UNKNOWN_PROTECTION 0x100  // bigger than 5 bits!

#define MM_INVALID_PROTECTION ((ULONG)-1)  // bigger than 5 bits!

#define MM_PROTECTION_WRITE_MASK     4
#define MM_PROTECTION_COPY_MASK     1
#define MM_PROTECTION_OPERATION_MASK 7 // mask off guard page and nocache.
#define MM_PROTECTION_EXECUTE_MASK   2  

//第二次申请
8830ae18  5       200       200      0 Private      NO_ACCESS          
87e88138  4       210       210      1 Private      NO_ACCESS

typedef enum _MI_VAD_TYPE {


   VadNone,
   VadDevicePhysicalMemory,//R0映射到R3
   VadImageMap,//EXE
   VadAwe,
   VadWriteWatch,
   VadLargePages,//大页
   VadRotatePhysical,//R0映射到R3
   VadLargePageSection
} MI_VAD_TYPE, *PMI_VAD_TYPE;
2.强写

1.当页是大页的时候,会查询VAD.__MMVAD_FLAGS.Protection
2.当页是小页的时候,会查询_MMPFN的原型PTE。
//在执行的时候,发现当前PTE的属性和原型PTE不一样,就会把PTE改成原型PTE的属性,原理是发生异常,
走OE号异常中断。
锁住硬件PTE,可以让CE的Protection显示为NO_ACCESS
     
//CE
 CE的Protection不会显示PTE的属性。  

1.修改PTE
1.修改系统DLL地址PTE

总结:修改后没有作用,属性会被还原。

//系统DLL的地址:7ffdd000

0: kd> .process /i 866d4430

0: kd> !pte 7ffdd000


                   VA 7ffdd000
PDE at C0601FF8            PTE at C03FFEE8
contains 0000000038DEC867  contains 8000000037392867
pfn 38dec     ---DA--UWEV  pfn 37392     ---DA--UW-V

//0: kd> eq C03FFEE8 8000000037392865

//修改成功    
0: kd> !pte 7ffdd000
                   VA 7ffdd000
PDE at C0601FF8            PTE at C03FFEE8
contains 0000000038DEC867  contains 8000000037392865
pfn 38dec     ---DA--UWEV  pfn 37392     ---DA--UR-V
   
1: kd> !pte 7ffdd000
                   VA 7ffdd000
PDE at C0601FF8            PTE at C03FFEE8
contains 0000000007781867  contains 0000000000000000
pfn 7781      ---DA--UWEV  not valid

1: kd> .process /i 866d4430

//又被改回去了    
1: kd> !pte 7ffdd000
                   VA 7ffdd000
PDE at C0601FF8            PTE at C03FFEE8
contains 0000000038DEC867  contains 8000000037392867
pfn 38dec     ---DA--UWEV  pfn 37392     ---DA--UW-V
2.修改普通地址PTE

总结:修改也无效。

2.修改PFN项(私有内存

0: kd> .process /i 86b37510

0: kd> !pte 7ffdf000


                   VA 7ffdf000
PDE at C0601FF8            PTE at C03FFEF8
contains 000000003C171867  contains 800000002FFC2867
pfn 3c171     ---DA--UWEV  pfn 2ffc2     ---DA--UW-V

0: kd> dd MMPFNDATABASE
83f7c700  84e00000 00000000 00000001 0003ffff
83f7c710  0003ff7e 7ffeffff 80000000 7fff0000
83f7c720  80741000 000bffff c03fff78 c0601ff8
83f7c730  00000000 00000001 00000002 00000001
83f7c740  00000000 00000002 00000000 00000001
83f7c750  00000002 00000001 00000000 00000002
83f7c760  00000000 00000000 00000000 80000000
83f7c770  00000000 00000000 00000000 00000000
//MMPFN  
0: kd> dt _MMPFN 84e00000+2ffc2*1c
nt!_MMPFN
  +0x000 u1               : <unnamed-tag>
  +0x004 u2               : <unnamed-tag>
  +0x008 PteAddress       : 0xc03ffef8 _MMPTE
  +0x008 VolatilePteAddress : 0xc03ffef8 Void
  +0x008 Lock             : 0n-1069547784
  +0x008 PteLong         : 0xc03ffef8
  +0x00c u3               : <unnamed-tag>
// +0x010 OriginalPte     : _MMPTE
  +0x010 AweReferenceCount : 0n128
  +0x018 u4               : <unnamed-tag>
//OriginalPte
0: kd> dt _MMPTE 84e00000+2ffc2*1c+0x10 -r1
nt!_MMPTE
  +0x000 u               : <unnamed-tag>
     +0x000 Long             : 0x80
     +0x000 VolatileLong     : 0x80
     +0x000 HighLow         : _MMPTE_HIGHLOW
     +0x000 Flush           : _HARDWARE_PTE
     +0x000 Hard             : _MMPTE_HARDWARE
     +0x000 Proto           : _MMPTE_PROTOTYPE
//   +0x000 Soft             : _MMPTE_SOFTWARE
     +0x000 TimeStamp       : _MMPTE_TIMESTAMP
     +0x000 Trans           : _MMPTE_TRANSITION
     +0x000 Subsect         : _MMPTE_SUBSECTION
     +0x000 List             : _MMPTE_LIST
//Soft
0: kd> dt _MMPTE_SOFTWARE 84e00000+2ffc2*1c+0x10 -r1
nt!_MMPTE_SOFTWARE
  +0x000 Valid           : 0y0
  +0x000 PageFileLow     : 0y0000
 // +0x000 Protection       : 0y00100 (0x4) 0x4代表可读可写,0110(6)=011000000=C0
  +0x000 Prototype       : 0y0
  +0x000 Transition       : 0y0
  +0x000 InStore         : 0y0
  +0x000 Unused1         : 0y0000000000000000000 (0)
  +0x000 PageFileHigh     : 0y00000000000000000000000000000000 (0)
               
#define MM_READWRITE           4  // bit 2 is set if this is writable.
#define MM_WRITECOPY           5
#define MM_EXECUTE_READWRITE   6

0: kd> ed 84e00000+2ffc2*1c+0x10 C0
0: kd> dt _MMPTE_SOFTWARE 84e00000+2ffc2*1c+0x10 -r1
nt!_MMPTE_SOFTWARE
  +0x000 Valid           : 0y0
  +0x000 PageFileLow     : 0y0000
  +0x000 Protection       : 0y00110 (0x6)
  +0x000 Prototype       : 0y0
  +0x000 Transition       : 0y0
  +0x000 InStore         : 0y0
  +0x000 Unused1         : 0y0000000000000000000 (0)
  +0x000 PageFileHigh     : 0y00000000000000000000000000000000 (0)
     
3.MiLocateAddres
X64和x86不一样

1.IDAF5分析

ntdll!_MM_AVL_TABLE
  +0x000 BalancedRoot     : _MMADDRESS_NODE
  +0x014 DepthOfTree     : Pos 0, 5 Bits
  +0x014 Unused           : Pos 5, 3 Bits
  +0x014 NumberGenericTableElements : Pos 8, 24 Bits//元素个数
  +0x018 NodeHint         : Ptr32 Void //某个热点结点
  +0x01c NodeFreeHint     : Ptr32 Void
     
1: kd> dt _MMADDRESS_NODE
ntdll!_MMADDRESS_NODE
  +0x000 u1               : <unnamed-tag>
  +0x004 LeftChild       : Ptr32 _MMADDRESS_NODE
  +0x008 RightChild       : Ptr32 _MMADDRESS_NODE
  +0x00c StartingVpn     : Uint4B
  +0x010 EndingVpn       : Uint4B

_MMVAD *__fastcall MiLocateAddress(unsigned int VirtualAddress)


{
 _EPROCESS *eprocess; // esi
 _MMVAD *nodeHint; // eax
 _MM_AVL_TABLE *vadroot; // esi
 unsigned int v4; // ecx
 _MMVAD *nodehint_copy; // [esp+4h] [ebp-4h] BYREF
 eprocess = KeGetCurrentThread()->ApcState.Process;
 nodeHint = eprocess->VadRoot.NodeHint;
 vadroot = &eprocess->VadRoot;
 nodehint_copy = nodeHint;
 if ( !nodeHint )                              // NodeHint是缓存某个结点 _MMVAD
   return 0;
 v4 = VirtualAddress >> 12;
 if ( v4 < nodeHint->StartingVpn || v4 > nodeHint->EndingVpn )// 算法
{
   if ( MiFindNodeOrParent(vadroot, v4, &nodehint_copy) != 1 )
     return 0;
   nodeHint = nodehint_copy;
   vadroot->NodeHint = nodehint_copy;
}
 return nodeHint;
}

int __userpurge MiFindNodeOrParent@<eax>(_MM_AVL_TABLE *vadroot@<eax>, unsigned


int Vpn@<edx>, _MMVAD **node)
{
 int result; // eax
 _MMVAD *i; // ecx
 _MMVAD *v5; // eax
 int v6; // [esp-4h] [ebp-4h]

 if ( (*(vadroot + 5) & 0xFFFFFF00) == 0 )     // NumberGenericTableElements


   return 0;
 for ( i = vadroot->BalancedRoot.RightChild; ; i = v5 )
{
   if ( Vpn < i->StartingVpn )
  {
     v5 = i->LeftChild;
     if ( !v5 )
    {
       v6 = 2;
LABEL_7:
       result = v6;
       goto LABEL_8;
    }
     continue;
  }
   if ( Vpn <= i->EndingVpn )
     break;
   v5 = i->RightChild;
   if ( !v5 )
  {
     v6 = 3;
     goto LABEL_7;
  }
}
2.手写VAD遍历

int MiFindNodeOrParent(MM_AVL_TABLE* vadroot, ULONG Vpn, _MMVAD** Node)


{
   if (vadroot->NumberGenericTableElements == 0) return 0;

   _MMADDRESS_NODE* i=NULL;
   _MMVAD* v5=NULL;
   int result = 0;
   int v6 = 0;
   for (i = vadroot->BalancedRoot.RightChild;; i = (_MMADDRESS_NODE*)v5)
  {
       if (Vpn < i->StartingVpn)
      {
           v5 = (_MMVAD*)i->LeftChild;
           if (!v5)
          {
LABEL_7:
               v6 = 2;
               result = v6;
               goto LABEL_8;
          }
           continue;
      }
       if (Vpn <= i->EndingVpn)
      {
           break;
      }
       v5 = (_MMVAD*)i->RightChild;
       if (!v5)
      {
           v6 = 3;
           goto LABEL_7;
      }
  }
   result = 1;
LABEL_8:
   *Node = (_MMVAD*)i;
   return result;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)


{
pDriver->DriverUnload = DRIVERUNLOAD;
DbgBreakPoint();

HANDLE pid = (HANDLE)3788;


PEPROCESS ep = 0;
PsLookupProcessByProcessId(pid, &ep);
if (!ep) return 0;

KAPC_STATE apc = { 0 };
KeStackAttachProcess(ep,&apc);

MM_AVL_TABLE* vadroot = (MM_AVL_TABLE*)((ULONG)ep + 0x278);


ULONG Vpn = 0x77280;
_MMVAD* node = 0;
MiFindNodeOrParent(vadroot,Vpn,&node);

KeUnstackDetachProcess(&apc);

return STATUS_SUCCESS;
}

3.驱动锁页

注意:只针对私有内存;

注意:只是在页面无效或发生页面异常,对PTE进行修复。

BOOLEAN LockPTE(HANDLE pid,ULONG VirtualAddress)


{
PEPROCESS ep = 0;
PsLookupProcessByProcessId(pid, &ep);
if (!ep) return FALSE;
KAPC_STATE apc = { 0 };
KeStackAttachProcess(ep, &apc);

if (!MmIsAddressValid((PVOID)VirtualAddress))
{
KeUnstackDetachProcess(&apc);
return FALSE;
}

ULONG MMPFNdatabase = (ULONG32)MmUnlockPages;


ULONG offest = 0;
for (int i = 0; i <= 200; i++)
{
if( (*(ULONG*)(MMPFNdatabase + i)) == 0x031CC06B )
{
if( (*(char*)(MMPFNdatabase+i+4)) == 0x05 )
{
offest = i+5;
break;
}

}
}
if (!offest)
{
KeUnstackDetachProcess(&apc);
return FALSE;
}
MMPFNdatabase = *(ULONG*)(*(ULONG*)(MMPFNdatabase + offest));

ULONG sizeMMPFN = 0x1c;


ULONG offestPFN = 0;

ULONG64 PDPTE = VirtualAddress >> 30;


ULONG64 PDE = (VirtualAddress>>21) & 0x1FF;
ULONG64 PTE = (VirtualAddress >> 12) & 0x1FF;
ULONG64 CR3 = *(ULONG*)((ULONG)ep + 0x018);

PHYSICAL_ADDRESS phy;
phy.QuadPart = CR3;
PVOID mem=MmMapIoSpace(phy,0x1000,MmCached);
PDPTE=*(ULONG64*)((ULONG64)mem + PDPTE * 8);
MmUnmapIoSpace(mem,0x1000);
PDPTE = PDPTE & ~0xFFF;

phy.QuadPart = PDPTE;
mem = MmMapIoSpace(phy, 0x1000, MmCached);
PDE = *(ULONG64*)((ULONG64)mem + PDE * 8);
MmUnmapIoSpace(mem, 0x1000);
PDE = PDE & ~0xFFF;

phy.QuadPart = PDE;
mem = MmMapIoSpace(phy, 0x1000, MmCached);
PTE = *(ULONG64*)((ULONG64)mem + PTE * 8);
MmUnmapIoSpace(mem, 0x1000);
PTE = PTE & ~0xFFF;

offestPFN = (ULONG32)PTE >> 12;


_MMPFN* ptePFN = (_MMPFN*)(MMPFNdatabase + offestPFN * sizeMMPFN);
ptePFN->OriginalPte.Protection = 0x1;//只读

KeUnstackDetachProcess(&apc);
return TRUE;
}

3.VAD映射2
1.共享内存

87e31090  7     76e40     76f13      2 Mapped  Exe  EXECUTE_WRITECOPY


 \Windows\System32\kernel32.dll

0: kd> dt _MMVAD 87e31090


nt!_MMVAD
  +0x000 u1               : <unnamed-tag>
  +0x004 LeftChild       : (null)
  +0x008 RightChild       : (null)
  +0x00c StartingVpn     : 0x76e40
  +0x010 EndingVpn       : 0x76f13
  +0x014 u               : <unnamed-tag>
  +0x018 PushLock         : _EX_PUSH_LOCK
  +0x01c u5               : <unnamed-tag>
  +0x020 u2               : <unnamed-tag>
  +0x024 Subsection       : 0x86fe7e98 _SUBSECTION//
  +0x024 MappedSubsection : 0x86fe7e98 _MSUBSECTION//更应该关注这个
  +0x028 FirstPrototypePte : 0x92b64928 _MMPTE
  +0x02c LastContiguousPte : 0xfffffffc _MMPTE
  +0x030 ViewLinks       : _LIST_ENTRY [ 0x87db4cc0 - 0x87dbbf48 ]
  +0x038 VadsProcess     : 0x87e37031 _EPROCESS //多了一个1。????
     
0: kd> dt _SUBSECTION 0x86fe7e98
nt!_SUBSECTION
  +0x000 ControlArea     : 0x86fe7e48 _CONTROL_AREA//与上个SUBSECTION的区段一致。
  +0x004 SubsectionBase   : 0x92b64928 _MMPTE//存放PTE的线性地址
  +0x008 NextSubsection   : 0x86fe7eb8 _SUBSECTION
  +0x00c PtesInSubsection : 1
  +0x010 UnusedPtes       : 0
  +0x010 GlobalPerSessionHead : (null)
  +0x014 u               : <unnamed-tag>
  +0x018 StartingSector   : 0
  +0x01c NumberOfFullSectors : 4//结点数量

0: kd> dt _SUBSECTION 0x86fe7eb8


nt!_SUBSECTION
  +0x000 ControlArea     : 0x86fe7e48 _CONTROL_AREA //与上个SUBSECTION的区段一致。
  +0x004 SubsectionBase   : 0x92b64930 _MMPTE
  +0x008 NextSubsection   : 0x86fe7ed8 _SUBSECTION
  +0x00c PtesInSubsection : 0xc5
  +0x010 UnusedPtes       : 0
  +0x010 GlobalPerSessionHead : (null)
  +0x014 u               : <unnamed-tag>
  +0x018 StartingSector   : 4
  +0x01c NumberOfFullSectors : 0x624

0: kd> dt _CONTROL_AREA 0x86fe7e48


nt!_CONTROL_AREA
  +0x000 Segment         : 0x92b648f8 _SEGMENT//指向_SUBSECTION
  +0x004 DereferenceList : _LIST_ENTRY [ 0x0 - 0x0 ]
  +0x00c NumberOfSectionReferences : 1
  +0x010 NumberOfPfnReferences : 0xc1
  +0x014 NumberOfMappedViews : 0x21
  +0x018 NumberOfUserReferences : 0x22
  +0x01c u               : <unnamed-tag>
  +0x020 FlushInProgressCount : 0
  +0x024 FilePointer     : _EX_FAST_REF//文件指针,去掉末尾的一位数字,就是文件对象。
  +0x028 ControlAreaLock : 0n0
  +0x02c ModifiedWriteCount : 0
  +0x02c StartingFrame   : 0
  +0x030 WaitingForDeletion : (null)
  +0x034 u2               : <unnamed-tag>
  +0x040 LockedPages     : 0n1//锁定在内存中,不被换出
  +0x048 ViewList         : _LIST_ENTRY [ 0x87d95b98 - 0x86ed9d40 ]

0: kd> dt _FILE_OBJECT 87987440


ntdll!_FILE_OBJECT
  +0x030 FileName         : _UNICODE_STRING
"\Windows\winsxs\x86_microsoft.windows.common-
controls_6595b64144ccf1df_6.0.7601.17514_none_41e6975e2bd6f2b2\comctl32.dll"
     
//指向_SUBSECTION      
0: kd> dt _SEGMENT 0x92b648f8
nt!_SEGMENT
  +0x000 ControlArea     : 0x86fe7e48 _CONTROL_AREA
  +0x004 TotalNumberOfPtes : 0xd4
  +0x008 SegmentFlags     : _SEGMENT_FLAGS
  +0x00c NumberOfCommittedPages : 0
  +0x010 SizeOfSegment   : 0xd4000
  +0x018 ExtendInfo       : 0x76e40000 _MMEXTEND_INFO
  +0x018 BasedAddress     : 0x76e40000 Void //ImageBase
  +0x01c SegmentLock     : _EX_PUSH_LOCK
  +0x020 u1               : <unnamed-tag>
  +0x024 u2               : <unnamed-tag>
  +0x028 PrototypePte     : 0x92b64928 _MMPTE
  +0x030 ThePtes         : [1] _MMPTE

//MappedSubsection _MSUBSECTION,一段一段地管理内存段
0: kd> dt _MSUBSECTION 0x87986058
nt!_MSUBSECTION
  +0x000 ControlArea     : 0x87986008 _CONTROL_AREA
  +0x004 SubsectionBase   : 0x8b27f038 _MMPTE
  +0x008 NextSubsection   : 0x87986078 _SUBSECTION
  +0x008 NextMappedSubsection : 0x87986078 _MSUBSECTION
  +0x00c PtesInSubsection : 1
  +0x010 UnusedPtes       : 0
  +0x010 GlobalPerSessionHead : (null)
  +0x014 u               : <unnamed-tag>
  +0x018 StartingSector   : 0
  +0x01c NumberOfFullSectors : 2
  +0x020 u1               : <unnamed-tag>
  +0x024 LeftChild       : 0x8b27f040 _MMSUBSECTION_NODE
  +0x028 RightChild       : 0x87986098 _MMSUBSECTION_NODE
  +0x02c DereferenceList : _LIST_ENTRY [ 0x14b - 0x0 ]
  +0x034 NumberOfMappedViews : 6
0: kd> dx -id 0,0,863e98e8 -r1 (*((ntkrpamp!_MSUBSECTION *)0x87986058)).u
(*((ntkrpamp!_MSUBSECTION *)0x87986058)).u [Type: <unnamed-tag>]
  [+0x000] LongFlags       : 0x2 [Type: unsigned long] //0x2
  [+0x000] SubsectionFlags [Type: _MMSUBSECTION_FLAGS]
0: kd> dt _MMSUBSECTION_FLAGS 0x87986058
nt!_MMSUBSECTION_FLAGS
  +0x000 SubsectionAccessed : 0y0
  +0x000 Protection       : 0y00100 (0x4)//VAD的Protect描述符
  +0x000 StartingSector4132 : 0y0110000000 (0x180)
  +0x002 SubsectionStatic : 0y0
  +0x002 GlobalMemory     : 0y0
  +0x002 DirtyPages       : 0y0
  +0x002 Spare           : 0y1
  +0x002 SectorEndOffset : 0y100001111001 (0x879)

     
//+0x030 ViewLinks : _LIST_ENTRY [0x87db4cc0-0x87dbbf48]    
0: kd> dt _MMVAD 0x87db4cc0-0x30
nt!_MMVAD
  +0x000 u1               : <unnamed-tag>
  +0x004 LeftChild       : (null)
  +0x008 RightChild       : (null)
  +0x00c StartingVpn     : 0x76e40
  +0x010 EndingVpn       : 0x76f13
  +0x014 u               : <unnamed-tag>
  +0x018 PushLock         : _EX_PUSH_LOCK
  +0x01c u5               : <unnamed-tag>
  +0x020 u2               : <unnamed-tag>
  +0x024 Subsection       : 0x86fe7e98 _SUBSECTION
  +0x024 MappedSubsection : 0x86fe7e98 _MSUBSECTION
  +0x028 FirstPrototypePte : 0x92b64928 _MMPTE
  +0x02c LastContiguousPte : 0xfffffffc _MMPTE
  +0x030 ViewLinks       : _LIST_ENTRY [ 0x87da6b10 - 0x87e310c0 ]//触发写拷贝,
会把这个链表断链一节。只是修改一部分,没有将整个DLL复制一份。
  +0x038 VadsProcess     : 0x87db4d41 _EPROCESS //别的进程
0: kd> dt _EPROCESS 0x87db4d41-1
ntdll!_EPROCESS      
   +0x16c ImageFileName   : [15]  "svchost.exe"
       
       
       
0: kd> dt _MMVAD_FLAGS2
nt!_MMVAD_FLAGS2
  +0x000 FileOffset       : Pos 0, 24 Bits
  +0x000 SecNoChange     : Pos 24, 1 Bit
  +0x000 OneSecured       : Pos 25, 1 Bit
  +0x000 MultipleSecured : Pos 26, 1 Bit
  +0x000 Spare           : Pos 27, 1 Bit
  +0x000 LongVad         : Pos 28, 1 Bit
  +0x000 ExtendableFile   : Pos 29, 1 Bit
  +0x000 Inherit         : Pos 30, 1 Bit
  +0x000 CopyOnWrite     : Pos 31, 1 Bit//
       

2.VAD锁页

1.私有内存大多第一个 _MMVAD_FLAGS就够了
2.映射内存还需要_MMVAD_FLAGS2
   或者通过 ZwCreateSection ZwMapViewOfFile 来锁页

int main()
{
HMODULE h = LoadLibraryA("ntdll.dll");
ZwCreateSectionProc ZwCreateSection = (ZwCreateSectionProc)GetProcAddress(h,
"ZwCreateSection");
NtMapViewOfSectionProc NtMapViewOfSection =
(NtMapViewOfSectionProc)GetProcAddress(h, "ZwMapViewOfSection");

HANDLE sHandle = NULL;


LARGE_INTEGER max;
max.QuadPart = 0x2000;
NTSTATUS status = ZwCreateSection(&sHandle, SECTION_ALL_ACCESS, NULL, &max,
PAGE_READWRITE, SEC_COMMIT, NULL);
if (status != 0)
{
printf("创建失败\r\n");
}
else
{
LARGE_INTEGER mSize = { 0 };
SIZE_T ViewSize = { 0x2000 };
PVOID base = NULL;
status = NtMapViewOfSection(sHandle, GetCurrentProcess(), &base, 0, 0,
&mSize, &ViewSize, ViewShare, 0, PAGE_WRITECOPY);
printf("base = %x,%x\r\n", base, status);
}

system("pause");
return 0;
}

4.页异常

1.通用异常错误码

EXT  bit 0 外部(外设)异常 如果为1,代表外部触发的异常


IDT  bit 1 中断表中的异常(陷阱门或中断门或任务门)
TI   bit 2 IDT被设置为0才生效,TI被设置为0,代表GDT,否则是LDT。    

3~16位
2.页异常

P    0.错误是由不存在的页引起的
     1.错误是由页保护冲突引起的
W/R   0.读的时候错误
     1.写的时候错误
U/S   0.内核模式访问的错误
     1.用户模式访问的错误
RSVD  0.故障不是由保留位冲突引起的
     1.The fault was caused by a reserved bit set to 1 in some paging-structure
entry.
I/D   0.执行的时候没有出错  
     1.执行的时候出错
PK    0.The fault was not caused by protection keys.//密钥保护
     1.There was a protection-key violation.
SS    0.The fault was not caused by a shadow-stack access.    
     1.The fault was caused by a shadow-stack access.//影子栈,win10上被废弃,Linux
上被使用
SGX   0.The fault is not related to SGX.
     1.The fault resulted from violation of SGX-specific access-control
requirements.//新机制,目前没使用
3.异常保存位置
_KTRAP_FRAME

struct _KTRAP_FRAME
{
   union
  {
       ULONGLONG ErrorCode; //在这里                                
       ULONGLONG ExceptionFrame;                                    
  };
};

//The contents of the CR2 register.


//出现页异常时,地址保存在CR2中。

4.检测MDL和MmMapIo
x64和x86同理

1.检测MDL

IoAllocateMdl会在KPCR.PRCB.PPLookasideList[3]中找到ExAllocatePoolWithTag这个函数。

检测方案:
   1.替换KPCR指针
   2.HOOK获取映射的虚拟地址
   3.检测线程是否挂靠
   4.获取线程所属进程
   5.获取当前进程对比
   6.统计计数,封号

_KPRCB
   
kd> !prcb
PRCB for Processor 0 at fffff80004007e80:

kd> dt _KPRCB fffff80004007e80


ntdll!_KPRCB
  +0x780 PPLookasideList : [16] _PP_LOOKASIDE_LIST

kd> dx -id 0,0,fffffa80018d0130 -r1 (*((ntdll!_PP_LOOKASIDE_LIST (*)


[16])0xfffff80004008600))
(*((ntdll!_PP_LOOKASIDE_LIST (*)[16])0xfffff80004008600))                 [Type:
_PP_LOOKASIDE_LIST [16]]
  [3]             [Type: _PP_LOOKASIDE_LIST]

kd> dx -id 0,0,fffffa80018d0130 -r1 (*((ntdll!_PP_LOOKASIDE_LIST


*)0xfffff80004008630))
(*((ntdll!_PP_LOOKASIDE_LIST *)0xfffff80004008630))                 [Type:
_PP_LOOKASIDE_LIST]
  [+0x000] P               : 0xfffffa80018c9c20 [Type: _GENERAL_LOOKASIDE *]
  [+0x008] L               : 0xfffff80004011700 [Type: _GENERAL_LOOKASIDE *]

kd> dx -id 0,0,fffffa80018d0130 -r1 ((ntdll!_GENERAL_LOOKASIDE


*)0xfffff80004011700)
((ntdll!_GENERAL_LOOKASIDE *)0xfffff80004011700)                 :
0xfffff80004011700 [Type: _GENERAL_LOOKASIDE *]
  [+0x024] Type             : NonPagedPool (0) [Type: _POOL_TYPE]
  [+0x028] Tag             : 0x206c644d [Type: unsigned long]
  [+0x02c] Size             : 0xb8 [Type: unsigned long]
 //[+0x030] AllocateEx       : 0xfffff80003fc13d0 [Type: void * (__cdecl*)
(_POOL_TYPE,unsigned __int64,unsigned long,_LOOKASIDE_LIST_EX *)]
  [+0x030] Allocate         : 0xfffff80003fc13d0 [Type: void * (__cdecl*)
(_POOL_TYPE,unsigned __int64,unsigned long)]
  [+0x038] FreeEx           : 0xfffff80003fc0e80 [Type: void (__cdecl*)(void
*,_LOOKASIDE_LIST_EX *)]
  [+0x038] Free             : 0xfffff80003fc0e80 [Type: void (__cdecl*)(void
*)]
     

//效果并不怎么明显咩,待修复

#include<ntifs.h>

ULONG64 ExAllocate_Func = 0;
VOID DRIVERUNLOAD(_In_ struct _DRIVER_OBJECT* DriverObject)
{
ExAllocate_Func = (ULONG64)ExAllocatePoolWithTag;
}

BOOLEAN KeIsAttachedProcess();
PVOID ExAllocatePoolWithTag_HOOK(
POOL_TYPE PoolType,
SIZE_T    NumberOfBytes,
ULONG     Tag
)
{
   //直接读r13d 就能出地址 这里懒得实现
DbgBreakPoint();
if (KeIsAttachedProcess() == TRUE)
{
DbgBreakPoint();
PEPROCESS ep=IoThreadToProcess(NtCurrentThread());
PUNICODE_STRING name = NULL;
NTSTATUS sta=SeLocateProcessImageName(ep,&name);
if (sta==STATUS_SUCCESS)
{
DbgPrintEx(77, 0, "%wZ",name);
ExFreePool(name);
}
}
PVOID mem=ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
return mem;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
pDriver->DriverUnload = DRIVERUNLOAD;

DbgBreakPoint();

//单线程 只修改了一个KPCR
ULONG64 _KPRCB=__readgsqword(0x20);
ULONG64 ExAllocate = *(ULONG64*)(_KPRCB+0x780+3*0x10);
ExAllocate = ExAllocate + 0x030;
ExAllocate_Func = ExAllocate;
*(ULONG64*)ExAllocate =(ULONG64)ExAllocatePoolWithTag_HOOK;

return STATUS_SUCCESS;
}

5.x64基础
1.X64调用约定

__fastcall rcx rdx r8 r9


x64不再使用 __declspec(naked) 作为裸函数    
x64不再使用pushad/pushaq,push 超过四个字节时push不进去,但是pushfq还有
mov qwrod [地址],0x12345678 超过四个四节时,mov不进去  
x64中,x32操作全部升级为x64,但是不影响16位操作    

算法和x86一样,当前RIP+指令长度+偏移

注意:64位下,地址偏移计算通常会进位,去掉进位 才是真正的地址。
2.内联汇编

.code      ;代表节区

abc proc ;定义一个过程

   ret
abc endp

end

;;;;;;;;;;; 生成依赖项 优先生成汇编


;;;;;;;;;;; 写16进制 不能用0x 要用h
;;;;;;;;;;; 下层汇编会修改上层汇编的rsp,所以在函数开头应该sub 0x28,用于存放参数和rip,调用
再加add 0x28回去。
extern test1:proc    

.code      ;代表节区

abc proc ;定义一个过程


   sub rcx,rdx
   mov rax,rcx
   ret
abc endp

end

EXTERN_C int abc(int x, int y);

EXTERN_C void test1()


{

int main()
{
int result=abc(2, 1);
printf("%d\n", result);
return 0;
}

3.x64函数debug和Realse

注意Debug 和Realse的优化不同 计算cookie


   x64函数的传参,传入的都是结构体指针,无论是指针还是结构体

4.x64inline hook

//12字节HOOK
mov rax,0x123456789
jmp rax //call rax call qword ptr [rax]    
//6字节HOOK
FF25 XXXXXXXX  
//12字节HOOK
FF25 XXXXXXXXXXXXXXXX
   
//call
FF15    
 
//代码在文件夹内  
6.x64段
x64下 base和limit对于64位的段 不再有意义
//待研究 x86/x64体系探索

rd msr 0xc0000080

L位:1是64位模式,0是compatibility模式

x86代码段和数据段 和x64的代码段和数据段完全一致。(x64下 cs仍然指向64位段


x86系统段是64位。

x64系统段是128位。

1.调用门

7.x64页表
PML4的NX位不影响PTE的NX位
1G页 只有PML4 PDPTE
//需要确定物理地址的大小 (通过CPUID)

1.X64分页
2.CPUID

0~7位,是物理地址的位数

8~15位,是线性地址的大小
48 C7 C0 08 00 00 80 mov rax, 0xFFFFFFFF80000008;rax功能号
                    moc rcx, 0;注意清空rcx
0F A2                cpuid
rax=0000000000003030
0x30=48 根地址总线
0x30=48 位线性地址大小

#include<intrin.h> //封装了汇编指令
__cpuid(功能号,返回值)
__cpuidex(,,)    

3.获取PML4,PDPTE,PDE,PTE
1.WIN7获取

bool __fastcall MiIsAddressValid(__int64 a1)


{
 __int64 v1; // rdx
 __int64 v2; // rax

 if ( a1 >> 48 != -1 && a1 >> 48 != 0 )


   return 0;
 if ( (*(8 * ((a1 >> 39) & 0x1FF) - 0x90482413000i64) & 1) == 0 )//
+FFFFF6FB7DBED000 PML4
   return 0;
 if ( (*(((a1 >> 27) & 0x1FFFF8) - 0x90482600000i64) & 1) == 0 )//
FFFFF6FB7DA00000 //PDPTE
   return 0;
 v1 = *(((a1 >> 18) & 0x3FFFFFF8) - 0x904C0000000i64);// FFFFF6FB40000000 //PDE
 if ( (v1 & 1) == 0 )
   return 0;
 if ( (v1 & 0x80u) == 0i64 )
{
   v2 = *(((a1 >> 9) & 0x7FFFFFFFF8i64) - 0x98000000000i64);// FFFFF68000000000
//PTE
   if ( (v2 & 1) != 0 )
     return (v2 & 0x80) != 0x80;
   return 0;
}
 return 1;
}

ULONG64 GetPML4_WIN7(ULONG64 VirtualAddress)


{
return *(ULONG64*)(8 * ((VirtualAddress >> 39) & 0x1FF)+PML4_BASE);
}
ULONG64 GetPDPTE_WIN7(ULONG64 VirtualAddress)
{
return *(ULONG64*)(((VirtualAddress >> 27) & 0x1FFFF8)+PDPTE_BASE);
}
ULONG64 GetPDE_WIN7(ULONG64 VirtualAddress)
{
ULONG64 v1 = GetPDPTE_WIN7(VirtualAddress);
if (v1 & 80 == 0) return 0;
return *(ULONG64*)(((VirtualAddress >> 18) & 0x3FFFFFF8)+PDE_BASE);
}
ULONG64 GetPTE_WIN7(ULONG64 VirtualAddress)
{
ULONG64 v1=GetPDE_WIN7(VirtualAddress);
if (!v1) return 0;
if (v1 & 80 == 0) return 0;
return *(ULONG64*)(((VirtualAddress >> 9) & 0x7FFFFFFFF8)+PTE_BASE);
}

2.WIN10获取

   v10 = ((a1 >> 9) & 0x7FFFFFFFF8i64) - 0x98000000000i64;// FFFFF68000000000


PTE
   v11 = ((v10 >> 9) & 0x7FFFFFFFF8i64) - 0x98000000000i64;// PDE
   v12 = ((v11 >> 9) & 0x7FFFFFFFF8i64) - 0x98000000000i64;// PDPTE
   v13 = ((v12 >> 9) & 0x7FFFFFFFF8i64) - 0x98000000000i64;// PML4

//获取动态基址
.text:00000001402C1570                                     ; PVOID __stdcall
MmGetVirtualForPhysical(PHYSICAL_ADDRESS PhysicalAddress)
.text:00000001402C1570                                                    
public MmGetVirtualForPhysical
.text:00000001402C1570                                    
MmGetVirtualForPhysical proc near       ; DATA XREF: .pdata:00000001405345E4↓o
.text:00000001402C1570 48 8B C1                                            mov  
  rax, rcx
.text:00000001402C1573 48 C1 E8 0C                                         shr  
  rax, 0Ch
.text:00000001402C1577 48 8D 14 40                                         lea  
  rdx, [rax+rax*2]
.text:00000001402C157B 48 03 D2                                            add  
  rdx, rdx
.text:00000001402C157E 48 B8 08 00 00 00 80 FA FF FF                       mov  
  rax, 0FFFFFA8000000008h
.text:00000001402C1588 48 8B 04 D0                                         mov  
  rax, [rax+rdx*8]
.text:00000001402C158C 48 C1 E0 19                                         shl  
  rax, 19h
//.text:00000001402C1590 48 BA 00 00 00 00 80 F6 FF FF                       mov
    rdx, 0FFFFF68000000000h

ULONG64 GetPML4_WIN10(ULONG64 VirtualAddress)


{
ULONG64 result = GetPDPTE_WIN10(VirtualAddress);
return ((result >> 9) & 0x7FFFFFFFF8) + BASE_WIN10;
}
ULONG64 GetPDPTE_WIN10(ULONG64 VirtualAddress)
{
ULONG64 result = GetPDE_WIN10(VirtualAddress);
return ((result >> 9) & 0x7FFFFFFFF8) + BASE_WIN10;
}
ULONG64 GetPDE_WIN10(ULONG64 VirtualAddress)
{
ULONG64 result = GetPTE_WIN10(VirtualAddress);
return ((result >> 9) & 0x7FFFFFFFF8)+BASE_WIN10;
}
ULONG64 GetPTE_WIN10(ULONG64 VirtualAddress)
{
if (BASE_WIN10 == 0)
{
UNICODE_STRING name;
RtlInitUnicodeString(&name,L"MmGetVirtualForPhysical");
BASE_WIN10=(ULONG64)MmGetSystemRoutineAddress(&name);
BASE_WIN10 = *(ULONG64*)(BASE_WIN10 + 0x22);
}
return ((VirtualAddress>>9) & 0x7FFFFFFFF8)+ BASE_WIN10;
}

8.突破页表隔离
//Intel独有双页表,AMD只有单页表,双页表限制的是NX位,让R0不能执行R3的地址,R3不能执行R0
//整个CR3有 4096/16=0x100(256)行,前面128项是用户态,后面128项是内核态

//R3进R0,切换CR3,不会刷新TLB,因为从缓存里拿的
1: kd> dt _KPROCESS ffffad0e02bbc080
nt!_KPROCESS
  +0x028 DirectoryTableBase : 0x84b2a002 //内核CR3结尾为2
     
  //两个CR3相差一个页
  +0x280 UserDirectoryTableBase : 0x84b29001 //用户CR3结尾为1
  +0x288 AddressPolicy   : 0 ''//地址策略,非0代表只有一个CR3。 这个地方不能修改,蓝
屏。    

//注意:
修改用户CR3的PML4项,也要修改内核CR3的PML4项,因为有轮询扫。

1.用户CR3的保存

1: kd> dt _EPROCESS
nt!_EPROCESS
+0x500 Vm               : _MMSUPPORT_FULL
   
1: kd> dt _MMSUPPORT_FULL
nt!_MMSUPPORT_FULL
  +0x000 Instance         : _MMSUPPORT_INSTANCE
  +0x0c0 Shared           : _MMSUPPORT_SHARED
     
1: kd> dt _MMSUPPORT_SHARED
nt!_MMSUPPORT_SHARED
  +0x000 WorkingSetLock   : Int4B
  +0x004 GoodCitizenWaiting : Int4B
  +0x008 ReleasedCommitDebt : Uint8B
  +0x010 ResetPagesRepurposedCount : Uint8B
  +0x018 WsSwapSupport   : Ptr64 Void
  +0x020 CommitReleaseContext : Ptr64 Void
  +0x028 AccessLog       : Ptr64 Void
  +0x030 ChargedWslePages : Uint8B
  +0x038 ActualWslePages : Uint8B
  +0x040 WorkingSetCoreLock : Uint8B
  +0x048 ShadowMapping   : Ptr64 Void //0xffff9e01`aeeb700 保存了用户cr3,拿不到
PDPTE。

2.KVASCODE
CR3只映射KVASCODE,因为用户CR3在系统调用时,只用到KPCR

3.无附加映射

//win10上无附加映射失败
MmMapIoSpace,不附加,每个物理地址都映射失败。

//需要修改PreviousMode 保证是内核模式
//驱动调用Nt系列函数一直失败 不知道为什么
PVOID MapPhysicalAddress(ULONG64 PhysicalAddress)
{

   HANDLE sectionHandle;
   OBJECT_ATTRIBUTES obj;
   UNICODE_STRING sectionName;
   RtlInitUnicodeString(&sectionName,L"\\Device\\PhysicalMemory");
 
 InitializeObjectAttributes(&obj,&sectionName,OBJ_CASE_INSENSITIVE,NULL,NULL);
  // NTSTATUS sta=NtOpenSection(&sectionHandle,SECTION_ALL_ACCESS,&obj);
   NTSTATUS sta=ZwOpenSection(&sectionHandle, SECTION_ALL_ACCESS, &obj);
   if (!NT_SUCCESS(sta)) return 0;

   PVOID mem = 0;
   LARGE_INTEGER offest;
   offest.QuadPart = PhysicalAddress;
   SIZE_T size = PAGE_SIZE;
   sta=ZwMapViewOfSection(
       sectionHandle,
       NtCurrentProcess(),
       &mem,
       0,
       PAGE_SIZE,
       &offest,
       &size,
       ViewUnmap,
       MEM_TOP_DOWN,
       PAGE_READWRITE
      );
   if (!NT_SUCCESS(sta))
  {
       NtClose(sectionHandle);
       return 0;
  }
   NtClose(sectionHandle);
   return mem;
}

9.x64下x86API进内核
TEB64 +0x2000 =TEB32  
PEB64 -0x1000 =PEB32
垫片:IAT HOOK 原名叫windows shim 在 winodws/AppPatch目录下
垫片:https://www.freebuf.com/articles/system/114287.html
x64下x86程序,能做简单HOOK达到无痕。    

1.x86api简单调用流程

用Yzdbg x86dbg看不到wow64cpu
//win7 是fs:[0x30] win10直接变成一个地址    

jmp far 0x0033


0X33>>3 =6
   
0020fb00`00000000    
2=0010    L=1 D/B=0
fb=1111 1011    

2.WOW64CPU
1.找到对应点
IDA找到对应点

2.调用流程

保存环境,判断服务号,传 服务号和esp参数 call SystemServiceEx(WOW64.dll)。


3.WOW64
1.Wow64SystemServiceEx

1.判断服务号

2.计算TEB32

3.获取函数地址

4.调用函数whNtOpenProcess

5.调用完然后返回到WOW64cpu

4.WOW64.whNtOpenProcess
5.WOW64CPU
1.返回

9.x64下x86API进内核
1.ntdll64
2.syscall

EIP 176h
CS  174h
SS
ESP 175
EFALG    
   
RIP c0000082h //rdmsr c0000082h
CS  c0000081h
SS  174h
RSP 175
EFALG        

1.RIP c0000082h

2.CS c0000081h

1: kd> rdmsr c0000081h


msr[c0000081] = 00230010`00000000 //低32位保留
//0023 是r3的cs
//0010 是r0的cs
//按需求拿cs    

3.KiSystemCall64

1.保存堆栈KTRAP_FRAME,关闭内核读写数据隔离
2.将eprocess的SecurityDomain设置到KPCR中,并写两次MSR    
//3.疑似打开Smep,但并没有置位    
4.切换Mxcsr
//5.判断协程
6.调用函数
7.切回Mxcsr
8.恢复DR寄存器
9.写两次MSR
//10.判断KVA,切换用户CR3  
11.恢复rcx=rip,r11=eflags,切回rsp,rbp,调用sysret.    

1.保存堆栈KTRAP_FRAME,关闭内核读写数据隔离
2.将eprocess的SecurityDomain设置到KPCR中,并写两次MSR

3.疑似打开Smep,但并没有置位

call loc_1401D509E ; E8 EE FF FF FF 往上call FF-EE+1个字节

4.切换Mxcsr
5.判断协程

6.调用函数
10.Instruent HOOK监控X86进程API
r10=rip,rip=KPROCESS.InstrumentaionCallback

1.NtSetInformationProcess
总结:

1.当前线程所属进程有SeDebug权限

2.目标进程是WOW64PROCESS

3.当前线程所属进程是WOW64PROCESS

4.函数地址是R3地址

5.函数地址放到PEB32.0x254
NTSYSCALLAPI NTSTATUS NTAPI NtSetInformationProcess(
   __in HANDLE ProcessHandle,
   __in PROCESSINFOCLASS ProcessInformationClass,
   __in_bcount(ProcessInformationLength) PVOID ProcessInformation,
   __in ULONG ProcessInformationLength
);
ProcessInstrumentationCallback = 40;

11.X64SSDT HOOK
__readmsr(0xc0000082)  //判断影子页表 KiSystemCall64Shadow

1.注意低四字节进位问题

/*
利用LARGE_INTERGE 来代替ULONG64 保证低四字节的计算不会影响到高四字节。
*/

2.x64SSDT 算法

/*
1.取出函数表地址 fffff800`5bc24cc0

/*
2.按四字节解析函数地址表,找到函数偏移
3.*(函数地址表+索引*4)=函数偏移
4.函数地址表+函数偏移>>4(二进制)=目标函数地址

3.PsGetProcessSectionBaseAddress

return *(_QWORD *)(eprocess + 0x3C8);


在EPROCESS中
VOID* SectionBaseAddress; //0x3c8
//返回当前exe在内存中的地址
4.PsGetProcessWow64Process

判断x86进程还是x86进程
//eprocess
struct _EWOW64PROCESS* WoW64Process; //0x428
struct _EWOW64PROCESS
{
   VOID* Peb;  //PEB32                                                    
//0x0
   USHORT Machine;                                                        
//0x8
   enum _SYSTEM_DLL_TYPE NtdllType;                                      
 //0xc
};

5.WIN7/WIN10特征码定位查找SSDT

//特征码定位SSDT表,SSDT表的算法
//查找函数序号,进程遍历(名称对比),导出表遍历(x32和x64)

//注意低四字节溢出到高四字节
.h
//功能区
ULONG64 findSSDTtable();
ULONG32 findOrderByFuncName(char* funcName);
ULONG64 findFuncAddrBySSDT(ULONG64 SSDTtable, ULONG64 order);

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)


{
pDriver->DriverUnload = DRIVERUNLOAD;
DbgBreakPoint();

ULONG64 ssdt=findSSDTtable();
ULONG32 ord=findOrderByFuncName("ZwWriteVirtualMemory");
ULONG64 funcAddr=findFuncAddrBySSDT(ssdt,ord);

return STATUS_SUCCESS;
}

12.注入之修复Shellcode
/*
利用shellcode来对PE文件进行修复,但是火绒注入的shellcode是利用VirtualAlloc来申请内存,所以
要修复它的申请内存。
1.bp bl bc *(xx)

13.注入绕过堆栈回溯
1.堆栈回溯

1.RtlWalkFrameChain() 可以看到堆栈的调用地址  
   //主要靠ebp来找地址

//堆栈回溯示例
typedef ULONG (WINAPI* pRtlWalkFrameChain)(
   OUT PVOID* Callers,
   IN ULONG Count,
   IN ULONG Flags);
int main()
{
   ULONG64 retAddr[20] = { 0 };
   pRtlWalkFrameChain RtlWalkFrameChain =
(pRtlWalkFrameChain)GetProcAddress(GetModuleHandleA("ntdll.dll"),"RtlWalkFrameCh
ain");
   RtlWalkFrameChain((PVOID*)retAddr,20,0);
   //判断返回地址即可
   return 0;
}

2.反堆栈回溯

call xxxxxxxx
   改为:push retAddress(用for循环搜索0xc3)
        jmp   xxxxxxxx
   
__asm
{
   push ebp //或者可以自建堆栈
   push 标签
   push retAddress
   push retAddress
   push retAddress
   push retAddress
   push retAddress
   push retAddress
   push retAddress //理论上能搞无限个
   mov ebp,0//目的是破坏ebp,让RtlWalkFrameChain结果为0    
   ****
   jmp  xxxxxxxx
标签:    
   pop ebp    
}
//实例
/*void AntiEbpTrace()
{
   PUCHAR retAddr = (PUCHAR)Game_func;

   for (int i = 0;; i++)


   {
       if (retAddr[i] == 0xc3)
       {
           retAddr = &retAddr[i];
           break;
       }
   }

   __asm
   {
       push ebp
       push label
       push retAddr
       push retAddr
       push retAddr
       mov ebp,0
       jmp Game_func
label:
       pop ebp
   }
}*/

方法2:
  E8 FF FF FF FF 不好写

3.注入流程

1.申请三块内存,PE文件(读写 用户内存) shellcode(读写执行 用户内存) imageFile(读写执行 用户


内存)
2.如何跑shellcode?
   1.HOOK一个函数,问题是何时释放内存?
   2.APC(插入一个用户APC) ZwContinue
   3.调用线程//容易被扫描
   4.x64 Process HOOK//不容易被捕获
   5.插入内核APC,获取trap_frame,劫持RIP
3.释放内存    

/*x86注入*/
BOOLEAN injectDll(HANDLE gamePid, PUCHAR dllAddr, ULONG fileSize)
{
   if (!gamePid || !dllAddr || !fileSize) return FALSE;

   PVOID dllNewAddr = ExAllocatePool(PagedPool, fileSize);


   if (!dllNewAddr) return FALSE;
   memcpy(dllNewAddr, dllAddr, fileSize);

   PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)dllNewAddr;


   PIMAGE_NT_HEADERS32 pNt = (PIMAGE_NT_HEADERS32)((ULONG64)dllNewAddr + dos-
>e_lfanew);  
   ULONG sizeofImage=pNt->OptionalHeader.SizeOfImage;
   if (pNt->Signature != 0x00004550) return FALSE;

   //game Pid
   PEPROCESS ep = NULL;
   NTSTATUS sta=PsLookupProcessByProcessId(gamePid,&ep);
   if (!NT_SUCCESS(sta)) return FALSE;
   ObDereferenceObject(ep);

   /*申请内存*/
   PVOID dll_File = NULL;
   PUCHAR dll_Shellcode = NULL;
   PVOID dll_inMem = NULL;
   SIZE_T dll_File_Size = fileSize;
   SIZE_T dll_Shellcode_Size = sizeof(MemLoadShellcode_x86);
   SIZE_T dll_inMem_Size = sizeofImage;

   KAPC_STATE apc = { 0 };
   KeStackAttachProcess(ep, &apc);
   do
  {
       sta=ZwAllocateVirtualMemory(
           NtCurrentProcess(),
           &dll_File,
           0,
           &dll_File_Size,
           MEM_COMMIT,
           PAGE_READWRITE);
       if (!NT_SUCCESS(sta)) break;

       sta = ZwAllocateVirtualMemory(
           NtCurrentProcess(),
           &dll_Shellcode,
           0,
           &dll_Shellcode_Size,
           MEM_COMMIT,
           PAGE_EXECUTE_READWRITE);
       if (!NT_SUCCESS(sta)) break;

       sta = ZwAllocateVirtualMemory(
           NtCurrentProcess(),
           &dll_inMem,
           0,
           &dll_inMem_Size,
           MEM_COMMIT,
           PAGE_EXECUTE_READWRITE);
       if (!NT_SUCCESS(sta)) break;

  } while (0);
   if (dll_File == NULL || dll_Shellcode == NULL || dll_inMem == NULL)
  {
       KeUnstackDetachProcess(&apc);
       ExFreePool(dllNewAddr);
       return FALSE;
  }
   memcpy(dll_File, dllNewAddr, dll_File_Size);
   memcpy(dll_Shellcode, MemLoadShellcode_x86, dll_Shellcode_Size);
   memset(dll_inMem, 0, dll_inMem_Size);

   /*修复shellcode*/
   *(PULONG)&dll_Shellcode[0x346] = dll_inMem;

   /*找到创建线程*/
   ULONG64 ssdt=findSSDTtable();
   if (ssdt)
  {
       ULONG32 order=findOrderByFuncName("ZwCreateThreadEx");
       if (order)
      {
           ZwCreateThreadEx=
(pfnZwCreateThreadEx)findFuncAddrBySSDT(ssdt,order);
      }
  }
   if (!ZwCreateThreadEx)
  {
       KeUnstackDetachProcess(&apc);
       ExFreePool(dllNewAddr);
       return FALSE;
  }

   /*启动线程*/
   MODE mode = KernelMode;
   SetThreadMode(KeGetCurrentThread(), mode, &mode);
   HANDLE th = NULL;
   sta=ZwCreateThreadEx(
       &th,
       THREAD_ALL_ACCESS,
       NULL,
       NtCurrentProcess(),
       dll_Shellcode,
       dll_File,
       0,
       0,
       0x10000,
       0x20000,
       0
  );
   SetThreadMode(KeGetCurrentThread(), mode, &mode);

   if (NT_SUCCESS(sta))
  {
       PETHREAD eth = 0;
       sta=ObReferenceObjectByHandle(th,THREAD_ALL_ACCESS,
           *PsThreadType,KernelMode,&eth,0);
       NtClose(th);
       if (NT_SUCCESS(sta))
      {
           KeWaitForSingleObject(eth,Executive,KernelMode,FALSE,0);
           /*线程运行完毕*/
           memset(dll_inMem, 0, PAGE_SIZE);//清空PE头
           ObDereferenceObject(eth);

           ZwFreeVirtualMemory(NtCurrentProcess(),
               &dll_File,
               &dll_File_Size,
               MEM_RELEASE);

           ZwFreeVirtualMemory(NtCurrentProcess(),
               &dll_Shellcode,
               &dll_Shellcode_Size,
               MEM_RELEASE);
      }
  }
   else
  {
       ZwFreeVirtualMemory(NtCurrentProcess(),
           &dll_File,
           &dll_File_Size,
           MEM_RELEASE);

       ZwFreeVirtualMemory(NtCurrentProcess(),
           &dll_Shellcode,
           &dll_Shellcode_Size,
           MEM_RELEASE);

       ZwFreeVirtualMemory(NtCurrentProcess(),
           &dll_inMem,
           &dll_inMem_Size,
           MEM_RELEASE);
  }
   ExFreePool(dllNewAddr);
   KeUnstackDetachProcess(&apc);
   return TRUE;
}

4.程序崩溃原因

多线程DLL (MD) 是动态的


多线程调试DLL (MT)是静态的    
   //所以会导致程序崩溃

5.x64修复64位dll

/*修复0x511 8字节*/
/*注意Pe的SizeOfimage*/

14.隐藏内存注入
1.指定地址挂物理页(绕过内存检测)

1.找到地址对应的PDPTE PDE PTE对应的线性地址


2.修改线性地址的值==挂上物理页    
//注意:ZwAllocateUserPhysicalPages 申请物理页
//   通过MmGetPhysicalForVitrual,找到动态基地址来计算保存PDPTE PDE PTE的线性地址
//0x867 代表可读可写可执行  

/*隐藏内存注入*/
/*win10需要修复VAD的问题*/
/*1903 1909需要修复物理内存的问题*/

/*需要提前附加到目标进程*/
BOOLEAN SetPhyPages(ULONG64 virtualAddress, ULONG64* pfnArray, ULONG
numberofPages);
BOOLEAN AllocateAndHideMemory(ULONG64 virtualAddress,ULONG fileSize)
{
   typedef NTSTATUS(__stdcall* pfnZwAllocateUserPhysicalPages)(
       HANDLE ProcessHandle,
       PULONG_PTR NumberOfPages,
       PULONG_PTR UserPfnArray);
   pfnZwAllocateUserPhysicalPages ZwAllocateUserPhysicalPages = NULL;;
   /*找到申请内存*/
   ULONG64 ssdt = findSSDTtable();
   if (ssdt)
  {
       ULONG32 order = findOrderByFuncName("ZwAllocateUserPhysicalPages");
       if (order)
      {
           ZwAllocateUserPhysicalPages =
(pfnZwAllocateUserPhysicalPages)findFuncAddrBySSDT(ssdt, order);
      }
  }
   if (!ZwAllocateUserPhysicalPages) return FALSE;

   /*调用*/
   ULONG64 numberofPages = (fileSize >> 12) + 1+ 0x20;
   ULONG64* pfnArray = ExAllocatePool(PagedPool,(numberofPages*8)+1);
   memset(pfnArray, 0, (numberofPages * 8) + 1);
   MODE mode = KernelMode;
   SetThreadMode(KeGetCurrentThread(), mode, &mode);
   NTSTATUS
sta=ZwAllocateUserPhysicalPages(NtCurrentProcess(),&numberofPages,pfnArray);
   SetThreadMode(KeGetCurrentThread(), mode, &mode);
   if (!NT_SUCCESS(sta)) return FALSE;

   SetPhyPages(virtualAddress, pfnArray, numberofPages);


   ExFreePool(pfnArray);
   return TRUE;
}
#include"../GetPTE/GetPTE.h"
BOOLEAN SetPhyPages(ULONG64 virtualAddress, ULONG64* pfnArray, ULONG
numberofPages)
{
   typedef struct HardwarePteX64 {
       ULONG64 valid : 1;               //!< [0]
       ULONG64 write : 1;               //!< [1]
       ULONG64 owner : 1;               //!< [2]
       ULONG64 write_through : 1;       //!< [3]
       ULONG64 cache_disable : 1;       //!< [4]
       ULONG64 accessed : 1;            //!< [5]
       ULONG64 dirty : 1;               //!< [6]
       ULONG64 large_page : 1;          //!< [7]
       ULONG64 global : 1;              //!< [8]
       ULONG64 copy_on_write : 1;       //!< [9]
       ULONG64 prototype : 1;           //!< [10]
       ULONG64 reserved0 : 1;           //!< [11]
       ULONG64 page_frame_number : 36;  //!< [12:47]
       ULONG64 reserved1 : 4;           //!< [48:51]
       ULONG64 software_ws_index : 11;  //!< [52:62]
       ULONG64 no_execute : 1;          //!< [63]
  }HardwarePte;
   ULONG64 tempaddr = virtualAddress;
   for (int i = 0; i < numberofPages; i++)
  {
       HardwarePte* p = (HardwarePte*)GetPDPTE(tempaddr);
       if (MmIsAddressValid(p) && p->valid == 0)
      {
           ULONG64 initPTE = (pfnArray[i] << 12) | 0x867;
           memcpy(p,&initPTE,8);
           i++;
      }

       p = (HardwarePte*)GetPDE(tempaddr);
       if (MmIsAddressValid(p) && p->valid == 0)
      {
           ULONG64 initPTE = (pfnArray[i] << 12) | 0x867;
           memcpy(p, &initPTE, 8);
           i++;
      }

       p = (HardwarePte*)GetPTE(tempaddr);
       if (MmIsAddressValid(p) && p->valid == 0)
      {
           ULONG64 initPTE = (pfnArray[i] << 12) | 0x867;
           memcpy(p, &initPTE, 8);
           //i++;
      }
       tempaddr += PAGE_SIZE;
  }
   return TRUE;
}

2.错误

ULONG64 aimAddress_x86 = 0xFFFFF000 - 0x1000- dll_inMem_Size;


//这个地址对于x86进程,win7能完美注入.win10 2004--2009(20h2)也能完美注入。1903---1909会
蓝屏

//这个地址对于x64进程,会蓝屏(win7也会),错误号为0x1A,VAD错误

3.1903 1909蓝屏原因

蓝屏原因:aimAddress_x86这个x86进程下的最高地址,仍然在VAD的描述范围内,修改它的pte等,
会导致描述不一样。检测到描述

不一样就蓝屏。(win10 2004-2009取消了这个检测)

即使解决了VAD的错误,还有别的错误(mmPFNdatabase)
总结原因:

4.(widnows版本)
Windows 10(21h1) 19043

Windows 10(20H2) 19042

Windows 10(2004) 19041

Windows 10(1909) 18363

Windows 10(1903) 18362

Windows 10(1809) 17763

Windows 10(1803) 17134

Windows 10(1709) 16299

Windows 10(1703) 15063

Windows 10(1607) 14393

Windows 10(1511) 10586

Windows 10 (1507) 10240

Windows 8.1(更新1) MajorVersion = 6 MinorVersion = 3 BuildNumber = 9600

Windows 8.1 MajorVersion = 6 MinorVersion = 3 BuildNumber = 9200

Windows 8 MajorVersion = 6 MinorVersion = 2 BuildNumber = 9200

4.绕过线程检测

//1.线程回调,给线程的函数直接写0xc3 ret了
//2.Kernel32!BaseThreadInitThunnk hook
//3.线程创建日志。
5.另一种寻找地址的思路

MiAllocateAddress MiInsertVadCharges (modmap-master.zip)


//原理是把我们的dll挂到系统dll的末尾(vad),然后继续用指定地址挂物理页。
//推演:修改系统文件DLL的sizeOfImage,保证匹配(?)
//     为了更安全,或者把dll数据也贴进去(?)    

15.CPU异常
操作系统指定CPU的EIP,当CPU产生异常的时候,查CPU的IDT表,IDT表的函数由操作系统指定。
   最终返回给操作系统。

1.什么是异常?
   异常:意外出错,CPU主动生成信息,调用IDT函数,交给操作系统处理,操作系统选择性派发给开发者。
   中断:意外打断,CPU意外被打断后派发  
   
   
2.异常有几种方式?  CPU异常 和软件模拟异常  
1.异常注册,注册回调函数//(VEH)(SEH)
2.异常登记 记录出错信息和出错位置,打包成一个结构体
3.异常派发
       
3.异常类型:
SEH:编译器或者C/C++中,try{} catech{} 线程级异常,方便判断
VEH: 进程级异常,全局性的,不方便判断
   
4.为什么要设计两套异常?
VEH:全局性的,比如一触发异常就打印日志,不需要判断异常类型。//VEH捕获异常太多,处理太多,慢
SEH:局部性的,可以判断异常类型    //SEH捕获一部分异常,快
//注意:在内核中,进程只是地址空间,所以内核中只有SEH异常。    
   
/*
除0异常 是0号异常
通用异常13号
缺页异常14号
*/
1.VEH简单解析

LONG NTAPI except(


   struct _EXCEPTION_POINTERS* ExceptionInfo
)
{
   ExceptionInfo->ContextRecord->Eip += 3;
   return EXCEPTION_CONTINUE_EXECUTION;
}

int main()
{
   AddVectoredExceptionHandler(0, except);
   int x = 0;
   int y = 0;
   int z = x / y;
   printf("-------------\n");
   return 0;
}

16.异常2
异常的三种类型
1.断点异常

2.页异常

3.通用异常

异常流程分析(残)
返回ntdll.KiUserDispatch

17.异常3(VEH)
先调用VEH,再调用SEH,再调用VCH(做日志记录)

VEH,有个异常链表,出现异常要一个个call链表的地址,

遇到 EXCEPTION_CONTINUE_EXECUTION,表示不再call地址

遇到 EXCEPTION_CONTINUE_SEARCH,表示继续call地址

1.VEH调用流程
1.注册流程

VEH
{
LIST_ENTRY unknow;
QWORD      count; //默认1
QWORD      func;//调用RtlEncodePointer加密后的,RtlDecodePointer调用后解密    
}
2.call流程
2.反VEH思路
1.RtlAllocateHeap

2.VEH结构替换

3.&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessUsingVEH:1

18.VEH 无痕HOOK
51.项目

19.SEH(结构化异常)
定义:SEH是线程级异常,栈的异常。

struct _NT_TIB64
{
   ULONGLONG ExceptionList;//SEH异常链表地址,SEH 是 SLIST 单链表。
                           //最后一个节点的地址是-1 (0xFFFFFFFF)
   ULONGLONG func          //函数地址
};

1.自定义添加SEH异常

typedef struct _Exceptioninfo


{
   struct _Exceptioninfo* pExceptioninfo;
   ULONG func;
}Exceptioninfo,*pExceptioninfo;

EXCEPTION_DISPOSITION SehHandler(EXCEPTION_RECORD* record,


   pExceptioninfo info, PCONTEXT context, pExceptioninfo dispath)
{
   context->Eip += 3;
   printf("异常触发\n");
   return ExceptionContinueExecution;
}

void test()
{
   Exceptioninfo node;
   pExceptioninfo ps;
   __asm
  {
       mov eax,fs:[0]
       mov ps, eax
  }
   node.pExceptioninfo = ps;
   node.func = (ULONG)SehHandler;
   __asm
  {
       lea eax, [node]
       mov fs: [0],eax
  }
   int x = 0;
   int a = x / x;
}

int main()
{
   test();
   printf("线程继续执行\n");

   system("pause");
   return 0;
}

2.SEH校验
3.RtlLookupFunctionEntry

20.VMP云编译与加签名
利用bat文件来编译。

1.一些命令解析
2.BAT编译

/r 签名规则 /f 给哪个文件签名 /ac 驱动签名

注意:使用windows计划任务定时编译(比如下午四点)

21.SEH 2
1.C++异常与C异常

//cpp  
   try
  {
  }
   catch ( )
  {
  };

//C  
   __try
  {

  }
   __except(1)
  {

  };

   __try
  {
  }
   __finally
  {

  };
2.SEH异常例子

int test(ULONG code,EXCEPTION_POINTERS* pointer)


{
   if (code == 0xC0000094)
  {
       return 1;
  }
   printf("---1---\n");
   pointer->ContextRecord->Eip += 3;
   return -1;
}

int main()
{

   __try
  {
       int x, y, z;
       x = 0;
       y = 0;
       z = x / y;
       printf("---continue Execute---\n");
  }
   __except (test(GetExceptionCode(),GetExceptionInformation()))
  {
       printf("---异常发生---\n");
  };
   
}

3.探究SEH信息
3是 "如何派发的"
4.nginx
编译好的驱动放在 html目录下面

22.简单调试器

1.DebugActiveProcess逆向
1.DbgUiConnectToDbg@0(创建调试对象)
ZwCreateDebugObject@16(TEB32+0xF24,0x1F000F,OBJECT_ATTRIBUTE,1)
ObInsertObject 插入到句柄表中

2.DbgUiDebugActiveProcess@4
1.NtDebugActiveProcess@8
1.DbgkpPostFakeProcessCreateMessages@12

看思维导图

2.DbgkpSetProcessDebugObject@16

看思维导图

3.DbgUiDebugActiveProcess@4

看思维导图

2.WaitForDebugEvent逆向
细节总结
好用的细节:

TEB32 +0xF24 存放DebugObjectHandle

RemoteEProcess--ULONG ProtectedProcess:1 //0x26c 保护进程 类似权限

RemoteprocessObject.RundownProtect 修改进程锁

不好用的细节:

cmp RemoteprocessObject, [eax+_KTHREAD.___u12.ApcState.Process] ; 判断是否调试自己

cmp RemoteprocessObject, ds:_PsInitialSystemProcess ; 不能调试系统进程

11.Sfilter
控制设备与卷设备

1.有fastfat.sys(FAT32) ntfs.sys(ntfs)两种文件系统,文件系统给有自己的一个控制设备,和几个
没有名字的卷设备
2.当某个逻辑卷(C D E F)使用了某个文件系统,就会生成对应的"无名字的"卷设备 ,由卷管理器生成
 但是符号链接为 "c:",设备对象为"\\Device\HarddiskVolume1",是真实设备,不是文件系统的设备
对象。  

Sfilter的控制设备
1.设备对象名字挂在 "\\FileSystem\\Filters" 下。如果没有"Filters",就挂在 "\\FileSystem"下

2.设备类型为 FILE_DEVICE_DISK_FILE_SYSTEM

12.MiniFilter
1.FltRegisterFilter返回0xC0000034

原因是注册表下没有初始化 Instance (Alltitude 和 flags)

启动驱动的函数

BOOL WINAPI TsLoadMiniflt()


{
char filepath[1024] = { 0 };
OPENFILENAMEA sysfile = { 0 };
sysfile.lStructSize = sizeof(OPENFILENAMEA);
sysfile.lpstrFilter = "sys文件(*.sys)\0";
sysfile.lpstrFile = filepath;
sysfile.lpstrInitialDir = "./";
sysfile.nMaxFile = sizeof(filepath) / sizeof(*filepath);
GetOpenFileNameA(&sysfile);
if (strcmp(filepath, "") == 0)
{
printf("获取文件路径为空!\r\n");
return FALSE;
}

char* FilePath = filepath;


char* ServiceName = NULL;
for (int i = strlen(filepath); i > 0; i--)
{
if (filepath[i - 1] == '\\')
{
ServiceName = &filepath[i];
break;
}
}
for (int i=0;i<strlen(ServiceName);i++)
{
if (ServiceName[i] == '.')
{
char* a = (char*)malloc(12);
ZeroMemory(a,12);
memcpy(a, ServiceName, i);
ServiceName = a;
break;
}
}
SC_HANDLE hSc = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSc) return FALSE;
SC_HANDLE hService = OpenServiceA(hSc, ServiceName, SC_MANAGER_ALL_ACCESS);
if (hService != 0)
{
DeleteService(hService);
hService = NULL;
}
hService = CreateServiceA(hSc,
ServiceName,
ServiceName,
SC_MANAGER_ALL_ACCESS,
SERVICE_FILE_SYSTEM_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
FilePath,
"FSFilter Activity Monitor",
NULL,
"FltMgr",
NULL,
NULL
);
if (hService != 0)
{
HKEY hkey = NULL;
char* regpath = (char*)malloc(0x100);
ZeroMemory(regpath,0x100);
memcpy(regpath, "SYSTEM\\CurrentControlSet\\Services\\",
strlen("SYSTEM\\CurrentControlSet\\Services\\"));
strcat(regpath, ServiceName);
strcat(regpath,"\\Instances");
hkey = NULL;
RegCreateKeyA(HKEY_LOCAL_MACHINE,
regpath,
&hkey);
if (hkey != NULL)
{
RegSetValueExA(hkey,
"DefaultInstance",
NULL,
REG_SZ,
(const byte*)ServiceName,
strlen(ServiceName));
RegFlushKey(hkey);
RegCloseKey(hkey);
hkey = NULL;
strcat(regpath, "\\");
strcat(regpath, ServiceName);
RegCreateKeyA(HKEY_LOCAL_MACHINE,
regpath,
&hkey);
if (hkey != NULL)
{
RegSetValueExA(hkey,
"Altitude",
NULL,
REG_SZ,
(const byte*)"324000",
strlen("324000"));

int Flags = 0;
RegSetValueExA(hkey,
"Flags",
NULL,
REG_DWORD,
(const byte*)&Flags,
4);
RegFlushKey(hkey);
RegCloseKey(hkey);
hkey = NULL;
}
}
BOOL flag = StartServiceA(hService, 0, 0);
if (flag == TRUE)
{
printf("启动服务成功!\r\n");
flag = TRUE;
}
else
{
printf("启动服务失败Error:%d\r\n",GetLastError());
flag = FALSE;
}
CloseServiceHandle(hService);
CloseServiceHandle(hSc);
hService = NULL;
hSc = NULL;
if (flag == TRUE)
{
return TRUE;
}
}
if (!hService)
{
CloseServiceHandle(hService);
}
if (!hSc)
{
CloseServiceHandle(hSc);
}
return FALSE;
}

2.FltGetFileNameInformation
FltParseFileNameInformation(nameInfo);
1: kd> dt nameInfo
Local var @ 0xffffb206b99640f8 Type _FLT_FILE_NAME_INFORMATION*
0xffffb709`30418e30
  +0x000 Size             : 0x78
  +0x002 NamesParsed     : 0xf 'FltParseFileNameInformation()后为0xf 之前是0'
  +0x004 Format           : 1
  +0x008 Name             : _UNICODE_STRING
"\Device\HarddiskVolume2\Windows\System32\cmd.exe"
  +0x018 Volume           : _UNICODE_STRING "\Device\HarddiskVolume2"
  +0x028 Share           : _UNICODE_STRING ""
  +0x038 Extension       : _UNICODE_STRING "exe" '()后有'
  +0x048 Stream           : _UNICODE_STRING ""
  +0x058 FinalComponent   : _UNICODE_STRING "cmd.exe" '()后有'
  +0x068 ParentDir       : _UNICODE_STRING "\Windows\System32\" '()后有'

You might also like