IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    再谈Burp破解

    admin发表于 2016-05-16 12:41:15
    love 0

    0x01 Java反编译工具

    Java反编译提供了在线的反汇编方式,同时也给出几款反编译工具作为参考,罗列如下:
    1. Procyon
    https://bitbucket.org/mstrobel/procyon/wiki/Java%20Decompiler
    2. CFR
    http://www.benf.org/other/cfr/
    3. JD
    http://jd.benow.ca/
    4. Fernflower
    https://github.com/fesh0r/fernflower
    5. JAD(非开源)
    http://www.javadecompilers.com/jad

    0x02 反编译BurpLoader

    在Mac为了方便,我直接使用Jd-gui来载入Burploader.jar,但是很显然的能看到已经经过了混淆了。转换成字节码打开,如下:

    // Original Bytecode:
        //
        // 0: bipush 12
        // 2: anewarray Ljava/lang/String;
        // 5: dup
        // 6: iconst_0
        // 7: ldc “\u0002\u001bW\tY\u0002\”
        // 9: jsr 216
        // 12: aastore
        // 13: dup
        // 14: iconst_1
        // 15: ldc “2C\fBN\u0016Y\nV\u001c\u0007FER\u000f\b”
        // 17: jsr 216
        // 20: aastore
        // 21: dup
        // 22: iconst_2
        // 23: ldc “\u0004^\u0017A@5_\u0004C\u001a$^\u0017A”
        // 25: jsr 216
        // 28: aastore
        // 29: dup
        // 30: iconst_3
        // 31: ldc “*e\f\\\f\u0013X”
        // 33: jsr 216
        // 36: aastore
        // 37: dup
        // 38: iconst_4
        // 39: ldc “\u000bJ\f_”
        // 41: jsr 216
        // 44: aastore
        // 45: dup
        // 46: iconst_5
        // 47: ldc “II\u0010C\u001e”
        // 49: jsr 216

    根据乌云Drops的资料来看,混淆的算法依旧没变是Zelix KlassMaster(http://www.zelix.com/klassmaster/index.html),这个提问中同时提到了一些其他的 混淆器(http://stackoverflow.com/questions/13098606/decompiler-bytecode-and- obfuscators)。在参考链接Defcon的议题中也提到了这个混淆器的特征。我们这里用DirtyJoe(http://dirty- joe.com/)来帮反混出ZKM加密的字符串信息,使用其的Py脚本(http://dirty-joe.com/help /python_scripting.php)。
    打开DirtyJoe载入Burploader.class(先解压Burploader.jar),然后宣导Method的标签栏,中间有两项没有名字 的函数clinit,往下找可以找到ZKM的加密Key.然后在Constant Pool中找到加密过的常量的值,右键选择Run Python Script,载入ZKM的解密脚本,并修正Py代码中的Key值,则可以解出加密串的内容,如图所示:

    依次解出加密串,并尝试还原程序流程。我们来对比一下目前能下载到且没有混淆过的BurpLoader的代码(http://pan.baidu.com/share/link?shareid=442575&uk=2466540631),删减部分常量:

    package larry.lau;
    
    import burp.StartBurp;
    import java.lang.reflect.Field;
    import java.util.prefs.Preferences;
    import javax.swing.JOptionPane;
    
    public class BurpLoader
    {
      public static final String readme1 = "------------------------------------------";
      public static final String readme2 = "     x    ";
      public static final String readme3 = "     x     ";
      public static final String readme4 = "     x  ";
      public static final String readme5 = "    x ";
      public static final String readme6 = "     x";
      public static final String readme7 = "   larry_lau@163.com ";
      public static final String readme0 = "------------------------------------------";
      private static final String[] strData = {
        "a", 
        "b", 
        "c", 
        "d", 
        "e", 
        "f", 
        "g", 
        "h" };
      private static final String[] clzzData = { "burp.ecc", "burp.voc", "burp.jfc", 
        "burp.gtc", "burp.zi", "burp.q4c", "burp.pid", "burp.y0b" };
      private static final String[] fieldData = { "b", "b", "c", "c", "c", "b", "c", "c" };
      private static final String tip = "This program can not be used for commercial purposes!";
      private static final String errortip = "This program can only run with burpsuite_pro_v1.5.01.jar";
      private static final String[] keys = { "license1", "uG4NTkffOhFN/on7RT1nbw==" };
      private static final String[] vals = {
        "like base64 string", 
        "like base64 string" };
      
      public static void main(String[] args)
      {
        try
        {
          int ret = JOptionPane.showOptionDialog(null, "This program can not be used for commercial purposes!", "BurpLoader by larry_lau@163.com", 
            0, 2, null, new String[] { "I Accept", "I Decline" }, null);
          if (ret == 0)
          {
            for (int i = 0; i < clzzData.length; i++)
            {
              Class<?> clzz = Class.forName(clzzData[i]);
              Field field = clzz.getDeclaredField(fieldData[i]);
              field.setAccessible(true);
              
              field.set(null, strData[i]);
            }
            Preferences prefs = Preferences.userNodeForPackage(StartBurp.class);
            for (int i = 0; i < keys.length; i++)
            {
              String v = prefs.get(keys[i], null);
              if (!vals[i].equals(v)) {
                prefs.put(keys[i], vals[i]);
              }
            }
            StartBurp.main(args);
          }
        }
        catch (Exception e)
        {
          JOptionPane.showMessageDialog(null, "This program can only run with burpsuite_pro_v1.5.01.jar", "BurpLoader by larry_lau@163.com", 
            0);
        }
      }
    }

    再来对比我们混淆过的,且解出了字符串的版本(这里是1.6.37的Burp)。

    0x03 BurpLoader源码分析

    经过对比,整理出差不多的反汇编后的代码:

    // 
    // Decompiled by Procyon v0.5.30
    // 
    
    package larry.lau;
    
    import java.lang.reflect.Field;
    import java.io.InputStream;
    import java.security.CodeSource;
    import java.awt.HeadlessException;
    import java.awt.GraphicsEnvironment;
    import java.util.prefs.Preferences;
    import java.awt.Component;
    import javax.swing.JOptionPane;
    import java.security.MessageDigest;
    import javax.swing.UIManager;
    
    public class BurpLoader
    {
        public static final String readme0 = "Burp Suite is an integrated platform for performing security testing of web applications. ";
        public static final String readme1 = "If you like it, please try Free edition or <b>buy</b> Pro edition.";
        public static final String readme2 = "This loader is Free and CAN NOT be used for Commercial purposes!";
        public static final String readme3 = "If you bought it somewhere else, you should take action against the seller.";
        public static final String readme4 = "No exploiting and no malware in my code. Shaby is boring!";
        public static final String readme5 = "Usage:";
        public static final String readme6 = "1. you need a burpsuite_pro jar file.";
        public static final String readme7 = "2. add burpsuite_pro jar into classpath then run burploader";
        public static final String readme8 = "<ul><li>java -jar BurpLoader.jar</li>";
        public static final String readme9 = "<li>java -cp BurpLoader.jar;burpsuite_pro.jar larry.lau.BurpLoader</li>";
        public static final String readme10 = "<li>java -cp BurpLoader.jar:burpsuite_pro.jar larry.lau.BurpLoader</li></ul>";
        public static final String readme11 = "3. To Support headless mode, add -Djava.awt.headless=true into jvm arguments.";
        public static final String readme12 = "4. Any suggestions, let me know.";
        private static final String[] a; //stringdata 对应解密出密文的那一大堆
        private static final String[] b = {"llc" , "frb" , "dfd" ,"zud" ,"bdf", "uxh", "a7b" , "u6b" }; //classname数组
        private static final String[] c = {}; //fileddata数组
        private static final String[] d = {"license1", "uG4NTkffOhFN/on7RT1nbw=="}; // keys数组
        private static final String[] e = {"pQwzPmoS+nV4oph/ti7SdybjoUB9IWHt0BGBVS1kycSvYAn2zh0uJq9gCfbOHS4mrpBSDMCrw+Aw6t2wCDaKXMJoXejEZIvQifD7ev/ieLttU9OZmtQxiQvOezD/tIy96RrqBxRJQqO1M+cHUq0emgxViBsoFVklsQmr6ayz0rTcwz9sXYvE9N4LvQ7thuRKMaO49TJR+9sjImBql1kBGTOHsJCETT5Mh62lIzXUYnpKhnWi1IjmSYXhhQnHSrTJtPMnN4lc0W36TPXlqWE7KmcGSWrjNiEWMVJ8ez1jIk2J5kSD3dV3gokc2tAm3MeslXO39AhD3RCbXV4SzJNb9A==","CONSTANT_String : 6Oxo0eZXXJNgBSjf5x9U7CXRqLnEIQaqNhLHKcSKbabe//W7jgdzbDMQor2PE44WeyvBtJFh848jEZys6bvlyLN70lJi5wqkoXe+BtrTnpS3Y9+9ygkcaUleLj7/UPie18gUNblikWyctTG/IKCPKGPZSe4JuPclh3HH9FAcd4shrJmrcAhJYCTYOFO3bqxs0kIhcZKUBUJ/DG//UIFceegfGVijiBeM9K4xbR+HfxTIg49Pqa1JTNcoWqjeq1xewqd8Ovqt+J9Zrsn7XC1zy8XyK6U65vHBA6HY/h/2Li7sxatMzfGX8m8L3hiAx7eOKBBtFJj/8VnuVggQZodIPna6xhrBBIcA1YLrQ3EXxXDLlO5yVM/S+B7oFgYMgMd4"}; // values数组
        public static boolean f;
        public static boolean g;
        private static final String[] z = { "d0287d85d288c2af116e0d60878a8a24" , "This program can only run with burpsuite_pro_v1.6.37.jar", "burp.StartBurp",  "LNimbus" , "main", "/burp", "md5", "BurpLoader by larry_lau", "larry.lau.javax.swing.plaf.nimbus.NimbusLookAndFeel",
        "burpsuite_pro_v1.6.37.jar was corrupted!" , "burp." , "%02x"};
        
        static {} //error
        
        public static void main(final String[] array) {
            final boolean g = BurpLoader.g;
            try {
                try {
                    final String s = BurpLoader.z[8];
                    Class.forName(s); //实例化一个字符串为名称的类 http://blog.csdn.net/kaiwii/article/details/7405761
                    UIManager.installLookAndFeel(BurpLoader.z[3], s); //Swing用来设置外观与风格的相关函数
                }
                catch (ClassNotFoundException ex8) {}
                final Class<?> forName = Class.forName(BurpLoader.z[2]); //找不到那个外观类就实例化 burp.StartBurp 既BurpSuite的启动类
                
                //用md5验证了啥东西
                try {
                    MessageDigest messageDigest = null;
                Label_0086_Outer:
                    while (true) {
                        final CodeSource codeSource = forName.getProtectionDomain().getCodeSource(); //取CodeSource,一般配合getLocation使用取Jar包中的路径
                        final MessageDigest instance = MessageDigest.getInstance(BurpLoader.z[6]); //动态获取加密算法,这里是md5
                        final InputStream openStream = codeSource.getLocation().openStream(); //OpenStream()打开流以读取当前生成提供程序对象的虚拟路径。
                        final byte[] array2 = new byte[1024];
                        int read = 0;
                        while (true) {
                            while (true) {
                                Label_0094: {
                                    try {
                                        if (!g) {
                                            break Label_0094;
                                        }
                                    }
                                    catch (ClassNotFoundException ex) {
                                        throw ex;
                                    }
                                    messageDigest.update(array2, 0, read); //// // array2是输入字符串转换得到的字节数组
                                }
                                if ((read = openStream.read(array2)) > 0) {
                                    continue Label_0086_Outer;
                                }
                                break;
                            }
                            openStream.close();
                            messageDigest = instance;
                            if (!g) {
                                break;
                            }
                            continue;
                        }
                    }
                    StringBuffer sb = null;
                Label_0178_Outer:
                    while (true) {
                        final byte[] digest = messageDigest.digest(); //生成md5
                        sb = new StringBuffer();
                        int n = 0;
                        while (true) {
                            while (true) {
                                Label_0181: {
                                    try {
                                        if (!g) {
                                            break Label_0181;
                                        }
                                        //sb.append(String.format(BurpLoader.z[11], digest[n] & 0xFF)); 优化
                                        sb.append(String.format("%02x", digest[n] & 0xFF)) //准备输出md5?
                                    }
                                    catch (ClassNotFoundException ex2) {
                                        throw ex2;
                                    }
                                    ++n;
                                }
                                if (n < digest.length) {
                                    continue Label_0178_Outer;
                                }
                                break;
                            }
                            if (!g) {
                                break;
                            }
                            continue;
                        }
                    }
                    int equals = 0;
                    /*
                    用于确认版本
                    ~>>> md5 burpsuite_pro_v1.6.37.jar
                    MD5 (burpsuite_pro_v1.6.37.jar) = d0287d85d288c2af116e0d60878a8a24
                    */
                    Label_0245: {
                        Label_0219: {
                            int n2;
                            try {
                                n2 = (equals = (BurpLoader.z[0].equals(sb.toString()) ? 1 : 0)); // 比较md5的值
                                if (g) {
                                    break Label_0245;
                                }
                                if (n2 == 0) {
                                    break Label_0219;
                                }
                                break Label_0219;
                            }
                            catch (ClassNotFoundException ex3) {
                                throw ex3;
                            }
                            try {
                                if (n2 == 0) {
                                    JOptionPane.showMessageDialog(null, BurpLoader.z[9], BurpLoader.z[7], 0); //弹出提示版本不符或者被修改
                                    System.exit(-1);
                                }
                            }
                            catch (ClassNotFoundException ex4) {
                                throw ex4;
                            }
                        }
                        equals = 0;
                    }
                    /*
                    利用反射机制修改BurpSuite类相关信息,对于未混淆版本的Burploader和解密出的字符串可以重构前面的定义
                    */
                    int n3 = equals; //0
                    while (true) {
                        Label_0316: {
                            if (!g) {
                                break Label_0316;
                            }
                            //final Field declaredField = Class.forName(BurpLoader.z[10] + BurpLoader.b[n3]).getDeclaredField(BurpLoader.c[n3]); 优化
                            //通过反射机制获取类相关的属性或去修改它 http://my.oschina.net/swords/blog/117357
                            //从 burp.xxx 的类中取变量,可以用jd-gui反编译去看,取对应类中的第一个Strinig变量
                            final Field declaredField = Class.forName("burp.b_classarray").getDeclaredField(BurpLoader.c[n3]);
                            declaredField.setAccessible(true);
                            declaredField.set(null, BurpLoader.a[n3]); //插入stringdata
                            ++n3;
                        }
                        if (n3 < BurpLoader.b.length) {
                            continue;
                        }
                        break;
                    }
                    Preferences preferences = null;
                Label_0352_Outer:
                    while (true) {
                        //保存用户偏好,Windows是注册表,Linux是Home目录下的文件
                        final Preferences node = Preferences.userRoot().node(BurpLoader.z[5]); //node("/burp")
                        int n4 = 0;
                        while (true) {
                            while (true) {
                                Label_0398: {
                                    try {
                                        if (!g) {
                                            break Label_0398;
                                        }
                                    }
                                    catch (ClassNotFoundException ex5) {
                                        throw ex5;
                                    }
                                    //比较一些偏好设定,这里其实是key和values的比较
                                    /*
                                    String v = prefs.get(keys[i], null);
                                    if (!vals[i].equals(v)) {
                                        prefs.put(keys[i], vals[i]);
                                    }
                                    */
                                    if (!BurpLoader.e[n4].equals(preferences.get(BurpLoader.d[n4], null))) {
                                        node.put(BurpLoader.d[n4], BurpLoader.e[n4]);
                                    }
                                    ++n4;
                                }
                                if (n4 < BurpLoader.d.length) {
                                    continue Label_0352_Outer;
                                }
                                break;
                            }
                            preferences = node;
                            if (!g) {
                                break;
                            }
                            continue;
                        }
                    }
                    preferences.flush();
                    //反射调用 StartBurp.main(args); 
                    forName.getDeclaredMethod(BurpLoader.z[4], String[].class).invoke(null, array); // z4 = main
                }
                catch (Throwable t) {
                    t.printStackTrace();
                    int headless = GraphicsEnvironment.isHeadless() ? 1 : 0; //测试当前是否为图形环境
                    Label_0504: {
                        int n5 = 0;
                        Label_0503: {
                            try {
                                n5 = headless;
                                if (g) {
                                    break Label_0504;
                                }
                                if (n5 != 0) {
                                    break Label_0503;
                                }
                            }
                            catch (ClassNotFoundException ex6) {
                                throw ex6;
                            }
                            try {
                                GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); //取默认图形环境
                            }
                            catch (HeadlessException ex9) {
                                headless = 1;
                            }
                            catch (InternalError internalError) {
                                headless = 1;
                            }
                        }
                        try {
                            if (n5 != 0) {
                                System.err.println(BurpLoader.z[1]);
                                if (!g) {
                                    return;
                                }
                            }
                        }
                        catch (ClassNotFoundException ex7) {
                            throw ex7;
                        }
                    }
                    //JOptionPane.showMessageDialog(null, BurpLoader.z[1], BurpLoader.z[7], 0); 弹出提示框
                    JOptionPane.showMessageDialog(null, "This program can only run with burpsuite_pro_v1.6.37.jar", "Powered by XXX", 0);
                    
                }
            }
            catch (ClassNotFoundException ex10) {
                System.exit(-1);
            }
        }
    }

    从以上代码可以看出,BurpLoader的新版本破解BurpSuite的方式依旧没有发生改变,还是通过反射机制修改相关Burp类的成员变量 值来固定检测环境,同时写入Key来实现的。只不过比之前的版本,多了通过md5等方式来判断要启动的Burp主体是否是对应的版本。

    0x04 使坏
    原谅用了这么一个2B的小标题,Raphael Mudge牛曾在自己的Blog上写过(http://blog.cobaltstrike.com/2013/09/05/how-to-crack- cobalt-strike-and-backdoor-it/)如何破解自己的产品并加后门。事实上在BurpLoader中加上一点dirty code也是很容易的,然后再各大论坛或者某F传播出去也是能收获一批灰阔的,显而易见的例子是(http://it.rising.com.cn /dongtai/18192.html),堪比二十世纪出头灰阔圈子中各大XX联盟和XX技术小组了。最后感谢乌云Drops带来的好文章,多学习多实 践,有机会也去感受一把逆向Burp。

    参考:
    http://neeao.com/an-obfuscated-java-class-decompiler-algorithm
    http://www.iteye.com/topic/851544
    http://drops.wooyun.org/tips/2689
    https://www.defcon.org/images/defcon-15/dc15-presentations/dc-15-subere.pdf
    http://www.contextis.com/resources/blog/automating-removal-java-obfuscation/
    https://boredliner.wordpress.com/2014/02/07/cracking-obfuscated-java-code-adwind-3/
    http://www.the-playground.dk/index.php?page=zelix-klassmaster-string-encryption
    http://blog.csdn.net/stevenhu_223/article/details/9286121
    站内相关文章参考《对burpsuite_pro逆向的一点心得》


沪ICP备19023445号-2号
友情链接