DOTNET_EnableWriteXorExecute引起另外一个异常

前言

本篇来看下有:DOTNET_EnableWriteXorExecute(简称:W^E)导致的另外一个异常现象,实际上不是异常。因为:W^E,开启了就是主内存映射,只不过断点不能够在内存映射范围内。

概括

1.引起的异常
.Net7及其以后是默认开启的W^E,而.Net6则是默认关闭的。如下所示:

.Net7:
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableWriteXorExecute, W("EnableWriteXorExecute"), 1, "Enable W^X for executable memory.");


.Net6
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableWriteXorExecute, W("EnableWriteXorExecute"), 0, "Enable W^X for executable memory.");

如下例子:

static void Main(string[] args)
{
   //Task tk= Task.CompletedTask;
    Console.ReadLine();         
    //TextWriter tr= Console.Out;
    Console.WriteLine("Hello, World!"); // 12行
    Program pm=new Program();
}

这也就导致了Debug.Net7的时候则出现了问题,如下Windbg.Net7里面:

0:007> !bpmd Program.cs:12
MethodDesc = 00007FFEE719EF18
Setting breakpoint: bp 00007FFEE70D06CA [ConsoleApp3.Program.Main(System.String[])]
Adding pending breakpoints...
0:007> g
Breakpoint 0 hit
ConsoleApp3!ConsoleApp3.Program.Main+0x1a:
00007ffe`e70d06ca 48b9d82040f4f8020000 mov rcx,2F8F44020D8h
0:000> g
(560.44c0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
00007ffe`e70d0938 0000            add     byte ptr [rax],al ds:00007ffe`e70d0938=00

这里有个c0000005的异常,这里可以看到它是执行异常。它其实不是BUG,而是.Net7里面W^E环境变量的作用的结果。

看下它的ASM

00007ffe`e70d0938 0000                 add     byte ptr [rax], al
00007ffe`e70d093a 0000                 add     byte ptr [rax], al
00007ffe`e70d093c 0000                 add     byte ptr [rax], al
00007ffe`e70d093e 0000                 add     byte ptr [rax], al

异常的地方是地址,00007ffee70d0938 而Main函数的函数头地址则是:00007ffee70d06ca.可以看到这两个地址非常近。而函数头上下左右偏移约0x1000字节范围内,基本上都属于内存映射。所以如果在Console.WriteLine下了断点,地址即是在内存映射范围内下了断点,地址00007ffee70d0938赋值不上,导致了异常。

2.异常的地址哪里来的
通过上面知道了异常是断点+内存映射引起的。
异常的地址是00007ffe`e70d0938,它是被下面代码调用:

DoCall:
        call    qword ptr [rbx+CallDescrData__pTarget]     ; call target function

这个DoCall函数是调用所有托管函数进行编译,注意它不是编译之后的地址而是之前。CallDescrData__pTarget是函数描述结构体MethodDesc的偏移位的地址指向的值。

rbx寄存器是一个结构体,CallDescrData__pTarget是这个结构体里面的一个变量。那么CallDescrData__pTarget哪里来的呢?

一般来说,CLR的内存结构链如下所示:

PreCode->MethodDescChunk->MethodDesc

它们在内存中依次从左至右排列的。

这个CallDescrData__pTarget最先的值就是PreCode的某个地址。后这个地址被赋值为MethodDesc的某个地址偏移位置指向的值的地方(PreCode某个地址取代原有值),这里看下它是如何在PreCode地址里面赋值的?

void *UnlockedLoaderHeap::UnlockedAllocAlignedMem_NoThrow(size_t  dwRequestedSize,
                                                          size_t  alignment,
                                                          size_t *pdwExtra
                                                          COMMA_INDEBUG(_In_ const char *szFile)
                                                          COMMA_INDEBUG(int  lineNum))
{
    void *pResult;
    pResult = m_pAllocPtr;
#ifdef _DEBUG
    BYTE *pAllocatedBytes = (BYTE *)pResult;
    ExecutableWriterHolderNoLog<void> resultWriterHolder;
    if (IsExecutable())
    {
        resultWriterHolder.AssignExecutableWriterHolder(pResult, dwSize - extra);
        pAllocatedBytes = (BYTE *)resultWriterHolder.GetRW();
    }
}

注意看,m_pAllocPtr就是PreCode地址里面的值。可以看到这里微软比较贴心的通过#ifdef_DEBUG来让读者能够看得清楚这里是内存映射。
所以这里也就很清楚了,PreCode的值就是m_pAllocPtr.而PreCode的地址则是DoCall调用的函数

【rbx+CallDescrData__pTarget】取的值。它的来源是PreCode。因为内存映射范围内进行托管函数调用的编译,又在内存映射范围(Console.WriteLine)下了断点,即异常。

结尾

作者:江湖评谈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
dotnet_reactor是一个用于对.NET应用程序进行保护和加密的工具,可以防止未经授权的访问和逆向工程。以下是dotnet_reactor下载的步骤: 1. 首先,在您的浏览器中,打开dotnet_reactor的官方网站。 2. 导航到网站的下载页面,通常可以在主页上找到一个类似于“下载”或“产品”页面的链接。 3. 在下载页面上,您可能会看到不同版本的dotnet_reactor可供选择。选择与您正在开发的.NET框架版本兼容的正确版本。 4. 单击相应的下载按钮或链接。这将触发文件的下载,并将其保存到您的计算机上。 5. 下载完成后,找到并双击下载的文件。这将启动dotnet_reactor安装程序。 6. 根据安装程序的指示,选择适当的选项并完成安装过程。可能需要接受许可协议,并选择安装目录。 7. 安装完成后,您可以在开始菜单、桌面或指定的安装目录中找到dotnet_reactor的可执行文件。 8. 运行dotnet_reactor,它将打开一个用户界面,允许您选择要保护和加密的.NET应用程序,并配置其他选项。 9. 根据您的需求和dotnet_reactor的功能,进行必要的设置和配置。您可以选择加密、混淆代码,添加许可证功能等等。 10. 确认配置后,点击“保护”按钮或类似的按钮。dotnet_reactor将开始对选择的应用程序进行保护和加密。 11. 保护过程完成后,您将获得一个加密后的应用程序,该应用程序在运行时更难以破解和逆向工程。 请注意,下载dotnet_reactor之前,请确保您遵守软件许可证和相关法律的规定,并确保您有权使用和保护相关应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值