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小兵来负责