首页
论坛
课程
招聘
如何保护自己的代码?给自己的代码添加NoChange属性
2022-9-26 10:49 15655

如何保护自己的代码?给自己的代码添加NoChange属性

2022-9-26 10:49
15655

什么是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)
{

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
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_DOS_HEADER       pDosHdr = (PIMAGE_DOS_HEADER)pInfo->lpBaseOfDll;
pNtHeaders = (PIMAGE_NT_HEADERS64)((PUCHAR)pInfo->lpBaseOfDll + pDosHdr->e_lfanew);
 
sectionData dwSection;
DWORD nSize = 0;
PIMAGE_SECTION_HEADER pFirstSection = (PIMAGE_SECTION_HEADER)(pNtHeaders + 1);
if (IMAGE32(pNtHeaders))
    pFirstSection = (PIMAGE_SECTION_HEADER)((PIMAGE_NT_HEADERS32)pNtHeaders + 1);
 
for (PIMAGE_SECTION_HEADER pSection = pFirstSection;
    pSection < pFirstSection + pNtHeaders->FileHeader.NumberOfSections;
    pSection++)
{
    if (IMAGE_SCN_MEM_EXECUTE & pSection->Characteristics)
    {
        nSize += pSection->Misc.VirtualSize;
    }
    else
    {
        dwSection.VirtualAddress = pSection->VirtualAddress;
        dwSection.VirtualSize = pSection->Misc.VirtualSize;
        dwSection.nProtection = BBCastSectionProtection(pSection->Characteristics, FALSE);
        pSectionData.emplace_back(dwSection);
    }
}
if (nSize > 0x10000)
{
    nSize = nSize & (~0xffff);
    nSize += 0x10000;
    if ((pSectionData.at(0).VirtualAddress+pSectionData.at(0).VirtualSize) >= nSize)
    {
        pSectionData.at(0).VirtualAddress = nSize;
 
        pSectionData.at(0).VirtualSize = pSectionData.at(1).VirtualAddress - pSectionData.at(0).VirtualAddress ;
    }
    else
    {
        pSectionData.~vector();
    }
}
else
{
    nSize = 0;
}
 
return nSize;

}

 

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;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (characteristics & IMAGE_SCN_MEM_DISCARDABLE)
{
    dwResult = PAGE_NOACCESS;
}
else if (characteristics & IMAGE_SCN_MEM_EXECUTE)
{
    if (characteristics & IMAGE_SCN_MEM_WRITE)
        dwResult = noDEP ? PAGE_READWRITE : PAGE_EXECUTE_READWRITE;
    else if (characteristics & IMAGE_SCN_MEM_READ)
        dwResult = noDEP ? PAGE_READONLY : PAGE_EXECUTE_READ;
    else
        dwResult = noDEP ? PAGE_READONLY : PAGE_EXECUTE;
}
else
{
    if (characteristics & IMAGE_SCN_MEM_WRITE)
        dwResult = PAGE_READWRITE;
    else if (characteristics & IMAGE_SCN_MEM_READ)
        dwResult = PAGE_READONLY;
    else
        dwResult = PAGE_NOACCESS;
}
 
return dwResult;

}


[2022冬季班]《安卓高级研修班(网课)》月薪两万班招生中~

最后于 2022-9-26 11:02 被一夜酒狂编辑 ,原因:
收藏
点赞7
打赏
分享
最新回复 (11)
雪    币: 226
活跃值: 活跃值 (2086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yy虫子yy 活跃值 2022-9-26 17:53
2
0
某p就是这样阻止内存写入的
雪    币: 2328
活跃值: 活跃值 (1749)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
gamehack 活跃值 2022-9-26 21:31
3
0
感谢分享,回头好好研究一下
雪    币: 391
活跃值: 活跃值 (715)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wowocock 活跃值 1 2022-9-27 10:23
4
0
所有的内存保护,只能保护线性地址,不能保护物理地址。归根还得EPT吧。
雪    币: 10112
活跃值: 活跃值 (10371)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
pureGavin 活跃值 2 2022-9-27 10:32
5
0
感谢分享
雪    币: 297
活跃值: 活跃值 (270)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
一夜酒狂 活跃值 2022-9-27 13:20
6
0
wowocock 所有的内存保护,只能保护线性地址,不能保护物理地址。归根还得EPT吧。
你的概念怎么奇奇怪怪的,为什么会有EPT出现。给你举个例子,当你调用VirtualProtect置某段内存位PAGE_NOACCESS的时候。pte->pfn被微软额外加工过的 同时pte->属性位都是无效的
雪    币: 25
活跃值: 活跃值 (1362)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tmflxw 活跃值 2022-9-30 02:26
7
0
支持32位程序吗?
雪    币: 2955
活跃值: 活跃值 (2232)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Mr.hack 活跃值 2022-10-2 11:19
8
1
人家直接去r0修改pte了
雪    币: 31
活跃值: 活跃值 (140)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MaMy 活跃值 2022-10-14 22:51
9
0
https://github.com/changeofpace/Self-Remapping-Code
雪    币: 1705
活跃值: 活跃值 (1639)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小希希 活跃值 2022-10-24 10:13
10
0
mark
雪    币: 41
活跃值: 活跃值 (575)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wx_不够 活跃值 2022-11-23 20:14
11
0
....了解一下VAD
雪    币: 126
活跃值: 活跃值 (690)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Oxygen1a1 活跃值 2022-11-23 20:21
12
0
顺便提一嘴,你这个好像是只能保护Mapped内存吧?
MmSecureVirtualMemoryEx这个已经文档化了,可以锁Private内存
但是这个函数本质上是改的 VadFlags.Nochange
游客
登录 | 注册 方可回帖
返回