CalebFenton / simplify

Android virtual machine and deobfuscator
Other
4.41k stars 438 forks source link

Unable to deobfuscate reflection in obfuscated-app.apk #151

Closed wzj1695224 closed 3 years ago

wzj1695224 commented 3 years ago

According to simplify/ObfuscatedApp/README.md, it may easily to deobfuscate reflection in obfuscated-app.apk. But when I tried with

java -jar simplify/build/libs/simplify.jar -it 'org/cf/obfuscated' -et 'MainActivity' simplify/obfuscated-app.apk
...
(8 / 8) Executing top level method: Lorg/cf/obfuscated/Reflection;->reflectSecretMethod()V
14:07:35.555 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:07:35.611 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:07:35.662 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:07:35.717 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:07:35.767 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:07:35.821 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:07:35.873 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:07:35.961 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:07:36.017 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
Simplifying: Lorg/cf/obfuscated/Reflection;->reflectSecretMethod()V
Optimizations:
    constantized ifs = 0
    constantized ops = 0
    dead assignments removed = 0
    dead ops removed = 0
    dead results removed = 0
    nops removed = 0
    peephole optmizations = 0
    unreflected fields = 0
    unreflected methods = 0
    useless gotos removed = 0

...

[8 / 20] Processing top level class Lorg/cf/obfuscated/StringHolder;
(1 / 5) Executing top level method: Lorg/cf/obfuscated/StringHolder;->get(I)Ljava/lang/String;
14:07:36.125 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z

I found nothing did in the Reflection.reflectSecretMethod(...)

Then I tried

java -jar simplify/build/libs/simplify.jar -it 'org/cf/obfuscated/Reflection;->reflectSecretMethod\(' -et 'MainActivity' simplify/obfuscated-app.apk
[1 / 1] Processing top level class Lorg/cf/obfuscated/Reflection;
(1 / 1) Executing top level method: Lorg/cf/obfuscated/Reflection;->reflectSecretMethod()V
14:10:48.420 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:10:48.502 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:10:48.586 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:10:48.671 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:10:48.750 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:10:48.828 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:10:48.906 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:10:49.023 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
14:10:49.090 WARN  InvokeOp     - org.cf.smalivm.exception.MaxAddressVisitsExceededException: Exceeded max address visits @0 ExecutionNode{signature=Landroid/util/Base64$Decoder;->process([BIIZ)Z, op=iget r9, r11, Landroid/util/Base64$Decoder;->state:I, @=0} in Landroid/util/Base64$Decoder;->process([BIIZ)Z
Simplifying: Lorg/cf/obfuscated/Reflection;->reflectSecretMethod()V
Optimizations:
    constantized ifs = 0
    constantized ops = 0
    dead assignments removed = 0
    dead ops removed = 0
    dead results removed = 0
    nops removed = 0
    peephole optmizations = 0
    unreflected fields = 0
    unreflected methods = 0
    useless gotos removed = 0
Simplification complete:
    total classes = 1
    total methods = 1
    optimized methods = 1
    failed methods = 0
    run time = 4902 ms
Total optimizations:
    constantized ifs = 0
    constantized ops = 0
    dead assignments removed = 0
    dead ops removed = 0
    dead results removed = 0
    nops removed = 0
    peephole optmizations = 0
    unreflected fields = 0
    unreflected methods = 0
    useless gotos removed = 0
Writing output to obfuscated-app_simple.apk

still nothing change in Reflection.reflectSecretMethod(...)

next I did the following

java -jar simplify/build/libs/simplify.jar -it 'org/cf/obfuscated/Reflection;->reflectSecretMethod\(' -et 'MainActivity' simplify/obfuscated-app.apk --max-execution-time 600 --max-address-visits 1000000 --max-method-visits 1000000

and finally

java -Xmx24G -jar simplify/build/libs/simplify.jar -it 'org/cf/obfuscated/Reflection;->reflectSecretMethod\(' -et 'MainActivity' simplify/obfuscated-app.apk --max-execution-time 600 --max-address-visits 100000000 --max-method-visits 100000000
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded

What''s wrong?😭

CalebFenton commented 3 years ago

After some investigation, it appears the problem is that recent framework changes moved some of the Base64 decoding to object state. I.e. instead of having some static methods, they instantiate a Decoder and that has some instance state which simplify doesn't trust and assumes it's unknown. It's related to this: https://github.com/CalebFenton/simplify/issues/22

Two possible solutions come to mind. First, convert Base64 code to Java, include in Simplify, and emulate instead of virtually execute. This was done in the past and one of the benefits is that the code is hella fast and won't break between frameworks. The second solution is to allow users to trust object instance state, which is almost always going to be a bad idea in general. Could be reasonable by whitelisting certain fields. Explaining wtf is happening in the docs will be harder than writing the code.

CalebFenton commented 3 years ago

https://github.com/CalebFenton/simplify/commit/edc784d7f7fc3380cc37a6313d80147455016260 should fix your issue. Want to try and let me know?

wzj1695224 commented 3 years ago

It's working now. Thank you very much.