You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测Windows PE可执行文件是原生代码还是托管代码?

如何程序化区分PE文件的原生代码与托管代码

要判断PE文件是原生代码还是托管代码(.NET/C#/Mono等),核心是检查PE可选头数据目录表中的CLR Runtime Header条目,具体实现步骤如下:

1. 定位PE文件的关键结构

所有操作基于小端字节序(PE格式的标准字节序):

  • 读取DOS头(文件起始处)的e_lfanew字段(偏移0x3C),这是一个4字节整数,指向PE签名(PE\0\0)的偏移位置。
  • 跳转到PE签名位置,验证签名后,跳过4字节签名,读取后续20字节的COFF头:
    • COFF头的SizeOfOptionalHeader字段(偏移0x14,2字节整数)表示可选头的长度。
    • COFF头的Machine字段(偏移0x0,2字节整数)可区分x86(0x14C)/x64(0x8664)架构,你已经熟悉这部分。

2. 定位数据目录表中的CLR Runtime Header条目

数据目录表包含16个条目,其中第15个条目(索引从0开始为14)对应CLR运行时头:

  • PE32(32位PE):可选头长度为224字节,数据目录表从可选头的0x60偏移开始,每个条目占8字节(4字节VirtualAddress + 4字节Size)。
  • PE32+(64位PE):可选头长度为240字节,数据目录表从可选头的0x70偏移开始,每个条目占16字节(8字节VirtualAddress + 8字节Size)。

3. 判定托管/原生代码

读取第14索引的条目值:

  • 如果VirtualAddress和Size均不为0,则该PE文件是托管代码(包括纯托管和混合模式的托管+原生代码)。
  • 如果VirtualAddress和Size均为0,则该PE文件是原生代码。

程序化实现示例(伪代码)

def is_managed_pe(file_path):
    with open(file_path, 'rb') as f:
        # 读取DOS头的e_lfanew
        f.seek(0x3C)
        pe_offset = int.from_bytes(f.read(4), byteorder='little')
        
        # 验证PE签名
        f.seek(pe_offset)
        if f.read(4) != b'PE\x00\x00':
            return False
        
        # 读取COFF头的SizeOfOptionalHeader和Machine
        f.seek(pe_offset + 4)
        coff_header = f.read(20)
        size_of_optional_header = int.from_bytes(coff_header[20:22], byteorder='little')
        machine = int.from_bytes(coff_header[0:2], byteorder='little')
        
        # 定位数据目录表
        is_pe32_plus = (machine == 0x8664)
        if is_pe32_plus:
            data_dir_offset = pe_offset + 4 + 20 + 0x70
            entry_size = 16
        else:
            data_dir_offset = pe_offset + 4 + 20 + 0x60
            entry_size = 8
        
        # 跳转到CLR Runtime Header条目(索引14)
        f.seek(data_dir_offset + 14 * entry_size)
        if is_pe32_plus:
            virtual_addr = int.from_bytes(f.read(8), byteorder='little')
            size = int.from_bytes(f.read(8), byteorder='little')
        else:
            virtual_addr = int.from_bytes(f.read(4), byteorder='little')
            size = int.from_bytes(f.read(4), byteorder='little')
        
        return (virtual_addr != 0) and (size != 0)

内容的提问来源于stack exchange,提问作者hippietrail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 19:59:55