Sử dụng vlx-vmengine để giải rối mã
vlx-vmengine-jvm là công cụ thực thi bytecode Java được triển khai bằng Java. Vui lòng tham khảo https://github.com/vlinx-io/vlx-vmengine-jvm để biết cách sử dụng.
Có một đoạn mã Java đơn giản như sau:
class HelloWorld {
private String name = "";
public HelloWorld(String name){
this.name = name;
}
public void sayHi(){
System.out.println("Hi, " + name);
}
public static void main(String[] args){
String name = "George";
HelloWorld hello = new HelloWorld(name);
hello.sayHi();
}
}
Sau khi biên dịch thành tệp class và làm rối bằng một công cụ làm rối nhất định, các tệp sau được thu được:
Sau khi mở bằng jadx, phát hiện ngoài hàm main, tất cả các thông tin khác đều không thể nhận dạng và các chuỗi đã bị mã hóa.

Tuy nhiên, ngay cả khi đã bị làm rối, cấu trúc cơ bản của class và thông tin bytecode vẫn tồn tại. Sử dụng ClassViewer để mở a.class, bạn có thể thấy các phương thức và thông tin bytecode của class.

Dù làm rối như thế nào, nó chỉ có thể làm rối mã ở cấp độ tĩnh và tăng độ phức tạp của phân tích. Trong quá trình thực thi động, nó vẫn cần khôi phục logic chạy gốc của chương trình. Sử dụng vlx-vmengine-jvm để chạy mã đã bị làm rối trong phương thức main, chúng tôi nhận được đầu ra sau
2023-05-21 18:19:05 [DEBUG] LocalVars: [kotlin.Unit, kotlin.Unit, kotlin.Unit]
2023-05-21 18:19:05 [DEBUG] "L0: SIPUSH"
2023-05-21 18:19:05 [DEBUG] "push" 7144
2023-05-21 18:19:05 [DEBUG] "L3: SIPUSH"
2023-05-21 18:19:05 [DEBUG] "push" -13249
2023-05-21 18:19:05 [DEBUG] "L6: INVOKESTATIC"
2023-05-21 18:19:05 [DEBUG] "#20"
2023-05-21 18:19:05 [DEBUG] "class a, NameAndType(name='a', type='(II)Ljava/lang/String;')"
2023-05-21 18:19:05 [DEBUG] private static java.lang.String a.a(int,int)
2023-05-21 18:19:05 [DEBUG] "pop" -13249
2023-05-21 18:19:05 [DEBUG] "pop" 7144
2023-05-21 18:19:05 [DEBUG] Execute method: private static java.lang.String a.a(int,int)
2023-05-21 18:19:05 [DEBUG] Args: [7144, -13249]
2023-05-21 18:19:05 [DEBUG] "push" "George"
2023-05-21 18:19:05 [DEBUG] "L9: ASTORE_1"
2023-05-21 18:19:05 [DEBUG] "pop" "George"
2023-05-21 18:19:05 [DEBUG] "localVars[1] = George"
2023-05-21 18:19:05 [DEBUG] "L10: NEW"
2023-05-21 18:19:05 [DEBUG] class a
2023-05-21 18:19:05 [DEBUG] "push" InstanceToCreate(clazz=class a)
2023-05-21 18:19:05 [DEBUG] "L13: DUP"
2023-05-21 18:19:05 [DEBUG] "pop" InstanceToCreate(clazz=class a)
2023-05-21 18:19:05 [DEBUG] "push" InstanceToCreate(clazz=class a)
2023-05-21 18:19:05 [DEBUG] "push" InstanceToCreate(clazz=class a)
2023-05-21 18:19:05 [DEBUG] "L14: ALOAD_1"
2023-05-21 18:19:05 [DEBUG] "#1"
2023-05-21 18:19:05 [DEBUG] "push" "George"
2023-05-21 18:19:05 [DEBUG] "L15: INVOKESPECIAL"
2023-05-21 18:19:05 [DEBUG] "#47"
2023-05-21 18:19:05 [DEBUG] "class a, NameAndType(name='<init>', type='(Ljava/lang/String;)V')"
2023-05-21 18:19:05 [DEBUG] public a(java.lang.String)
2023-05-21 18:19:05 [DEBUG] "pop" "George"
2023-05-21 18:19:05 [DEBUG] "Execute new instance: public a(java.lang.String)"
2023-05-21 18:19:05 [DEBUG] "Args: [George]"
2023-05-21 18:19:05 [DEBUG] "pop" InstanceToCreate(clazz=class a)
2023-05-21 18:19:05 [DEBUG] "L18: ASTORE_2"
2023-05-21 18:19:05 [DEBUG] "pop" a@4612b856
2023-05-21 18:19:05 [DEBUG] "localVars[2] = a@4612b856"
2023-05-21 18:19:05 [DEBUG] "L19: ALOAD_2"
2023-05-21 18:19:05 [DEBUG] "#2"
2023-05-21 18:19:05 [DEBUG] "push" a@4612b856
2023-05-21 18:19:05 [DEBUG] "L20: INVOKEVIRTUAL"
2023-05-21 18:19:05 [DEBUG] "#54"
2023-05-21 18:19:05 [DEBUG] "class a, NameAndType(name='a', type='()V')"
2023-05-21 18:19:05 [DEBUG] public void a.a()
2023-05-21 18:19:05 [DEBUG] "pop" a@4612b856
2023-05-21 18:19:05 [DEBUG] Execute method: public void a.a()
2023-05-21 18:19:05 [DEBUG] Receiver: a@4612b856
2023-05-21 18:19:05 [DEBUG] Args: [a@4612b856]
Hi, George
2023-05-21 18:19:05 [DEBUG] "L23: RETURN"
Từ đầu ra console, chúng ta có thể thấy rằng chương trình đã khôi phục hành vi gốc, đó là in Hi, George. Đồng thời, từ đầu ra, chúng ta cũng có thể xác định rằng hàm giải mã chuỗi nằm trong private static java.lang.String a.a(int,int), với các tham số 7144 và -13249. Nếu chúng ta tiếp tục sử dụng vmengine để gỡ lỗi phương thức a.a(int,int), chúng ta có thể phát hiện phương pháp mã hóa chuỗi được sử dụng bởi công cụ làm rối này.