{"id":657,"date":"2017-08-06T13:47:54","date_gmt":"2017-08-06T21:47:54","guid":{"rendered":"https:\/\/www.pnfsoftware.com\/blog\/?p=657"},"modified":"2017-08-07T11:58:08","modified_gmt":"2017-08-07T19:58:08","slug":"debugging-dynamically-loaded-dex-files-with-jeb","status":"publish","type":"post","link":"https:\/\/www.pnfsoftware.com\/blog\/debugging-dynamically-loaded-dex-files-with-jeb\/","title":{"rendered":"Debugging Dynamically Loaded DEX Bytecode Files"},"content":{"rendered":"<p>The <a href=\"https:\/\/www.pnfsoftware.com\">JEB 2.3.2<\/a> release contains several enhancements of our JDWP and GDB\/LLDB<sup class='footnote'><a href='#fn-657-1' id='fnref-657-1' onclick='return fdfootnote_show(657)'>1<\/a><\/sup> debugger clients used to debug both the Dalvik bytecode and native code of Android applications.<\/p>\n<h2>Dynamically loaded DEX files<\/h2>\n<p>In this post, we wanted to highlight a neat addition to our Dalvik debugger. Up until now, we did not support debugging several DEX files within a single debugging session. <sup class='footnote'><a href='#fn-657-2' id='fnref-657-2' onclick='return fdfootnote_show(657)'>2<\/a><\/sup><\/p>\n<p>So, we decided to add<strong>\u00a0support for debugging DEX files loaded in a dynamic fashion<\/strong>. Below is a use-case, step-by-step study of a simple app whose workflow goes along these lines:<\/p>\n<ol>\n<li>A routine in the principal classes.dex file looks for an encrypted asset<\/li>\n<li>That asset is extracted and decrypted; it is a Jar file containing additional DEX bytecode<\/li>\n<li>The Jar file is dynamically loaded using DexClassLoader, and its code is executed<\/li>\n<\/ol>\n<p>Now, we want to debug that additional bytecode. How do we proceed?<\/p>\n<h2>An example of debugging dynamically loaded bytecode<\/h2>\n<p>The app is called <strong>EnDyna<\/strong> (a benign crackme-like app, <a href=\"https:\/\/www.pnfsoftware.com\/other\/endyna.apk\">download it here<\/a>). It offers a simple text box, and waits for the user to input a passcode. When entering the proper passcode, a success message is displayed.<\/p>\n<figure style=\"width: 272px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/47da9dad6f90f953d80ca84b34b85900.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/47da9dad6f90f953d80ca84b34b85900.png\" alt=\"\" width=\"272\" height=\"484\" \/><\/a><figcaption class=\"wp-caption-text\">The app requires the right password<\/figcaption><\/figure>\n<p>Open the app in JEB. It contains a seemingly-encrypted asset file called <strong>edd.bin<\/strong>.<\/p>\n<figure style=\"width: 796px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/b01d19a100f4f66d41046c287f2bdbe8.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/b01d19a100f4f66d41046c287f2bdbe8.png\" alt=\"\" width=\"796\" height=\"492\" \/><\/a><figcaption class=\"wp-caption-text\">Encrypted asset file<\/figcaption><\/figure>\n<p>A closer look at the MainActivity class shows that the edd.bin file is extracted, decrypted (using a simple XOR cipher) and loaded using <a href=\"https:\/\/developer.android.com\/reference\/dalvik\/system\/DexClassLoader.html\">DexClassLoader<\/a> in order to validate the user input.<\/p>\n<figure style=\"width: 896px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/defd57dd8741d97203a2e9480dcad021.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/defd57dd8741d97203a2e9480dcad021.png\" alt=\"\" width=\"896\" height=\"394\" \/><\/a><figcaption class=\"wp-caption-text\">Passcode verification routine<\/figcaption><\/figure>\n<p>Let&#8217;s attach the debugger to the app, and set a breakpoint where the call to the\u00a0<a href=\"https:\/\/developer.android.com\/reference\/dalvik\/system\/DexClassLoader.html#DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader)\">DexClassLoader constuctor<\/a>\u00a0is made.<\/p>\n<figure style=\"width: 1010px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/983b26db50753e8853afbcd03bf2c3dc.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/983b26db50753e8853afbcd03bf2c3dc.png\" alt=\"\" width=\"1010\" height=\"564\" \/><\/a><figcaption class=\"wp-caption-text\">A breakpoint was set on the DexClassLoader constructor invocation<\/figcaption><\/figure>\n<p>We then trigger the verify() routine by inputting a passcode and hitting the <em>Verify<\/em> button. Our breakpoint is immediately hit. By examining the stackframe of the paused thread, we can retrieve the class loader variables and see where the decrypted DEX file was written to &#8211; and is about to get loaded from.<\/p>\n<figure style=\"width: 1526px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/2f36a6e02981872916b12016c8dfc76b.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/2f36a6e02981872916b12016c8dfc76b.png\" alt=\"\" width=\"1526\" height=\"422\" \/><\/a><figcaption class=\"wp-caption-text\">The decrypted Jar file about to be loaded from the path referenced by the stack variable v8<\/figcaption><\/figure>\n<p>We use the <a href=\"https:\/\/www.pnfsoftware.com\/blog\/jeb-debuggers-interpreter\/\">Dalvik debugger interpreter<\/a> to retrieve the file (command &#8220;pull&#8221;).<\/p>\n<p><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/0ac7f81700d5782c89496f27190815a2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/0ac7f81700d5782c89496f27190815a2.png\" alt=\"\" width=\"933\" height=\"424\" \/><\/a><\/p>\n<p>We now have the Jar file containing our dynamically-loaded DEX file in hand! We load it in JEB by <strong>adding an additional artifact to the project<\/strong> (command <em>File, Add an Artifact&#8230;<\/em>).<\/p>\n<p><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/75f4dc90e17ec813517af6b9df23b58e.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/75f4dc90e17ec813517af6b9df23b58e.png\" alt=\"\" width=\"612\" height=\"632\" \/><\/a><\/p>\n<p>After processing is complete, the Android debugger notices that the added artifact contains a DEX file, and integrates it in its list of managed units.<\/p>\n<p>We can set a breakpoint on the method of the second DEX file that&#8217;s about to be called.<sup class='footnote'><a href='#fn-657-3' id='fnref-657-3' onclick='return fdfootnote_show(657)'>3<\/a><\/sup><\/p>\n<figure style=\"width: 1468px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/1e85f8d179dd537784058c777edd8328.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/1e85f8d179dd537784058c777edd8328.png\" alt=\"\" width=\"1468\" height=\"792\" \/><\/a><figcaption class=\"wp-caption-text\">The second DEX file; notice the decompiled chk() method on the right-side. Here, we set a breakpoint on the method&#8217;s first instruction. It&#8217;s about to be called from MainActivity.verify(), in the primary classes.dex file.<\/figcaption><\/figure>\n<p>We resume execution, our breakpoint is hit: <strong>we can start debugging the dynamically dropped DEX file!<\/strong><\/p>\n<p><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/e5850b2715e6049e3a270ef40f2723b0.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2017\/08\/e5850b2715e6049e3a270ef40f2723b0.png\" alt=\"\" width=\"534\" height=\"308\" \/><\/a><\/p>\n<p>Of course, all of the above actions can be automated by a Python script or a Java plugin. (We will upload a sample script that hooks DexClassLoader on our public GitHub repository shortly.)<\/p>\n<p>We published a short video that demos the above steps, have a look at it if you want to know precisely the steps that we took to get to debug the additional DEX file.<\/p>\n<p><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/RBCKjPdHGyQ\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>Thank you &#8211; stay tuned for more updates, and happy debugging!<\/p>\n<div class='footnotes' id='footnotes-657'>\n<div class='footnotedivider'><\/div>\n<ol>\n<li id='fn-657-1'> Our native GDB debugger client underwent a major revamp, as we upgraded to the LLDB debugger server instead of gdbserver. More details in a separate post! <span class='footnotereverse'><a href='#fnref-657-1'>&#8617;<\/a><\/span><\/li>\n<li id='fn-657-2'> It was a non-issue for standard multi-DEX APKs since JEB automatically merges them into a single, virtual DEX file, <a href=\"https:\/\/twitter.com\/jebdec\/status\/725761834549018624\">bypassing the 64Kref limits if it has to<\/a> <span class='footnotereverse'><a href='#fnref-657-2'>&#8617;<\/a><\/span><\/li>\n<li id='fn-657-3'> Note that the class in question (com.xyz.kf.Ver) may not even be loaded at this point; it is perfectly fine to do so: JEB handles dynamically loaded types fine and will register breakpoints timely and accordingly. <span class='footnotereverse'><a href='#fnref-657-3'>&#8617;<\/a><\/span><\/li>\n<\/ol>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>The JEB 2.3.2 release contains several enhancements of our JDWP and GDB\/LLDB1 debugger clients used to debug both the Dalvik bytecode and native code of Android applications. Dynamically loaded DEX files In this post, we wanted to highlight a neat addition to our Dalvik debugger. Up until now, we did not support debugging several DEX &hellip; <a href=\"https:\/\/www.pnfsoftware.com\/blog\/debugging-dynamically-loaded-dex-files-with-jeb\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Debugging Dynamically Loaded DEX Bytecode Files<\/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":[15,14,8,12],"tags":[],"class_list":["post-657","post","type-post","status-publish","format-standard","hentry","category-android","category-debugging","category-jeb2","category-tutorial"],"_links":{"self":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts\/657","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=657"}],"version-history":[{"count":0,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts\/657\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/media?parent=657"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/categories?post=657"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/tags?post=657"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}