Java逆向记录(三),ASM的使用

分析

之前的招不太管用,然后只能从字节码下手,分析之后字符串混淆的字节码基本是

1
2
3
SIPUSH xxxx
SIPUSH xxxx
INVOKESTATIC a(int,int)String;

这种形式,于是打算使用ASM修改字节码,将这一段改成具体的字符串入栈,即:

1
LDC "xxxxxx"

修改字节码时,并没有使用原始的ClassVisitor和MethodVisitor,而是使用ClassNode和MethodNode,以迭代器的形式进行遍历:

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
public static void test(String className) throws Exception {
ClassReader reader = new ClassReader(className);
ClassNode classNode = new ClassNode();
reader.accept(classNode, ClassReader.EXPAND_FRAMES);
final List<MethodNode> methods = classNode.methods;
for (MethodNode methodNode : methods) {
final ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
while (iterator.hasNext()) {
final AbstractInsnNode sipush1 = iterator.next();
if (sipush1 instanceof IntInsnNode) {
//这地方主要是判断字节是否是SIPUSH,SIPUSH,INVOKESTATIC的形式
if (sipush1.getOpcode() == SIPUSH && iterator.hasNext()) {
final AbstractInsnNode siPush2 = sipush1.getNext();
final AbstractInsnNode invokeStatic = siPush2.getNext();
if (sipush1.getOpcode() == siPush2.getOpcode() &&
invokeStatic.getOpcode() == INVOKESTATIC) {
int v1 = ((IntInsnNode) sipush1).operand;
int v2 = ((IntInsnNode) siPush2).operand;
final String value1 = getValue(className, v1, v2);
if (value1 == null) {
continue;
}
System.out.println(" do replace... [" + value1 + "] in " + className);
iterator.remove();
iterator.next();
iterator.remove();
iterator.next();
iterator.set(new LdcInsnNode(value1));
}
}
}

}
}
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
classNode.accept(writer);
final byte[] bytes1 = writer.toByteArray();
//write to file ....
}

遇到的坑

其中遇到的坑大概是设置ASM修改级别的时候,使用ASM5级别的时候会导致修改lambda报错。

还有就是设置ClassReader的ClassReader.EXPAND_FRAMES 和ClassWriter的ClassWriter.COMPUTE_FRAMES,搞不好会搞混了。