freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

.Net内存加载与卸载探讨
绿盟科技 2023-09-11 13:55:44 123686

0x00 简介

随着攻防博弈的发展,无文件攻击在各项场景中出现频率越来越高,研究无文件攻击的实现与检测对于抵御外部攻击有着重要的意义。.Net程序集的内存加载是无文件攻击实施的手段之一,目前现有的加载技术大多适用于Net FrameWork框架, 本文针对.Net Core和.Net FrameWork中的加载方式和卸载方式进行了分析探讨。

0x01 加载

.Net程序集加载应用很普遍,像冰蝎中aspx马,就是使用Assembly.Load来加载各种功能的程序集从而实现webshell控制。yso.net工具中有条反序列化利用链通过Assembly.load直接加载恶意程序集。asp.net内存马也可以通过Assembly.load注入,还可以通过多阶段加载方式来进行防御规避。

根据微软官方文档,.NET中的程序集加载方式有下面几种。

Assembly.Load

此方式将程序集加载到当前上下文

Assembly.LoadFrom

此方式将程序集加载到当前上下文

Assembly.LoadFile

此方式将程序集加载到当前上下文

Assembly.ReflectionOnlyLoad AssemblyReflectionOnlyLoadFrom 程序集加载到反射上下文,无法执行代码
AppDomain .CreateInstance

创建指定类型的实例

AppDomain.CreateInstanceAndUnwrap 返回创建的实例的代理, 把其他应用程序域中的变量传到当前的应用程序域
Type.GetType
AppDomain.Load
AssemblyLoadContext.Load

.Net Core中的新增,允许加载同一程序集的不同版本到不同上下文

以上加载方式,Assembly.Load和AssemblyLoadContext.Load支持字节流加载。

Assembly.LoadFrom 加载dll文件及依赖项。它还可以从远程加载程序集,支持http、file等协议,但从.Net FrameWork 4后,默认禁止远程加载。此外,如果目标程序集已经加载过,LoadFrom()不会重新进行加载。

Assembly.LoadFile 仅加载dll不加载依赖项。

AssemblyLoadContext.Load是Net core中为替代Appdomain提出的新的进程内隔离解决方案。Load会第一次解析、加载和返回程序集。如果第一次返回null,则加载程序会尝试将程序集加载到默认上下文AssemblyLoadContext.Default中。如果AssemblyLoadContext.Default无法解析程序集,则原始AssemblyLoadContext将有第二次机会解析程序集。运行时引发Resolving事件,我们可以自定义Resolving事件来编写依赖项解析行为。下面这个例子,将Test.dll加载到新的上下文中,Test.dll会打印出当前的上下文名字。

AssemblyLoadContext assemblyLoadContext =  new AssemblyLoadContext("New1",true); //true允许unload
var assem = assemblyLoadContext.LoadFromStream(new MemoryStream( File.ReadAllBytes("Test.dll")));
aa.GetType("Test.Test").GetMethod("Run").Invoke(null,null);
ass

运行结果如下,可以看到,程序集加载到了新的上下文中

如果只是想在其他Appdomain执行方法,可以调用domain.DoCallBack()。CrossAppDomainDelegate是委托类型,签名如下

举个例子,运行该代码,可以把字节码加载到新的Appdomain中

public static void Main(){
    AppDomain domain = AppDomain.CreateDomain("MyDomain");
    domain.DoCallBack(new CrossAppDomainDelegate(CallbackTest));
}

public static void CallbackTest()
{
    Assembly.Load(System.IO.File.ReadAllBytes(@"E.dll"));
   var s =  AppDomain.CurrentDomain.FriendlyName;
}

0x02 卸载

在.NET Core 中,System.Runtime.Loader.AssemblyLoadContext类处理程序集的卸载。在Net FrameWork中,如果我们想要卸载单独的程序集,那是做不到的,想要在 .NET Framework 中卸载程序集,必须卸载包含它的所有应用程序域。假设内存加载了一个恶意程序集到新的应用程序域,来看一下应用程序域如何被卸载。卸载应用程序域使用AppDomain.Unload 方法。

下面看一段代码,这段代码的作用是弹窗,编译成程序集E.dll

namespace E
{
    public class E
    {
        public void Run()
        {
            try
            {
                System.Windows.Forms.MessageBox.Show("Run","Title");
            }
            catch (Exception)
            {
            }
        }
    }
}

下面代码读取了E.dll的字节码,新创建一个Appdomain,然后以Load(byte[])方法加载程序集E.dll到新应用程序域当中,反射调用Run方法,最后卸载Appdomain。

byte[] bytes = File.ReadAllBytes("E.dll"); // dll  bytes
AppDomain domain = AppDomain.CreateDomain("Test");
    Assembly assembly = domain.Load(bytes);
    MethodInfo method = assembly.GetType("E.E").GetMethod("Run");
    if (method != null)
    {
        object o = assembly.CreateInstance("E.E");
        try
        {
            method.Invoke(o, null);
        }
        catch (TargetInvocationException ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

看起来没什么错误,但一旦运行后,就会报下面异常。

其原因是Appdomain.Load(byte[])加载的程序集,在Appdomain间是无法共享类型信息的。如果默认Appdomain没有加载这个程序集,那么就不会有关于此程序集的类型信息,第二个Appdomian用Load(Byte[])加载后,要把程序集对象传递到默认Appdomain中,但默认Appdomain找不到此对象的信息,所以会报错。解决方式就是使用跨应用程序域访问。

一般来说,有两种方式进行跨域通信,marshalbyrefobject和Serializable,前者是引用传递,后者是值传递。看个引用传递的例子。首先创建Proxy类继承MarshalByObject,MarshalByObject类属于基元类型,在默认Appdomain中存在。然后调用CreateInstanceAndUnwrap得到Proxy类的代理类。CreateInstanceAndUnwrap方法是CreateInstance和Objecthandle.Unwrap方法的结合,Proxy类实际上在MyDomain中实例化,然后通过Objecthandle.Unwrap包装后传递给默认Appdomain,这样便实现了跨AppDomain的对象传递。之后Proxy类的方法调用,实际上也是在Mydomain中执行的。

void Main(){
    byte[] classbytes =  File.ReadAllBytes("E.dll");
    AppDomainSetup domaininfo = new AppDomainSetup();
    domaininfo.ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    System.Security.Policy.Evidence adevidence = AppDomain.CurrentDomain.Evidence;
    AppDomain currentDomain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo);
    Type type = typeof(Proxy);
    Proxy p = (Proxy)currentDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, type.FullName);
    p.LoadAssembly(classbytes);
    AppDomain.Unload(currentDomain);
}

public class Proxy: MarshalByObject{
     public Object LoadAssembly(byte[] bytes)
        {
            Console.WriteLine(Appdomain.Currentdomain.FriendlyName);
            Assembly assembly =  AppDomain.CurrentDomain.Load(bytes);
            MethodInfo method = assembly.GetType("E.E").GetMethod("Run");
            if (method != null)
            {
                object o = assembly.CreateInstance("E.E");
                try
                {
                    var res = method.Invoke(o, null);
                    return res;
                }
                catch (TargetInvocationException ex)
                {
                    Console.WriteLine(ex.ToString());
                  
                }
            } 
            return null;
        }
}

运行结果如下

0x03 总结

本文主要针对.Net Core和.Net FrameWork框架下的程序集加载技术进行了总结,针对程序集的卸载技术进行了分析,指出了使用无文件加载后,如何正确卸载程序集的方式。

附录 参考链接

https://learn.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext?view=net-7.0

https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/understanding-assemblyloadcontext

https://learn.microsoft.com/en-us/dotnet/api/system.runtime.remoting.objecthandle?view=net-7.0

https://3gstudent.github.io/%E4%BB%8E%E5%86%85%E5%AD%98%E5%8A%A0%E8%BD%BD.NET%E7%A8%8B%E5%BA%8F%E9%9B%86(Assembly.Load)%E7%9A%84%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90

# .Net # .NET Framework # .NET Core
本文为 绿盟科技 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
M01N Team
绿盟科技 LV.10
绿盟科技官方账号
  • 1637 文章数
  • 335 关注者
《网络安全2025:冲刺“十四五”》发布
2025-04-01
《2025网络安全趋势报告》发布
2025-04-01
攻防演练竟成“翻车现场”,是哪个环节没盯住?
2025-04-01
文章目录