Skip to content

Commit 21f6613

Browse files
authored
Branchlock salting complete (#117)
1 parent 8f2635e commit 21f6613

File tree

40 files changed

+1118
-10
lines changed

40 files changed

+1118
-10
lines changed

deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,10 @@ protected void registerAll() {
225225
.inputJar("branchlock/branchlock-string-flow-number.jar")
226226
.register();
227227

228-
// test("Branchlock String + Salting + Flow + Number")
229-
// .transformers(ComposedBranchlockTransformer::new)
230-
// .inputJar("branchlock/branchlock-string-salting-flow-number.jar")
231-
// .register();
228+
test("Branchlock String + Salting + Flow + Number")
229+
.transformers(ComposedBranchlockTransformer::new)
230+
.inputJar("branchlock/branchlock-string-salting-flow-number.jar")
231+
.register();
232232

233233
test("Branchlock Flow 9")
234234
.transformers(BranchlockFlowTransformer::new)

deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockSaltingTransformer.java

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.objectweb.asm.Opcodes;
44
import org.objectweb.asm.Type;
55
import org.objectweb.asm.tree.*;
6+
import uwu.narumi.deobfuscator.api.asm.ClassWrapper;
67
import uwu.narumi.deobfuscator.api.asm.MethodContext;
78
import uwu.narumi.deobfuscator.api.asm.matcher.Match;
89
import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch;
@@ -11,8 +12,7 @@
1112
import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch;
1213
import uwu.narumi.deobfuscator.api.transformer.Transformer;
1314

14-
import java.util.Map;
15-
import java.util.WeakHashMap;
15+
import java.util.*;
1616

1717
public class BranchlockSaltingTransformer extends Transformer {
1818

@@ -22,8 +22,6 @@ public class BranchlockSaltingTransformer extends Transformer {
2222

2323
private final Map<MethodInsnNode, Integer> salts = new WeakHashMap<>();
2424

25-
//TODO: Fix superClass`s / interface`s overridden methods not being deobfuscated
26-
2725
@Override
2826
protected void transform() throws Exception {
2927
scopedClasses().forEach(classWrapper -> {
@@ -48,6 +46,21 @@ protected void transform() throws Exception {
4846
});
4947
});
5048
/* Replace ILOAD var with saved salts */
49+
salts.forEach((min, salt) -> {
50+
resolvePossibleTargets(min, context().getClassesMap(), buildSubclassMap(context().getClassesMap())).forEach(resolvedMethod -> {
51+
MethodNode methodNode = resolvedMethod.mn();
52+
ClassNode cn = resolvedMethod.cn();
53+
int lastParamIndex = getLastParameterSlot(methodNode.access, methodNode.desc);
54+
MethodContext methodContext = MethodContext.of(context().getClassesMap().get(cn.name), methodNode);
55+
saltingXor.findAllMatches(methodContext).forEach(matchContext -> {
56+
VarInsnNode varInsnNode = (VarInsnNode) matchContext.insn();
57+
if (varInsnNode.var == lastParamIndex) {
58+
methodNode.instructions.set(matchContext.insn(), pushInt(salt));
59+
markChange();
60+
}
61+
});
62+
});
63+
});
5164
scopedClasses().forEach(classWrapper -> {
5265
classWrapper.methods().forEach(methodNode -> {
5366
int lastParamIndex = getLastParameterSlot(methodNode.access, methodNode.desc);
@@ -77,6 +90,64 @@ public AbstractInsnNode pushInt(int value) {
7790
}
7891
}
7992

93+
public static Map<String, List<String>> buildSubclassMap(Map<String, ClassWrapper> classMap) {
94+
Map<String, List<String>> subclassMap = new HashMap<>();
95+
96+
for (ClassWrapper cw : classMap.values()) {
97+
ClassNode cn = cw.classNode();
98+
if (cn.superName != null) {
99+
subclassMap.computeIfAbsent(cn.superName, k -> new ArrayList<>()).add(cn.name);
100+
}
101+
if (cn.interfaces != null) {
102+
for (String iface : cn.interfaces) {
103+
subclassMap.computeIfAbsent(iface, k -> new ArrayList<>()).add(cn.name);
104+
}
105+
}
106+
}
107+
108+
return subclassMap;
109+
}
110+
111+
public static List<ResolvedMethod> resolvePossibleTargets(MethodInsnNode methodInsn, Map<String, ClassWrapper> classMap, Map<String, List<String>> subclassMap) {
112+
String methodName = methodInsn.name;
113+
String methodDesc = methodInsn.desc;
114+
String ownerInternalName = methodInsn.owner;
115+
116+
Set<String> visited = new HashSet<>();
117+
Queue<String> toVisit = new ArrayDeque<>();
118+
List<ResolvedMethod> results = new ArrayList<>();
119+
120+
toVisit.add(ownerInternalName);
121+
122+
while (!toVisit.isEmpty()) {
123+
String className = toVisit.poll();
124+
if (!visited.add(className)) continue;
125+
126+
ClassWrapper cw = classMap.get(className);
127+
if (cw == null) continue;
128+
ClassNode cn = cw.classNode();
129+
130+
for (MethodNode mn : cn.methods) {
131+
if (mn.name.equals(methodName) && mn.desc.equals(methodDesc)) {
132+
results.add(new ResolvedMethod(cn, mn));
133+
}
134+
}
135+
136+
if (cn.superName != null) {
137+
toVisit.add(cn.superName);
138+
}
139+
if (cn.interfaces != null) {
140+
toVisit.addAll(cn.interfaces);
141+
}
142+
143+
List<String> subclasses = subclassMap.getOrDefault(className, Collections.emptyList());
144+
toVisit.addAll(subclasses);
145+
}
146+
147+
return results;
148+
}
149+
150+
80151
public int getLastParameterSlot(int access, String desc) {
81152
Type[] args = Type.getArgumentTypes(desc);
82153
int index = ((access & Opcodes.ACC_STATIC) != 0) ? 0 : 1;
@@ -86,4 +157,7 @@ public int getLastParameterSlot(int access, String desc) {
86157
}
87158
return index;
88159
}
160+
161+
public record ResolvedMethod(ClassNode cn, MethodNode mn) {
162+
}
89163
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package pack;
2+
3+
public class Clazz {
4+
public String BRANCHLOCK_DOT_NET_DEMO;
5+
6+
public Clazz(int var1) {
7+
}
8+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package pack;
2+
3+
import java.io.File;
4+
import pack.tests.basics.accu.Digi;
5+
import pack.tests.basics.ctrl.Ctrl;
6+
import pack.tests.basics.inner.Test;
7+
import pack.tests.basics.overwirte.Sub;
8+
import pack.tests.basics.runable.Task;
9+
import pack.tests.basics.sub.Solver;
10+
import pack.tests.bench.Calc;
11+
import pack.tests.reflects.annot.annot;
12+
import pack.tests.reflects.counter.Count;
13+
import pack.tests.reflects.field.FTest;
14+
import pack.tests.reflects.loader.LRun;
15+
import pack.tests.reflects.res.Accesor;
16+
import pack.tests.reflects.retrace.Tracer;
17+
import pack.tests.security.SecTest;
18+
19+
public class Main {
20+
public int BRANCHLOCK_DOT_NET_DEMO;
21+
22+
public Main(int var1) {
23+
}
24+
25+
public static void main(String[] var0) {
26+
System.out
27+
.println(
28+
"-----------------------------------------------------------------------------------------\n| This java application has been obfuscated using a demo version of Branchlock 4. |\n| Did you know that anyone can read the source code of your exported java software? |\n| For more information about how to protect your projects, visit https://branchlock.net |\n-----------------------------------------------------------------------------------------\n"
29+
);
30+
System.out.println("Obfuscator Test Program");
31+
System.out.println("Author: huzpsb");
32+
System.out.println("Version: 1.0r");
33+
System.out.println("Link: https://github.com/huzpsb/JavaObfuscatorTest");
34+
File var1 = new File("IK");
35+
if (!var1.exists()) {
36+
var1.createNewFile();
37+
System.out.println();
38+
System.out.println("[HINT]");
39+
System.out.println("Only compatibility and efficiency are tested here!");
40+
System.out.println("For most users, pass all of the basics means the obfuscator is good enough.");
41+
System.out.println("The Test #2 is for SpringBoot and Android like environment.");
42+
System.out.println("Choose wisely among strength, compatibility, efficiency, size, and price.");
43+
System.out.println("[HINT]");
44+
System.out.println();
45+
}
46+
47+
System.out.println("-------------Test #1: Basics-------------");
48+
System.out.print("Test 1.1: Inheritance ");
49+
50+
try {
51+
new Sub(8122).run(29865);
52+
} catch (Throwable var15) {
53+
System.out.println("ERROR");
54+
}
55+
56+
System.out.print("Test 1.2: Cross ");
57+
58+
try {
59+
new Sub(8122).run(29865);
60+
} catch (Throwable var14) {
61+
System.out.println("ERROR");
62+
}
63+
64+
System.out.print("Test 1.3: Throw ");
65+
66+
try {
67+
new Ctrl(32735).run(12620);
68+
} catch (Throwable var13) {
69+
System.out.println("ERROR");
70+
}
71+
72+
System.out.print("Test 1.4: Accuracy ");
73+
74+
try {
75+
new Digi(7043).run(22257);
76+
} catch (Throwable var12) {
77+
System.out.println("ERROR");
78+
}
79+
80+
System.out.print("Test 1.5: SubClass ");
81+
82+
try {
83+
new Solver(16217);
84+
} catch (Throwable var11) {
85+
System.out.println("ERROR");
86+
}
87+
88+
System.out.print("Test 1.6: Pool ");
89+
90+
try {
91+
new Task(30959).run(15887);
92+
} catch (Throwable var10) {
93+
System.out.println("ERROR");
94+
}
95+
96+
System.out.print("Test 1.7: InnerClass ");
97+
98+
try {
99+
new Test(9340).run(18150);
100+
} catch (Throwable var9) {
101+
System.out.println("ERROR");
102+
}
103+
104+
System.out.println("-------------Test #2: Reflects-------------");
105+
System.out.print("Test 2.1: Counter ");
106+
107+
try {
108+
new Count(4824).run(18228);
109+
} catch (Throwable var8) {
110+
System.out.println("ERROR");
111+
}
112+
113+
System.out.print("Test 2.2: Chinese 通过LMAO\b\b\b\b \n");
114+
System.out.print("Test 2.3: Resource ");
115+
116+
try {
117+
new Accesor(15232).run(27444);
118+
} catch (Throwable var7) {
119+
System.out.println("ERROR");
120+
}
121+
122+
System.out.print("Test 2.4: Field ");
123+
124+
try {
125+
new FTest(3122).run(29896);
126+
} catch (Throwable var6) {
127+
System.out.println("ERROR");
128+
}
129+
130+
System.out.print("Test 2.5: Loader ");
131+
132+
try {
133+
new LRun(4393).run(12617);
134+
} catch (Throwable var5) {
135+
System.out.println("ERROR");
136+
}
137+
138+
System.out.print("Test 2.6: ReTrace ");
139+
140+
try {
141+
new Tracer(23239).run(20986);
142+
} catch (Throwable var4) {
143+
System.out.println("ERROR");
144+
}
145+
146+
System.out.print("Test 2.7: Annotation ");
147+
148+
try {
149+
new annot(615).run(27375);
150+
} catch (Throwable var3) {
151+
System.out.println("ERROR");
152+
}
153+
154+
System.out.print("Test 2.8: Sec ");
155+
156+
try {
157+
new SecTest(30139).run(22458);
158+
} catch (Throwable var2) {
159+
System.out.println("ERROR");
160+
}
161+
162+
System.out.println("-------------Test #3: Efficiency-------------");
163+
Calc.runAll(28038);
164+
System.out.println("-------------Tests r Finished-------------");
165+
}
166+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package pack.tests.basics.accu;
2+
3+
public class Digi {
4+
public int BRANCHLOCK_DOT_NET_DEMO;
5+
6+
public Digi(int var1) {
7+
}
8+
9+
public void run(int var1) {
10+
double var2 = 0.0;
11+
int var4 = 0;
12+
13+
do {
14+
var2 += 1.0E-18;
15+
} while (++var4 <= 100 && (float)var2 != 2.0E-17F);
16+
17+
if (var4 == 20) {
18+
System.out.println("PASS");
19+
} else {
20+
System.out.println("FAIL");
21+
}
22+
}
23+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package pack.tests.basics.cross;
2+
3+
public abstract class Abst1 {
4+
public int BRANCHLOCK_DOT_NET_DEMO;
5+
6+
public Abst1(int var1) {
7+
}
8+
9+
public abstract int add(int var1, int var2, int var3);
10+
11+
public int mul(int var1, int var2, int var3) {
12+
return var1 * var2;
13+
}
14+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package pack.tests.basics.cross;
2+
3+
public interface Inte {
4+
int mul(int var1, int var2, int var3);
5+
}

0 commit comments

Comments
 (0)