记录黑客技术中优秀的内容, 传播黑客文化,分享黑客技术精华

再谈Burp破解

2016-05-17 15:30

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逆向的一点心得
知识来源: https://www.91ri.org/15799.html

阅读:204630 | 评论:0 | 标签:逆向工程 渗透测试

想收藏或者和大家分享这篇好文章→复制链接地址

“再谈Burp破解”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

公告

关注公众号hackdig,学习最新黑客技术

推广

工具

标签云