二进制文件加载研究

LoadDll ->LdrLoadDll

GetProcAddr ->  LdrGetProcAddr 

位于操作系统服务接口层, 根本不用uchar这些字符串, 而是使用unicode_string字符串,我想是和以前windows刚开始使用ansi字符有关

所以 multibytetowidechar的实现原理和rtlinitializeString也是不相同的

Lodlibrary ->  ldrLoadDll

loadlibrary是属于kernel32的内容, 但是真正的实现体是在  ntdll.dll里面, ldr系列api

NTSTATUS出现在ntdll里面, 看来服务层已经包含了驱动层的某些api了

UnicodeString工作在系统服务层级, 一般开发者用不到他

NT系列api都是win32子系统的api

上次我写的判断用户态指针的语句获得圆满成功, 目前判断是否是用户空间的指针的标准做法如下

#define ProbeForWriteGenericType(Ptr, Type)                                    \
    do {                                                                       \
        if ((ULONG_PTR)(Ptr) + sizeof(Type) - 1 < (ULONG_PTR)(Ptr) ||          \
            (ULONG_PTR)(Ptr) + sizeof(Type) - 1 >= (ULONG_PTR)MmUserProbeAddress) { \
            ExRaiseAccessViolation();                                          \
        }                                                                      \
        *(volatile Type *)(Ptr) = *(volatile Type *)(Ptr);                     \
    } while (0)

ULONG64 MmUserProbeAddress = 0x7FFFFFF0000ULL;

用户态指针是不能超过  0x7FFFFFF0000, 这里我也有一个疑问, 那就是用户空间的最后一页是干什么用的呢?

ob系列指针是工作在内核层, 注意了

ob系列管理的是内核对象

user系列管理的是用户对象

以下是 内核对象的管理层的对象结构, 对象结构其实还有一个存储层的对象结构,  我想为了便于管理, 微软付出的可真多

typedef struct _OBJECT_DIRECTORY
{
    struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[NUMBER_HASH_BUCKETS];
#if (NTDDI_VERSION < NTDDI_WINXP)
    ERESOURCE Lock;
#else
    EX_PUSH_LOCK Lock;
#endif
#if (NTDDI_VERSION < NTDDI_WINXP)
    BOOLEAN CurrentEntryValid;
#else
    struct _DEVICE_MAP *DeviceMap;
#endif
    ULONG SessionId;
#if (NTDDI_VERSION == NTDDI_WINXP)
    USHORT Reserved;
    USHORT SymbolicLinkUsageCount;      //上层的引用计数
#endif
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;

typedef struct _OBJECT_HEADER
{
    LONG PointerCount;
    union
    {
        LONG HandleCount;
        volatile PVOID NextToFree;
    };
    POBJECT_TYPE Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;
    union
    {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    QUAD Body;
} OBJECT_HEADER, *POBJECT_HEADER;

内核中管理对象的基本结构

现在我们来对比下用户空间中管理用户对象的基本结构

typedef struct _USER_HANDLE_ENTRY
{
    void          *ptr;          /* pointer to object */
    union
    {
        PVOID pi;
        PTHREADINFO pti;          // pointer to Win32ThreadInfo
        PPROCESSINFO ppi;         // pointer to W32ProcessInfo
    };
    unsigned char  type;         /* object type (0 if free) */
    unsigned char  flags;
    unsigned short generation;   /* generation counter */
} USER_HANDLE_ENTRY, * PUSER_HANDLE_ENTRY;

大致上我们可以预先得出这样的判断:  用户空间的对象数据较内核数据少了  安全描述符、引用计数啥的

同样用户空间有进程和线程的概念比较强烈,

ObpLookupObjectName 这个函数的实现很简单:

RootHandle  -》  句柄转成RootDirectory    -> 转成 object 搞定

内核对象存储层的对象结构

typedef struct _HANDLE_TABLE_ENTRY
{
    union
    {
        PVOID Object;
        ULONG_PTR ObAttributes;
        PHANDLE_TABLE_ENTRY_INFO InfoTable;
        ULONG_PTR Value;
    };
    union
    {
        ULONG GrantedAccess;
        struct
        {
            USHORT GrantedAccessIndex;
            USHORT CreatorBackTraceIndex;
        };
        LONG NextFreeTableEntry;
    };
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;

RtlAllocHeap 是通过ZwAllocateVirtualMemory 来进行分配内存的, 那么内核模式中的ExAllocPageNoZero系列的api和这个又是什么关系呢, 接下来看

LdrpLoadModule  ---->  准备进入内核级, 所以我们调用了 NtMapViewOfSection  -> 准备进入内核级中的内存管理级, 即由我们的内存管理代言人, 即 内核中mm组 组长来帮我们处理这个事情 MmMapViewOfSection  -》  内存分配执行者的小兵呢,这时section小弟就出现了,好,交给你吧 MmFindGapTopDown -》 section找好了房间后, 就根据exe中section来对号安排内存安置啦-》 交由region小兵来负责

posted @ 2011-08-05 10:45  麦峰强  阅读(671)  评论(0编辑  收藏  举报