{
	"id": "0ace1a56-fef7-41ef-9ad0-58206c4da599",
	"created_at": "2026-04-06T00:08:48.447734Z",
	"updated_at": "2026-04-10T03:20:04.820445Z",
	"deleted_at": null,
	"sha1_hash": "5917f8c128632d85d34e136f78450036258bf220",
	"title": "A native packer for Android/MoqHao",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1262380,
	"plain_text": "A native packer for Android/MoqHao\r\nBy @cryptax\r\nPublished: 2021-05-20 · Archived: 2026-04-05 22:50:10 UTC\r\n3 min read\r\nMay 18, 2021\r\nUpdate May 20, 2021. Added info on Pinterest URLs + Kudos to @bl4ckh0l3z + actually was discovered on May\r\n12 not May 13.\r\nOn May 12, 2021 a new sample of Android/MoqHao (aka XLoader, Wroba) banking trojan was detected. There\r\nare several changes compared to 2019: new commands, communicating CnC URL through malicious Pinterest\r\naccounts etc. See below.\r\nsha256: aad80d2ad20fe318f19b6197b76937bf7177dbb1746b7849dd7f05aab84e6724\r\nPress enter or click to view image in full size\r\nComparing sample of 2021 (sha256:\r\naad80d2ad20fe318f19b6197b76937bf7177dbb1746b7849dd7f05aab84e6724 ) with sample of 2019\r\n(analyzed here)\r\nPress enter or click to view image in full size\r\nhttps://cryptax.medium.com/a-native-packer-for-android-moqhao-6362a8412fe1\r\nPage 1 of 6\n\nThis is the part of the malicious payload that processes (malicious) Pinterest accounts to retrieve\r\ninformation on the CnC. For each targeted bank, the malware searches for the corresponding\r\npackage on the smartphone, displays a given Pinterest URL and “hint” message. See this tweet of\r\n@bl4ckh0l3z.\r\nIn this article, we will focus on the packer which is quite interesting because it uses a native library + the\r\ndecryption algorithm has changed (see table above).\r\nDecrypting the payload\r\nThe malware is packed. The unpacking process consists in processing correctly an encrypted file in an asset\r\ndirectory named ./whrlrsu . The asset is encrypted with an XOR key, and zipped. The XOR key is memorized\r\nin the encrypted file at the 12th byte.\r\nPress enter or click to view image in full size\r\nhttps://cryptax.medium.com/a-native-packer-for-android-moqhao-6362a8412fe1\r\nPage 2 of 6\n\nPayload decryption process\r\nI implemented a payload decryptor, available on GitHub.\r\nPreparing dynamic class\r\nLoading dynamic classes is typically done via the DexClassLoader class, from the Android API. To conceal it\r\nloads a dynamic class, the malware does not directly call DexClassLoader . Instead, it implements a native\r\nlibrary ( libgdx.so ) that calls DexClassLoader from the native layer.\r\nPress enter or click to view image in full size\r\nhttps://cryptax.medium.com/a-native-packer-for-android-moqhao-6362a8412fe1\r\nPage 3 of 6\n\nA DexClassLoader object is instantiated by function nd(). This consists in (1) calling FindClass, (2)\r\nsearching for a constructor, and (3) using the constructor to create a new object.\r\nThe native library implements the following low level tasks:\r\nObject cr(Class class) : calls create() for the given class ( com.Loader ). This actually instantiates a\r\nLoader object.\r\nObject lrd(int arg0, Object arg1, String classname, String arg3) : call loadClass() on the given\r\nclass name and return the loaded class object.\r\nString g(int arg0) : returns a different string depending on the argument. Beware, JEB currently\r\ndecompiles it incorrectly: you must read the assembly.\r\nPress enter or click to view image in full size\r\nhttps://cryptax.medium.com/a-native-packer-for-android-moqhao-6362a8412fe1\r\nPage 4 of 6\n\nIf the integer is 0, the routine returns “dalvik.system.DexClassLoader”, for 1 it returns\r\n“com.Loader”, for 2 “()Ljava/lang/Object;” and for 3 “java.util.zip.InflaterInputStream”\r\nIn our case, the malware uses the routine with argument 1, so g() returns “com.Loader”. This is provided to\r\nlrd() , so the malware will load a class named com.Loader and contained in the dynamic DEX. Finally, it\r\nlocates the method create() within com.Loader .\r\nGet @cryptax’s stories in your inbox\r\nJoin Medium for free to get updates from this writer.\r\nRemember me for faster sign in\r\nThere are some other native functions, but they are not used in the next stage. Note that up to know, the malware\r\ndoes not execute its payload, it only “prepares” things. This is all OmApplication.onCreate() does. Execution is\r\nwithin the next stage.\r\nExecuting the payload\r\nThe next stage occurs when the main activity is launched. Actually, strangely, the manifest references 2 main\r\nactivities: adlbect.kvActivity and adlbect.BnActivity , but actually adlbect.kvActivity does nothing\r\nmore than calling adlbect.BnActivity .\r\nPress enter or click to view image in full size\r\nSilly kvActivity does nothing more than starting BnActivity.\r\nBnActivity starts the WqService — we’ll discuss it later — and calls native function a.ed() . The method\r\ndecompiles in JEB quite nicely, and we quickly recognize code to hide an application icon.\r\nPress enter or click to view image in full size\r\nHiding an application icon consists in calling setComponentEnabledSetting method (name is\r\ntruncated on the image above) on the PackageManager class, with special flags\r\nhttps://cryptax.medium.com/a-native-packer-for-android-moqhao-6362a8412fe1\r\nPage 5 of 6\n\nPackageManager.COMPONENT_ENABLED_STATE_DISABLED and\r\nPackageManager.DONT_KILL_APP. This is a well known trick to run an app while hiding its\r\napplication icon.\r\nAs for the WqService, it launches start() of com.Loader — this is how the banking trojan payload\r\nactually starts — and sets an alarm in 30 seconds.\r\nPress enter or click to view image in full size\r\nThis is onStartCommand() of WqService. This method is automatically called by Android when the\r\nWqService starts. a_set_alarm calls native function a.snc() to set an alarm. I don’t actually know\r\nwhat it uses this alarm for.\r\nThe implementation hardens the reversing because it does not call methods directly but delegates the work to 2\r\nnative functions: a.start() calls com.Loader.start() , and a.snc() to set the alarm.\r\nPress enter or click to view image in full size\r\nList of native functions, and their description, in libgdx.so\r\nKudos to @MalwareHunterTeam and @bl4ckh0l3z.\r\n— Cryptax\r\nSource: https://cryptax.medium.com/a-native-packer-for-android-moqhao-6362a8412fe1\r\nhttps://cryptax.medium.com/a-native-packer-for-android-moqhao-6362a8412fe1\r\nPage 6 of 6",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://cryptax.medium.com/a-native-packer-for-android-moqhao-6362a8412fe1"
	],
	"report_names": [
		"a-native-packer-for-android-moqhao-6362a8412fe1"
	],
	"threat_actors": [],
	"ts_created_at": 1775434128,
	"ts_updated_at": 1775791204,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/5917f8c128632d85d34e136f78450036258bf220.pdf",
		"text": "https://archive.orkl.eu/5917f8c128632d85d34e136f78450036258bf220.txt",
		"img": "https://archive.orkl.eu/5917f8c128632d85d34e136f78450036258bf220.jpg"
	}
}