[原创]Burp Suite Pro 破解
2022-6-13 08:22:0 Author: bbs.pediy.com(查看原文) 阅读量:22 收藏

前言

感谢scz、surferxyz、h3110w0r1d-y等各位老师傅在前面开路,这篇文章只是跟着前面的老师傅脚步走,用了自己的方式(ClassFileTransformer)开刀。

基于burpsuite_pro_v2022.3.9.jar

使用工具

  • cfr - 反编译工具

  • jadx - 反编译gui工具,可以查找引用

  • btrace - 运行状态跟踪工具

  • arthas - 用起来比btrace更方便的跟踪工具

  • IDEA

正文

这里直接用h3110w0r1d-y老师傅的jar开看

1

2

3

4

5

6

7

8

文件名称: E:\xxx\burp_latest\BurpLoaderKeygen.jar

文件大小: 18.1 KB (18,580 字节)

修改时间: 20210723日,10:20:48

MD5: B7E345B5594331516F49A709C04A3E41

SHA1: B9F4E9CA60E7493E459E21019441D115D2F43D98

SHA256: 63BE39F1AEEBEA9B86477ACEBBEFEE469A7562216BA8B253A4BB87B0A7A68566

CRC32: BCF7BD4F

计算时间: 0.00s

启动方式:java -javaagent:BurpLoaderKeygen.jar -noverify -jar burpsuite_pro_v2022.3.9.jar

启动解析

  1. -noverify 这个是跳过jvm对class文件的验证,后面详细说为什么要跳过
  2. -javaagent 这个是class加载之前对class进行修改

原理分析

关于javaagent的详细介绍,可以看知道创宇的paper 认识 JavaAgent

破解原理

上jadx,先看看老师傅们都搞了啥.

这里很明显,找到Class里面包含751a8be34c1a9ed9633d04be3ba075a7的Class文件进行修改,变量p以及p2是负责定位要修改的位置,找到位置后进行patch.

先照搬进IDEA看看到底干了啥

这里可以看到,修改的地方其实很相近,那就dump整个class下来看看情况.

dump的办法

然后调用下

得到两个class文件

还记得之前的启动参数么,-noverify,由于这里简单粗暴的修改了原class的byte,导致jvm的字节码校验失败,根据这个道理,很容易就能找到师傅们干了什么,直接上图把.

用cfr反编译后,直接找empty

两个if被改成empty了,但是到这里我们还是不知道老师傅这么干的道理,继续往下走把.

查找调用链

根据之前cfr反编译出来的源码,能看到两个超级混淆的办法,void a以及bool b,知道类名跟方法名了,直接写个btrace,把调用链弄出来.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

import org.openjdk.btrace.core.annotations.*;

import org.openjdk.btrace.core.BTraceUtils;

@BTrace(unsafe = true)

public class nls {

    @OnMethod(clazz="burp.nls", method="a")

    public static void void_a(Object[] var1, Object var2) {

        BTraceUtils.println("calleded void a");

        BTraceUtils.println("1st arg");

        BTraceUtils.println("arg length: " + var1.length);

        BTraceUtils.printArray(var1);

        byte[] my_var1 = (byte [])var1[0];

        BTraceUtils.println(new String(my_var1));

        BTraceUtils.println("2nd arg");

        String var2_str = String.valueOf(var2);

        BTraceUtils.println(var2_str);

        BTraceUtils.println("-----------");

    }

    @OnMethod(clazz="burp.nls", method="b")

    public static void bool_b(Object[] var1, Object var2) {

        BTraceUtils.println("called boolean b");

        BTraceUtils.println("1st arg");

        BTraceUtils.println("arg length: " + var1.length);

        BTraceUtils.printArray(var1);

        BTraceUtils.println("2nd arg");

        String var2_str = String.valueOf(oos);

        BTraceUtils.print(var2_str);

        BTraceUtils.jstack();

        BTraceUtils.println("-----------");

    }

}

过滤后,得到以下输出

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

burp.nls.b(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.pev.a(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.dcw.b(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.ib2.b(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.gw4.a(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.hcp.b(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.ciq.b(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.a_q.a(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.f09.a(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.bh5.a(Unknown Source)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

java.base/java.lang.reflect.Method.invoke(Method.java:566)

burp.fqs.a(Unknown Source)

burp.e20.b(Unknown Source)

burp.etx.b(Unknown Source)

burp.etx.g(Unknown Source)

burp.etx.<init>(Unknown Source)

burp.epi.d(Unknown Source)

burp.StartBurp.main(Unknown Source)

这里能看出,很多类都是动态加载进去的,想知道怎么调用还是得看看上一个调用类干了什么.

还记得之前的javaagent工程里面写了writeModifyClass方法不,把他放到最外层,然后修改下即可dump整个burp加载的class.

分析后发现...pev.class其实就是把nls.class从string数组变成byte数组然后解密加载

无实质性进展..尝试硬啃混淆过的验证类

代码分析

首先,nls里面有两个核心方法,一个void a,另外一个boolean b

这里看到b方法,直接调用了a方法,其中var_9是new的object array,内容是var3_3的byte array,整个传入a方法第一个参数就是object [][],第二个参数就是固定的一串字符串

再查找整个nls.a调用,发现整个文件就两次调用,第二次调用也是差不多

那就可以认定,nls.a的第二个参数是固定的字符串,第一个参数是object [][]类型,具体传入了什么上arthas看看传入

获取验证函数的调用信息

由于是Windows,写个bat放到arthas的目录方便arthas attach到burp的进程

这里有个小技巧,如果burp调用太快手速不够,可以进入主界面后,用help->License->Update License来触发验证类的调用

1

2

3

4

5

@echo off

for /f "tokens=1" %%a in ('jps ^| findstr /rc:"burpsuite_pro_"') do @set BURP_PID=%%a

as.bat %BURP_PID% --ignore-tools

用老师傅的jar先启动,然后运行bat就行

这里监控用watch 类名 方法名 -b -s -x 4

先输入个错误的license key,看看nls类里面方法a跟b什么情况

这里输入的是abcd,所以对着的是97,98,99,100,那就知道了其实nls.a传入的是字符串的byte array再放进Object[]

再尝试正确的License Key,根据之前代码进行分析得到下面的结论

  • b方法进入时收到的参数是Object[][],第一个数组是int的数组负责控制走哪个流程,第二个是字符串获取到的Byte数组;退出时第一个数组变成了Object数组套着的验证信息,第二数组没变
  • a方法进入时收到的参数是Object[][],第一个参数是字符串获取到的Byte数组,第二个参数是固定的字符串;退时,第一个参数变成验证信息,第二个参数没变

结合注册流程,可以得知

  • 用户输入的License Key,先进入nls.b,然后由nls.b调用nls.a进行解密,解密成功则修改传入的第一个变量作为字符串数组给nls.b进行下一步操作
  • nls.a是解密函数
  • nls.a会被调用两次,两次修改的变量长度不一致,对应License Key解密跟Activation Respond解密

有了以上信息,尝试构造nls.a的调用

分析解密函数

之前有dump过破解跟原版的验证class,使用破解后的class用jar打包

jar -cvf burp.jar burp/nls.class

作为依赖塞进IDEA的工程,这里注意Run的配置要加上jvm参数-noverify

这里能成功解密了,现在就是这串License Key是怎么生成的问题了

继续用jadx查看Loader的注册机部分

这里很明显了,DES加密,key在最顶上是祖传的burpr0x!

大体流程就是字符串数组然后转成byte array用0作为分隔,再进行DES加密,最后base64

那么我们就可以根据这个流程反向写出解密函数

写自己的解密函数

这里没什么好说的,直接跟着原理,先base64解码,然后des解密成byte array,转化成字符串后再用0分割成字符串数组

这里注意,解密出来的字符串数组长度会比原生的nls.a解密出来的字符串数组长,需要根据字符串数组长度删减返回的数组长度

其中长度是7的是License Key解密,长度10的是Activation Respond解密

到这里就差不多了,可以开始写自己的javaagent了

编写Javaagent

获取java版本的asm代码

要把上面的java代码覆盖到原来的文件,我用的org.ow2.asm这个库,当然你用其他的库也可以,例如bytebuddy.

首先把java方法变成asm库的代码,这里我直接用asm库里面的asmifier(org.ow2.asm:asm-util:9.3)

  1. 下载asm本体以及asm.util两个jar
  2. 把之前写的Main编译成class,什么方式都行
  3. 把class丢到下载的jar同目录
  4. java -cp asm-9.3.jar;asm-util-9.3.jar org.objectweb.asm.util.ASMifier Main.class
  5. 得到java版的asm代码

写ClassFileTransformer

  1. 在manifest定义Premain-Class以及Agent-Class

  2. 实现接口ClassFileTransformer

  3. 覆写激活类的方法

代码部分我就不详说了,有兴趣的可以自己围观

展示

测试版本burpsuite_pro_v2022.5.1.jar

结束

自己还是太菜不会用动态debug,只能用这样的笨方法来研究,代码附上,成品附上,欢迎各位大佬指导.

在这里感谢各位老师傅的路子,让刀burp不用找具体激活类具体是哪个,方便我这种后来破解的小白.

截至写完本文,2022.5.1还能这么刀

[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

上传的附件:
  • BurpLoader-1.0-SNAPSHOT.jar (125.38kb,154次下载)
  • BurpLoader-src.zip (64.30kb,139次下载)

文章来源: https://bbs.pediy.com/thread-273274.htm
如有侵权请联系:admin#unsafe.sh