Skip to content

Commit a46a6b0

Browse files
committed
Oops, include these files too
1 parent 8029344 commit a46a6b0

File tree

3 files changed

+295
-0
lines changed

3 files changed

+295
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright 2018 Sam Sun <github-contact@samczsun.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.javadeobfuscator.deobfuscator.transformers.stringer.invokedynamic;
18+
19+
import com.javadeobfuscator.deobfuscator.config.*;
20+
import com.javadeobfuscator.deobfuscator.exceptions.*;
21+
import com.javadeobfuscator.deobfuscator.transformers.*;
22+
import com.javadeobfuscator.deobfuscator.utils.*;
23+
import com.javadeobfuscator.javavm.*;
24+
import com.javadeobfuscator.javavm.exceptions.*;
25+
import com.javadeobfuscator.javavm.mirrors.*;
26+
import com.javadeobfuscator.javavm.nativeimpls.*;
27+
import com.javadeobfuscator.javavm.values.*;
28+
import org.objectweb.asm.*;
29+
import org.objectweb.asm.Type;
30+
import org.objectweb.asm.tree.*;
31+
32+
import java.lang.reflect.*;
33+
import java.util.*;
34+
35+
/**
36+
* This mode of Stringer's invokedynamic obfuscation encodes the target method within
37+
* the method name and an additional string param. It can be identified by a method of signature
38+
* {@code (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/Object;}
39+
* and a randomly generated name
40+
*/
41+
public class Invokedynamic1Transformer extends Transformer<TransformerConfig> implements Opcodes {
42+
public static final String BSM_DESC = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/Object;";
43+
44+
List<JavaWrapper> data = new ArrayList<>();
45+
46+
@Override
47+
public boolean transform() throws WrongTransformerException {
48+
VirtualMachine vm = TransformerHelper.newVirtualMachine(this);
49+
50+
for (ClassNode classNode : classes.values()) {
51+
for (MethodNode methodNode : new ArrayList<>(classNode.methods)) {
52+
InstructionModifier modifier = new InstructionModifier();
53+
54+
int decryptorMethodCount = 0;
55+
56+
for (AbstractInsnNode insn : TransformerHelper.instructionIterator(methodNode)) {
57+
if (!(insn instanceof InvokeDynamicInsnNode)) continue;
58+
59+
InvokeDynamicInsnNode invokeDynamicInsnNode = (InvokeDynamicInsnNode) insn;
60+
if (!invokeDynamicInsnNode.bsm.getOwner().equals(classNode.name)) continue;
61+
if (!invokeDynamicInsnNode.bsm.getDesc().equals(BSM_DESC)) continue;
62+
63+
MethodNode decryptorMethod = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "Decrypt" + decryptorMethodCount++, "()V", null, null);
64+
65+
Type[] argTypes = Type.getArgumentTypes(invokeDynamicInsnNode.desc);
66+
for (Type type : argTypes) {
67+
decryptorMethod.instructions.add(TransformerHelper.zero(type));
68+
}
69+
decryptorMethod.instructions.add(invokeDynamicInsnNode.clone(null));
70+
decryptorMethod.instructions.add(new InsnNode(RETURN));
71+
72+
73+
vm.beforeCallHooks.add(info -> {
74+
if (info.getClassNode().name.equals("java/lang/invoke/MethodHandles$Lookup")
75+
&& info.getMethodNode().desc.equals("(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;")) {
76+
// Make sure it's the BSM calling the find method and not the JVM
77+
if (vm.getStacktrace().get(0).getClassNode() == classNode) {
78+
logger.info("got data " + info.getParams().get(0) + " " + vm.convertJavaObjectToString(info.getParams().get(1)));
79+
data.addAll(info.getParams());
80+
throw AbortException.INSTANCE;
81+
}
82+
}
83+
});
84+
85+
classNode.methods.add(decryptorMethod);
86+
try {
87+
data.clear();
88+
if (classNode.name.equals("com/licel/stringer/V")) {
89+
TransformerHelper.dumpMethod(decryptorMethod);
90+
}
91+
logger.info("Decrypting {} {}{} {} {}", classNode.name, methodNode.name, methodNode.desc, invokeDynamicInsnNode.bsmArgs[0], invokeDynamicInsnNode.name);
92+
vm.execute(classNode, decryptorMethod);
93+
} catch (AbortException ignored) {
94+
} catch (VMException e) {
95+
logger.info("Exception while decrypting invokedynamic in {}", classNode.name);
96+
logger.info(vm.exceptionToString(e));
97+
continue;
98+
} catch (Throwable e) {
99+
logger.info("Severe exception while decrypting invokedynamic in {}", classNode.name, e);
100+
continue;
101+
} finally {
102+
classNode.methods.remove(decryptorMethod);
103+
vm.beforeCallHooks.clear();
104+
}
105+
106+
if (data.size() != 3) {
107+
oops("got bad data for {} {}{}: {}", classNode.name, methodNode.name, methodNode.desc, data);
108+
continue;
109+
}
110+
111+
JavaClass owner = java_lang_Class.getJavaClass(data.get(0));
112+
String name = vm.convertJavaObjectToString(data.get(1));
113+
String desc = java_lang_invoke_MethodType.asSignature(data.get(2), false);
114+
MethodNode indyMethod = owner.findMethodNode(name, desc, true);
115+
116+
int opcode;
117+
if (Modifier.isStatic(indyMethod.access)) {
118+
opcode = INVOKESTATIC;
119+
} else {
120+
if (Modifier.isInterface(owner.getClassNode().access)) {
121+
opcode = INVOKEINTERFACE;
122+
} else {
123+
opcode = INVOKEVIRTUAL;
124+
}
125+
}
126+
127+
modifier.replace(invokeDynamicInsnNode, new MethodInsnNode(opcode, owner.getClassNode().name, indyMethod.name, indyMethod.desc, opcode == INVOKEINTERFACE));
128+
129+
logger.info("Decrypted {} {}{}: {} {}{}", classNode.name, methodNode.name, methodNode.desc, owner.getClassNode().name, name, desc);
130+
}
131+
132+
modifier.apply(methodNode);
133+
}
134+
}
135+
136+
vm.shutdown();
137+
return false;
138+
}
139+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright 2018 Sam Sun <github-contact@samczsun.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.javadeobfuscator.deobfuscator.transformers.stringer.invokedynamic;
18+
19+
import com.javadeobfuscator.deobfuscator.config.*;
20+
import com.javadeobfuscator.deobfuscator.exceptions.*;
21+
import com.javadeobfuscator.deobfuscator.transformers.*;
22+
import com.javadeobfuscator.deobfuscator.utils.*;
23+
import com.javadeobfuscator.javavm.*;
24+
import com.javadeobfuscator.javavm.exceptions.*;
25+
import com.javadeobfuscator.javavm.mirrors.*;
26+
import com.javadeobfuscator.javavm.nativeimpls.*;
27+
import com.javadeobfuscator.javavm.values.*;
28+
import org.objectweb.asm.*;
29+
import org.objectweb.asm.Type;
30+
import org.objectweb.asm.tree.*;
31+
32+
import java.lang.reflect.*;
33+
import java.util.*;
34+
35+
/**
36+
* This mode of Stringer's invokedynamic obfuscation generates a bootstrap method for each invokedynamic with the signature
37+
* {@code (Ljava/lang/Object;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object;}
38+
*/
39+
public class Invokedynamic2Transformer extends Transformer<TransformerConfig> implements Opcodes {
40+
public static final String BSM_DESC = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object;";
41+
42+
@Override
43+
public boolean transform() throws WrongTransformerException {
44+
VirtualMachine vm = TransformerHelper.newVirtualMachine(this);
45+
46+
for (ClassNode classNode : classes.values()) {
47+
JavaClass.forName(vm, classNode.name).setInitializationState(JavaClass.InitializationState.INITIALIZED, null);
48+
}
49+
50+
for (ClassNode classNode : classes.values()) {
51+
for (MethodNode methodNode : new ArrayList<>(classNode.methods)) {
52+
InstructionModifier modifier = new InstructionModifier();
53+
54+
int decryptorMethodCount = 0;
55+
56+
for (AbstractInsnNode insn : TransformerHelper.instructionIterator(methodNode)) {
57+
if (!(insn instanceof InvokeDynamicInsnNode)) continue;
58+
59+
InvokeDynamicInsnNode invokeDynamicInsnNode = (InvokeDynamicInsnNode) insn;
60+
if (!invokeDynamicInsnNode.bsm.getOwner().equals(classNode.name)) continue;
61+
if (!invokeDynamicInsnNode.bsm.getDesc().equals(BSM_DESC)) continue;
62+
63+
MethodNode decryptorMethod = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "Decrypt" + decryptorMethodCount++, "()Ljava/lang/", null, null);
64+
65+
Type[] argTypes = Type.getArgumentTypes(invokeDynamicInsnNode.desc);
66+
for (Type type : argTypes) {
67+
decryptorMethod.instructions.add(TransformerHelper.zero(type));
68+
}
69+
decryptorMethod.instructions.add(invokeDynamicInsnNode.clone(null));
70+
decryptorMethod.instructions.add(new InsnNode(RETURN));
71+
72+
List<JavaWrapper> data = new ArrayList<>();
73+
74+
vm.beforeCallHooks.add(info -> {
75+
if (info.getClassNode().name.equals("java/lang/invoke/MethodHandles$Lookup")
76+
&& info.getMethodNode().desc.equals("(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;")) {
77+
// Make sure it's the BSM calling the find method and not the JVM
78+
if (vm.getStacktrace().get(0).getClassNode() == classNode) {
79+
data.addAll(info.getParams());
80+
throw AbortException.INSTANCE;
81+
}
82+
}
83+
});
84+
85+
classNode.methods.add(decryptorMethod);
86+
try {
87+
vm.execute(classNode, decryptorMethod);
88+
} catch (AbortException ignored) {
89+
} catch (VMException e) {
90+
logger.info("Exception while decrypting invokedynamic in {}", classNode.name);
91+
logger.info(vm.exceptionToString(e));
92+
continue;
93+
} catch (Throwable e) {
94+
logger.info("Severe exception while decrypting invokedynamic in {}", classNode.name, e);
95+
continue;
96+
} finally {
97+
classNode.methods.remove(decryptorMethod);
98+
vm.beforeCallHooks.clear();
99+
}
100+
101+
if (data.size() != 3) {
102+
oops("got bad data for {} {}{}: {}", classNode.name, methodNode.name, methodNode.desc, data);
103+
continue;
104+
}
105+
106+
JavaClass owner = java_lang_Class.getJavaClass(data.get(0));
107+
String name = vm.convertJavaObjectToString(data.get(1));
108+
String desc = java_lang_invoke_MethodType.asSignature(data.get(2), false);
109+
MethodNode indyMethod = owner.findMethodNode(name, desc, true);
110+
111+
if (indyMethod == null) {
112+
oops("couldn't find method {} {}{}", classNode.name, name, desc);
113+
continue;
114+
}
115+
116+
int opcode;
117+
if (Modifier.isStatic(indyMethod.access)) {
118+
opcode = INVOKESTATIC;
119+
} else {
120+
if (Modifier.isInterface(owner.getClassNode().access)) {
121+
opcode = INVOKEINTERFACE;
122+
} else {
123+
opcode = INVOKEVIRTUAL;
124+
}
125+
}
126+
127+
modifier.replace(invokeDynamicInsnNode, new MethodInsnNode(opcode, owner.getClassNode().name, indyMethod.name, indyMethod.desc, opcode == INVOKEINTERFACE));
128+
129+
logger.info("Decrypted {} {}{}", owner.getClassNode().name, name, desc);
130+
}
131+
132+
modifier.apply(methodNode);
133+
}
134+
}
135+
136+
vm.shutdown();
137+
return false;
138+
}
139+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright 2018 Sam Sun <github-contact@samczsun.com>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.javadeobfuscator.deobfuscator.transformers.stringer.invokedynamic;

0 commit comments

Comments
 (0)