内存编译C#文件代码无效问题排查及RunPE等替代方案咨询
Why Your Current Code Isn't Executing the Expected Logic
The issue here is super straightforward: you're creating an instance of the Program class, but you never actually invoke the static Main method that contains your file-writing and console output logic.
When you call results.CompiledAssembly.CreateInstance("Program"), you're just instantiating the class (though since Main is static, you don't even need an instance). The Main method won't run automatically unless you explicitly call it via reflection.
Here's the fixed version of your code:
var param = new CompilerParameters { GenerateExecutable = false, IncludeDebugInformation = false, GenerateInMemory = true }; param.ReferencedAssemblies.Add("System.dll"); param.ReferencedAssemblies.Add("System.Xml.dll"); param.ReferencedAssemblies.Add("System.Data.dll"); param.ReferencedAssemblies.Add("System.Core.dll"); param.ReferencedAssemblies.Add("System.Xml.Linq.dll"); var codeProvider = new CSharpCodeProvider(); var results = codeProvider.CompileAssemblyFromFile(param, @"C:\Users\xxx\Desktop\code.txt"); if (results.Errors.HasErrors) { foreach (var error in results.Errors) { Console.WriteLine(error); } } else { // Get the Program type from the compiled assembly var programType = results.CompiledAssembly.GetType("Program"); // Find the static Main method (with string[] parameter) var mainMethod = programType.GetMethod("Main", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic); // Invoke the method (pass null for instance since it's static, and an empty string array as args) mainMethod.Invoke(null, new object[] { new string[0] }); }
Alternative: RunPE Method (In-Memory PE Execution)
First, let's clarify: RunPE is different from runtime compilation. Runtime compilation turns source code into IL and executes it in-process, while RunPE loads a pre-compiled PE (EXE/DLL) into memory and executes it, often by injecting into a target process or running it without writing to disk.
Here's a simplified example of a basic RunPE implementation (note: this requires P/Invoke and works on Windows only):
using System; using System.Diagnostics; using System.Runtime.InteropServices; class RunPESample { [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out uint lpNumberOfBytesWritten); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId); [DllImport("kernel32.dll")] private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); const uint MEM_COMMIT = 0x1000; const uint MEM_RESERVE = 0x2000; const uint PAGE_EXECUTE_READWRITE = 0x40; static void Main() { // Replace with your PE file bytes (read from disk or embed as resource) byte[] peBytes = System.IO.File.ReadAllBytes(@"C:\Path\To\Your\Target.exe"); // Create a suspended process to inject into var processStartInfo = new ProcessStartInfo("notepad.exe") { CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false }; var process = Process.Start(processStartInfo); process.Suspend(); // Allocate memory in the target process IntPtr remoteMem = VirtualAllocEx(process.Handle, IntPtr.Zero, (uint)peBytes.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Write the PE bytes to the allocated memory WriteProcessMemory(process.Handle, remoteMem, peBytes, (uint)peBytes.Length, out _); // Start a remote thread to execute the PE entry point IntPtr thread = CreateRemoteThread(process.Handle, IntPtr.Zero, 0, remoteMem, IntPtr.Zero, 0, out _); WaitForSingleObject(thread, uint.MaxValue); process.Resume(); } }
Note: This is a basic example—real-world RunPE requires parsing the PE header to find the entry point, handling relocation tables, and other low-level details. For production use, you'd need to add error handling and proper PE parsing.
Automating Entry Point Detection (No Hardcoded Class Names)
To avoid specifying the class name every time, you can scan the compiled assembly for any type that has a static Main method (the standard entry point for .NET apps). Here's how to implement that:
else { var assembly = results.CompiledAssembly; // Iterate through all types in the assembly foreach (var type in assembly.GetTypes()) { // Look for a static Main method (supports both public and private) var mainMethod = type.GetMethod("Main", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, null, new[] { typeof(string[]) }, // Match the Main method signature with string[] args null); if (mainMethod != null) { // Invoke the found Main method mainMethod.Invoke(null, new object[] { new string[0] }); break; // Stop after finding the first valid entry point } } }
This code will automatically find and execute any Main method in the compiled assembly, just like a .NET runtime would when launching an EXE.
内容的提问来源于stack exchange,提问作者dewina thrice

