{"id":4526,"date":"2022-11-03T20:19:43","date_gmt":"2022-11-04T04:19:43","guid":{"rendered":"https:\/\/www.pnfsoftware.com\/blog\/?p=4526"},"modified":"2022-11-04T09:03:11","modified_gmt":"2022-11-04T17:03:11","slug":"reversing-dprotect","status":"publish","type":"post","link":"https:\/\/www.pnfsoftware.com\/blog\/reversing-dprotect\/","title":{"rendered":"Reversing dProtect"},"content":{"rendered":"\n<p>In this post, we&#8217;re having a look at the first release of <a href=\"https:\/\/obfuscator.re\/dprotect\/\">dProtect<\/a> (v 1.0) by Romain Thomas. dProtect is a fork of ProGuard that provides four additional self-explanatory configuration flags:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>-obfuscate-strings<\/code><\/li>\n\n\n\n<li><code>-obfuscate-constants<\/code><\/li>\n\n\n\n<li><code>-obfuscate-arithmetic<\/code><\/li>\n\n\n\n<li><code>-obfuscate-control-flow<\/code> (via flattening &amp; opaque predicates &#8212; unfortunately, I was unable to get this flag to work, so it&#8217;s something we&#8217;ll have to revisit in the future.)<\/li>\n<\/ul>\n\n\n\n<p>Let&#8217;s see how JEB&#8217;s dexdec&#8217;s built-in optimizers as well as custom IR plugins can be used to defeat some implementations of strings obfuscation, constants obfuscation, and arithmetic operations obfuscation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Strings Obfuscation<\/h2>\n\n\n\n<p>The test method is as follows:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/ targeted by: -obfuscate-strings\npublic String provideString() {\n    return &quot;hello dProtect&quot;;\n}\n<\/pre><\/div>\n\n\n<p>Let&#8217;s disable dexdec&#8217;s built-in deobfuscators (CTRL+TAB to decompile, untick &#8220;Enable deobfuscators&#8221;) to get a chance to look at the obfuscated code. It decompiles to:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic static String a(String arg14) {\n    StringBuilder v0 = new StringBuilder();\n    int v1 = ((int)DPTest1.b&#x5B;4]) ^ 1684628051;\nlabel_8:\n    while(v1 &lt; arg14.length()) {\n        int v2 = arg14.charAt(v1);\n        while(true) {\n            int v9 = v2 ^ -1;\n            v0.append(((char)((((int)DPTest1.b&#x5B;10]) ^ 0x2AE022E9) + v2 + (((int)DPTest1.b&#x5B;3]) ^ 0x35A299BD) + (((int)DPTest1.b&#x5B;10]) ^ 0x2AE022E9 ^ -1 | v9) - ((((int)DPTest1.b&#x5B;10]) ^ 0x2AE022E9) + v2 - ((((int)DPTest1.b&#x5B;10]) ^ 0x2AE022E9) + v2 + (((int)DPTest1.b&#x5B;3]) ^ 0x35A299BD) + (((int)DPTest1.b&#x5B;10]) ^ 0x2AE022E9 ^ -1 | v9))))));\n            long&#x5B;] v3 = DPTest1.b;\n            int v6 = v1 ^ -1;\n            v1 = v1 + (((int)v3&#x5B;3]) ^ 0x35A299BD) + (((int)v3&#x5B;3]) ^ 0x35A299BD) + (((int)v3&#x5B;3]) ^ 0x35A299BD ^ -1 | v6) + ((((int)v3&#x5B;3]) ^ 0x35A299BD) + v1 - ((((int)v3&#x5B;3]) ^ 0x35A299BD) + v1 + (((int)v3&#x5B;3]) ^ 0x35A299BD) + (((int)v3&#x5B;3]) ^ 0x35A299BD ^ -1 | v6)));\n            if((DPTest1.a + (((int)v3&#x5B;3]) ^ 0x35A299BD)) % (((int)v3&#x5B;7]) ^ 0x2B0F969A) != 0) {\n                continue label_8;\n            }\n        }\n    }\n\n    return v0.toString();\n}\n\npublic String provideString() {\n    return DPTest1.a(&quot;\u6b6c\u6b61\u6b68\u6b68\u6b6b\u6b24\u6b60\u6b54\u6b76\u6b6b\u6b70\u6b61\u6b67\u6b70&quot;);\n}\n<\/pre><\/div>\n\n\n<p>A decryptor method <code>a(String):String<\/code> was generated by dProtect. It performs various computations  to decrypt the input string.<\/p>\n\n\n\n<p>One built-in optimizer that ships with JEB&#8217;s dexdec uses the <a href=\"https:\/\/www.pnfsoftware.com\/jeb\/apidoc\/reference\/com\/pnfsoftware\/jeb\/core\/units\/code\/android\/ir\/IDState.html\">IDState<\/a> object to perform emulation (explained in <a href=\"https:\/\/www.pnfsoftware.com\/blog\/jeb-gendec-ir-emulation-for-auto-decryption-of-data-items\/\">a previous blog<\/a>). It cleans up such code automatically:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"154\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1024x154.png\" alt=\"\" class=\"wp-image-4530\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1024x154.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-300x45.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-768x115.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1536x230.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image.png 1680w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">provideString() is auto-deobfuscated by JEB&#8217;s dexdec<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Arithmetic Operations Obfuscation<\/h2>\n\n\n\n<p>The test method is as follows:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/ targeted by: -obfuscate-arithmetic\npublic int calculate(int x) {\n    return 100 + x;\n}\n<\/pre><\/div>\n\n\n<p>With standard JEB settings (re-tick &#8220;Enable deobfuscators&#8221; if you had disabled it), the obfuscated code decompiles to:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\nstatic {\n    long&#x5B;] v0 = new long&#x5B;12];\n    DPTest1.b = v0;\n    v0&#x5B;0] = 0x371C2961L;\n    v0&#x5B;1] = 0x13DD5724L;\n    v0&#x5B;2] = 0x17EB3014L;\n    v0&#x5B;3] = 0x35A299BCL;\n    v0&#x5B;4] = 1684628051L;\n    v0&#x5B;5] = 1720310111L;\n    v0&#x5B;6] = 0x576F77CBL;\n    v0&#x5B;7] = 0x2B0F9698L;\n    v0&#x5B;8] = 360862103L;\n    v0&#x5B;9] = 0x5A9D6037L;\n    v0&#x5B;10] = 0x2AE049EDL;\n    v0&#x5B;11] = 2060383159L;\n    DPTest1.a = ((int)v0&#x5B;11]) ^ 1305664179;\n}\n\npublic int calculate(int arg4) {\n    return arg4 + (((int)DPTest1.b&#x5B;0]) ^ 0x371C2905);\n}\n<\/pre><\/div>\n\n\n<p>As can be seen, the constant 100 has been replaced by an arithmetic operation, here, a XOR operating on an immediate and a static array element set up in the class initializer.<\/p>\n\n\n\n<p>JEB does not ship with overly complex deobfuscators operating on arrays, because it is near-impossible in the general case to assess their finality (i.e. answer the question &#8220;will values be changed during the program execution?&#8221; definitively). However, to solve particular cases of obfuscation, writing a custom IR plugin to tackle this obfuscation is an acceptable solution. (Have a look at <a href=\"https:\/\/www.pnfsoftware.com\/blog\/writing-dexdec-ir-optimizer-plugins\/\">this post to get started on dexdec IR plugins<\/a>.)<\/p>\n\n\n\n<p>Let&#8217;s check <a href=\"https:\/\/github.com\/pnfsoftware\/jeb-samplecode\/blob\/master\/plugins\/scripts\/DOptUnsafeArrayAccessSubst.java\">DOptUnsafeArrayAccessSubst.java<\/a>, a sample IR plugin that ships with JEB (folder coreplugins\/scripts\/) and does does exactly what we need: <strong>detecting the use of static array elements and replacing them by their actual values<\/strong>. We can enable the plugin by removing the &#8220;.DISABLED&#8221; extension. Now redecompile (CTRL+TAB). And&#8230; well, nothing has changed! It is time to examine the plugin code carefully, maybe even use your favorite IDE to troubleshoot and augment it. Here is what prevented the original plugin from kicking in: the plugin was looking for IR elements such as: <code>IDArrayElt ^ IDImm<\/code>. However, the IR it got was: <code>(&lt;int>IDArrayElt) ^ IDImm<\/code>, that is, the array element was cast to <code>int<\/code>, making the IR expression an IDOperation, not an IDArrayElt.<\/p>\n\n\n\n<p>The <a href=\"https:\/\/gist.github.com\/nfalliere\/e9166a3c6eedf4b4326d575b69cedf7d\">DOptUnsafeArrayAccessSubstV2.java<\/a> plugin takes care of that (refer to isLikeArrayElt method).<\/p>\n\n\n\n<p>Now we can redecompile. and things were deobfuscated as expected:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"87\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1-1024x87.png\" alt=\"\" class=\"wp-image-4531\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1-1024x87.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1-300x25.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1-768x65.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1-1536x130.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-1.png 1696w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">calculate() is deobfuscated by DOptUnsafeArrayAccessSubstV2<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Constants Scrambling<\/h2>\n\n\n\n<p>Finally, let&#8217;s have a look at how constants obfuscation is achieved. The documentation gives examples of cryptographic-like S-boxes being initialized. The test method is as follows:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n\/\/ targeted by: -obfuscate-constants\npublic void initArray(int&#x5B;] a) {\n    a&#x5B;0] = 0x61707865;\n    a&#x5B;1] = 0x3320646e;\n    a&#x5B;2] = 0x79622d32;\n    a&#x5B;3] = 0x6b206574;\n}\n<\/pre><\/div>\n\n\n<p>Out of the box, JEB decompiles the obfuscated code to:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\nstatic {\n    long&#x5B;] v0 = new long&#x5B;12];\n    DPTest1.b = v0;\n    v0&#x5B;0] = 0x371C2961L;\n    v0&#x5B;1] = 0x13DD5724L;\n    v0&#x5B;2] = 0x17EB3014L;\n    v0&#x5B;3] = 0x35A299BCL;\n    v0&#x5B;4] = 1684628051L;\n    v0&#x5B;5] = 1720310111L;\n    v0&#x5B;6] = 0x576F77CBL;\n    v0&#x5B;7] = 0x2B0F9698L;\n    v0&#x5B;8] = 360862103L;\n    v0&#x5B;9] = 0x5A9D6037L;\n    v0&#x5B;10] = 0x2AE049EDL;\n    v0&#x5B;11] = 2060383159L;\n    DPTest1.a = ((int)v0&#x5B;11]) ^ 1305664179;\n}\n\npublic void initArray(int&#x5B;] arg5) {\n    long&#x5B;] v0 = DPTest1.b;\n    arg5&#x5B;1684628051 ^ ((int)v0&#x5B;4])] = 133800250 ^ ((int)v0&#x5B;5]);\n    arg5&#x5B;0x35A299BD ^ ((int)v0&#x5B;3])] = 0x644F13A5 ^ ((int)v0&#x5B;6]);\n    arg5&#x5B;0x2B0F969A ^ ((int)v0&#x5B;7])] = 0x6CE07CA5 ^ ((int)v0&#x5B;8]);\n    arg5&#x5B;0x13DD5727 ^ ((int)v0&#x5B;1])] = ((int)v0&#x5B;9]) ^ 0x31BD0543;\n}\n<\/pre><\/div>\n\n\n<p>Note that the use of synthetic static arrays is made, as was the case for the arithmetic operations obfuscation pass. Therefore, let&#8217;s try the DOptUnsafeArrayAccessSubstV2 plugin. As careful examination of the above code may give in, the plugin fails to deobfuscate this code on the first go. The reason: if you examine the IR produced while debugging the plugin, you will notice that the static array elements are accessed via a variable (<em>v0<\/em>, above). In IR, those elements are IDVar. Therefore, we need to check whether this variable references a static array. We will do that by using the <a href=\"https:\/\/www.pnfsoftware.com\/jeb\/apidoc\/reference\/com\/pnfsoftware\/jeb\/core\/units\/code\/IDFA3.html\">data flow analysis<\/a> facility made available to all dexdec plugins (public field <a href=\"https:\/\/www.pnfsoftware.com\/jeb\/apidoc\/reference\/com\/pnfsoftware\/jeb\/core\/units\/code\/android\/ir\/AbstractDOptimizer.html#dfa\">dfa<\/a> of optimizers sub-classing AbstractDOptimizer):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">...\nanalyzeChains();  \/\/ initialize the `dfa` member field\nLong defaddr = dfa.checkSingleDef(insnAddress, varid);  \/\/ use-def chains\n...<\/pre>\n\n\n\n<p>The improved plugin can be found here: <a href=\"https:\/\/gist.github.com\/nfalliere\/f3f051bcdeb2e93665eee75dd69c1e6d\">DOptUnsafeArrayAccessSubstV3.java<\/a><\/p>\n\n\n\n<p>The obfuscated code is now processed as expected, and dexdec generates the following decompilation:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"155\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-2-1024x155.png\" alt=\"\" class=\"wp-image-4532\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-2-1024x155.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-2-300x46.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-2-768x116.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-2-1536x233.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2022\/11\/image-2.png 1714w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">initArray() is deobfuscated by DOptUnsafeArrayAccessSubstV3<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion and Future Work<\/h2>\n\n\n\n<p>dProtect is a great project to provide code obfuscation for the masses. Its compatibility with ProGuard makes integration into new and existing Android projects a breeze. I have little doubt many developers will try it out in the future. Let&#8217;s see how upcoming upgrades to the obfuscators fare against the decompiler!<\/p>\n\n\n\n<p>In future blogs, we will have a look at dProtect&#8217;s control-flow obfuscation (once I&#8217;ve got it to work!) and we will see how O-MVLL, the LLVM-based native code obfuscator counterpart, does against JEB&#8217;s gendec (generic decompiler for native code).<\/p>\n\n\n\n<p>Until next time! &#8211; Nicolas<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, we&#8217;re having a look at the first release of dProtect (v 1.0) by Romain Thomas. dProtect is a fork of ProGuard that provides four additional self-explanatory configuration flags: Let&#8217;s see how JEB&#8217;s dexdec&#8217;s built-in optimizers as well as custom IR plugins can be used to defeat some implementations of strings obfuscation, constants &hellip; <a href=\"https:\/\/www.pnfsoftware.com\/blog\/reversing-dprotect\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Reversing dProtect<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,22,5],"tags":[],"class_list":["post-4526","post","type-post","status-publish","format-standard","hentry","category-decompilation","category-jeb4","category-obfuscation"],"_links":{"self":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts\/4526","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/comments?post=4526"}],"version-history":[{"count":0,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts\/4526\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/media?parent=4526"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/categories?post=4526"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/tags?post=4526"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}