在win10内存中,很多win7中的结构体都被微软废除了,取而代之的使用了一个全局的变量来存放内存相关信息。看了很多中文的资料,发现对win10内存的资料介绍甚少,仅有的几篇也是我豆总在看雪发表的,不知道是大哥们对这个不屑一顾,还是不屑一顾,win10版本马上都停止维护了,但是在我看来比较有用的知识点还是没有人点出,(英文的资料还是有的),windows虽然日薄西山把,但也不至于这么日薄西山吧。这篇文章就来说下win10 内存的一些知识点。
这篇文章算是纯逆向所得,如果出现有明显错误的观点,欢迎指教,并请直接说出你认为的正确观点及证据。
0.背景知识介绍
MI_SYSTEM_INFORMATION :MiState的类型就是它。具体这样:
引子:win10内存区域如何获取
其实到这里依旧是拾人牙慧,只不过是从符号的角度来讲,说明当初豆总说的那个mark标记在哪里。如果只是单纯的想要判断那些地址是在那个内存区域,到这里基本就不用看了,下面讲解的都是为什么能够从这个成员变量得到内存区域枚举值。
_MI_SYSTEM_VA_ASSIGNMENT
{
VOID* BaseAddress; //0x0 ULONGLONG
NumberOfBytes; //0x8
};
MiInitializeSystemVa 函数是负责填充 SystemVaRegions 结构体的关键函数,也是 windows内存区域能够动态初始化的关键。
在初始化这个bitmap之后, MiInitializeSystemVa 会调用 MiAssignTopLevelRanges ,而 MiAssignTopLevelRanges 是梦最初的地方。
ps: 如果想要通过windbg 调试MmInitSystem 的0xff阶段的话,可能需要进行 额外的设置。
嗯。没错,这个Base 和 SystemVaRegions 有着千丝万缕的关系。
其中我定义的Base 的结构体为:
struct MyBase_VIsibleType
{
unsigned __int32 index;
unsigned __int32 randseed;
unsigned __int64 BaseAddress;
unsigned __int64 Length;
};
int64 MiAssignSystemVa(ULONG NumberToFind, unsigned int a2)
v19 = (*p_Length + 0x7FFFFFFFFFi64) & 0xFFFFFF8000000000ui64;
*p_Length = v19;
vaBaseaddress = MiAssignSystemVa(v19 >> 0x27, a1);
MiAssignSystemVa 的主要功能是取到已经初始化好的MiState.SystemVa.SystemVaAssignment 和 已经随机化好的MiState.SystemVa.SystemVaAssignmentHint,通过RtlFindClearBitsAndSet 去查找到符合满足条件的位图索引。
最后,得到位图的索引值 ,通过 index – 0x100 ,通过左移0x27,得到baseaddress。
5. MI_ASSIGNED_REGION_TYPES 和 MI_SYSTEM_VA_TYPE之间的转换
MiConvertAssignedRegionToVaType 的原理就是内建了一张表,通过 输入MI_ASSIGNED_REGION_TYPES类型的枚举值,然后根据表 输出 对应的MI_SYSTEM_VA_TYPE类型的值。
在win11中,MiConvertAssignedRegionToVaType被封装到了MiSetSystemRegionTypes(i)中,各个小版本之间这张表可能也不同。
win10
__int64 __fastcall MiConvertAssignedRegionToVaType(int a1)
{
int v1; // ecx
int v2; // ecx
int v3; // ecx
int v5; // ecx
int v6; // ecx
int v7; // ecx
int v8; // ecx
if ( a1 > 7 )
{
v5 = a1 - 8;
if ( v5 )
{
v6 = v5 - 1;
if ( !v6 )
return 4i64;
v7 = v6 - 1;
if ( v7 )
{
v8 = v7 - 1;
if ( v8 )
{
if ( v8 != 1 )
return 0i64;
return 12i64;
}
else
{
return 15i64;
}
}
else
{
return 1i64;
}
}
else
{
return 14i64;
}
}
else if ( a1 == 7 )
{
return 2i64;
}
else if ( a1 )
{
v1 = a1 - 1;
if ( v1 )
{
v2 = v1 - 1;
if ( v2 )
{
v3 = v2 - 1;
if ( v3 )
{
if ( v3 != 2 )
return 0i64;
return 4i64;
}
return 9i64;
}
else
{
return 8i64;
}
}
else
{
return 6i64;
}
}
else
{
return 5i64;
}
}
win 11
__int64 __fastcall MiConvertAssignedRegionToVaType(int a1)
{
int v1; // ecx
int v2; // ecx
int v3; // ecx
int v4; // ecx
int v6; // ecx
int v7; // ecx
int v8; // ecx
int v9; // ecx
int v10; // ecx
if ( a1 > 8 )
{
v6 = a1 - 9;
if ( !v6 )
return 14i64;
v7 = v6 - 1;
if ( v7 )
{
v8 = v7 - 1;
if ( !v8 )
return 1i64;
v9 = v8 - 1;
if ( !v9 )
return 15i64;
v10 = v9 - 1;
if ( !v10 )
return 16i64;
if ( v10 != 1 )
return 0i64;
return 12i64;
}
return 4i64;
}
if ( a1 == 8 )
return 2i64;
if ( !a1 )
return 4i64;
v1 = a1 - 1;
if ( !v1 )
return 5i64;
v2 = v1 - 1;
if ( !v2 )
return 6i64;
v3 = v2 - 1;
if ( !v3 )
return 8i64;
v4 = v3 - 1;
if ( !v4 )
return 9i64;
if ( v4 != 1 )
return 0i64;
return 17i64;
}
6. SystemVaRegions与SystemVaType的建立关联
for ( i = 0; i < 0xD; i ++ ) // SystemVaRegions与SystemVaType有多少个 数组成员 就循环多少次
{
BaseAddress = systemVaRegions[i].BaseAddress;
Length = systemVaRegions[i].NumberOfBytes; // 和填充长度有关
offset = ((BaseAddress >> 0x27) & 0x1FF) - 0x100; //这个offset 眼熟不,和MiGetSystemRegionType
// 的计算数组的偏移是一样的。
paddinglength = Length>> 0x27
value = MiConvertAssignedRegionToVaType(i); //枚举类型转换
for ( j = Length >> 0x27; j; --j )
{
Systemvatype[offset] = value // 对Systemvatype填充转换后的枚举类型
offset ++ ;
}
}
((a1 >> 0x27) & 0x1FF) – 0x100背后的设计理念:
a1 为 一个内核的虚拟地址, a1 >> 0x27 是在取 pml4的值, (pml4 & 0x1ff) 这个是 确保能取到 pml4索引,因为pml4 占位 9bit,最终 pml4的index – 0x100 得出最终的索引。因为虚拟地址是连续的,假设存在 nopagedpool 的内存地址 A, A必定满足 大于等于nopagedpool.baseaddress,小于等于
nopagedpool.baseaddress+nopagedpool.length,如果使用我们的符号表示:
systemVaRegions[0].BaseAddress<= A <= systemVaRegions[0].BaseAddress +systemVaRegions[0].NumberOfBytes , 所以 A地址代表的pml4索引必定Systemvatype中代表nopagedpool的连续为分区内。
7. 后话
1.SystemVaType、SystemVaRegions、MI_ASSIGNED_REGION_TYPES 和 MI_SYSTEM_VA_TYPE基本类型。
2.MmInitSystem函数初始化流程。
3.windows内核内存的区域的动态随机划分的本质是什么。
4.MI_ASSIGNED_REGION_TYPES 和 MI_SYSTEM_VA_TYPE之间转换的关系。
5.SystemVaRegions与SystemVaType是如何建立关联的。
6.((a1 >> 0x27) & 0x1FF) – 0x100背后的设计理念,以及为什么可以通过MiGetSystemRegionType得出指定虚拟地址的内存类型。
(ps:使用MiState 有一个小坑, 正式版本的 MI_SYSTEM_INFORMATION 微软提供的有些许问题,需要自己改动,如果自己仔细思考的话,解决这个问题应该不在话下)。
看雪ID:青丝梦
https://bbs.kanxue.com/user-home-724114.htm
# 往期推荐
球分享
球点赞
球在看
点击阅读原文查看更多
原文始发于微信公众号(看雪学苑):Win10和Win11内存区域划分及动态随机的本质