MiCreatePebOrTeb函数注释

MiCreatePebOrTeb 函数注释

修改订正日期:2009-7-29

 

 

今天看以前关于 FS 寄存器的文章 , 看到说进程的 PEB 的地址总是 0x7FFDF000. 于是写了一个程序来验证一下 . 但是程序运行之后发现却不是这样的 :PEB 地址总是不停的变化的 , 是随机的 . 怎么回事呢 ? 找到 WRK 的代码 ,

PEB 地址的分配在函数 MiCreatePebOrTeb 函数 , 于是仔细阅读了这个函数 , 才知道了怎么回事 .

  晚上在 baidu 上搜了一下 , 发现早就有人发表文章说明这个情况了 :Windows xp SP2 开始 ( 包括 SP2), 就开始随机返回 PEB 的地址了 .

  下面是我的代码注释 :

 NTSTATUS
MiCreatePebOrTeb (
    IN PEPROCESS TargetProcess,
    IN ULONG Size,
    OUT PVOID *Base
    )

/*++

Routine Description:

    This routine creates a TEB or PEB page within the target process.

Arguments:

    TargetProcess - Supplies a pointer to the process in which to create
                    the structure.

    Size - Supplies the size of the structure to create a VAD for.

    Base - Supplies a pointer to place the PEB/TEB virtual address on success.
           This has no meaning if success is not returned.

Return Value:

    NTSTATUS.

Environment:

    Kernel mode, attached to the specified process.

--*/

{
    PMMVAD_LONG Vad;
    PETHREAD Thread;
    NTSTATUS Status;

    Thread = PsGetCurrentThread ();

    //
    // Allocate and initialize the Vad before acquiring the address space
    // and working set mutexes so as to minimize mutex hold duration.
    //

    Vad = (PMMVAD_LONG) ExAllocatePoolWithTag (NonPagedPool,
                                               sizeof(MMVAD_LONG),
                                               'ldaV');

    if (Vad == NULL) {
        return STATUS_NO_MEMORY;
    }

    Vad->u.LongFlags = 0;

    Vad->u.VadFlags.CommitCharge = BYTES_TO_PAGES (Size);
    Vad->u.VadFlags.MemCommit = 1;
    Vad->u.VadFlags.PrivateMemory = 1;
    Vad->u.VadFlags.Protection = MM_READWRITE;

    //
    // Mark VAD as not deletable, no protection change.
    //

    Vad->u.VadFlags.NoChange = 1;
    Vad->u2.LongFlags2 = 0;
    Vad->u2.VadFlags2.OneSecured = 1;
    Vad->u2.VadFlags2.LongVad = 1;
    Vad->u2.VadFlags2.ReadOnly = 0;

    //
    // Get the address creation mutex to block multiple threads from
    // creating or deleting address space at the same time and
    // get the working set mutex so virtual address descriptors can
    // be inserted and walked.
    //

    LOCK_ADDRESS_SPACE (TargetProcess);


    //
    // Find a VA for the PEB on a page-size boundary.
    //
下面这段代码是关键, 专门针对PEB 分配的. 从这段代码可以看出是从Size 的大小是否为

// 0x210 来判断是否为PEB. PEB 是随机出现的.
//

if (Size == sizeof(PEB)
#if defined(_WIN64)
        || (Size == sizeof(PEB32))
#endif
    ) {
        PVOID HighestVadAddress;

           LARGE_INTEGER CurrentTime;

            HighestVadAddress = (PVOID) ((PCHAR)MM_HIGHEST_VAD_ADDRESS + 1);
            //MM_HIGHEST_VAD_ADDRESS=MM_HIGH_USER_ADDRESS – (64 * 1024)

            //HighestVadAddress = 0x7FFE0000

            KeQueryTickCount (&CurrentTime);

            CurrentTime.LowPart &= ((X64K >> PAGE_SHIFT) - 1);  

                                  // (X64K >> PAGE_SHIFT) – 1 = 0Xf, 下面就从这个随机数中取值。
           if (CurrentTime.LowPart <= 1) {
             CurrentTime.LowPart = 2;
           }
          //
          // Select a varying PEB address without fragmenting the address space.
          //
          HighestVadAddress = (PVOID) ((PCHAR)HighestVadAddress - (CurrentTime.LowPart << PAGE_SHIFT));
          //PAGE_SHIFT = 12.
          //
上面可以看出.PEB 地址要求从14 个地址中取出一个: 0x7FFE0000 – 2<<12 /

//0x7FFE0000– 3<<12/ 0x7FFE0000– 4<<12 …0x7FFE0000– 15<<12

          if (MiCheckForConflictingVadExistence (TargetProcess, HighestVadAddress,

 (PVOID) ((PCHAR) HighestVadAddress + ROUND_TO_PAGES (Size) - 1)) == FALSE) {

//MiCheckForConflictingVadExistence 函数用来检查指定进程的地址中从

//HighestVadAddress (PCHAR) HighestVadAddress +

//ROUND_TO_PAGES (Size) – 1 是否已经分配了. 如果没有分配, 返回FALSE. 则表

// 示分配成功了.
          // Got an address ...
          //
        *Base = HighestVadAddress;
        goto AllocatedAddress;
        }
    }
//
分配TEB, 或者上面分配PEB 不成功, 就到下面的分配流程了.
// 下面这个函数从(PCHAR)MM_HIGHEST_VAD_ADDRESS + 1,( 值为7FFE0000)

// 向下分配一个空闲页( 大小为0x1000).
    Status = MiFindEmptyAddressRangeDown (&TargetProcess->VadRoot,
                                          ROUND_TO_PAGES (Size),
                                          ((PCHAR)MM_HIGHEST_VAD_ADDRESS + 1),
                                          PAGE_SIZE,
                                          Base);

    if (!NT_SUCCESS(Status)) {

        //
        // No range was available, deallocate the Vad and return the status.
        //

        UNLOCK_ADDRESS_SPACE (TargetProcess);
        ExFreePool (Vad);
        return Status;
    }
//
好了, 到此为止,PEBTEB 的内存空间已经分配好了. 下面进行一些后续操作.
AllocatedAddress:

    //
    // An unoccupied address range has been found, finish initializing the
    // virtual address descriptor to describe this range.
    //

    Vad->StartingVpn = MI_VA_TO_VPN (*Base);
    Vad->EndingVpn = MI_VA_TO_VPN ((PCHAR)*Base + Size - 1);

    Vad->u3.Secured.StartVpn = (ULONG_PTR)*Base;
    Vad->u3.Secured.EndVpn = (ULONG_PTR)MI_VPN_TO_VA_ENDING (Vad->EndingVpn);

    Status = MiInsertVadCharges ((PMMVAD) Vad, TargetProcess);

    if (!NT_SUCCESS (Status)) {

        //
        // A failure has occurred.  Deallocate the Vad and return the status.
        //

        UNLOCK_ADDRESS_SPACE (TargetProcess);
        ExFreePool (Vad);

        return Status;
    }

    LOCK_WS_UNSAFE (Thread, TargetProcess);

    MiInsertVad ((PMMVAD) Vad, TargetProcess);

    UNLOCK_WS_UNSAFE (Thread, TargetProcess);

    UNLOCK_ADDRESS_SPACE (TargetProcess);

    return Status;
}

 

网上有一篇文章 < 系统维护技巧 :windows xp sp2 溢出保护 > 上说到了 PEB 地址随机出现 , 该文把 0x210 看成是一个 flag . 从上面的源码我们可出 0x210 PEB 的结构大小 .MiCreatePebOrTeb 函数就是根据此大小来判读是 PEB 还是 TEB 的分配 . 不管是 PEB 还是 TEB, 系统最终都是分配一个 1 PAGE.

 

下面是这个过程的内存示意图:

 



参考文献 :
<
系统维护技巧 :windows xp sp2 溢出保护 >
<
加密与解密 > 第三版 P402

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值