Skip to content

Commit 9d3cf73

Browse files
committed
feat(obfuscator): wip on proper type computation
1 parent 3a744ff commit 9d3cf73

10 files changed

Lines changed: 245 additions & 19 deletions

File tree

dev.skidfuscator.maple-ir/org.mapleir.ir/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,11 @@
3737
<version>1.18.20</version>
3838
<scope>provided</scope>
3939
</dependency>
40+
<dependency>
41+
<groupId>org.apache.commons</groupId>
42+
<artifactId>commons-lang3</artifactId>
43+
<version>3.11</version>
44+
<scope>compile</scope>
45+
</dependency>
4046
</dependencies>
4147
</project>

dev.skidfuscator.maple-ir/org.mapleir.ir/src/main/java/org/mapleir/ir/code/stmt/ConditionalJumpStmt.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ public void toCode(MethodVisitor visitor, BytecodeFrontend assembler) {
163163
visitor.visitJumpInsn(type == ComparisonType.EQ ? Opcodes.IF_ACMPEQ : Opcodes.IF_ACMPNE, assembler.getLabel(trueSuccessor));
164164
}
165165
} else if (opType == Type.INT_TYPE) {
166-
boolean canShorten = right instanceof ConstantExpr && ((ConstantExpr) right).getConstant() instanceof Number
166+
boolean canShorten = right instanceof ConstantExpr
167+
&& ((ConstantExpr) right).getConstant() instanceof Number
167168
&& ((Number) ((ConstantExpr) right).getConstant()).intValue() == 0;
168169

169170
left.toCode(visitor, assembler);
@@ -225,6 +226,8 @@ public void toCode(MethodVisitor visitor, BytecodeFrontend assembler) {
225226
}
226227
}
227228

229+
230+
228231
@Override
229232
public boolean canChangeFlow() {
230233
return true;
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package org.mapleir.ir.locals.type;
2+
3+
import org.mapleir.ir.code.ExpressionPool;
4+
import org.objectweb.asm.Type;
5+
6+
import java.util.Collections;
7+
import java.util.HashSet;
8+
import java.util.Set;
9+
import java.util.function.Predicate;
10+
11+
/**
12+
* WIP
13+
*/
14+
public class TypeHeader {
15+
/**
16+
* Set denoting of all the parent type headers
17+
*/
18+
private final Set<TypeHeader> parents;
19+
20+
/**
21+
* Warning: Can be null
22+
*/
23+
private Type type;
24+
25+
/**
26+
* Set denoting of all the excluded types for the computation
27+
*/
28+
private final Set<Type> excluded;
29+
30+
public TypeHeader() {
31+
this(null);
32+
}
33+
34+
public TypeHeader(Type type) {
35+
this.type = type;
36+
this.parents = new HashSet<>();
37+
this.excluded = new HashSet<>();
38+
}
39+
40+
public Set<Type> get() {
41+
return _get(new HashSet<>());
42+
}
43+
44+
public void set(final Type type) {
45+
this.type = type;
46+
}
47+
48+
public void addParent(final TypeHeader typeHeader) {
49+
parents.add(typeHeader);
50+
}
51+
52+
public void addExclusion(final Type type) {
53+
excluded.add(type);
54+
}
55+
56+
private Set<Type> _get(final Set<TypeHeader> visited) {
57+
visited.add(this);
58+
59+
/*
60+
* Root node. There are a couple of essential requirements for this
61+
* node:
62+
*
63+
* 1) It must not be a null type
64+
* 2) It must not be exempted by its own exclusions
65+
*/
66+
if (parents.isEmpty()) {
67+
if (type == null) {
68+
throw new IllegalStateException("Root type is denoted as null!");
69+
}
70+
71+
if (excluded.contains(type)) {
72+
throw new IllegalStateException("Root type excluded by root composition");
73+
}
74+
75+
return new HashSet<>(Collections.singleton(type));
76+
}
77+
78+
/*if (depth >= maxDepth) {
79+
return null;
80+
}
81+
82+
for (ExpressionPool parent : parents) {
83+
if ((type = parent.get(index, predicate, depth + 1, maxDepth)) == null)
84+
continue;
85+
86+
return type;
87+
*/
88+
89+
final Set<Type> types = new HashSet<>();
90+
91+
if (type != null && !excluded.contains(type)) {
92+
types.add(type);
93+
}
94+
95+
for (TypeHeader parent : parents) {
96+
if (visited.contains(parent))
97+
continue;
98+
99+
final Set<Type> parentTypes = parent._get(visited);
100+
101+
for (Type parentType : parentTypes) {
102+
if (excluded.contains(parentType))
103+
continue;
104+
105+
types.add(parentType);
106+
}
107+
}
108+
109+
return types;
110+
}
111+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package org.mapleir.ir.locals.type;
2+
3+
import org.objectweb.asm.Type;
4+
5+
import java.util.Arrays;
6+
import java.util.Set;
7+
8+
public class TypePool {
9+
private final TypeHeader[] types;
10+
11+
public TypePool(TypeHeader[] types) {
12+
this.types = types;
13+
}
14+
15+
public Set<Type> get(final int index) {
16+
return types[index].get();
17+
}
18+
19+
public void set(final int index, Type type) {
20+
types[index].set(type);
21+
}
22+
23+
public int computeSize() {
24+
for (int i = size(); i > 0; i--) {
25+
final Set<Type> computed = this.get(i);
26+
27+
/*
28+
* If the computed types are empty, it means there's
29+
* no defined type at this index; Meaning, it has to
30+
* be either a dead local end or something.
31+
*/
32+
if (computed.isEmpty()) {
33+
continue;
34+
}
35+
36+
if (i > 1) {
37+
final Set<Type> subType = this.get(i - 2);
38+
39+
if (subType.contains(Type.DOUBLE_TYPE) || subType.contains(Type.LONG_TYPE)) {
40+
return i;
41+
}
42+
}
43+
44+
for (Type type : computed) {
45+
if (type.equals(Type.VOID_TYPE)) {
46+
continue;
47+
}
48+
49+
return i;
50+
}
51+
}
52+
return 0;
53+
}
54+
55+
public int size() {
56+
return types.length;
57+
}
58+
59+
public TypePool createChild(int index, Type header) {
60+
return createChild(new int[]{index}, new Type[]{header});
61+
}
62+
63+
public TypePool createChild(int[] indexes, Type[] headers) {
64+
assert indexes.length == headers.length : "No changes matched";
65+
66+
TypeHeader[] array = Arrays.copyOf(types, types.length);
67+
68+
for (int i = 0; i < indexes.length; i++) {
69+
final int index = indexes[i];
70+
final TypeHeader header = new TypeHeader(headers[i]);
71+
72+
header.addParent(array[index]);
73+
array[index] = header;
74+
}
75+
76+
return new TypePool(array);
77+
}
78+
}

dev.skidfuscator.obfuscator/obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ public void run() {
389389
for (Listener o : Arrays.asList(
390390
new StringTransformer(this),
391391
//new NegationTransformer(this),
392-
//new FlatteningFlowTransformer(this),
392+
new FlatteningFlowTransformer(this),
393393
new NumberTransformer(this),
394394
new SwitchTransformer(this),
395395
new BasicSimplifierTransformer(this),

dev.skidfuscator.obfuscator/obfuscator/src/main/java/dev/skidfuscator/obfuscator/frame/FrameComputer.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,6 @@ public boolean test(FlowEdge<BasicBlock> basicBlockFlowEdge) {
631631
System.out.println(FrameExporterUtils.makeDotGraph(frameGraph, dict).toString());
632632
}
633633

634-
635634
/*
636635
* FRAME STACK
637636
*/

dev.skidfuscator.obfuscator/obfuscator/src/main/java/dev/skidfuscator/obfuscator/frame/FrameExporterUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public static DotGraph makeDotGraph(FrameGraph cfg, IPropertyDictionary properti
8282
if (labelEdges) {
8383
dotE.with(
8484
ComplexLabel.of(simplifyEdges ? e.getClass().getSimpleName().replace("Edge", "") : e.toGraphString()),
85+
ComplexLabel.of("Exempts: " + Arrays.toString(e.frame().getExcludedTypes().toArray())),
8586
ComplexLabel.of(Arrays.toString(e.frame().getTypes()))
8687
);
8788
}

dev.skidfuscator.obfuscator/obfuscator/src/main/java/dev/skidfuscator/obfuscator/skidasm/SkidExpressionPool.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,29 @@ public Type get(int index, Predicate<Type> predicate, Set<ExpressionPool> visite
105105
return currentType;
106106
}
107107

108+
public Set<Type> getTypes(int index) {
109+
return getTypes(index, new HashSet<>(), new HashSet<>());
110+
}
111+
112+
protected Set<Type> getTypes(int index, Set<Type> computedTypes, Set<ExpressionPool> visited) {
113+
visited.add(this);
114+
115+
final Type currentType = types[index];
116+
117+
if (currentType != null) {
118+
computedTypes.add(currentType);
119+
}
120+
121+
for (ExpressionPool parent : parents) {
122+
if (visited.contains(parent))
123+
continue;
124+
125+
computedTypes = ((SkidExpressionPool) parent).getTypes(index, computedTypes, visited);
126+
}
127+
128+
return computedTypes;
129+
}
130+
108131
@Deprecated
109132
public boolean isConflicting() {
110133
return conflict.values().stream().anyMatch(e -> e);

dev.skidfuscator.obfuscator/obfuscator/src/main/java/dev/skidfuscator/obfuscator/transform/impl/flow/FlatteningFlowTransformer.java

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.mapleir.ir.locals.impl.BasicLocal;
3737
import org.mapleir.ir.locals.impl.VersionedLocal;
3838
import org.objectweb.asm.ClassWriter;
39+
import org.objectweb.asm.Opcodes;
3940
import org.objectweb.asm.Type;
4041
import org.objectweb.asm.tree.analysis.Analyzer;
4142
import org.objectweb.asm.tree.analysis.BasicInterpreter;
@@ -71,7 +72,7 @@ void handle(final InitMethodTransformEvent event) {
7172
}
7273

7374
@Listen
74-
void handle(final FinalMethodTransformEvent event) {
75+
void handle(final RunMethodTransformEvent event) {
7576
final SkidMethodNode methodNode = event.getMethodNode();
7677
final Skidfuscator skidfuscator = event.getSkidfuscator();
7778

@@ -102,16 +103,16 @@ void handle(final FinalMethodTransformEvent event) {
102103
exempt.add(range.getHandler());
103104
}
104105

105-
for (BasicBlock vertex : cfg.vertices()) {
106+
/*for (BasicBlock vertex : cfg.vertices()) {
106107
if (vertex.getStack() == null)
107108
exempt.add(vertex);
108-
}
109+
}*/
109110

110111
if (cfg.vertices()
111112
.stream()
112-
.filter(exempt::contains)
113+
.filter(e -> !exempt.contains(e) && !e.isEmpty())
113114
.flatMap(Collection::stream)
114-
.noneMatch(e -> e instanceof UnconditionalJumpStmt))
115+
.noneMatch(e -> e instanceof ConditionalJumpStmt))
115116
return;
116117

117118
final LinkedHashMap<Integer, BasicBlock> destinations = new LinkedHashMap<>();
@@ -217,23 +218,26 @@ void handle(final FinalMethodTransformEvent event) {
217218

218219
new HashSet<>(cfg.vertices())
219220
.stream()
220-
.filter(e -> !exempt.contains(e))
221+
.filter(e -> !exempt.contains(e) && !e.isEmpty())
221222
.flatMap(Collection::stream)
222-
.filter(e -> e instanceof UnconditionalJumpStmt && e.getBlock().getStack().isEmpty())
223-
.map(e -> (UnconditionalJumpStmt) e)
223+
.filter(e -> e instanceof ConditionalJumpStmt)
224+
.map(e -> (ConditionalJumpStmt) e)
224225
.forEach(e -> {
225226
final SkidBlock currentBlock = (SkidBlock) e.getBlock();
226-
final SkidBlock oldTarget = (SkidBlock) e.getTarget();
227+
final SkidBlock oldTarget = (SkidBlock) e.getTrueSuccessor();
227228

228229
/* Replace target block */
229-
e.setTarget(dispatcherBlock);
230+
e.setTrueSuccessor(dispatcherBlock);
230231

231232
/* Replace edge */
232-
final UnconditionalJumpEdge<BasicBlock> edge = new UnconditionalJumpEdge<>(
233+
final ConditionalJumpEdge<BasicBlock> edge = new ConditionalJumpEdge<>(
233234
currentBlock,
234-
dispatcherBlock
235+
dispatcherBlock,
236+
e.getEdge() == null ? Opcodes.IFEQ : e.getEdge().opcode
235237
);
236-
cfg.removeEdge(e.getEdge());
238+
239+
if (e.getEdge() != null)
240+
cfg.removeEdge(e.getEdge());
237241
cfg.addEdge(edge);
238242
e.setEdge(edge);
239243

@@ -242,8 +246,9 @@ void handle(final FinalMethodTransformEvent event) {
242246
cfg.addEdge(new SwitchEdge<>(dispatcherBlock, oldTarget, seed));
243247
});
244248

245-
final BasicBlock fuck = Blocks.exception(cfg, "We messed up bogo...");
249+
// We put it here to prevent adding a dead block
246250

251+
final BasicBlock fuck = Blocks.exception(cfg, "We messed up bogo...");
247252
dispatcherBlock.add(new SwitchStmt(
248253
getter.get(dispatcherBlock),
249254
destinations,
@@ -252,7 +257,7 @@ void handle(final FinalMethodTransformEvent event) {
252257

253258
cfg.addEdge(new DefaultSwitchEdge<>(dispatcherBlock, fuck));
254259

255-
if (IntegerBlockPredicateRenderer.DEBUG) {
260+
/*if (IntegerBlockPredicateRenderer.DEBUG) {
256261
methodNode.dump();
257262
258263
try {
@@ -261,6 +266,6 @@ void handle(final FinalMethodTransformEvent event) {
261266
} catch (Exception e) {
262267
e.printStackTrace();
263268
}
264-
}
269+
}*/
265270
}
266271
}
Binary file not shown.

0 commit comments

Comments
 (0)