{"id":6983,"date":"2017-03-15T07:40:38","date_gmt":"2017-03-15T15:40:38","guid":{"rendered":"http:\/\/www.palada.net\/index.php\/2017\/03\/15\/news-774\/"},"modified":"2017-03-15T07:40:38","modified_gmt":"2017-03-15T15:40:38","slug":"news-774","status":"publish","type":"post","link":"http:\/\/www.palada.net\/index.php\/2017\/03\/15\/news-774\/","title":{"rendered":"Teardown of a Recent Variant of Android\/Ztorg (Part 1)"},"content":{"rendered":"<p><strong>Credit to Author: Axelle Apvrille| Date: Wed, 15 Mar 2017 08:20:51 -0700<\/strong><\/p>\n<div class=\"entry\">\n<p><strong>Ztorg<\/strong>, also known as Qysly, is one of those big families of Android malware. It first appeared in&nbsp;<em>April 2015<\/em>, and now has over 25 variants, some of which are still active in 2017. Yet, there aren&#39;t many technical descriptions for it &#8211; except for the initial&nbsp;<a href=\"http:\/\/www.fortiguard.com\/encyclopedia\/virus\/6651192\">Ztorg.A sample<\/a>&nbsp;&#8211; so I decided to have a look at one of the newer variants,&nbsp;<strong>Android\/Ztorg.AM!tr<\/strong>, that we detected on January 20, 2017.<\/p>\n<p>The sample poses a &quot;Cool Video Player&quot; and&nbsp;<strong>its malicious activity was so well hidden I initially thought I had run into a False Positive<\/strong>. Definitely not, however, as we&#39;ll see.<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg11.png\" style=\"width: 177px; height: 205px;\" \/><\/p>\n<h2>Locating the Malicious Code<\/h2>\n<p>The sample&#39;s manifest shows the main activity is located in com.mx.cool.videoplayer.activity.MainActivity.<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg12.png\" style=\"width: 900px; height: 102px;\" \/><\/p>\n<p>This activity initializes multiple SDKs, from which I could not detect malicious intent:<\/p>\n<ul>\n<li>com.adjust:&nbsp;<a href=\"https:\/\/github.com\/adjust\/android_sdk\">Adjust SDK<\/a>, for app analytics<\/li>\n<li>com.batmobi:&nbsp;<a href=\"https:\/\/www.batmobi.net\/page\/index.html\">Batmobi<\/a>&nbsp;for mobile advertising<\/li>\n<li>com.catchgift: code shows this is clearly for advertising<\/li>\n<li>com.marswin89: this is a&nbsp;<a href=\"https:\/\/github.com\/Marswin\/MarsDaemon\">MarsDaemon<\/a>, a library to keep apps alive. Interesting, but not malicious as such.<\/li>\n<li>com.squareup: well-known mobile payment<\/li>\n<li>com.umeng: well-known mobile advertising &amp; analytics<\/li>\n<\/ul>\n<p>So, where is the malicious code? Or is it just some not-so-clean code in one of these SDKs that triggered a (false positive) alert?<\/p>\n<p>I kept on looking in other namespaces of the app:<\/p>\n<ul>\n<li>u.aly contained code for Mobclick &#8211; advertising again (hey, for the sake of AV analysts at least, can you developers stop using so many advertising SDKs, huh?),<\/li>\n<li>android.support.v4 is standard for app development.<\/li>\n<li>Namespace&nbsp;e.i.o.q&nbsp;isn&#39;t doing anything apart calling functions from the&nbsp;a&nbsp;namespace.<\/li>\n<\/ul>\n<p>So, that&#39;s when I started looking into namespace&nbsp;a&#8230;<\/p>\n<h2>String Obfuscation<\/h2>\n<p>I immediately noticed many obfuscated strings, and couldn&#39;t resist de-obfuscating them (after all, I&#39;m the Crypto Girl, right?).<\/p>\n<p>For instance, we have this:<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg13.png\" style=\"width: 614px; height: 27px;\" \/><\/p>\n<p>and c.a() is implemented as follows:<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg14.png\" style=\"width: 583px; height: 343px;\" \/><\/p>\n<p>This basically takes the first and last byte as XOR key for the rest of the byte array. From that, I wrote a quick standalone Python decoder, mimicking the decompiled code. It is handy, but as I use&nbsp;<a href=\"https:\/\/www.pnfsoftware.com\">JEB2<\/a>&nbsp;a script is even better where I can have it replace the strings directly in the decompiled output.<\/p>\n<p><strong>JEB scripts<\/strong>&nbsp;are a little trickier to write. Mine parses the decompiled classes, and in each class locates statements with a&nbsp;c.a(new byte[] { &#8230; }). The call to the decoding function occurs in several situations though, e.g&nbsp;v0[6] = c.a(new byte[]{&#8230;&nbsp;but also&nbsp;a = new String(c.a(new byte[]{&#8230;. Consequently, the right hand side of the line needs to be analyzed quite closely. Then, when a call is detected, the script decodes the value, and replaces it with the result.<\/p>\n<p>For example, the first figure (on the left) illustrates the initial decompiled code for a.a.a. The second figure shows the result after applying the script.&nbsp;&nbsp;<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg15.png\" style=\"width: 900px; height: 116px;\" \/><\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg16.png\" style=\"width: 680px; height: 186px;\" \/><\/p>\n<p>My scripts are available on&nbsp;<a href=\"https:\/\/github.com\/cryptax\/misc-code\">Github<\/a>.<\/p>\n<h2>Emulator Detection<\/h2>\n<p>Among the decoded strings, we notice&nbsp;<strong>many references to VirtualBox, QEMU etc<\/strong>. This is emulator detection, and we&#39;ll see that it is particularly advanced.<\/p>\n<p>Let&#39;s go back to the flow of execution. The&nbsp;onCreate()&nbsp;method of the main activity (&nbsp;MainActivity) calls&nbsp;f(), which calls&nbsp;e.i.o.q.d(). Reversing&nbsp;e.i.o.q.d(), we understand the function tests whether it is running on an emulator or not.&nbsp;<strong>It only runs the malicious part if not on an emulator<\/strong>, which explains why sandboxes won&#39;t be able to record any malicious activity.<\/p>\n<p><strong>The emulator detection routine is particularly advanced and extensive. It detects standard Android emulators, Genymotion emulators, Bluestacks emulators,&nbsp;<\/strong><a href=\"http:\/\/jeeradate.com\/wp\/?p=345\"><strong>BuilDroid VMs<\/strong><\/a><strong>,&nbsp;and also tainted environments that use&nbsp;<\/strong><a href=\"https:\/\/www.usenix.org\/legacy\/event\/osdi10\/tech\/full_papers\/Enck.pdf\"><strong>TaintDroid<\/strong><\/a><strong>.<\/strong><\/p>\n<p>The detection is based on:<\/p>\n<ol>\n<li>Specific values in system properties. This is quite standard, except the tests are particularly extensive (see Table) in this case.<\/li>\n<li>Typical values for IMEI, IMSI and phone number on emulators. On Genymotion, the IMEI can be customized, but not the IMSI. On standard Android SDK emulators, none of these are easily customizable. It is possible to patch and re-compile one&#39;s emulator.<\/li>\n<li>Presence of specific files. For example,&nbsp;\/dev\/qemu_pipe. From an AV analyst&#39;s perspective, this is&nbsp;<strong>difficult to counter<\/strong>, because many of the emulating environments won&#39;t work properly without these files.<\/li>\n<li>Checking values in given system files. In particular, it&#39;s the&nbsp;<strong>first time I have seen malware checking values inside&nbsp;<\/strong><strong>\/proc\/net\/tcp<\/strong>. This is interesting: the file records active TCP connections. The first column corresponds to the number of entries, second column is local address, third column local port, and fourth column remote address. On a real device, we have something like this:<\/li>\n<\/ol>\n<blockquote>\n<p>0: 4604D20A:B512 A3D13AD8&#8230;<\/p>\n<\/blockquote>\n<p>But on emulators, the addresses are zeroed and easily noticeable:<\/p>\n<blockquote>\n<p>0: 00000000:0016 00000000:0000<\/p>\n<\/blockquote>\n<ol>\n<li value=\"5\">Specific&nbsp;<strong>TaintDroid<\/strong>&nbsp;class (dalvik.system.Taint) and injected fields (name&nbsp;in FileDescriptor class and&nbsp;key&nbsp;in Cipher). The code was probably inspired from&nbsp;<a href=\"https:\/\/github.com\/strazzere\/anti-emulator\/blob\/fe9999a03da60c2b49e138fbf45450a7592a2c05\/AntiEmulator\/src\/diff\/strazzere\/anti\/taint\/FindTaint.java\">Tim Strazzere&#39;s Anti Emulator code<\/a>.<\/li>\n<\/ol>\n<h2>Downloading Remote Content<\/h2>\n<p>We have seen that the sample implements advanced emulator detection. However, many clean apps do that for various reasons. So where is the malicious stuff? At this point, we aren&#39;t convinced yet that this is not a False Positive.<\/p>\n<p>Actually, we&#39;re getting closer. After the sample has tested it is not running on an emulator, it&nbsp;<strong>sends an HTTP request<\/strong>&nbsp;to&nbsp;hXXp:\/\/bbs.tihalf.com\/only\/[$1]\/2.html?. This is a URL we de-obfuscated at the previous step. The&nbsp;[$1]&nbsp;is replaced with&nbsp;gp1187&nbsp;(another de-obfuscated string), and an information blob is appended to the url, where the blob is a DES-encrypted JSON object containing code version, SDK version, etc.<\/p>\n<p>This is getting more suspicious.<\/p>\n<p>The response is base64 encoded, and encrypted with DES-CBC (see class&nbsp;a.c.a):<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg17.png\" style=\"width: 615px; height: 234px;\" \/><\/p>\n<p>The key is hard-coded (it&#39;s the de-obfuscated string&nbsp;sokhlwej) and the IV is&nbsp;DES_e.IV = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};. We decrypt the server&#39;s response:<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg18.png\" style=\"width: 614px; height: 158px;\" \/><\/p>\n<p>We notice that&nbsp;o&nbsp;and&nbsp;p&nbsp;contain&nbsp;<strong>a link to an Android package<\/strong>. Are they used? Yes! As soon as the JSON object is retrieved, the sample reads the URL in&nbsp;o&nbsp;and tries to download the file. If ever&nbsp;o&nbsp;does not work, it tries&nbsp;p.<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg19.png\" style=\"width: 610px; height: 108px;\" \/><\/p>\n<p>So, basically, in this case, the sample&nbsp;<strong>downloads another Android package from&nbsp;<\/strong><strong>hXXp:\/\/alla.tihalf.com\/only\/gp1187\/gp1187.apk<\/strong>&nbsp;and stores it locally on the smartphone.<\/p>\n<p>But we are not done yet. The downloaded APK is not in clear text:<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg20.png\" style=\"width: 609px; height: 43px;\" \/><\/p>\n<p><strong>It is XOR-ed with 0x99<\/strong>&nbsp;(see code excerpt of class&nbsp;a.d.f) and copied to a file named&nbsp;dba.jar:<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg21.png\" style=\"width: 611px; height: 138px;\" \/><\/p>\n<p>This indeed results in a valid Android package:<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg22.png\" style=\"width: 611px; height: 176px;\" \/><\/p>\n<p>And then? It loads the downloaded application, of course! See code below &#8211; taken from&nbsp;a.d.n.<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg23.png\" style=\"width: 605px; height: 195px;\" \/><\/p>\n<p>The installation of the application is done via&nbsp;DexClassLoader&nbsp;and is&nbsp;<strong>invisible to the end-user<\/strong>.<\/p>\n<p>Finally, it invokes a method of that application. Specifically, it loads the class referenced by key&nbsp;q&nbsp;in the JSON object, and invokes method&nbsp;h&nbsp;from the JSON object:<\/p>\n<p><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg24.png\" style=\"width: 603px; height: 92px;\" \/><\/p>\n<p>In our case,&nbsp;q&nbsp;is&nbsp;n.a.c.q&nbsp;and&nbsp;h&nbsp;is&nbsp;c, so the sample invokes&nbsp;n.a.c.q.c().<\/p>\n<h2>Conclusion<\/h2>\n<p>This Ztorg sample<strong> does a very good job of concealing its maliciousness<\/strong>, but we can confirm that it is malicious and not a False Positive.<\/p>\n<ul>\n<li>It implements many emulator detection features.&nbsp;<strong>It detects the Android SDK emulator, but also emulators from Genymotion, Bluestacks and BuilDroid. It also detects tainted environments. Several of its checks will be difficult to bypass.<\/strong><\/li>\n<li>It uses&nbsp;<strong>string obfuscation<\/strong>, based on XOR.<\/li>\n<li>It communicates with a remote server using&nbsp;<strong>DES-CBC encryption<\/strong>.<\/li>\n<li>It&nbsp;<strong>downloads, installs and launches an Android application<\/strong>&nbsp;from that remote server.<\/li>\n<\/ul>\n<p><a href=\"http:\/\/blog.fortinet.com\/2017\/03\/08\/teardown-of-android-ztorg-part-2\">In part 2 of this analysis, we will examine the downloaded application.<\/a><\/p>\n<p>&#8212; the Crypto Girl<\/p>\n<p>Appendix:<\/p>\n<p>Sample analyzed in this article:<\/p>\n<p>sha256: 2c546ad7f102f2f345f30f556b8d8162bd365a7f1a52967fce906d46a2b0dac4<\/p>\n<p>Table 1: Elements tested by Android\/Ztorg.AM!tr to detect emulators<\/p>\n<p>&nbsp;<\/p>\n<\/div<br \/><a href=\"http:\/\/blog.fortinet.com\/2017\/03\/15\/teardown-of-a-recent-variant-of-android-ztorg-part-1\" target=\"bwo\" >https:\/\/blog.fortinet.com\/feed<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/ztorg11.png\"\/><\/p>\n<p><strong>Credit to Author: Axelle Apvrille| Date: Wed, 15 Mar 2017 08:20:51 -0700<\/strong><\/p>\n<p>Ztorg, also known as Qysly, is one of those big families of Android malware. It first appeared in\u00a0April 2015, and now has over 25 variants, some of which are still active in 2017. Yet, there aren&#039;t many technical descriptions for it &#8211; except for the initial\u00a0Ztorg.A sample\u00a0&#8211; so I decided to have a look at one of the newer variants,\u00a0Android\/Ztorg.AM!tr, that we detected on January 20, 2017.    The sample poses a &quot;Cool Video Player&quot; and\u00a0its malicious activity was so well hidden I initially thought I had run into&#8230;<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[10424,10378],"tags":[],"class_list":["post-6983","post","type-post","status-publish","format-standard","hentry","category-fortinet","category-security"],"_links":{"self":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/6983","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/comments?post=6983"}],"version-history":[{"count":0,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/6983\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/media?parent=6983"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/categories?post=6983"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/tags?post=6983"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}