{"id":3689,"date":"2020-06-09T10:58:51","date_gmt":"2020-06-09T18:58:51","guid":{"rendered":"https:\/\/www.pnfsoftware.com\/blog\/?p=3689"},"modified":"2021-09-10T14:12:41","modified_gmt":"2021-09-10T22:12:41","slug":"reversing-android-protector-obfuscation","status":"publish","type":"post","link":"https:\/\/www.pnfsoftware.com\/blog\/reversing-android-protector-obfuscation\/","title":{"rendered":"Reversing an Android app Protector, Part 1 &#8211; Code Obfuscation &#038; RASP"},"content":{"rendered":"\n<p><em>In this series: Part 1, <a href=\"https:\/\/www.pnfsoftware.com\/blog\/reversing-dexguard-encryption\/\">Part 2<\/a>, <a href=\"https:\/\/www.pnfsoftware.com\/blog\/reversing-dexguard-virtualization\/\">Part 3<\/a><\/em><\/p>\n\n\n\n<p>What started as a ProGuard + <a href=\"https:\/\/www.pnfsoftware.com\/blog\/a-look-inside-dexguard\/\">basic string encryption + code reflection<\/a> tool evolved into a multi-platform, complex solution including: control-flow obfuscation, complex and varied data and resources encryption, bytecode encryption, virtual environment and rooted system detection, application signature and certificate pinning enforcement, native code protection, as well as bytecode virtualization <sup class='footnote'><a href='#fn-3689-1' id='fnref-3689-1' onclick='return fdfootnote_show(3689)'>1<\/a><\/sup>, and more.<\/p>\n\n\n\n<p>This article presents the <strong>obfuscation techniques used by this app protector<\/strong>, as well as <strong>facility made available at runtime<\/strong> to protected programs <sup class='footnote'><a href='#fn-3689-2' id='fnref-3689-2' onclick='return fdfootnote_show(3689)'>2<\/a><\/sup>. The analysis that follows was done statically, with JEB 3.20.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Identification<\/h2>\n\n\n\n<p>Identifying apps protected by this protector is relatively easy. It seems the default bytecode obfuscation settings place most classes in the <code>o<\/code> package, and some will be renamed to invalid names on a Windows system, such as <code>con<\/code> or <code>aux<\/code>. Closer inspection of the code will reveal stronger hints than obfuscated names: decryption stubs, specific encrypted data, the presence of some <code>so<\/code> library files, are all tell tale signs, as shown below.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Running a Global Analysis<\/h3>\n\n\n\n<p>Let&#8217;s run a Global Analysis (menu <em>Android, Global analysis&#8230;<\/em>) with standard settings on the file and see what gets auto-decrypted and auto-unreflected:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"947\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-3-1024x947.png\" alt=\"\" class=\"wp-image-3699\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-3-1024x947.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-3-300x277.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-3-768x710.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-3-1536x1420.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-3.png 1632w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Results subset of Global Analysis (redacted areas are meant to keep the analyzed program anonymous; it is a clean app, whose business logic is irrelevant to the analysis of the app protector)<\/figcaption><\/figure>\n\n\n\n<p>Lots of strings were decrypted, many of them specific to the app&#8217;s business logic itself, others related to RASP &#8211; that is, library code embedded within the APK, responsible for performing app signature verification for instance. That gives us valuable pointers into where we should be looking at if we&#8217;d like to focus on the protection code specifically.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Deobfuscating Code<\/h2>\n\n\n\n<p>The first section of this blog focuses on bytecode obfuscation and how JEB deals with it. It is mostly automated, but a final step requires manual assistance to achieve the best results.<\/p>\n\n\n\n<p>Most obfuscated routines exhibit the following characteristics:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Dynamically generated strings via the use of per-class decryption routines<\/li><li>Most calls to external routines are done via reflection<\/li><li>Flow obfuscation via the use of a couple of opaque integer fields &#8211; let&#8217;s call them OPI0, OPI1. They are class fields generally initialized to 0 and 1.<\/li><li>Arithmetic operation obfuscation<\/li><li>Garbage code insertion<\/li><li>Unusual protected block structure, leading to fragmented try-blocks, unavoidable to produce semantically accurate raw code<\/li><\/ul>\n\n\n\n<p>As an example, the following class is used to perform app certificate validation in order,  for instance, to prevent resigned apps from functioning. A few items were renamed for clarity; decompilation is done with disabled Deobfuscators (MOD1+TAB, untick <em>&#8220;Enable deobfuscators&#8221;<\/em>):<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"648\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-1024x648.png\" alt=\"\" class=\"wp-image-3694\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-1024x648.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-300x190.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-768x486.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-1536x971.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-2048x1295.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Take #1 (snippet) &#8211; The protected class is decompiled without deobfuscation in order to show semi-raw output (a few optimizers doing all sort of code cleanup are not categorized as deobfuscators internally, and will perform even if Deobfuscation is disabled). Note that a few items were also renamed for clarity.<\/figcaption><\/figure>\n\n\n\n<p>In practice, such code is quite hard to comprehend on complex methods. With obfuscators enabled (the default setting), most of the above will be cleared.<\/p>\n\n\n\n<p>See the re-decompilation of the same class, below.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>strings are decrypted&#8230;<\/li><li>&#8230;enabling unreflection<\/li><li>most obfuscation is removed&#8230;<\/li><li>except for some control flow obfuscation that remains because JEB was unable to process OPI0\/OPI1 directly (below, <\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-9.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"967\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-9-1024x967.png\" alt=\"\" class=\"wp-image-3710\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-9-1024x967.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-9-300x283.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-9-768x725.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-9-1536x1450.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-9.png 1792w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Take #2 (full routine) &#8211; obfuscators enabled (default). The red blocks highlight use of opaque variables used to obfuscate control flow.<\/figcaption><\/figure>\n\n\n\n<p>Let&#8217;s give a hint to JEB as to what OPI0\/OPI1 are.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>When analyzing protected apps, <strong>you can rename OPI0 and OPI1 to <em>guard0<\/em> and <em>guard1<\/em>, respectively, to allow JEB go aggressively clean the code<\/strong><\/li><li>Redecompile the class after renaming the fields<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"522\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-2-1024x522.png\" alt=\"\" class=\"wp-image-3696\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-2-1024x522.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-2-300x153.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-2-768x391.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-2-1536x783.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-2.png 1860w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Take #3 (full routine) &#8211; with explicit guard0\/guard1<\/figcaption><\/figure>\n\n\n\n<p>That final output is clean and readable.<\/p>\n\n\n\n<p>Other obfuscation techniques not exposed in this short routine above are arithmetic obfuscation and other operation complexification techniques. JEB will seamlessly deal with many of them. Example:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-4.png\" alt=\"\" class=\"wp-image-3701\" width=\"441\" height=\"42\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-4.png 856w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-4-300x29.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-4-768x74.png 768w\" sizes=\"auto, (max-width: 441px) 100vw, 441px\" \/><\/figure>\n\n\n\n<p>is optimized to<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-5.png\" alt=\"\" class=\"wp-image-3702\" width=\"350\" height=\"42\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-5.png 694w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-5-300x36.png 300w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/figure>\n\n\n\n<p>To summarize bytecode obfuscation:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>decryption and unreflection is done automatically <sup class='footnote'><a href='#fn-3689-3' id='fnref-3689-3' onclick='return fdfootnote_show(3689)'>3<\/a><\/sup><\/li><li>garbage clean-up, code clean-up is also generic and done automatically<\/li><li>control flow deobfuscation needs a bit of guidance to operate (guard0\/guard1 renaming)<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Runtime Verification<\/h2>\n\n\n\n<p>RASP library routines are used at the developers&#8217; discretion. They consist of a set of classes that the application code can call at any time, to perform tasks such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>App signing verification<\/li><li>Debuggability\/debugger detection<\/li><li>Emulator detection<\/li><li>Root detection<\/li><li>Instrumentation toolkits detection<\/li><li>Certificate pinning<\/li><li>Manifest check<\/li><li>Permission checks<\/li><\/ul>\n\n\n\n<p>The client decides when and where to use them as well as what action should be taken on the results. The code itself is protected, that goes without saying.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">App Signing Verification<\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li>Certificate verification uses the PackageManager to retrieve app&#8217;s signatures: <code>PackageManager.getPackageInfo(packageName, GET_SIGNATURES).signatures<\/code><\/li><li>The signatures are hashed and compared to caller-provided values in an <code>IntBuffer<\/code> or <code>LongBuffer<\/code>.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-10.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"427\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-10-1024x427.png\" alt=\"\" class=\"wp-image-3712\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-10-1024x427.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-10-300x125.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-10-768x320.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-10-1536x641.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-10-2048x854.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Debug Detection<\/h3>\n\n\n\n<p><strong>Debuggability check<\/strong><\/p>\n\n\n\n<p>The following checks must pass:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>assert that <code>Context.ctx.getApplicationInfo().flags &amp; ApplicationInfo.FLAG_DEBUGGABLE<\/code> is false<\/li><li>check the <code>ro.debuggable<\/code> property, in two ways to ensure consistency<ul><li>using <code>android.os.SystemProperties.get()<\/code> (private API)<\/li><li>using the <code>getprop<\/code>&#8216;s binary<\/li><\/ul><\/li><li>verify that no hooking framework is detected (see specific section below)<\/li><\/ul>\n\n\n\n<p><strong>Debugging session check<\/strong><\/p>\n\n\n\n<p>The following checks must pass:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>assert that <code>android.os.Debug.isDebuggerConnected()<\/code> is false<\/li><li>verify no tracer process: <code>tracerpid<\/code> entry in <code>\/proc\/&lt;pid&gt;\/status<\/code> must be &lt;= 0<\/li><li>verify that no hooking framework is detected (see specific section below)<\/li><\/ul>\n\n\n\n<p><strong>Debug key signing<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>enumerate the app&#8217;s signatures via <code>PackageInfo.signatures<\/code><\/li><li>use <code>getSubjectX500Principal()<\/code> to verify that no certificate has a subject distinguished name (DN) equals to <code>\"CN=Android Debug,O=Android,C=US\"<\/code>, which is the standard DN for debug certificates generated by the SDK tools<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Emulator Detection<\/h3>\n\n\n\n<p>Emulator detection is done by checking any of the below.<\/p>\n\n\n\n<p>1) All properties defined in <code>system\/build.prop<\/code> are retrieved, hashed, and matched against a small set of hard-coded hashes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">86701cb958c69d64cd59322dfebacede -&gt; property ???\n19385aafbb452f39b5079513f668bbeb -&gt; property ???\n24ad686ec83d904347c5a916acbe1779 -&gt; property ???\nb8c8255febc6c46a3e43b369225ded3e -&gt; property ???\nd76386ddf2c96a9a92fc4bc8f829173c -&gt; property ???\n15fed45d5ca405da4e6aa9805daf2fbf -&gt; property ??? (unused)<\/pre>\n\n\n\n<p>Unfortunately, we were not able to reverse those hashes back to known property strings &#8211; however, it was tried only on AOSP emulator images. If anybody wants to help and run the below on other build.prop files, feel free to let us know what property strings those hashes match to. <a href=\"https:\/\/gist.github.com\/nfalliere\/42fef0d8a0af75b314512008ae3f9c44\">Here is the hash verification source<\/a>, to be run be on build.prop files.<\/p>\n\n\n\n<p>2) The following file is readable:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/sys\/devices\/system\/cpu\/cpu0\/cpufreq\/cpuinfo_cur_freq<\/pre>\n\n\n\n<p>3) Verify if any of those qemu, genymotion and bluestacks emulator files exist and are readable:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/dev\/qemu_pipe\n\/dev\/socket\/baseband_genyd\n\/dev\/socket\/genyd\n\/dev\/socket\/qemud\n\/sys\/qemu_trace\n\/system\/lib\/libc_malloc_debug_qemu.so\n\/dev\/bst_gps\n\/dev\/bst_time\n\/dev\/socket\/bstfolderd\n\/system\/lib\/libbstfolder_jni.so<\/pre>\n\n\n\n<p>4) Check for the presence of wired network interfaces: (via <code>NetworkInterface.getNetworkInterfaces<\/code>)<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">eth0\neth1<\/pre>\n\n\n\n<p>5) If the app has the permission <code>READ_PHONE_STATE<\/code>, telephony information is verified, an emulator is detected if any of the below matches (standard emulator image settings):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">- \"getLine1Number\": \"15555215554\", \"15555215556\", \"15555215558\", \"15555215560\", \"15555215562\", \"15555215564\", \"15555215566\", \"15555215568\", \"15555215570\", \"15555215572\", \"15555215574\", \"15555215576\", \"15555215578\", \"15555215580\", \"15555215582\", \"15555215584\"\n- \"getNetworkOperatorName\": \"android\"\n- \"getSimSerialNumber\": \"89014103211118510720\"\n- \"getSubscriberId\": \"310260000000000\"\n- \"getDeviceId\": \"000000000000000\", \"e21833235b6eef10\", \"012345678912345\"<\/pre>\n\n\n\n<p>6) <code>\/proc<\/code> checks:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/proc\/ioports: entry \"0ff :\" (unknown port, likely used by some emulators)\n\/proc\/self\/maps: entry \"gralloc.goldfish.so\" (GF: older emulator kernel name)<\/pre>\n\n\n\n<p>7) Property checks (done in multiple ways with a consistency checks, as explained earlier), failed if any entry is found and start with one of the provided values:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">- \"ro.product.manufacturer\": \"Genymotion\", \"unknown\", \"chromium\"\n- \"ro.product.device\": \"vbox86p\", \"generic\", \"generic_x86\", \"generic_x86_64\"\n- \"ro.product.model\": \"sdk\", \"emulator\", \"App Runtime for Chrome\", \"Android SDK built for x86\", \"Android SDK built for x86_64\"\n- \"ro.hardware\": \"goldfish\", \"vbox86\", \"ranchu\"\n- \"ro.product.brand\": \"generic\", \"chromium\"\n- \"ro.kernel.qemu\": \"1\"\n- \"ro.secure\": \"0\"\n- \"ro.build.product\": \"sdk\", \"vbox86p\", \"full_x86\", \"generic_x86\", \"generic_x86_64\"\n- \"ro.build.fingerprint\": \"generic\/sdk\/generic\", \"generic_x86\/sdk_x86\/generic_x86\", \"generic\/google_sdk\/generic\", \"generic\/vbox86p\/vbox86p\", \"google\/sdk_gphone_x86\/generic_x86\"\n- \"ro.bootloader\": \"unknown\"\n- \"ro.bootimage.build.fingerprint\": \"Android-x86\"\n- \"ro.build.display.id\": \"test-\"\n- \"init.svc.qemu-props\" (any value)\n- \"qemu.hw.mainkeys\" (any value)\n- \"qemu.sf.fake_camera\" (any value)\n- \"qemu.sf.lcd_density\" (any value)\n- \"ro.kernel.android.qemud\" (any value)<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hooking Systems Detection<\/h3>\n\n\n\n<p>The term covers a wide range of techniques designed to intercept regular control flow in order to examine and\/or modify execution. <\/p>\n\n\n\n<p>1) Xposed instrumentation framework detection, by attempting to load any of the classes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">de.robv.android.xposed.XposedBridge\nde.robv.android.xposed.XC_MethodHook<\/pre>\n\n\n\n<p>Class loading is done in different ways in an attempt to circumvent hooking itself, using <code>Class.forName<\/code> with a variety of class loaders, custom class loaders and <code>ClassLoader.getLoadedClass<\/code>, as well as lower-level private methods, such as <code>Class.classForName<\/code>.<\/p>\n\n\n\n<p>2) Cydia Substrate instrumentation framework detection.<\/p>\n\n\n\n<p>3) ADBI (Android Dynamic Binary Instrumentation) detection<\/p>\n\n\n\n<p>4) Stack frame verification: an exception is generated in order to retrieve a stack frame. The callers are hashed and compared to an expected hard-coded value.<\/p>\n\n\n\n<p>5) Native code checks. This will be detailed in another blog, if time allows.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Root Detection<\/h3>\n\n\n\n<p>While root detection overlaps with most of the above, it is still another layer of security a determined attacker would have to jump over (or walk around) in order to get protected apps to run on unusual systems. Checks are plenty, and as is the case for all the code described here, heavily obfuscated. If you are analyzing such files, keeping the Deobfuscators enabled and providing <em>guard0\/guard1<\/em> hints is key to a smooth analysis.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-6.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"213\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-6-1024x213.png\" alt=\"\" class=\"wp-image-3705\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-6-1024x213.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-6-300x62.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-6-768x160.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-6-1536x320.png 1536w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-6-2048x426.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption>Static initializer of the principal root detection class. Most artifacts indicative of a rooted device are searched for by hash.<\/figcaption><\/figure>\n\n\n\n<p><strong>Build.prop checks.<\/strong> As was described in emulator detection.<\/p>\n\n\n\n<p><strong>su execution.<\/strong> Attempt to execute <code>su<\/code>, and verify whether <code>su -c id<\/code> == <code>root<\/code><\/p>\n\n\n\n<p><strong>su presence.<\/strong> <code>su<\/code> is looked up in the following locations:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/data\/local\/\n\/data\/local\/bin\/\n\/data\/local\/xbin\/\n\/sbin\/\n\/system\/bin\/\n\/system\/bin\/.ext\/\n\/system\/bin\/failsafe\/\n\/system\/sd\/xbin\/\n\/system\/usr\/we-need-root\/\n\/system\/xbin\/<\/pre>\n\n\n\n<p><strong>Magisk detection through mount.<\/strong> Check whether mount can be executed and contains <code>databases\/su.db<\/code> (indicative of Magisk) or whether <code>\/proc\/mounts<\/code> contains references to <code>databases\/su.db<\/code>.<\/p>\n\n\n\n<p><strong>Read-only system partitions.<\/strong> Check if any system partition is mounted as read-write (when it should be read-only). The result of <code>mount<\/code> is examined for any of the following entries marked <code>rw<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/system\n\/system\/bin\n\/system\/sbin\n\/system\/xbin\n\/vendor\/bin\n\/sbin\n\/etc<\/pre>\n\n\n\n<p><strong>Verify installed apps<\/strong> in the hope of finding one whose package name hashes to the hard-coded value:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">0x9E6AE9309DBE9ECFL<\/pre>\n\n\n\n<p>Unfortunately,  that value was not reversed, let us know if you find which package name generates this hash &#8211; see the algorithm below:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n    public static long hashstring(String str) {\n        long h = 0L;\n        for(int i = 0; i &amp;lt; str.length(); i++) {\n            int c = str.charAt(i);\n            h = h &amp;lt;&amp;lt; 5 ^ (0xFFFFFFFFF8000000L &amp;amp; h) &gt;&gt; 27 ^ ((long)c);\n        }\n        return h;\n    }\n<\/pre><\/div>\n\n\n<p>NOTE: App enumeration is performed in two ways to maximize chances of evading partial hooks.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Straightforward: <code>PackageManager.getInstalledApplications<\/code><\/li><li>More convoluted: iterate over all known <code>MAIN<\/code> intents: <code>PackageManager.queryIntentActivities(new Intent(\"android.intent.action.MAIN\"))<\/code>, derive the package name from the intent via <code>ResolveInfo.activityInfo.packageName<\/code><\/li><\/ul>\n\n\n\n<p><strong>SElinux verification.<\/strong> If the file <code>\/sys\/fs\/selinux\/policy<\/code> cannot be read, the check immediately passes. If it is readable, the policy is examined and hints indicative of a rooted device are looked for by hash comparison:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">472001035L\n-601740789L<\/pre>\n\n\n\n<p>The hashing algorithm is extremely simple, see below. For each byte of the file, the crc is updated and compared to hard-coded values.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nlong h = 0L;\n\/\/for each byte:\n    h = (h &amp;lt;&amp;lt; 5 ^ ((long)(((char)b)))) &amp;amp; 0x3FFFFFFFL;\n    \/\/ check h against known list\n<\/pre><\/div>\n\n\n<p><strong>Running processes checks.<\/strong> All running processes and their command-lines are enumerated and hashed, and specific values are indirectly looked up by comparing against hard-coded lists.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">APK Check<\/h3>\n\n\n\n<p>This verifier parses compressed entries in the APK (zip) file and compares them against well-known, hard-coded CRC values.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Manifest Check<\/h3>\n\n\n\n<p>Consistency checks on the application Manifest consists of enumerating the entries using two different ways and comparing results. Discrepancies are reported.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Open the archive&#8217;s MANIFEST.MF file via <code>Context.getAssets()<\/code>, parse manually<\/li><li>Use <code>JarFile(Context.getPackageCodePath()).getManifest().getEntries()<\/code><\/li><\/ul>\n\n\n\n<p>Discrepancies in the Manifest could indicate system hooks attempting to conceal files added to the application.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Permissions Check<\/h3>\n\n\n\n<p>This routine checks for permission discrepancies between what&#8217;s declared by the app and what the system grant the app.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Set A: App permission gathering: all permissions requested and defined by the app, as well as all permissions offered by the system, plus the <code>INTERACT_ACROSS_USERS<\/code> and <code>INTERACT_ACROSS_USERS_FULL<\/code> permissions, <\/li><li>Set B: Retrieve all permissions that exist on the system<\/li><li>Define set C = B &#8211; A<\/li><li>For every permission in C, use <code>checkCallingOrSelfPermission<\/code> (API 22-) or <code>checkSelfPermission<\/code> (API 23+) to verify that the permission is not granted.<\/li><\/ul>\n\n\n\n<p>Permission discrepancies could be used to find out system hooks or unorthodox execution environments.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"545\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-8-1024x545.png\" alt=\"\" class=\"wp-image-3707\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-8-1024x545.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-8-300x160.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-8-768x409.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-8.png 1494w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Note the &#8220;X &amp; -(A+1) | ~X &amp; A&#8221; checks. Several opaque arithmetic\/binary expressions attempt to complicate the control flow. Here, that expression is never equals to v2, and therefore, the if-check will always fail. JEB 3.20 does not clean all those artifacts.<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Miscellaneous<\/h3>\n\n\n\n<p>Other runtime components include library code to perform SSL certificate pinning, as well as obfuscated wrappers around web view clients. None of those are of particular interest.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"963\" src=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-7-1024x963.png\" alt=\"\" class=\"wp-image-3706\" srcset=\"https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-7-1024x963.png 1024w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-7-300x282.png 300w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-7-768x722.png 768w, https:\/\/www.pnfsoftware.com\/blog\/wp-content\/uploads\/2020\/06\/image-7.png 1356w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Wrapper for android.webkit.WebViewClient. Make sure to enable deobfuscators and provide guardX hints. When this is done, most methods will be crystal clear. In fact, the majority of them are simple forwarders.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>That&#8217;s it for the obfuscation and runtime protection facility. Key take-away to analyze such protected code:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Keep the obfuscators enabled<\/li><li>Locate the opaque integers, rename them to guard0\/guard1 to give JEB a hint on where control flow deobfuscation should be performed, and redecompile the class<\/li><\/ul>\n\n\n\n<p>The second part in the series presents bytecode encryption and assets encryption.<\/p>\n\n\n<div class='footnotes' id='footnotes-3689'><div class='footnotedivider'><\/div><ol><li id='fn-3689-1'> VM in VM, repeat <em>ad nauseam<\/em> &#8211; something not new to code protection systems, it&#8217;s existed on x86 for more than a decade, but new on Android, and other players in this field, commercial and otherwise, seem to be implementing similar solutions. <span class='footnotereverse'><a href='#fnref-3689-1'>&#8617;<\/a><\/span><\/li><li id='fn-3689-2'> So-called &#8220;RASP&#8221;, a relatively new acronym for <em>Runtime Application Self-Protection<\/em> <span class='footnotereverse'><a href='#fnref-3689-2'>&#8617;<\/a><\/span><\/li><li id='fn-3689-3'> Decryption and unreflection are generic processes of <em>dexdec<\/em> (the DEX Decompiler plugin); there is nothing specific to this protector here. The vast majority or encrypted data, regardless of the protection system in place, will be decrypted. <span class='footnotereverse'><a href='#fnref-3689-3'>&#8617;<\/a><\/span><\/li><\/ol><\/div>","protected":false},"excerpt":{"rendered":"<p>In this series: Part 1, Part 2, Part 3 What started as a ProGuard + basic string encryption + code reflection tool evolved into a multi-platform, complex solution including: control-flow obfuscation, complex and varied data and resources encryption, bytecode encryption, virtual environment and rooted system detection, application signature and certificate pinning enforcement, native code protection, &hellip; <a href=\"https:\/\/www.pnfsoftware.com\/blog\/reversing-android-protector-obfuscation\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Reversing an Android app Protector, Part 1 &#8211; Code Obfuscation &#038; RASP<\/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,18,5],"tags":[],"class_list":["post-3689","post","type-post","status-publish","format-standard","hentry","category-android","category-jeb3","category-obfuscation"],"_links":{"self":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts\/3689","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=3689"}],"version-history":[{"count":0,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/posts\/3689\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/media?parent=3689"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/categories?post=3689"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pnfsoftware.com\/blog\/wp-json\/wp\/v2\/tags?post=3689"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}