Skip to content

Commit 2ddaba9

Browse files
committed
many changes
- make deobfuscator logs more readable - show all test results using 'mvn test' - inlining static fields now also inlines default field type value
1 parent 7773f21 commit 2ddaba9

File tree

7 files changed

+117
-35
lines changed

7 files changed

+117
-35
lines changed

deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/helper/AsmHelper.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,25 @@ public static AbstractInsnNode toConstantInsn(Object value) {
123123
throw new IllegalArgumentException("Not a constant");
124124
}
125125

126+
/**
127+
* Get default value for the given type (https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.5)
128+
*
129+
* @param type The type
130+
* @return Default value for the type
131+
*/
132+
public static Object getDefaultTypeValue(Type type) {
133+
return switch (type.getSort()) {
134+
case Type.BOOLEAN -> false;
135+
case Type.CHAR -> '\u0000';
136+
case Type.BYTE, Type.SHORT, Type.INT -> 0;
137+
case Type.LONG -> 0L;
138+
case Type.FLOAT -> 0.0f;
139+
case Type.DOUBLE -> 0.0d;
140+
case Type.ARRAY, Type.OBJECT -> null;
141+
default -> throw new IllegalArgumentException("Unsupported type: " + type);
142+
};
143+
}
144+
126145
public static Type getTypeFromPrimitiveCast(MethodInsnNode insn) {
127146
if (insn.getOpcode() != INVOKEVIRTUAL) throw new IllegalArgumentException("Instruction is not an INVOKEVIRTUAL");
128147

deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/transformer/Transformer.java

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.apache.logging.log4j.LogManager;
44
import org.apache.logging.log4j.Logger;
5+
import org.apache.logging.log4j.ThreadContext;
56
import org.jetbrains.annotations.NotNull;
67
import org.jetbrains.annotations.Nullable;
78
import org.jetbrains.annotations.UnmodifiableView;
@@ -23,6 +24,9 @@
2324
public abstract class Transformer extends AsmHelper implements Opcodes {
2425
protected static final Logger LOGGER = LogManager.getLogger();
2526

27+
// ThreadLocal to track transformer nesting depth for log indentation
28+
private static final ThreadLocal<Integer> NESTING_DEPTH = ThreadLocal.withInitial(() -> 0);
29+
2630
private Context context = null;
2731
private ClassWrapper scope = null;
2832

@@ -33,6 +37,38 @@ public abstract class Transformer extends AsmHelper implements Opcodes {
3337
// Config
3438
protected boolean rerunOnChange = false;
3539

40+
/**
41+
* Increases the nesting depth and updates ThreadContext for automatic log indentation
42+
*/
43+
private static void increaseDepth() {
44+
int newDepth = NESTING_DEPTH.get() + 1;
45+
NESTING_DEPTH.set(newDepth);
46+
updateIndentContext(newDepth);
47+
}
48+
49+
/**
50+
* Decreases the nesting depth and updates ThreadContext for automatic log indentation
51+
*/
52+
private static void decreaseDepth() {
53+
int depth = NESTING_DEPTH.get();
54+
if (depth > 0) {
55+
int newDepth = depth - 1;
56+
NESTING_DEPTH.set(newDepth);
57+
updateIndentContext(newDepth);
58+
}
59+
}
60+
61+
/**
62+
* Updates ThreadContext with the indentation string (2 spaces per level)
63+
*/
64+
private static void updateIndentContext(int depth) {
65+
if (depth > 0) {
66+
ThreadContext.put("indent", " ".repeat(depth));
67+
} else {
68+
ThreadContext.remove("indent");
69+
}
70+
}
71+
3672
/**
3773
* Should the transformer rerun if it changed something
3874
*/
@@ -109,14 +145,14 @@ private void init(Context context, ClassWrapper scope) {
109145
* @return Changes count
110146
*/
111147
public static int transform(Supplier<@Nullable Transformer> transformerSupplier, @Nullable ClassWrapper scope, Context context) {
112-
return transform(transformerSupplier, scope, context, false);
148+
return transform(transformerSupplier, scope, context, 0);
113149
}
114150

115151
private static int transform(
116152
Supplier<@Nullable Transformer> transformerSupplier,
117153
@Nullable ClassWrapper scope,
118154
Context context,
119-
boolean reran
155+
int rerunsCount
120156
) {
121157
Transformer transformer = transformerSupplier.get();
122158
if (transformer == null) {
@@ -131,39 +167,46 @@ private static int transform(
131167
// Initialize transformer
132168
transformer.init(context, scope);
133169

134-
LOGGER.info("-------------------------------------");
135-
LOGGER.info("Running {} transformer", transformer.name());
170+
LOGGER.info("▶ {} started", transformer.name());
136171
long start = System.currentTimeMillis();
137172

138-
// Run the transformer!
173+
// Increase nesting depth for automatic log indentation
174+
increaseDepth();
175+
139176
try {
140-
transformer.transform();
141-
} catch (TransformerException e) {
142-
LOGGER.error("! {}: {}", transformer.name(), e.getMessage());
143-
return 0;
144-
} catch (Exception e) {
145-
LOGGER.error("Error occurred when transforming {}", transformer.name(), e);
146-
if (!context.getOptions().continueOnError()) {
147-
throw new RuntimeException(e);
177+
// Run the transformer!
178+
try {
179+
transformer.transform();
180+
} catch (TransformerException e) {
181+
LOGGER.error("! {}: {}", transformer.name(), e.getMessage());
182+
return 0;
183+
} catch (Exception e) {
184+
LOGGER.error("Error occurred when transforming {}", transformer.name(), e);
185+
if (!context.getOptions().continueOnError()) {
186+
throw new RuntimeException(e);
187+
}
188+
return 0;
189+
} finally {
190+
// Mark transformer that it was already used
191+
transformer.hasRan = true;
148192
}
149-
return 0;
193+
194+
LOGGER.info("Made {} changes", transformer.getChangesCount());
150195
} finally {
151-
// Mark transformer that it was already used
152-
transformer.hasRan = true;
196+
// Decrease nesting depth when leaving this transformer
197+
decreaseDepth();
198+
LOGGER.info("◀ {} ended in {} ms", transformer.name(), (System.currentTimeMillis() - start));
153199
}
154200

155201
int changesCount = transformer.getChangesCount();
156202

157-
LOGGER.info("Made {} changes", changesCount);
158-
LOGGER.info("Ended {} transformer in {} ms", transformer.name(), (System.currentTimeMillis() - start));
159-
160203
if (transformer.isChanged() && transformer.shouldRerunOnChange()) {
161-
LOGGER.info("\uD83D\uDD04 Changes detected. Rerunning {} transformer", transformer.name());
162-
changesCount += Transformer.transform(transformerSupplier, scope, context, true);
204+
LOGGER.info("\uD83D\uDD04 Changes detected. Rerunning {} transformer (rerun {})", transformer.name(), rerunsCount + 1);
205+
changesCount += Transformer.transform(transformerSupplier, scope, context, ++rerunsCount);
163206
}
164207

165208
// Bytecode verification
166-
if (context.getOptions().verifyBytecode() && !reran && transformer.isChanged()) {
209+
if (context.getOptions().verifyBytecode() && rerunsCount == 0 && transformer.isChanged()) {
167210
// Verify if bytecode is valid
168211
try {
169212
verifyBytecode(scope, context);

deobfuscator-impl/pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,24 @@
2424
<groupId>org.apache.maven.plugins</groupId>
2525
<artifactId>maven-surefire-plugin</artifactId>
2626
<version>3.4.0</version>
27+
<dependencies>
28+
<dependency>
29+
<groupId>me.fabriciorby</groupId>
30+
<artifactId>maven-surefire-junit5-tree-reporter</artifactId>
31+
<version>1.5.1</version>
32+
</dependency>
33+
</dependencies>
2734

2835
<configuration>
2936
<junitArtifactName>org.junit.jupiter:junit-jupiter</junitArtifactName>
3037
<trimStackTrace>false</trimStackTrace>
38+
<reportFormat>plain</reportFormat>
39+
<consoleOutputReporter>
40+
<disable>true</disable>
41+
</consoleOutputReporter>
42+
<statelessTestsetInfoReporter
43+
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
44+
</statelessTestsetInfoReporter>
3145
</configuration>
3246
</plugin>
3347
</plugins>

deobfuscator-impl/src/main/resources/log4j2.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
<Configuration status="WARN">
33
<Appenders>
44
<Console name="Console" target="SYSTEM_OUT">
5-
<PatternLayout pattern="%highlight{[%d{HH:mm:ss}] [%level]: %msg%n%throwable}{INFO=normal}" disableAnsi="false"/>
5+
<PatternLayout pattern="%highlight{[%d{HH:mm:ss}] [%level]: %X{indent}%msg%n%throwable}{INFO=normal}" disableAnsi="false"/>
66
</Console>
77
<File name="File" fileName="deobfuscator.log" immediateFlush="false" append="false">
8-
<PatternLayout pattern="[%d{HH:mm:ss}] [%level]: %msg%n%throwable"/>
8+
<PatternLayout pattern="[%d{HH:mm:ss}] [%level]: %X{indent}%msg%n%throwable"/>
99
</File>
1010
</Appenders>
1111
<Loggers>

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ protected void registerAll() {
3737
.transformers(StringBuilderTransformer::new)
3838
.inputClass(InputType.JAVA_CODE, "TestStringBuilderTransformer.class")
3939
.register();
40-
// TODO: Uninitialized static fields should replace with 0?
4140
test("Inline static fields")
4241
.transformers(InlineStaticFieldTransformer::new, UselessPopCleanTransformer::new)
4342
.inputClass(InputType.JAVA_CODE, "TestInlineStaticFields.class")

deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/pool/InlineStaticFieldTransformer.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package uwu.narumi.deobfuscator.core.other.impl.pool;
22

3+
import org.objectweb.asm.Type;
34
import org.objectweb.asm.tree.AbstractInsnNode;
45
import org.objectweb.asm.tree.FieldInsnNode;
56
import org.objectweb.asm.tree.analysis.BasicValue;
@@ -24,7 +25,7 @@ public class InlineStaticFieldTransformer extends Transformer {
2425
@Override
2526
protected void transform() throws Exception {
2627
Set<FieldRef> notConstantFields = new HashSet<>();
27-
Map<FieldRef, AbstractInsnNode> staticConstantFields = new HashMap<>();
28+
Map<FieldRef, AbstractInsnNode> staticConstantFields = new HashMap<>(); // field -> constant insn
2829

2930
// Find all static constant fields
3031
scopedClasses().forEach(classWrapper -> findClInit(classWrapper.classNode()).ifPresent(clInit -> {
@@ -61,16 +62,23 @@ protected void transform() throws Exception {
6162
});
6263
}));
6364

64-
// Also account for FieldNode#value
65+
// Also account for FieldNode#value and default field type value
6566
scopedClasses().forEach(classWrapper -> {
6667
classWrapper.classNode().fields.forEach(fieldNode -> {
67-
if (fieldNode.value != null) {
68-
FieldRef fieldRef = FieldRef.of(classWrapper.classNode(), fieldNode);
68+
FieldRef fieldRef = FieldRef.of(classWrapper.classNode(), fieldNode);
6969

70-
if (!staticConstantFields.containsKey(fieldRef)) {
71-
// Add it to static constant fields
72-
staticConstantFields.put(fieldRef, AsmHelper.toConstantInsn(fieldNode.value));
73-
}
70+
if (notConstantFields.contains(fieldRef)) return;
71+
72+
Object value = fieldNode.value;
73+
// If value is null, get the default value for type
74+
if (value == null) {
75+
Type fieldType = Type.getType(fieldNode.desc);
76+
value = AsmHelper.getDefaultTypeValue(fieldType);
77+
}
78+
79+
if (!staticConstantFields.containsKey(fieldRef)) {
80+
// Add it to static constant fields
81+
staticConstantFields.put(fieldRef, AsmHelper.toConstantInsn(value));
7482
}
7583
});
7684
});

testData/results/java/TestInlineStaticFields.dec

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
public class TestInlineStaticFields {
22
public static int TEST1 = 123;
3-
public static int TEST4;
43
public static String TEST5;
54

65
public static void test() {
76
System.out.println(TEST1);
87
System.out.println("placki");
98
System.out.println(true);
10-
System.out.println(TEST4);
9+
System.out.println(0);
1110
System.out.println(TEST5.toUpperCase());
1211
}
1312

0 commit comments

Comments
 (0)