Usar vlx-vmengine para la deofuscación.
vlx-vmengine-jvm es un motor de ejecución de bytecode Java implementado en Java. Consulte https://github.com/vlinx-io/vlx-vmengine-jvm para su uso.
Hay un código Java simple como el siguiente:
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();
}
}
Después de compilar en archivos class y ofuscar con un determinado motor de ofuscación, se obtienen los siguientes archivos:
Después de abrir con jadx, se descubrió que aparte de la función main, toda la demás información es irreconocible y las cadenas han sido cifradas.

Sin embargo, incluso si está ofuscado, la estructura básica de la clase y la información del bytecode aún existen. Usando ClassViewer para abrir a.class, puede ver los métodos y la información del bytecode de la clase.

Sin importar cómo se ofusque, solo puede confundir el código a nivel estático y aumentar la complejidad del análisis. En la ejecución dinámica, aún necesita restaurar la lógica de ejecución original del programa. Usando vlx-vmengine-jvm para ejecutar el código ofuscado en el método main, obtenemos la siguiente salida
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"
De la salida de la consola, podemos ver que el programa ha restaurado su comportamiento original, que es imprimir Hi, George. Al mismo tiempo, de la salida, también podemos determinar que la función de descifrado de cadenas está en private static java.lang.String a.a(int,int), con los parámetros 7144 y -13249. Si continuamos usando vmengine para depurar el método a.a(int,int), podemos descubrir el método de cifrado de cadenas utilizado por este motor de ofuscación.