{"id":4150,"date":"2021-06-26T23:32:24","date_gmt":"2021-06-27T07:32:24","guid":{"rendered":"https:\/\/www.pnfsoftware.com\/blog\/?p=4150"},"modified":"2021-10-06T08:01:09","modified_gmt":"2021-10-06T16:01:09","slug":"writing-dexdec-ir-optimizer-plugins","status":"publish","type":"post","link":"https:\/\/www.pnfsoftware.com\/blog\/writing-dexdec-ir-optimizer-plugins\/","title":{"rendered":"Writing dexdec IR optimizer plugins"},"content":{"rendered":"\n<p>Starting with JEB 4.2, users have the ability to instruct <em>dexdec<\/em><sup class='footnote'><a href='#fn-4150-1' id='fnref-4150-1' onclick='return fdfootnote_show(4150)'>1<\/a><\/sup> to load external Intermediate Representation (IR) optimizer plugins. <sup class='footnote'><a href='#fn-4150-2' id='fnref-4150-2' onclick='return fdfootnote_show(4150)'>2<\/a><\/sup><\/p>\n\n\n\n<p>From a very high-level perspective, a Dex method scheduled for decompilation goes through the following processing pipeline:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Dalvik method converted to low-level IR<\/li><li>SSA transformation and Typing<\/li><li><strong>IR optimizations<\/strong><\/li><li>Final high-level IR converted to AST<\/li><li>AST optimizations<\/li><li>Final clean AST rendered as pseudo-Java code (NOTE: access to the AST is already possible via JEB&#8217;s Java AST API)<\/li><\/ol>\n\n\n\n<p>Phase 3 consists of repeatedly calling IR processors, that essentially take an input IR and transform it into another, further refined IR (that process is called &#8220;lifting&#8221;). IR processors range from junk code cleaner, to variable propagation, immediate propagation, constant folding, higher-level construct rebuilding, compound predicate rebuilding, code restructuring, to all sort of obfuscation removal, advanced optimizers that may involve emulation, dynamic or symbolic execution, etc.<\/p>\n\n\n\n<p><strong><span class=\"has-inline-color has-medium-pink-color\">By working at this level, power-users have the ability to write custom deobfuscators<\/span><\/strong>, that we may not be able to deliver as JEB built-ins for a variety of reasons (e.g. obfuscation specific to a single group of files, custom protection to files under NDA, etc.).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/jeb\/assets\/jeb-dexdec-ir-plugin-example-dexguard91.gif\"><img decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/jeb\/assets\/jeb-dexdec-ir-plugin-example-dexguard91.gif\" alt=\"\" class=\"wp-image-4166\"\/><\/a><figcaption>Sample <em>dexdec <\/em>IR script plugin applying custom deobfuscation to recover strings on a protected sample <\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">A sample dexdec IR plugin<\/h2>\n\n\n\n<p>dexdec IR plugins are JEB back-end plugins (not front-end scripts). Therefore, they are to be dropped in the <code>coreplugins<\/code> folder (or <code>coreplugins\/scripts<\/code> for plugin scripts). They can be written as:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Precompiled jar files:<\/strong> the source language can be anything that compiles to Java bytecode; those plugins cannot be hot-swapped, and therefore are not ideal for prototyping\/experimenting; they are great for mature plugins though.<\/li><li><strong>Java plugin scripts:<\/strong> single Java source files. Strong typing and IDE integration (e.g. with Eclipse or IntelliJ) with Javadoc makes it ideal for developing complex plugins. Hot reload is supported. (They can be seamlessly modified while JEB is running, making them great for prototyping.)<\/li><li><strong>Python plugin scripts:<\/strong> written in 2.7 syntax. Hot reload is supported. <span style=\"text-decoration: underline;\">Restriction: unlike other plugins, an instance of a Python script plugin may be shared by multiple decompilation threads. Therefore, they must be thread-safe and support concurrency.<\/span><\/li><\/ul>\n\n\n\n<p>In this blog, we will show how to write a Python plugin script. Users familiar with JEB client scripting will be in familiar territory.<\/p>\n\n\n\n<p><strong><span class=\"has-inline-color has-medium-pink-color\">IMPORTANT!<\/span><\/strong> Note that loading such plugins is not enabled by default in JEB. Add the following line to your <code>bin\/jeb-engines.cfg<\/code> file to enable loading Python plugins: <code>.LoadPythonPlugins = true<\/code><\/p>\n\n\n\n<p><em>dexdec<\/em> ir plugins must implement the <code>IDOptimizer <\/code>interface. In practice, it is highly recommended to extend the implementing class <code>AbstractDOptimizer<\/code>, like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom com.pnfsoftware.jeb.core.units.code.android.ir import AbstractDOptimizer\n\n# sample IR plugin, does nothing but log the IR CFG\nclass DOptSamplePython(AbstractDOptimizer):\n\n  # perform() returns the number of optimizations performed\n  def perform(self):\n    self.logger.info(&#039;MARKER - Input IR-CFG: %s&#039;, self.cfg)\n    return 0\n<\/pre><\/div>\n\n\n<p><strong><span class=\"has-inline-color has-medium-pink-color\">IMPORTANT!<\/span><\/strong> All <em>dexdec<\/em> IR public interfaces and types are located in the <a href=\"https:\/\/www.pnfsoftware.com\/jeb\/apidoc\/reference\/com\/pnfsoftware\/jeb\/core\/units\/code\/android\/ir\/package-summary.html\">com.pnfsoftware.jeb.core.units.code.android.ir<\/a> package. Keep a tab opened on this page while you develop IR plugins!<\/p>\n\n\n\n<p>The skeleton above:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>must have the same filename as the plugin class, therefore <strong>DOptSamplePython.py<\/strong><\/li><li>must be dropped in <strong>coreplugins\/scripts\/<\/strong><\/li><li>requires Python script plugins to be enabled in your engines configuration<\/li><\/ul>\n\n\n\n<p>If you haven&#8217;t done so, start JEB. Your plugin should appear in the list of <em>dexdec<\/em> plugins. Check the <em>Android <\/em>menu, <em>Decompiler Plugins <\/em>handler:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"343\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1024x343.png\" alt=\"\" class=\"wp-image-4154\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1024x343.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-300x101.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-768x257.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1536x515.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image.png 1656w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>A list of external Dex decompiler plugins<\/figcaption><\/figure>\n\n\n\n<p>Now load a dex\/apk, and decompile any class. Your plugin will eventually be called. The logger view should attest to that by displaying multiple <em>&#8220;MARKER &#8211; Input IR-CFG: &#8230;&#8221;<\/em> lines.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">dexdec Intermediate Representation<\/h2>\n\n\n\n<p><em>dexdec<\/em>&#8216;s IR consists of <code>IDElement <\/code>objects. Every IR statement is an <code>IDInstruction<\/code>, itself an <code>IDElement<\/code>. (All those types and their attributes are described in depth in the API doc.) When an IR plugin is called, it &#8220;receives&#8221; an <code>IDMethodContext <\/code>(representing a decompiled method), stored in the optimizer&#8217;s <span class=\"has-inline-color has-medium-pink-color\"><strong>ctx<\/strong> <\/span>public field. The IR CFG, a control flow graph consisting of IR statements, can be retrieved via <code>ctx.getCfg()<\/code>. It is also stored in the <span class=\"has-inline-color has-medium-pink-color\"><strong>cfg<\/strong> <\/span>public field, for convenience. A formatted IR CFG may look like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n0000\/2+  !onCreate(v4&amp;lt;com.pnfsoftware.raasta.AppHelp&gt;, v5&amp;lt;android.os.Bundle&gt;)&amp;lt;void&gt;                            \n0002\/2:  !requestWindowFeature(v4&amp;lt;com.pnfsoftware.raasta.AppHelp&gt;, 1)&amp;lt;boolean&gt;                                 \n0004\/3:  !setContentView(v4&amp;lt;com.pnfsoftware.raasta.AppHelp&gt;, 7F030000)&amp;lt;void&gt;                                   \n0007\/5:  !x4&amp;lt;android.webkit.WebView&gt; = ((android.webkit.WebView)findViewById(v4&amp;lt;com.pnfsoftware.raasta.AppHelp&gt;, 7F070000)&amp;lt;android.view.View&gt;)&amp;lt;android.webkit.WebView&gt;  \n000C\/2:  !loadData(x4&amp;lt;android.webkit.WebView&gt;, getString(v4&amp;lt;com.pnfsoftware.raasta.AppHelp&gt;, 7F05005B)&amp;lt;java.lang.String&gt;, &quot;text\/html&quot;, &quot;utf-8&quot;)&amp;lt;void&gt;  \n000E\/3:  !setBackgroundColor(x4&amp;lt;android.webkit.WebView&gt;, 0)&amp;lt;void&gt;                                              \n0011\/1:  !setDefaultTextEncodingName(getSettings(x4&amp;lt;android.webkit.WebView&gt;)&amp;lt;android.webkit.WebSettings&gt;, &quot;utf-8&quot;)&amp;lt;void&gt;  \n0012\/1:  return         \n<\/pre><\/div>\n\n\n<p>Statements (<code>IDInstruction<\/code>) can have any of the following <strong>opcodes<\/strong> (see <code>DOpcodeType<\/code>):<br>&#8211; IR_NOP: no-operation<br>&#8211; IR_ASSIGN: assignment<br>&#8211; IR_INVOKE: invocation (including new object and new array construction)<br>&#8211; IR_JUMP: unconditional jump<br>&#8211; IR_JCOND: conditional jump<br>&#8211; IR_SWITCH: switch statement<br>&#8211; IR_RETURN: return statement<br>&#8211; IR_THROW: throw statement<br>&#8211; IR_STORE_EXCEPTION: exception retrieval (special)<br>&#8211; IR_MONITOR_ENTER: VM monitor acquisition<br>&#8211; IR_MONITOR_EXIT: VM monitor release<\/p>\n\n\n\n<p>Statement <strong>operands<\/strong> are themselves <code>IDElement<\/code>s, usually <code>IDExpression<\/code>s. Examples: <code>IDImm <\/code>(immediate values), <code>IDVar <\/code>(variables), <code>IDOperation <\/code>(arithmetic\/bitwise\/cast operations), <code>IDInvokeInfo <\/code>(method invocation details), <code>IDArrayElt <\/code>(representing array elements), <code>IDField <\/code>(representing static or instance fields), etc. Refer to the hierarchy of <code>IDElement <\/code>for a complete list.<\/p>\n\n\n\n<p>IR statements can be seen as recursive IR expression trees. They can be easily explored (<code>visitXxx<\/code> method()) and manipulated. They can be replaced by newly-created elements (see <code>IDMethodContext.createXxx<\/code> methods). Data-flow analysis can be performed on IR CFG, to retrieve use-def and def-use chains, and other variable liveness and reachability information (see <code>cfg.doDataFlowAnalysis<\/code>).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Use-case: cleaning useless Android calls<\/h2>\n\n\n\n<p>Let&#8217;s put this new API to practical, real-world use. First, some background: JEB ships with emulator-backed IR optimizers that attempt to auto-decrypt immediates such as strings. While this deobfuscator generally performs well on protected files, lately, we&#8217;ve received samples for which strings were not decrypted. The reason is quite straight-forward, see this example:<\/p>\n\n\n\n<p><code>throw new java.lang.IllegalStateException(o.isUserRecoverableError.<strong><span style=\"text-decoration: underline;\">read<\/span><\/strong>(((char)android.text.TextUtils.getOffsetBefore(\"\", 0)), 12 - java.lang.Long.compare(android.os.Process.getElapsedCpuTime(), 0L), (android.view.ViewConfiguration.getFadingEdgeLength() &gt;&gt; 16) + 798).intern());<\/code><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"379\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1-1024x379.png\" alt=\"\" class=\"wp-image-4157\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1-1024x379.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1-300x111.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1-768x284.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1-1536x568.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-1-2048x757.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>In the above code (extracted from a protected method), <code>read<\/code> is a string decryptor. Alas, the presence of calls such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>TextUtils.getOffsetBefore(&#8220;&#8221;, 0))<\/li><li>Long.compare(Process.getElapsedCpuTime(), 0L)<\/li><li>ViewConfiguration.getFadingEdgeLength() &gt;&gt; 16<\/li><\/ul>\n\n\n\n<p>prevent the generic decryptor from kicking in. Indeed, what would an emulator be supposed to make with those calls to external APIs, whose result is likely to be context-dependent? In practice though, they could be resolved by some ad-hoc optimizations:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>getOffsetBefore() algorithm is (almost) straightforward<\/li><li>getElapsedCpuTime() also returns strictly positive results, making compare() operation predictable<\/li><li>getFadingEdgeLength() returns small ints, less than 0x10000<\/li><\/ul>\n\n\n\n<p>We will craft the following IR optimizer: (file <strong>RemoveDummyAndroidApiCalls.py<\/strong>)<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nfrom com.pnfsoftware.jeb.core.units.code.android.ir import AbstractDOptimizer, IDVisitor\n\nclass RemoveDummyAndroidApiCalls(AbstractDOptimizer):  # note that we extend AbstractDOptimizer for convenience, instead of implementing IDOptimizer from scratch\n  def perform(self):\n    # create our instruction visitor\n    vis = AndroidUtilityVisitor(self.ctx)\n    # visit all the instructions of the IR CFG\n    for insn in self.cfg.instructions():\n      insn.visitInstruction(vis)\n    # return the count of replacements\n    return vis.cnt\n\nclass AndroidUtilityVisitor(IDVisitor):\n  def __init__(self, ctx):\n    self.ctx = ctx\n    self.cnt = 0\n\n  def process(self, e, parent, results):\n    repl = None\n\n    if e.isCallInfo():\n      sig = e.getMethodSignature()\n\n      # TextUtils.getOffsetBefore(&quot;&quot;, 0)\n      if sig == &#039;Landroid\/text\/TextUtils;-&gt;getOffsetBefore(Ljava\/lang\/CharSequence;I)I&#039; and e.getArgument(0).isImm() and e.getArgument(1).isImm():\n        buf = e.getArgument(0).getStringValue(self.ctx.getGlobalContext())\n        val = e.getArgument(1).toLong()\n        if buf == &#039;&#039; and val == 0:\n          repl = self.ctx.getGlobalContext().createInt(0)\n\n      # Long.compare(xxx, 0)\n      elif sig == &#039;Ljava\/lang\/Long;-&gt;compare(JJ)I&#039; and e.getArgument(1).isImm() and e.getArgument(1).asImm().isZeroEquivalent():\n        val0 = None\n        arg0 = e.getArgument(0)\n        if arg0.isCallInfo():\n          sig2 = arg0.getMethodSignature()\n          if sig2 == &#039;Landroid\/os\/Process;-&gt;getElapsedCpuTime()J&#039;:\n            # elapsed time always &gt;0, value does not matter since we are comparing against 0\n            val0 = 1\n        if val0 != None:\n          if val0 &gt; 0:\n            r = 1\n          elif val0 &lt; 0:\n            r = -1\n          else:\n            r = 0\n          repl = self.ctx.getGlobalContext().createInt(r)\n\n      # ViewConfiguration.getFadingEdgeLength()\n      elif sig == &#039;Landroid\/view\/ViewConfiguration;-&gt;getFadingEdgeLength()I&#039;:\n        # always a small positive integer, normally set to FADING_EDGE_LENGTH (12)\n        repl = self.ctx.getGlobalContext().createInt(12)\n\n    if repl != None and parent.replaceSubExpression(e, repl):\n      # success (this visitor is pre-order, we need to report the replaced node)\n      results.setReplacedNode(repl)\n      self.cnt += 1\n<\/pre><\/div>\n\n\n<p>What does this code do:<br>&#8211; First, it enumerates and visits all CFG instructions.<br>&#8211; The visitor checks for <code>IDCallInfo<\/code> IR expressions matching the kinds of Android framework API calls described above: getOffsetBefore(), compare(getElapsedCpuTime(), 0), getFadingEdgeLength()<br>&#8211; It evaluates and calculates the results, and replaces IR call expressions (<code>IDInvokeInfo<\/code>) by newly-created constants (<code>IDImm<\/code>).<\/p>\n\n\n\n<p>The resulting IR, which the plugin could print, would look like:<\/p>\n\n\n\n<p><code>throw new java.lang.IllegalStateException(o.isUserRecoverableError.<strong><span style=\"text-decoration: underline;\">read<\/span><\/strong>(((char)0, 12 - 1, 0 + 798).intern());<\/code><\/p>\n\n\n\n<p>Subsequently, other optimizers, built into <em>dexdec<\/em>, can kick in, clean the code further (e.g. fold constants), and make the read() invocation a candidate for string auto-decryption, yielding the following result:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"275\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-2-1024x275.png\" alt=\"\" class=\"wp-image-4158\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-2-1024x275.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-2-300x81.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-2-768x206.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-2-1536x413.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-2-2048x550.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Our external IR plugin is enabled. The IR can be cleaned, the auto-decryption takes place.<\/figcaption><\/figure>\n\n\n\n<p>Done!<\/p>\n\n\n\n<p>The sample script can be found in your <code>coreplugins\/scripts<\/code> folder. Feel free to extend it further.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tips<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><em>dexdec<\/em> IR plugins can also be written as Java source. Have a look at the sample file DOptSampleJava.java, located in <code>coreplugins\/scripts<\/code>. As a plugin grows in size and complexity, working with a strongly-typed language like Java, coupled with excellent javadoc integration in IDE, becomes extremely valuable.<\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li>When prototyping IR plugins, the Dalvik code targeted for deobfuscation is oftentimes contained in a single method. In such cases, it may be cumbersome or costly to decompile entire classes. To easily decompile a single method in the GUI, do <em>Decompile with Options<\/em> (Action menu or right-click), and untick &#8220;Decompile top level container class&#8221;:<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"301\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-3-1024x301.png\" alt=\"\" class=\"wp-image-4159\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-3-1024x301.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-3-300x88.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-3-768x226.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-3-1536x452.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-3.png 2006w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>With this option disabled, when your caret is positioned on a method, issuing a decompilation request will only decompile the target method, and nothing else (not even inner classes\/methods of the target will be decompiled.)<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Using the previous technique, the generated decompiled view represents an AST <code>IJavaMethod<\/code> &#8212; not the usual <code>IJavaClass<\/code>. Fully-qualified names are used to represent types, since import statements are not specified. An added value to the views associated with such units lies in the &#8220;IR-CFG&#8221; fragment, representing the final (most refined) IR before the AST generation phase kicked in:<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"866\" height=\"246\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-4.png\" alt=\"\" class=\"wp-image-4160\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-4.png 866w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-4-300x85.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2021\/06\/image-4-768x218.png 768w\" sizes=\"auto, (max-width: 866px) 100vw, 866px\" \/><\/a><figcaption>Final IR viewed in the source unit for an IJavaMethod<\/figcaption><\/figure>\n\n\n\n<ul class=\"wp-block-list\"><li>Many IR utility routines are located in the <code>DUtil <\/code>class. Generally, explore the ir\/ package&#8217;s javadoc, you will find plenty useful information in there.<\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li>We haven&#8217;t talked about accessing and using the emulator and sandbox. The main interface is <code>IDState<\/code>, and we will detail some of its functionality in a later post. In the meantime, you will find sample code on <a href=\"https:\/\/github.com\/pnfsoftware\/jeb-samplecode\/tree\/master\/plugins\/scripts\">our GitHub repo<\/a>.<\/li><\/ul>\n\n\n\n<p>That&#8217;s it for now &#8211; Have fun crafting your own IR plugins. As usual, reach us on Twitter&#8217;s @<a href=\"http:\/\/twitter.com\/jebdec\">jebdec<\/a>, Slack&#8217;s <a href=\"http:\/\/pnfsoftware.com\/chat\">jebdecompiler<\/a>, or privately over <a href=\"mailto:support@pnfsoftware.com\">email<\/a>. Until next time! &#8211; Nicolas<\/p>\n\n\n<div class='footnotes' id='footnotes-4150'><div class='footnotedivider'><\/div><ol><li id='fn-4150-1'> <em>dexdec<\/em> is JEB&#8217;s Dex\/Dalvik decompiler; <em>gendec<\/em> is JEB&#8217;s generic decompiler for all other architectures (x86, arm, etc.). <span class='footnotereverse'><a href='#fnref-4150-1'>&#8617;<\/a><\/span><\/li><li id='fn-4150-2'> Note that <em>gendec<\/em> has been allowing that for quite some time; its IR is different than <em>dexdec<\/em>&#8216;s IR though. <span class='footnotereverse'><a href='#fnref-4150-2'>&#8617;<\/a><\/span><\/li><\/ol><\/div>","protected":false},"excerpt":{"rendered":"<p>Starting with JEB 4.2, users have the ability to instruct dexdec1 to load external Intermediate Representation (IR) optimizer plugins. 2 From a very high-level perspective, a Dex method scheduled for decompilation goes through the following processing pipeline: Dalvik method converted to low-level IR SSA transformation and Typing IR optimizations Final high-level IR converted to AST &hellip; <a href=\"https:\/\/www.pnfsoftware.com\/blog\/writing-dexdec-ir-optimizer-plugins\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Writing dexdec IR optimizer plugins<\/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,12],"tags":[],"class_list":["post-4150","post","type-post","status-publish","format-standard","hentry","category-decompilation","category-jeb4","category-tutorial"],"_links":{"self":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts\/4150","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=4150"}],"version-history":[{"count":0,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts\/4150\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/media?parent=4150"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/categories?post=4150"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/tags?post=4150"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}