什么是NoChange?可以看一看这篇文章,自己去感受一下 https://bbs.pediy.com/thread-225080.htm
。添加NoChange 根本目的就是使VirtualProtect(ZwProtectVirtualMemory)这个函数失败。
废话少说,直接进入主题,介绍一下我的整体思路。
第一步:调用 ZwCreateSection 告诉我操作系统我要 SizeOfImage大小的物理内存。
第二步:调用 ZwMapViewOfSection映射内存,然后拷贝 RtlCopyMemory(pViewBase, pInfo->lpBaseOfDll, pInfo->SizeOfImage); 此时这个物理页已经有内容了。
第三步:ZwUnmapViewOfSection(NtCurrentProcess(), pInfo->lpBaseOfDll);
第四步:接下来就是最!最!最!最重要的就是 如何把物理内存重新 映射到指定地址并且加你想要的NoChange属性。我将着重说明一下如何映射(不要嫌我啰嗦):
如果 你完全明白 nCanMapSize 的大小是怎么来的,那么你可以跳过。
涉及一点PE的基础基址,直接看图吧
根据图片可以 ntdll.dll的代码段的最大只能是 0x0117000。
那么 nCanMapSize = 0x0117000,可以吗? 答案是肯定不行的。
需要说明一点:ZwMapViewOfSection(BaseAddress=ntdll.base,nSize=0x0117000)这个函数是会成功,但是接下来映射ntdll的其他数据段起始基址是:BaseAddress=(ntdll.base+0x0117000),此时ZwMapViewOfSection会失败。为什么呢,Msdn告诉我们答案:
坑了我很长时间,其实他的是意思就是 当你BaseAddress指定了值,那么他必须是0x10000的倍数而不是0x1000(靠,我也不知道为什么),因此nCanMapSize必须是 0x120000(当你出现了程序崩溃失败的时候,异常的时候,一般都是这个值的问题),自此我们完成了 关键的步骤喽。顺带看一下某pubg他是怎么重新映射ntdll的
需要注意一点:当你映射ntdll的时候,这个时候你已经卸载他 ZwMapViewOfSection已经不存在,你需要做点额外工作,自己去中断进内核。 。
如果喜欢,请给我一键三连。
方便你们C+V测试
DWORD AddDllNoChange::calcTextSize(MODULEINFO* pInfo,vector<sectionData>& pSectionData)
{
BOOL __stdcall AddDllNoChange::AddNoChange(MODULEINFO* pInfo)
{
BOOL bRet = FALSE;
if (!pInfo) return bRet;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
HANDLE hSection
=
0
;
LARGE_INTEGER cbSectionOffset
=
{};
PVOID pViewBase
=
NULL;
SIZE_T cbViewSize
=
0
;
NTSTATUS ntstatus
=
0
;
vector<sectionData> dwSectionData;
ULONG nCanMapSize
=
0
;
nCanMapSize
=
calcTextSize(pInfo,dwSectionData);
if
(nCanMapSize <
0x10000
) {
return
bRet;
}
ULONG64 nNextMapAddress
=
nCanMapSize
+
(ULONG64)pInfo
-
>lpBaseOfDll;
ULONG nNextMapSize
=
pInfo
-
>SizeOfImage
-
nCanMapSize;
LARGE_INTEGER cbSectionSize
=
{
0
};
cbSectionSize.QuadPart
=
pInfo
-
>SizeOfImage;
ntstatus
=
ZwCreateSection(
&hSection,
SECTION_ALL_ACCESS,
NULL,
&cbSectionSize,
PAGE_EXECUTE_READWRITE,
SEC_COMMIT,
NULL);
pViewBase
=
0
;
cbSectionOffset.QuadPart
=
0
;
cbViewSize
=
0
;
ntstatus
=
ZwMapViewOfSection(
hSection,
NtCurrentProcess(),
&pViewBase,
0
,
0
,
&cbSectionOffset,
&cbViewSize,
ViewUnmap,
0
,
PAGE_EXECUTE_READWRITE);
if
(NT_SUCCESS(ntstatus))
{
RtlCopyMemory(pViewBase, pInfo
-
>lpBaseOfDll, pInfo
-
>SizeOfImage);
/
/
把内容写入section后,就把当前得 地址 卸载
ntstatus
=
ZwUnmapViewOfSection(NtCurrentProcess(), pViewBase);
ntstatus
=
ZwUnmapViewOfSection(NtCurrentProcess(), pInfo
-
>lpBaseOfDll);
if
(NT_SUCCESS(ntstatus))
{
/
/
映射 代码节区 全给他 PAGE_EXECUTE_READ并且加上 SEC_NO_CHANGE
pViewBase
=
pInfo
-
>lpBaseOfDll;
cbSectionOffset.QuadPart
=
0
;
cbViewSize
=
nCanMapSize;
ntstatus
=
ZwMapViewOfSection(
hSection,
NtCurrentProcess(),
&pViewBase,
0
,
0
,
&cbSectionOffset,
&cbViewSize,
ViewUnmap,
SEC_NO_CHANGE,
PAGE_EXECUTE_READ);
if
(NT_SUCCESS(ntstatus))
{
/
/
映射数据节区 给PAGE_READWRITE
pViewBase
=
(PVOID)nNextMapAddress;
cbSectionOffset.QuadPart
=
nCanMapSize;
cbViewSize
=
nNextMapSize;
ntstatus
=
ZwMapViewOfSection(
hSection,
NtCurrentProcess(),
&pViewBase,
0
,
0
,
&cbSectionOffset,
&cbViewSize,
ViewUnmap,
0
,
PAGE_READWRITE);
if
(NT_SUCCESS(ntstatus) && !dwSectionData.empty())
{
/
/
这个只是 还原数据段 的内存属性 你不喜欢可以不执行
vector<sectionData> ::iterator it
=
dwSectionData.begin();
SIZE_T tmpSize
=
0
;
DWORD OldAccessProtection
=
0
;
ULONG prot
=
0
;
PVOID pAddr
=
NULL;
for
(it; it !
=
dwSectionData.end();
+
+
it)
{
if
(it
-
>nProtection
=
=
PAGE_READONLY)
{
prot
=
it
-
>nProtection;
pAddr
=
(PVOID)((ULONG64)pInfo
-
>lpBaseOfDll
+
it
-
>VirtualAddress);
tmpSize
=
it
-
>VirtualSize;
ZwProtectVirtualMemory(NtCurrentProcess(), &pAddr, &tmpSize, prot, &OldAccessProtection);
}
}
}
}
}
}
if
(hSection) {
CloseHandle(hSection);
}
return
bRet;
}
ULONG AddDllNoChange::BBCastSectionProtection( IN ULONG characteristics, IN BOOLEAN noDEP )
{
ULONG dwResult = PAGE_NOACCESS;