zoukankan      html  css  js  c++  java
  • 某APT组织样本混淆技巧解密与实现-compressed压缩转换成base64

    投放方式是一个zip包,里面是一个快捷方式文件xxx.lnk。xxx.lnk里的内容是mshta运行网址转向的xx.hta文件。中途还要收集一波点开人员的机器信息。

    hta里的加密形式遇见了好几次都是手工解的。效率很低,而且相关的样本很多。使用Python脚本进行解密是一个不错的选择。

    两种混淆加密形式原理

    • JS动态调用转成base64编码的C# DLL函数
    • C# DLL调用转成base64编码的compressed压缩数据

    JS动态调用转成base64编码的C# DLL函数

    网上用的比较多的方法,把C#写的DLL转成base64,然后动态调用DLL类里的方法。

    Jvascript代码如下:

    //动态调整窗口大小
    window.resizeTo(0,0);
    // 设置.net执行的版本
    function setversion() {
    var shell = new ActiveXObject('WScript.Shell');
    ver = 'v4.0.30319';
    try {
    shell.RegRead('HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\');
    } catch(e) { 
    ver = 'v2.0.50727';
    }
    shell.Environment('Process')('COMPLUS_Version') = ver;
    // Base64转码后的C# DLL代码赋值到da变量。
    var pa = "rk...DLL base64 CODE....";
    // 指定入口类名
    var fire = 'C# DLL类名';
    
    // Base64解码函数
    function base64ToStream(b) {
    	var enc = new ActiveXObject("System.Text.ASCIIEncoding");
    	var length = enc.GetByteCount_2(b);
    	var ba = enc.GetBytes_4(b);
    	var transform = new ActiveXObject("System.Security.Cryptography.FromBase64Transform");
    	ba = transform.TransformFinalBlock(ba, 0, length);
    	var ms = new ActiveXObject("System.IO.MemoryStream");
    	ms.Write(ba, 0, (length / 4) * 3);
    	ms.Position = 0;
    	return ms;
    }
    
    //执行函数
    try {
        // 设置.net运行环境
        setversion();
        // 解码Base64
        var Streamline = base64ToStream(pa);
        // 调用库
        var fireline = new ActiveXObject('System.Runtime.Serialization.For'+'matters.Binary.BinaryFormatter');
        var arraylist = new ActiveXObject('System.Collections.ArrayList');
        // 反序列化解开base64后的代码
        var d = fireline.Deserialize_2(Streamline);
        arraylist.Add(undefined);
        // 动态调用,fire变量里是C# DLL的类
        var realObject = d.DynamicInvoke(arraylist.ToArray()).CreateInstance(fire);
        // 调用类的方法
        realObject.类方法(参数1,参数2)} catch (e) {}
    finally{window.close();}
    
    

    解码python

    Input.txt文件里放加密后的代码,Output2.dat是输出的解密代码。

    ## 第一阶段 文件Base64解码,提取MZ文件头到末尾部分,拖到ILSpy就可以看C#代码。
    
    with open('Input.txt', 'r') as input_file :
        decoded = base64.b64decode(input_file.read())
        peIndex = decoded.find(b'x4Dx5A')
        outData = decoded[peIndex:]
        with open('Output2.dat', 'wb') as Outputfile:
            Outputfile.write(outData)
    

    C# DLL调用转成base64后的compressed压缩数据

    C# DLL从Javascript代码里读取被压缩转码成Base64代码的EXE,然后执行。

    举个例子,编码后的文本:

    EgAAAB+LCAAAAAAABAALycgsVgCi4vzcVAWFktSKEgC9n1/fEgAAAA==
    

    解码后的原文:

    This is some text
    

    使用以下的C#函数做解密:

    当然代码里是不应该用Encoding.Default.GetString的。对于中文来说,不同的语言编码占的字节数是不同的。攻击者显然没有注意这点,直接调用的默认编码,中文系统无法顺利运行。

    // 解压缩函数
    public string decompressData(string compressedText)
    {
    	byte[] array = Convert.FromBase64String(compressedText);
    	string @string;
    	using (MemoryStream memoryStream = new MemoryStream())
    	{
    		int num = BitConverter.ToInt32(array, 0);
    		memoryStream.Write(array, 4, array.Length - 4);
    		byte[] array2 = new byte[num];
    		memoryStream.Position = 0L;
    		using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
    		{
    			gZipStream.Read(array2, 0, array2.Length);
    		}
    		@string = Encoding.Default.GetString(array2);
    	}
    	return @string;
    }
    
    

    解码python

    Input.txt文件里放加密后的代码,Output2.dat是输出的解密代码。

    # 第二阶段文件Base64解码,解compressed压缩
    
    with open('Input.txt', 'r') as input_file :
        decoded = base64.b64decode(input_file.read())
        struct.unpack('i', decoded[:4])[0]
        with open('Output2.dat', 'wb') as Outputfile:
            Outputfile.write(gzip.decompress(decoded[4:]))
    

    加密GZIP Compress/Decompress in C#/JAVA

    既然有解密,那就肯定有加密代码。

    Program.cs

    using System;
    using System.IO;
    using System.IO.Compression;
    using System.Text;
    
    class Program {
    
        private static string Compress(string text)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(text);
            MemoryStream ms = new MemoryStream();
            using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
            {
                zip.Write(buffer, 0, buffer.Length);
            }
    
            ms.Position = 0;
            MemoryStream outStream = new MemoryStream();
    
            byte[] compressed = new byte[ms.Length];
            ms.Read(compressed, 0, compressed.Length);
    
            return Convert.ToBase64String(compressed);
        }
    
    
        public static string Decompress(string compressedText)
        {
            byte[] gZipBuffer = Convert.FromBase64String(compressedText);
            using (var memoryStream = new MemoryStream())
            {
                int dataLength = BitConverter.ToInt32(gZipBuffer, 0);
                memoryStream.Write(gZipBuffer, 0, gZipBuffer.Length);
    
                var buffer = new byte[dataLength];
    
                memoryStream.Position = 0;
                using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
                {
                    gZipStream.Read(buffer, 0, buffer.Length);
                }
    
                return Encoding.UTF8.GetString(buffer);
            }
        }
    
    
        public static void Main(string[] args) {
    
            string original = "Mary had a little LAMB";
            string compressed = Compress(original);
            string decompressed = Decompress(compressed);
    
            
            Console.WriteLine("Original String: "+original);
            Console.WriteLine("Compressed String: "+compressed);
            Console.WriteLine("Decompressed String: "+decompressed);
    
        }
    }
    

    Program.java

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.Base64;
    import java.util.zip.GZIPInputStream;
    import java.util.zip.GZIPOutputStream;
    
    
    /**
     * Created by salar on 10/3/16.
     */
    public class Program {
    
    
        private static String Compress(String data) {
            try {
    
                // Create an output stream, and a gzip stream to wrap over.
                ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length());
                GZIPOutputStream gzip = new GZIPOutputStream(bos);
    
                // Compress the input string
                gzip.write(data.getBytes());
                gzip.close();
                byte[] compressed = bos.toByteArray();
                bos.close();
    
                // Convert to base64
                compressed = Base64.getEncoder().encode(compressed);
    
                // return the newly created string
                return new String(compressed);
            } catch(IOException e) {
    
                return null;
            }
        }
    
    
    
        private static String Decompress(String compressedText) throws IOException {
    
            // get the bytes for the compressed string
            byte[] compressed = compressedText.getBytes("UTF8");
    
            // convert the bytes from base64 to normal string
            Base64.Decoder d = Base64.getDecoder();
            compressed = d.decode(compressed);
    
            // decode.
            final int BUFFER_SIZE = 32;
    
            ByteArrayInputStream is = new ByteArrayInputStream(compressed);
    
            GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
    
            StringBuilder string = new StringBuilder();
    
            byte[] data = new byte[BUFFER_SIZE];
    
            int bytesRead;
    
            while ((bytesRead = gis.read(data)) != -1)
            {
                string.append(new String(data, 0, bytesRead));
            }
            gis.close();
            is.close();
            return string.toString();
        }
    
    
    
    
        public static void main(String args[]) {
    
    
            String input = "Mary had a little LAMB";
    
    
            String compressed = Compress(input);
    
            String uncompressed = null;
            try {
                uncompressed = Decompress(compressed);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            System.out.println("Original String: " + input);
            System.out.println("Compressed String: "+compressed);
            System.out.println("Uncompressed String: "+uncompressed);
    
    
    
        }
    }
    

    参考

  • 相关阅读:
    iOS渠道分包2种模式之包内注入文件分包(iOS13验证签名问题)
    iOS13 新特性简介
    OC 字典dictionaryWithObjectsAndKeys报错
    博客迁移指南
    block内部实现原理(三)
    block内部实现原理(二)
    block内部实现原理(一)
    iOS:记一次Mac OS X 测试版(OS X EL Capitan) APP发布过程
    iOS: El Capitan Beta 下 Xcode6.4 不显示Scheme菜单
    iOS: UIWebView 中不加载图片(即浏览器常见的无图模式)
  • 原文地址:https://www.cnblogs.com/17bdw/p/12371872.html
Copyright © 2011-2022 走看看