Java 逆向相关

Posted by API Caller on January 1, 2020

.

JEB 3.7

最近 @DimitarSerg 放出的 JEB 3.7.0 , 然而实测时间限制没有去干净, 会自动退出.

不熟悉 Java 逆向, 边查资料边分析

静态分析

拖进去尝试搜了一下 sleep currentTimeMillis exit 之类我就放弃静态分析了, 工具都太难用了

动态分析

考虑注入, 搜了下注入方式, 可能是不熟悉的原因, 感觉都挺麻烦的, 选择了看起来最简单的 btrace.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;

@BTrace
public class hook {
    @OnMethod(clazz = "java.lang.System", method = "exit")
    public static void Trace_exit() {
        println("System.exit() :");
        println("[");
        jstack();
        println("]");
    }

}

本意想着能在目标 jar 刚启动就注入进去, 而且可以修改 currentTimeMillis sleep 之类的参数加速触发, 可惜尝试调试启动也不行.

1
2
3
4
5
6
7
8
9
# 启动
java -Xss4M -Xmx16G  -jar bin/app/jebc.jar

# 列出 pid
jps
# 22272 jebc.jar

# 注入
btrace 22272 hook.java

接着就可以放置 play 等退出了(后来群友说直接改系统时间也可以加速退出)

堆栈信息如下:

System.exit() :
[
java.lang.System.exit(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
com.pnfsoftware.jebglobal.LC.Le(SourceFile:45)
com.pnfsoftware.jebglobal.LC.run(SourceFile:33)
java.lang.Thread.run(Unknown Source)
]

去对应位置看一下:

1
2
3
4
5
6
7
8
9
10
11
12
private void Le() {
    while (true) {
        try {
            if (eO() - eO > ((long) ((eO % 10 == 0 ? 34 : 33) * 107 * 1000))) {
                Class.forName(Ls.eO(new byte[]{gB.eO, 11, MJ.Gk, MJ.Gk, 79, gB.Le, 13, 15, 9, gB.vT, 125, 42, 10, 7, MJ.gU, 8}, 1, 49)).getMethod(Ls.eO(new byte[]{38, MJ.Gk, MJ.AP, 13}, 2, 201), new Class[]{Integer.TYPE}).invoke((Object) null, new Object[]{0});
            }
            Class.forName(Ls.eO(new byte[]{41, 14, 6, MJ.Vj, 92, 5, 6, 6, MJ.cb, 14, 124, 11, gB.eO, 69, Uk.CV, 93}, 2, 7)).getMethod(Ls.eO(new byte[]{48, 3, MJ.hd, 28, 2}, 2, 179), new Class[]{Long.TYPE}).invoke((Object) null, new Object[]{120000L});
        } catch (Exception e) {
            return;
        }
    }
}

可见字符串混淆了然后反射调用, 当然这里可以继续修改分析 Ls.eO 看看去混淆的结果, 也可以搜索 new LC() 查找被调用的地方, 但既然有混淆有反射调用, 分析起来也麻烦, 蒙一把吧:

既然这是个 Thread 里的死循环, 那么很显然 com.pnfsoftware.jebglobal.LC.Le(SourceFile:45)Class.forName(Ls.eO(new byte[]{gB.eO, 11, MJ.Gk, MJ.Gk, 79, gB.Le, 13, 15, 9, gB.vT, 125, 42, 10, 7, MJ.gU, 8}, 1, 49)).getMethod(Ls.eO(new byte[]{38, MJ.Gk, MJ.AP, 13}, 2, 201), new Class[]{Integer.TYPE}).invoke((Object) null, new Object[]{0}); 也就是 System.exit(0), 那么可以猜到另一句 Class.forName(Ls.eO(new byte[]{41, 14, 6, MJ.Vj, 92, 5, 6, 6, MJ.cb, 14, 124, 11, gB.eO, 69, Uk.CV, 93}, 2, 7)).getMethod(Ls.eO(new byte[]{48, 3, MJ.hd, 28, 2}, 2, 179), new Class[]{Long.TYPE}).invoke((Object) null, new Object[]{120000L}); 必然就是 Thread.sleep(120000L) 了, if 条件则是对比时间, 所以修改系统时间之后最长触发时间是 120000L.

patch

找到位置了, 那就直接把这个线程干掉. patch 的方式搜索了一下, 觉得还是直接用 jar 命令更新原 jeb.jar 比较方便

1
2
3
4
5
6
package com.pnfsoftware.jebglobal;

public class LC extends Thread {
    public void run() {}
}

1
2
3
4
5
6
7
mkdir -p com/pnfsoftware/jebglobal

mv LC.java com/pnfsoftware/jebglobal/

javac -cp jeb.jar com/pnfsoftware/jebglobal/LC.java

jar -vuf jeb.jar com/pnfsoftware/jebglobal/LC.class

然后替换 jeb.jar, 再把系统时间调后几个小时, 静等两分钟, 没有问题~

jeb 也许还有别的暗桩, 遇到了再分析吧, 新年第一天, 算是稍微学习一下 java 的逆向

附加

分析到这里没啥意义了, 熟悉巩固下而已

去混淆
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package com.pnfsoftware.jebglobal;

import java.nio.charset.Charset;
import com.pnfsoftware.jeb.util.logging.GlobalLog;
import com.pnfsoftware.jeb.util.logging.ILogger;

public class Ls {
    private byte[] Le;
    private int Qx;
    private String eO;
    private int lS;

    private static final ILogger logger = GlobalLog.getLogger(Ls.class);

    public static String eO(String str) {
        return str;
    }

    public static String eO(byte[] bArr, int i, int i2) {

        String ret = new Ls(bArr, i, i2).eO();
        logger.warn("[eO] %s", ret);

        if (ret.equals("java.lang.Thread") || ret.equals("currentTimeMillis") || ret.equals("sleep")) {

            Throwable ex = new Throwable();
            StackTraceElement[] stackElements = ex.getStackTrace();
            String dump = "[eO] " + ret + ":\n";

            if (stackElements != null) {
                for (int j = 0; j < stackElements.length; j++) {
                    dump += "\t" + stackElements[j].getClassName() + " " + stackElements[j].getMethodName() + "("
                            + stackElements[j].getFileName() + ":" + String.valueOf(stackElements[j].getLineNumber())
                            + ")" + "\n";
                }
            }

            logger.warn("[eO.Stack] %s", dump);
        }

        return ret;
    }

    Ls(String str) {
        this.eO = str;
    }

    public Ls(byte[] bArr, int i, int i2) {
        this.Le = bArr;
        this.Qx = i;
        this.lS = i2;
    }

    public String eO() {
        if (this.eO != null) {
            return this.eO;
        }
        if (this.Le == null) {
            throw new RuntimeException();
        } else if (this.Qx == 0 || this.Le.length == 0) {
            try {
                return new String(this.Le, "UTF-8");
            } catch (Exception e) {
                return new String(this.Le, Charset.defaultCharset());
            }
        } else if (this.Qx == 1) {
            int length = this.Le.length;
            byte[] bArr = new byte[length];
            byte b = (byte) this.lS;
            for (int i = 0; i < length; i++) {
                bArr[i] = (byte) (b ^ this.Le[i]);
                b = bArr[i];
            }
            try {
                return new String(bArr, "UTF-8");
            } catch (Exception e2) {
                return new String(bArr, Charset.defaultCharset());
            }
        } else if (this.Qx == 2) {
            int length2 = this.Le.length;
            byte[] bArr2 = new byte[length2];
            int i2 = 0;
            int i3 = 0;
            while (i2 < length2) {
                bArr2[i2] = (byte) (this.Le[i2]
                        ^ ((byte) "Copyright (c) 1993, 2015, Oracle and/or its affiliates. All rights reserved. "
                                .charAt(i3)));
                i2++;
                i3 = (i3 + 1)
                        % "Copyright (c) 1993, 2015, Oracle and/or its affiliates. All rights reserved. ".length();
            }
            try {
                return new String(bArr2, "UTF-8");
            } catch (Exception e3) {
                return new String(bArr2, Charset.defaultCharset());
            }
        } else {
            throw new RuntimeException();
        }
    }
}
1
2
3
4
5
6
7
mkdir -p com/pnfsoftware/jebglobal

mv Ls.java com/pnfsoftware/jebglobal/

javac -cp jeb.jar com/pnfsoftware/jebglobal/Ls.java

jar -vuf jeb.jar com/pnfsoftware/jebglobal/Ls.class