如何用Python提取.NET可执行文件的Main函数代码?
我有一个C# .NET可执行文件样本,在DnSpy等反汇编器中显示结构如下:
->executable_name `->PE `->Type References `->References `->{ } - `->qCaVAPJGIk `-> OltkKtykOO `->Base Type and Interface `->OltkKtykOO(): void... `->GetProcAddress.... `-> ... `-> ... `-> Main()
请问能否通过Python读取该.exe文件,解析并获取Main函数的代码?
我尝试使用pefile和capstone模块但未成功,仅能通过以下代码提取嵌入资源,无法解析程序函数:
import pefile import clr clr.AddReference("System.Reflection") clr.AddReference("System") from System.IO import StreamReader clr.AddReference("System.IO") from System.Reflection import Assembly def extract_embedded_resource(assembly_path, resource_name, output_file): try: # Load the assembly from the specified path assembly = Assembly.LoadFile(assembly_path) # Get all the embedded resources within the loaded assembly for resource in assembly.GetManifestResourceNames(): if resource == resource_name: # Open the embedded resource stream resourceStream = assembly.GetManifestResourceStream(resource) if resourceStream is not None: try: # Read the content of the resource streamReader = StreamReader(resourceStream) content = streamReader.ReadToEnd() # Optionally, write the content to an output file with open(output_file, "w") as f: f.write(content) print(f"Resource '{resource_name}' extracted to '{output_file}'") return # Exit function after extracting the resource finally: # Ensure the stream is closed resourceStream.Close() # If resource is not found print(f"Resource '{resource_name}' not found in the assembly.") except Exception as e: print(f"Error extracting resource: {e}")
我用capstone编写的代码也未能找到任何与Main相关的内容:
from capstone import * def extract_main_function_code(pe_path): # Load the PE file pe = pefile.PE(pe_path) print(dir(pe)) # Iterate over the PE sections for section in pe.sections: # Check if the section contains executable code if section.Characteristics & 0x20: # Extract the code from the section code_offset = section.VirtualAddress code_size = section.SizeOfRawData code_data = section.get_data(code_offset, code_size) # Initialize Capstone disassembler md = Cs(CS_ARCH_X86, CS_MODE_32 if pe.FILE_HEADER.Machine == 0x014c else CS_MODE_64) # Disassemble the code for insn in md.disasm(code_data, code_offset): # Check if the disassembled instruction is the start of the 'main' function if 'main' in insn.op_str: # Print the disassembled instruction print(f"Address: 0x{insn.address:08x} \t {insn.mnemonic} {insn.op_str}") # Close the PE file pe.close()
你的问题核心在于对.NET可执行文件结构的误解:.NET程序编译后生成的是IL中间语言字节码,而非原生x86/x64机器指令。pefile仅能解析PE文件的外层结构,capstone是针对原生机器指令的反汇编工具,自然无法识别.NET的IL代码,因此找不到Main函数。
要在Python中解析.NET程序的IL代码并提取Main函数,可采用以下两种方法:
方法一:利用pythonnet调用.NET反射API(推荐)
你已经用到了pythonnet(即clr模块),可以扩展其功能,直接读取程序集中的类型和方法,获取IL字节码或反编译后的代码。
提取IL字节码示例
import clr clr.AddReference("System.Reflection") clr.AddReference("System") from System.Reflection import Assembly, BindingFlags def get_main_function_il(assembly_path): try: # 加载目标程序集 assembly = Assembly.LoadFile(assembly_path) # 遍历所有类型,查找包含静态Main方法的类型(C#入口通常为静态Main) for type in assembly.GetTypes(): main_method = type.GetMethod( "Main", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ) if main_method is not None: print(f"找到Main方法,所属类型:{type.FullName}") # 获取方法的IL字节码并以十六进制格式输出 il_bytes = main_method.GetMethodBody().GetILAsByteArray() print("IL字节码(十六进制):") print(' '.join([f"{byte:02x}" for byte in il_bytes])) return print("未找到Main方法") except Exception as e: print(f"解析出错:{e}") # 调用示例 get_main_function_il("你的程序路径.exe")
反编译为可读C#代码
若需要将IL转换为可读性更强的C#代码,可以使用DnSpy背后的反编译引擎ICSharpCode.Decompiler:
- 先通过NuGet安装该库,或下载对应的
ICSharpCode.Decompiler.dll文件 - 扩展代码如下:
import clr clr.AddReference("ICSharpCode.Decompiler") clr.AddReference("System.Reflection") clr.AddReference("System") from ICSharpCode.Decompiler.CSharp import CSharpDecompiler from System.Reflection import Assembly, BindingFlags from System.IO import FileStream, FileMode def decompile_main_function(assembly_path): try: # 以流方式加载程序集(避免文件锁定) with FileStream(assembly_path, FileMode.Open) as fs: decompiler = CSharpDecompiler(fs, None) # 遍历类型查找Main方法 assembly = Assembly.LoadFile(assembly_path) for type in assembly.GetTypes(): main_method = type.GetMethod( "Main", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ) if main_method is not None: print(f"反编译Main方法(所属类型:{type.FullName}):") # 反编译方法为C#代码字符串 decompiled_code = decompiler.DecompileAsString(main_method) print(decompiled_code) return print("未找到Main方法") except Exception as e: print(f"反编译出错:{e}") # 调用示例 decompile_main_function("你的程序路径.exe")
方法二:使用dnlib库解析
dnlib是DnSpy使用的.NET程序集解析库,可通过pythonnet加载dnlib.dll实现解析。核心思路是遍历模块、类型,定位Main方法并提取IL或反编译,操作逻辑与反射API类似,但对混淆后的程序集支持更好。
为什么你的capstone代码无效?
.NET可执行文件的PE入口是.NET运行时的引导函数(如corerun.dll或mscoree.dll中的函数),而非你的业务代码Main方法。Main方法以IL形式存储在PE的.text或.netmodule区段中,capstone无法识别IL指令格式,自然找不到包含"main"的操作数。
内容的提问来源于stack exchange,提问作者user21955070

