首页
社区
课程
招聘
如何保护自己的代码?给自己的代码添加NoChange属性
发表于: 2022-9-26 10:49 21499

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

2022-9-26 10:49
21499

什么是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;

}
ULONG AddDllNoChange::BBCastSectionProtection( IN ULONG characteristics, IN BOOLEAN noDEP )
{
ULONG dwResult = PAGE_NOACCESS;

}

 
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;
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;
 
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;
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后,就把当前得 地址 卸载

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-9-26 11:02 被一夜酒狂编辑 ,原因:
收藏
免费 10
支持
分享
最新回复 (11)
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
某p就是这样阻止内存写入的
2022-9-26 17:53
0
雪    币: 6084
活跃值: (5490)
能力值: ( LV5,RANK:65 )
在线值:
发帖
回帖
粉丝
3
感谢分享,回头好好研究一下
2022-9-26 21:31
0
雪    币: 405
活跃值: (2260)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
所有的内存保护,只能保护线性地址,不能保护物理地址。归根还得EPT吧。
2022-9-27 10:23
0
雪    币: 14492
活跃值: (17493)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2022-9-27 10:32
0
雪    币: 301
活跃值: (355)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
wowocock 所有的内存保护,只能保护线性地址,不能保护物理地址。归根还得EPT吧。
你的概念怎么奇奇怪怪的,为什么会有EPT出现。给你举个例子,当你调用VirtualProtect置某段内存位PAGE_NOACCESS的时候。pte->pfn被微软额外加工过的 同时pte->属性位都是无效的
2022-9-27 13:20
0
雪    币: 1510
活跃值: (3407)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
支持32位程序吗?
2022-9-30 02:26
0
雪    币: 3293
活跃值: (3888)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
人家直接去r0修改pte了
2022-10-2 11:19
1
雪    币: 12
活跃值: (418)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
https://github.com/changeofpace/Self-Remapping-Code
2022-10-14 22:51
0
雪    币: 1802
活跃值: (4000)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mark
2022-10-24 10:13
0
雪    币: 29
活跃值: (765)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
....了解一下VAD
2022-11-23 20:14
0
雪    币: 2134
活跃值: (5163)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
顺便提一嘴,你这个好像是只能保护Mapped内存吧?
MmSecureVirtualMemoryEx这个已经文档化了,可以锁Private内存
但是这个函数本质上是改的 VadFlags.Nochange
2022-11-23 20:21
0
游客
登录 | 注册 方可回帖
返回
//