Analyzing the mtop Device Risk-Control SDK - Jailbreak Detection, a VMP Layer, and Multi-Stage Encryption
About the author. I’m Colin Xiao — an independent reverse engineer, mostly working solo on contract jobs. I dig into compiled code of every kind, including but not limited to: Android and iOS apps, x86/x64/ARM native binaries, packers and obfuscators, DRM and license checks, network protocols and APIs, crypto and signature algorithms, malware, game binaries, and embedded/IoT firmware. I also handle large-scale data collection and vulnerability research. If you have any project in mind, I’d be glad to take it on — whatever it is, as long as it’s within my wheelhouse. Just reach out. You can reach me on X at @colinxiao_lab or on Telegram at https://t.me/ColinXiao666.
This research is published for educational and defensive purposes. The target sample is anonymized throughout.
mtop is the device risk-control SDK that sits as a gateway between a major Chinese e-commerce app’s mobile client and its backend, shielding a huge surface of APIs — product listings, ordering, payment, and so on. Reverse engineering it is worthwhile on three fronts:
- Anti-protocol-cracking and anti-device-spoofing. Understanding how the risk-control layer collects device data, encrypts it, and signs requests is the core of the analysis. Knowing the crypto and the parameter-generation logic shows you how the anti-tamper / anti-spoofing / “legal request construction” mechanisms work.
- Anti-scraping and anti-automation. Studying the mtop request flow reveals how the app throttles automated data collection and order generation.
- Anti-bypass. Picking apart the risk-control logic exposes the conditions that trigger risk flags, and in doing so surfaces both potential bypass paths and the corresponding defensive lessons.
Tools and environment
Frida, Charles, IDA Pro 9.0. Mac mini running macOS 14.6.1, iPhone X on iOS 14.8.
Device-side execution flow
3.0 Capture
First, capture the request parameters:

On first launch the risk-control layer makes three requests; the first returns risk features plus a device id (eeid):

The returned data JSON carries dt — risk features plus the logic instructions that control algorithm changes — and the device id (eeid), among other fields:
{
"cdnScriptUrl": "http://[redacted]/u6vr/g9m6/1gkepoi",
"cfg": {
"trust": {
"modifiedtime": 1606735713,
"v": 174084,
"type1": "{\"en\":0}"
},
"e1002": {
"modifiedtime": 1719282753,
"v": 400052,
"type1": "{\"e1002\":{\"p\":1,\"s\":true,\"c\":[{\"s\":\"9a85\",\"k\":\"47b0\"},{\"s\":\"82a0\",\"k\":\"51b6\"}],\"z\":1},\"e1011\":{\"p\":1,\"s\":true,\"c\":[{\"s\":\"c99e\",\"k\":\"9a1d\"},{\"s\":\"4337\"},{\"s\":\"f983\"},{\"s\":\"5f0d\"},{\"s\":\"9a66\"},{\"s\":\"9a85\",\"k\":\"47b0\"},{\"s\":\"75f8\",\"k\":\"d54f\"},{\"s\":\"7e2d\",\"k\":\"14ee\"},{\"s\":\"82a0\",\"k\":\"51b6\"}],\"z\":7}}"
},
"e1011": {
"modifiedtime": 1700535253,
"v": 400011,
"type1": "{\"e1011\":{\"p\":1,\"z\":7,\"s\":true,\"c\":[{\"k\":\"9a1d\",\"s\":\"c99e\"},{\"k\":null,\"s\":\"4337\"},{\"k\":null,\"s\":\"f983\"},{\"k\":null,\"s\":\"5f0d\"},{\"k\":null,\"s\":\"9a66\"},{\"k\":\"da1a\",\"s\":\"c7b1\"}]}}"
},
"e1000": {
"modifiedtime": 1719282754,
"v": 400107,
"type1": "{\"e1000\":{\"p\":0,\"s\":true,\"z\":1},\"e1011\":{\"p\":1,\"s\":true,\"c\":[{\"s\":\"c99e\",\"k\":\"9a1d\"},{\"s\":\"4337\"},{\"s\":\"f983\"},{\"s\":\"9a85\",\"k\":\"47b0\"},{\"s\":\"75f8\",\"k\":\"d54f\"},{\"s\":\"7e2d\",\"k\":\"14ee\"}],\"z\":7}}"
},
"ocrt": {
"modifiedtime": 1635995243,
"v": 400001,
"type1": "14.0"
},
"applist": {
"modifiedtime": 1583808665,
"v": 116009,
"type1": "com.360buy.jdmobile,com.xunmeng.pinduoduo,com.vipshop.iphone,com.tencent.mqq,com.tencent.ww,com.tencent.xin,com.baidu.map,com.tencent.sosomap,ctrip.com,com.tuniu.app,com.qunar.iphoneclient8,com.qiyi.iphone,com.tencent.live4iphone,com.ss.iphone.ugc.Aweme,com.wuba.zhuanzhuan,com.ss.iphone.article.News,com.meituan.itakeaway,com.dianping.dpscope,com.meituan.imeituan,com.mmp.mmp040608"
},
"sgpt": {
"modifiedtime": 1727261154,
"v": 400090,
"type1": "{\"o\":\"QgIAA3b7uxQAcDYAB6vaNgE/ABk2Aj8aHjYDPx9oNgQ/KTI4BT8zPDYGPz1GNgc/R1A2CD9RWjYJP1tkNgo/Zf82CxMBCJk2DBMCDZk2DRMDnJk2DhMECJk2DxMFnJk2EBMG3Jk2ERMHDZk2EhMIfZk2ExMJ3Jk2FBMKCJk2FRMLjjYWEwyONhcTDY42GBMOjjYZEw+ONhoTEI42GxMRjjYcExKONh0TE442HhMUjjYfExUTFhMXExgTGRMaExsTHBMdEx42IDQENiETHyETIDYiEyHumTYjNAQTIDQEEyLPBMAUBz4TAAdJB4gH8we7EyPAGA==\",\"s\":\"QgEAA3j7uwAANgAHSQeIB/MHuwc+NgI0AjYDc2MFc6gFc6oFc2UFc/Urc7EFc6QFNgQdAJ0HJygN+QQLVb8OEwPLNgUTBP4FDRMDNgYTBSETAjYHB6sTAhMGzwTAFBMAEwfAGA==\"}"
},
"bp": {
"modifiedtime": 1675837757,
"v": 400004,
"type1": "[{\"b\":0,\"o\":59607428}]"
},
"e1004": {
"modifiedtime": 1726738032,
"v": 400104,
"type1": "{\"e1011\":{\"p\":1,\"s\":true,\"c\":[{\"s\":\"4337\"},{\"s\":\"f53f\",\"k\":\"ea2f\"},{\"s\":\"2109\",\"k\":\"b9de\"},{\"s\":\"5f0d\"},{\"s\":\"9a66\",\"k\":\"0eb2\"},{\"s\":\"9a85\",\"k\":\"47b0\"},{\"s\":\"75f8\",\"k\":\"d54f\"},{\"s\":\"7e2d\",\"k\":\"14ee\"},{\"s\":\"82a0\",\"k\":\"51b6\"}],\"z\":7},\"e1004\":{\"p\":1,\"s\":true,\"c\":[{\"s\":\"f983\"},{\"s\":\"c99e\",\"k\":\"9a1d\"},{\"s\":\"4337\"},{\"s\":\"ad62\",\"k\":\"0141\"},{\"s\":\"7e2d\",\"k\":\"14ee\"},{\"s\":\"5f0d\"},{\"s\":\"9a66\",\"k\":\"0eb2\"},{\"s\":\"9a85\",\"k\":\"47b0\"},{\"s\":\"82a0\",\"k\":\"51b6\"}],\"z\":7}}"
},
"RConfig": {
"modifiedtime": 1728641375,
"v": 400262,
"type1": "{\"gtaop\":0,\"hevent\":2,\"switch\":{\"r_64_0\":0,\"rc\":0,\"mach2\":1,\"ihook\":1,\"r_61_0\":0,\"ulib\":0,\"ier\":1,\"lnk\":0,\"its\":1,\"ist\":0}}"
},
"RList": {
"modifiedtime": 1595903663,
"v": 135019,
"type1": "{\"v\":1,\"sp\":{\"AWZ.dylib\":1,\"NZT.dylib\":1,\"ALS.dylib\":1,\"rstweak.dylib\":1,\"YOY.dylib\":1,\"iGrimace.dylib\":1,\"hdfaker.dylib\":1,\"NewDevice.dylib\":1,\"HookDevice.dylib\":1,\"zzhardChange.dylib\":1,\"deviceInfoChange.dylib\":1,\"FakeTweak.dylib\":1,\"setmobile.dylib\":1,\"amg.dylib\":1,\"TEMain.dylib\":2,\"TweakEx.dylib\":2,\"tweaktest.dylib\":2,\"MAServiceEnEx.dylib\":2,\"SimulateTouch.dylib\":2,\"TSTweak.dylib\":2,\"XXScreenShot.dylib\":2,\"GPSCheat.dylib\":2,\"GPSTravellerTweakProX.dylib\":2,\"LocationChanger.dylib\":4,\"TEGPS.dylib\":4,\"txytweak.dylib\":4,\"txyfakegps.dylib\":4,\"OTRLocation.dylib\":4,\"altweak.dylib\":4},\"so\":{\"v\":1,\"l\":[[\"/Applications/Cydia.app\",\"/usr/sbin/frida-server\",\"/usr/lib/libjailbreak.dylib\",\"/jb/libjailbreak.dylib\"],[\"/Applications/iGrimace.app\",\"/Applications/NZT.app\",\"/Applications/hdFaker.app\"],[\"/Applications/TouchElf.app\",\"/Applications/AutoTouch.app\",\"/Applications/TouchSprite.app\",\"/Applications/handjingling.app\"],[\"/Applications/tianxiayou.app\",\"/Applications/TianXiaYou.app\",\"/Applications/anylocation.app\",\"/Applications/OTRLocation.app\"]]}}"
},
"dmtop": {
"modifiedtime": 1689046187,
"v": 400017,
"type1": "1"
},
"crpt": {
"modifiedtime": 1727261147,
"v": 400021,
"type1": "QgIAA3b7uxQAcDYAB6vaNgE/ABk2Aj8aHjYDPx9oNgQ/KTI2BT8zPDYGPz1GNgfsd/R1A2CD9RWjYJP1tkNgo/Zf82CxMBCJk2DBMCDZk2DRMDnJk2DhMECJk2DxMFnJk2EBMG3Jk2ERMHDZk2EhMIfZk2ExMJ3Jk2FBMKCJk2FRMLjjYWEwyONhcTDY42GBMOjjYZEw+ONhoTEI42GxMRjjYcExKONh0TE442HhMUjjYfExUTFhMXExgTGRMaExsTHBMdEx42IDQENiETHyETIDYiEyHumTYjNAQTIDQEEyLPBMAUBz4TAAdJB4gH8we7EyPAGA=="
},
"hash": {
"modifiedtime": 1583809627,
"v": 118007,
"type1": "{\"p\":0,\"z\":1,\"s\":true,\"c\":[{\"k\":\"f471\",\"s\":\"5a7a\"},{\"k\":\"0174\",\"s\":\"5a7a\"},{\"k\":\"c07a\",\"s\":\"6932\"},{\"k\":\"d79b\",\"s\":\"5a7a\"},{\"k\":\"db95\",\"s\":\"8c64\"}]}"
},
"bcud": {
"modifiedtime": 1669186615,
"v": 400007,
"type1": "1"
}
},
"cmd": 1011,
"eeid": "[redacted]",
"rmdata": "[redacted]",
"token": "[redacted]"
}
3.1 Risk detection
All three requests scan the device for risk features, named r_<digits>_<digits> (e.g. r_1_0). Collection is done primarily through svc syscalls:
__uvm_call_registry_llc_do_syscall_sub_1026F4850
__text:00000001048898DC svc_sub_1026CD8DC
__text:00000001048898DC
__text:00000001048898DC arg_0= 0
__text:00000001048898DC
__text:00000001048898DC F0 03 40 F9 LDR X16, [SP,#arg_0]
__text:00000001048898E0 01 00 00 D4 SVC 0
__text:00000001048898E4 43 00 00 54 B.CC locret_1048898EC
__text:00000001048898E8 7A 9B 00 14 B sub_1048B06D0
Jailbreak risk features:
MEMORY:0000000124F46652 2F 4C 69 62 72 61 72 79…aLibraryMobiles_1 DCB "/Library/MobileSubstrate",0
MEMORY:0000000124F4666B 2F 41 70 70 6C 69 63 61…aApplicationsCy_0 DCB "/Applications/Cydia.app",0
MEMORY:0000000124F46683 2F 41 70 70 6C 69 63 61…aApplicationsSi DCB "/Applications/Sileo.app",0
MEMORY:0000000124F4669B 2F 76 61 72 2F 6A 62 2F…aVarJbApplicati DCB "/var/jb/Applications/Sileo-Nightly.app",0
MEMORY:0000000124F466C2 2F 76 61 72 2F 6A 62 2F…aVarJbApplicati_0 DCB "/var/jb/Applications/Sileo-Beta.app",0
MEMORY:0000000124F466E6 2F 76 61 72 2F 6A 62 2F…aVarJbApplicati_1 DCB "/var/jb/Applications/Cydia.app",0
MEMORY:0000000124F46705 2F 76 61 72 2F 6A 62 2F…aVarJbApplicati_2 DCB "/var/jb/Applications/Sileo.app",0
MEMORY:0000000124F46724 2F 41 70 70 6C 69 63 61…aApplicationsZe DCB "/Applications/Zebra.app",0
MEMORY:0000000124F4673C 2F 75 73 72 2F 6C 69 62…aUsrLibexecCydi DCB "/usr/libexec/cydia",0
MEMORY:0000000124F4674F 2F 75 73 72 2F 6C 69 62…aUsrLibexecZebr DCB "/usr/libexec/zebra",0
MEMORY:0000000124F46762 2F 75 73 72 2F 6C 69 62…aUsrLibexecFilz DCB "/usr/libexec/filza",0
MEMORY:0000000124F46775 2F 75 73 72 2F 6C 69 62…aUsrLibexecSubs DCB "/usr/libexec/substrated",0
MEMORY:0000000124F4678D 2F 75 73 72 2F 6C 69 62…aUsrLibexecSubs_0 DCB "/usr/libexec/substituted",0
MEMORY:0000000124F467A6 2F 65 74 63 2F 61 70 74…aEtcApt_1 DCB "/etc/apt",0
MEMORY:0000000124F467AF 2F 65 74 63 2F 64 70 6B…aEtcDpkg DCB "/etc/dpkg",0
MEMORY:0000000124F467B9 2F 65 74 63 2F 73 73 68…aEtcSsh DCB "/etc/ssh",0
MEMORY:0000000124F467C2 2F 4C 69 62 72 61 72 79…aLibraryTweakin DCB "/Library/TweakInject",0
MEMORY:0000000124F467D7 2F 75 73 72 2F 62 69 6E…aUsrBinCycript DCB "/usr/bin/cycript",0
MEMORY:0000000124F467E8 2F 75 73 72 2F 6C 69 62…aUsrLibLibjailb DCB "/usr/lib/libjailbreak.dylib",0
MEMORY:0000000124F46804 2F 75 73 72 2F 6C 69 62…aUsrLibLibhooke DCB "/usr/lib/libhooker.dylib",0
MEMORY:0000000124F4681D 2F 75 73 72 2F 6C 69 62…aUsrLibLibsubst DCB "/usr/lib/libsubstitute.dylib",0
MEMORY:0000000124F4683A 2F 75 73 72 2F 6C 69 62…aUsrLibTweakinj DCB "/usr/lib/TweakInject",0
MEMORY:0000000124F4684F 2F 75 73 72 2F 62 69 6E…aUsrBinDebugser DCB "/usr/bin/debugserver",0
MEMORY:0000000124F46864 2F 75 73 72 2F 6C 69 62…aUsrLibexecAfc2 DCB "/usr/libexec/afc2d",0
MEMORY:0000000124F46877 2F 75 73 72 2F 62 69 6E…aUsrBinSsh DCB "/usr/bin/ssh",0
MEMORY:0000000124F46884 2F 75 73 72 2F 62 69 6E…aUsrBinDpkg DCB "/usr/bin/dpkg",0
MEMORY:0000000124F46892 2F 75 73 72 2F 62 69 6E…aUsrBinAptKey DCB "/usr/bin/apt-key",0
MEMORY:0000000124F468A3 2F 75 73 72 2F 62 69 6E…aUsrBinCynject DCB "/usr/bin/cynject",0
MEMORY:0000000124F468B4 2F 75 73 72 2F 6C 6F 63…aUsrLocalBinDro DCB "/usr/local/bin/dropbear",0
MEMORY:0000000124F468CC 2F 65 6C 65 63 74 72 61…aElectraInjectC DCB "/electra/inject_criticald",0
MEMORY:0000000124F468E6 2F 76 61 72 2F 62 69 6E…aVarBinpackLoad DCB "/var/binpack/loaderd_hook",0
MEMORY:0000000124F46900 2F 4C 69 62 72 61 72 79…aLibraryPrefere DCB "/Library/PreferenceBundles/LibertyPref.bundle",0
MEMORY:0000000124F4692E 2F 4C 69 62 72 61 72 79…aLibraryPrefere_0 DCB "/Library/PreferenceBundles/ShadowPreferences.bundle",0
MEMORY:0000000124F46962 2F 4C 69 62 72 61 72 79…aLibraryPrefere_1 DCB "/Library/PreferenceBundles/ABypassPrefs.bundle",0
MEMORY:0000000124F46991 2F 4C 69 62 72 61 72 79…aLibraryPrefere_2 DCB "/Library/PreferenceBundles/FlyJBPrefs.bundle",0
MEMORY:0000000124F469BE 2F 4C 69 62 72 61 72 79…aLibraryPrefere_3 DCB "/Library/PreferenceBundles/HestiaPrefs.bundle",0
MEMORY:0000000124F469EC 2F 4C 69 62 72 61 72 79…aLibraryPrefere_4 DCB "/Library/PreferenceBundles/KernBypassPrefs.bundle",0
MEMORY:0000000124F46A1E 2F 4C 69 62 72 61 72 79…aLibraryPrefere_5 DCB "/Library/PreferenceBundles/Avatar.bundle",0
MEMORY:0000000124F46A47 2F 65 74 63 2F 70 72 6F…aEtcProfileDCor DCB "/etc/profile.d/coreutils.sh",0
MEMORY:0000000124F46A63 2F 2E 69 6E 73 74 61 6C…aInstalledUnc0v DCB "/.installed_unc0ver",0
MEMORY:0000000124F46A77 2F 70 72 69 76 61 74 65…aPrivateVarMobi DCB "/private/var/mobile/staged_system_apps",0
MEMORY:0000000124F46A9E 2F 70 72 69 76 61 74 65…aPrivateVarMobi_0 DCB "/private/var/mobile/mobile",0
MEMORY:0000000124F46AB9 2F 64 65 76 2F 66 61 6B…aDevFakevar DCB "/dev/fakevar",0
MEMORY:0000000124F46AC6 2F 74 6D 70 2F 76 6E 6F…aTmpVnodememTxt DCB "/tmp/vnodeMem.txt",0
MEMORY:0000000124F46AD8 2F 75 73 72 2F 6C 69 62…aUsrLibEllekitM DCB "/usr/lib/ellekit/MobileSafety.dylib",0
MEMORY:0000000124F46AFC 2F 76 61 72 2F 6A 62 2F…aVarJbUsrLibTwe DCB "/var/jb/usr/lib/TweakInject",0
MEMORY:0000000124F46B18 2F 76 61 72 2F 6A 62 2F…aVarJbUsrLibEll DCB "/var/jb/usr/lib/ellekit/MobileSafety.dylib",0
MEMORY:0000000124F46B43 2F 76 61 72 2F 6A 62 2F…aVarJbLibraryMo DCB "/var/jb/Library/MobileSubstrate/DynamicLibraries",0
MEMORY:0000000124F46B74 2F 76 61 72 2F 6A 62 2F…aVarJbInstalled DCB "/var/jb/.installed_dopamine",0
MEMORY:0000000124F46B90 2F 76 61 72 2F 6A 62 2F…aVarJbBasebinJb DCB "/var/jb/basebin/jbctl",0
MEMORY:0000000124F46BA6 2F 76 61 72 2F 6A 62 2F…aVarJbUsrLibTwe_0 DCB "/var/jb/usr/lib/TweakLoader.dylib",0
MEMORY:0000000124F46BC8 2F 76 61 72 2F 6A 62 2F…aVarJbPrepBoots DCB "/var/jb/prep_bootstrap.sh",0
MEMORY:0000000124F46BE2 2F 65 74 63 2F 72 63 2E…aEtcRcDLibhooke DCB "/etc/rc.d/libhooker",0
MEMORY:0000000124F46BF6 2F 76 61 72 2F 6A 62 2F…aVarJbEtcRcDLib DCB "/var/jb/etc/rc.d/libhooker",0
MEMORY:0000000124F46C11 2F 41 70 70 6C 69 63 61…aApplications DCB "/Applications",0
MEMORY:0000000124F46C1F 2F 4C 69 62 72 61 72 79…aLibraryRington DCB "/Library/Ringtones",0
MEMORY:0000000124F46C32 2F 4C 69 62 72 61 72 79…aLibraryWallpap DCB "/Library/Wallpaper",0
MEMORY:0000000124F46C45 5F 4D 53 53 61 66 65 4D…aMssafemode DCB "_MSSafeMode",0
MEMORY:0000000124F46C51 73 75 62 73 74 69 74 75…aSubstitute DCB "substitute",0
MEMORY:0000000124F46C5C 4A 42 52 4F 4F 54 00 aJbroot DCB "JBROOT",0
MEMORY:0000000124F46C63 4A 42 52 41 4E 44 00 aJbrand DCB "JBRAND",0
MEMORY:0000000124F46C6A 4A 42 5F 52 4F 4F 54 5F…aJbRootPath DCB "JB_ROOT_PATH",0
MEMORY:0000000124F46C77 4A 42 5F 53 41 4E 44 42…aJbSandboxExten DCB "JB_SANDBOX_EXTENSIONS",0
MEMORY:0000000124F46C8D 63 79 64 69 61 3A 2F 2F…aCydiaInstalled DCB "cydia://installed",0
MEMORY:0000000124F46C9F 73 69 6C 65 6F 3A 2F 2F…aSileo DCB "sileo://",0
MEMORY:0000000124F46CA8 7A 62 72 61 3A 2F 2F 00 aZbra DCB "zbra://",0
MEMORY:0000000124F46CB0 66 69 6C 7A 61 3A 2F 2F…aFilza DCB "filza://",0
MEMORY:0000000124F46CB9 61 63 74 69 76 61 74 6F…aActivator DCB "activator://",0
Frida / device-spoofing detection:
MEMORY:000000012779091A aApplicationsIg DCB "/Applications/iGrimace.app",0
MEMORY:0000000127790935 aApplicationsNz DCB "/Applications/NZT.app",0
MEMORY:000000012779094B aApplicationsHd DCB "/Applications/hdFaker.app",0
MEMORY:0000000127790965 aApplicationsMo DCB "/Applications/MobileAnjian.app",0
MEMORY:0000000127790984 aApplicationsTo DCB "/Applications/TouchElf.app",0
MEMORY:000000012779099F aApplicationsAu DCB "/Applications/AutoTouch.app",0
MEMORY:00000001277909BB aApplicationsTo_0 DCB "/Applications/TouchSprite.app",0
MEMORY:00000001277909D9 aApplicationsTo_1 DCB "/Applications/TouchSpritePe.app",0
MEMORY:00000001277909F9 aApplicationsHa DCB "/Applications/handjingling.app",0
MEMORY:0000000127790A18 aApplicationsTi DCB "/Applications/tianxiayou.app",0
MEMORY:0000000127790A35 aApplicationsTi_0 DCB "/Applications/TianXiaYou.app",0
MEMORY:0000000127790A52 aApplicationsAn DCB "/Applications/anylocation.app",0
MEMORY:0000000127790A70 aApplicationsOt DCB "/Applications/OTRLocation.app",0
MEMORY:00000002822B0480 aApplicationsCy_1 DCB "/Applications/Cydia.app",0
MEMORY:00000002822B04A0 aUsrSbinFridaSe DCB "/usr/sbin/frida-server",0
MEMORY:0000000283671170 aLibraryMobiles_2 DCB "/Library/MobileSubstrate/MobileSubstrate.dylib",0
"/Library/LaunchDaemons/re.frida.server.plist"
There’s more besides — dump detection, re-signing, injection, frida, hooking, and so on. The three ways the SDK collects device information:
3.2 Device collection
Objective-C method collection:
UTDevice
ONI_FindClass
utdid
ONI_GetStaticMethodID
ONI_CallStaticObjectMethod
ONI_GetStringUTFcString
C function collection:
open、read、opendir readdir, etc.
Custom-method collection (via svc syscalls):
llc_do_syscall 0x0000000000000152 SYS_stat64
__text:00000001048898DC svc_sub_1026CD8DC
__text:00000001048898DC
__text:00000001048898DC arg_0= 0
__text:00000001048898DC
__text:00000001048898DC F0 03 40 F9 LDR X16, [SP,#arg_0]
__text:00000001048898E0 01 00 00 D4 SVC 0
__text:00000001048898E4 43 00 00 54 B.CC locret_1048898EC
__text:00000001048898E8 7A 9B 00 14 B sub_1048B06D0
MEMORY:000000011553502C 2F 76 61 72 2F 6D 6F 62+aVarMobileMedia DCB "/var/mobile/Media/DCIM/100APPLE",0
MEMORY:000000011553504C 2F 53 79 73 74 65 6D 2F+aSystemLibraryP DCB "/System/Library/Pearl/ReferenceFrames/reference-sparse.plist",0
MEMORY:0000000115535089 2F 53 79 73 74 65 6D 2F+aSystemLibraryP_0 DCB "/System/Library/Pearl/ReferenceFrames/reference-dense.plist",0
MEMORY:00000001155350C5 2F 53 79 73 74 65 6D 2F+aSystemLibraryP_1 DCB "/System/Library/Pearl/ReferenceFrames/reference-sparseLP.plist",0
// format string for collected content
%ld%c %ld.%ld%c
3.3 VMP, briefly
a. VM entry:
__text:000000010732D1D0 STP X29, X30, [SP,#-0x10+var_s0]!
__text:000000010732D1D4 MOV X29, SP
__text:000000010732D1D8 SUB SP, SP, #0x100
__text:000000010732D1DC STP X20, X19, [SP,#0x100+var_70]
__text:000000010732D1E0 STP X22, X21, [SP,#0x100+var_80]
__text:000000010732D1E4 STP X24, X23, [SP,#0x100+var_90]
__text:000000010732D1E8 STP X26, X25, [SP,#0x100+var_A0]
__text:000000010732D1EC STP X28, X27, [SP,#0x100+var_B0]
__text:000000010732D1F0 STP X15, X14, [SP,#0x100+var_C0]
__text:000000010732D1F4 STP X13, X12, [SP,#0x100+var_D0]
__text:000000010732D1F8 STP X11, X10, [SP,#0x100+var_E0]
__text:000000010732D1FC STP X9, X8, [SP,#0x100+var_F0]
__text:000000010732D200 MOV X26, X0
__text:000000010732D204 MOV X28, X1
__text:000000010732D208 MOV X19, X2
__text:000000010732D20C MOV X27, X19
__text:000000010732D210 MOV X24, X4
__text:000000010732D214 MOV X20, X5
__text:000000010732D218 MOV X25, X6
__text:000000010732D21C ADD X21, X24, #0x100
__text:000000010732D220 MOV X22, #0
__text:000000010732D224 MOV X23, #0
__text:000000010732D228 MOV X23, X27
__text:000000010732D22C ADD X27, X27, X3,LSL#4
__text:000000010732D230 LDR W8, [X27]
__text:000000010732D234 LDR X8, [X20,X8,LSL#3]
__text:000000010732D238 STR X27, [X28,#8]
__text:000000010732D23C BR X8
b. VM exit:
_text:000000010732D328 LDR X11, [X24,#0xF0]
__text:000000010732D32C LDP X9, X10, [X24,#0xC0]
__text:000000010732D330 STP X9, X10, [X24,#0x40]
__text:000000010732D334 LDP X9, X10, [X24,#0xD0]
__text:000000010732D338 STP X9, X10, [X24,#0x50]
__text:000000010732D33C LDP X9, X10, [X24,#0xE0]
__text:000000010732D340 STP X9, X10, [X24,#0x60]
__text:000000010732D344 LDR X9, [X24,#0xF8]
__text:000000010732D348 STR X9, [X24,#0x78]
__text:000000010732D34C MOV X23, X22
__text:000000010732D350 LDP X9, X10, [X11]
__text:000000010732D354 STP X9, X10, [X24,#0x80]
__text:000000010732D358 LDP X9, X10, [X11,#0x10]
__text:000000010732D35C STP X9, X10, [X24,#0x90]
__text:000000010732D360 LDP X9, X10, [X11,#0x20]
__text:000000010732D364 STP X9, X10, [X24,#0xA0]
__text:000000010732D368 LDP X9, X10, [X11,#0x30]
__text:000000010732D36C STP X9, X10, [X24,#0xB0]
__text:000000010732D370 LDP X9, X10, [X11,#0x40]
__text:000000010732D374 STP X9, X10, [X24,#0xC0]
__text:000000010732D378 LDP X9, X10, [X11,#0x50]
__text:000000010732D37C STP X9, X10, [X24,#0xD0]
__text:000000010732D380 LDP X9, X10, [X11,#0x60]
__text:000000010732D384 STP X9, X10, [X24,#0x70]
__text:000000010732D388 LDP X9, X10, [X11,#0x70]
__text:000000010732D38C STP X9, X10, [X24,#0xF0]
__text:000000010732D390 LDP X9, X10, [X11,#0x80]
__text:000000010732D394 STP X9, X10, [X24,#0x30]
__text:000000010732D398 LDR X22, [X11,#0x78]
__text:000000010732D39C STR X11, [X24,#0x70]
__text:000000010732D3A0 LDR X9, [X24,#0x78]
__text:000000010732D3A4 ADD X27, X9, #0x10
__text:000000010732D3A8 LDR W8, [X27]
__text:000000010732D3AC LDR X8, [X20,X8,LSL#3]
__text:000000010732D3B0 STR X27, [X28,#8]
__text:000000010732D3B4 BR X8
c. Handlers.
There are about 70 handlers; most basic instructions are emulated. The handlers themselves aren’t obfuscated, so it’s fairly easy to see which instruction each one simulates:
__text:000000010732D908 EOR_sub_1026C9908
__text:000000010732D908 LDRB W1, [X27,#5]
__text:000000010732D90C LDRB W2, [X27,#6] ; load vm register indices
__text:000000010732D910 LDR X1, [X24,X1,LSL#3]
__text:000000010732D914 LDR X2, [X24,X2,LSL#3]
__text:000000010732D918 LDRB W0, [X27,#7]
__text:000000010732D91C EOR X1, X1, X2 ; eor
__text:000000010732D920 AND X1, X1, #0xFFFFFFFF
__text:000000010732D924 STR X1, [X24,X0,LSL#3]
__text:000000010732D928 LDR W8, [X27,#0x10]!
__text:000000010732D92C LDR X8, [X20,X8,LSL#3]
__text:000000010732D930 STR X27, [X28,#8]
__text:000000010732D934 BR X8
__text:000000010697AA30 ; r9, r25, r27
__text:000000010697AA30
__text:000000010697AA30 _ADD_sub_10B2CAA30
__text:000000010697AA30 61 17 40 39 LDRB W1, [X27,#5]
__text:000000010697AA34 62 1B 40 39 LDRB W2, [X27,#6] ; load vm register indices
__text:000000010697AA38 01 7B 61 F8 LDR X1, [X24,X1,LSL#3]
__text:000000010697AA3C 02 7B 62 F8 LDR X2, [X24,X2,LSL#3]
__text:000000010697AA40 60 1F 40 39 LDRB W0, [X27,#7]
__text:000000010697AA44 21 00 02 8B ADD X1, X1, X2
__text:000000010697AA48 01 7B 20 F8 STR X1, [X24,X0,LSL#3]
__text:000000010697AA4C 68 0F 41 B8 LDR W8, [X27,#0x10]! ; handle index
__text:000000010697AA50 88 7A 68 F8 LDR X8, [X20,X8,LSL#3]
__text:000000010697AA54 9B 07 00 F9 STR X27, [X28,#8]
__text:000000010697AA58 00 01 1F D6 BR X8 ; index
__text:000000010697AA58
3.4 Encryption flow
After device data is collected, it’s encrypted for upload. The flow is complex: single-field encryption, per-segment encryption, and whole-payload encryption — and each segment uses a different algorithm. I’ll outline the flow; the details are an exercise.
Take MAC address collection as an example. The raw data:
00000002817806A0 37 38 3A 39 31 3A 32 33 3A 34 35 3A 36 33 3A 34 78:91:23:45:63:4
00000002817806B0 35
First layer
a. Generate a random number as the key:
00000319
b. First-layer encryption, byte-by-byte:
key "00000319" index 5 -> 0000000000000033
000000000000003A ADD 0000000000000033 = 000000000000006D
000000000000006D ADD FFFFFFFFFFFFFFC0 = 000000000000002D
000000000000002D ADD 0000000000000020 = 000000000000004D (encrypted)
Second layer
a. Fixed key:
02 00 00 00 00 00 00 00
b. Encryption:
length 000000000000000B AND 0000000000000003 = 0000000000000003
02 00 00 00 00 00 00 00 // index into the key (0x3) -> 0000000000000000
0000000000000000 EOR 0000000000000040 = 0000000000000040 // xor
// combined with a fixed field-key name
35 33 66 62 34 39 33 32 59 3C 5E 40 00 00 00 00 53fb4932Y<^@....
c. All fields are then combined and concatenated together.
Third layer
a. The combined device data is split into groups for encryption:
// combined device data xor
00000000536D7261 XOR 000000000AAE8E7A = 0000000059C3FC1B
000000000017473D ORR 0000000005400000 = 000000000557473D
000000000000074F XOR 0000000005574072 = 000000000557473D
00000000000BA39E ORR 0000000082A00000 = 0000000082ABA39E
00000000596D5721 XOR 0000000082ABA39E = 00000000DBC6F4BF
000000000015D1CF ORR 0000000041400000 = 000000004155D1CF
0000000000000011 XOR 000000004155D1CF = 000000004155D1DE
00000000000AE8E7 ORR 00000000A0A00000 = 00000000A0AAE8E7
0000000064656362 XOR 00000000A0AAE8E7 = 00000000C4CF8B85
00000000C4CF8B85 LSR 000000000000000A = 00000000003133E2
0000000005574072 LSL 0000000000000016 = 000000001C800000
00000000003133E2 ORR 000000001C800000 = 000000001CB133E2
0000000059C3FC1B LSR 000000000000000A = 00000000001670FF
00000000DBC6F4BF LSL 0000000000000016 = 000000002FC00000
000000002FC00000 ORR 00000000001670FF = 000000002FD670FF
0000000005574072 LSR 000000000000000A = 00000000000155D0
000000004155D1DE LSL 0000000000000016 = 0000000077800000
0000000077800000 ORR 00000000000155D0 = 00000000778155D0
00000000DBC6F4BF LSR 000000000000000A = 000000000036F1BD
00000000C4CF8B85 LSL 0000000000000016 = 00000000E1400000
00000000E1400000 ORR 000000000036F1BD = 00000000E176F1BD
b. Segments are typed differently:
0x16、0x17、0x18、0x15、0x14
Each type encrypts slightly differently.
c. After each segment is encrypted, they’re combined and XORed with a random number.
d. Base64-encoded, then combined with a fixed string (v0001ipx234001).
Fourth layer
a. Wrap the encrypted data into JSON:
String es = v0001ipx234001 + Base64.encodeToString(encBytes);
JsonObject jsonet = new JsonObject();
jsonet.addProperty("es", es);
b. Compress the combined JSON.
c. AES-encrypt the compressed data.
d. Base64-encode the AES output and send it as the request body.
Wrap-up
All told, the mtop risk-control SDK has strong code protection. The signing algorithm and the local encryption pipeline are complex, the cost of protocol recovery is high, and the algorithm logic is dynamically pushed from the server. From an attacker’s perspective, a device-spoofing approach is probably the cheaper route.
Still, there are solid defensive takeaways worth stealing:
a. Common libc string functions (strlen, strcpy, memset, etc.) are re-implemented inside the VMP.
b. The SDK manages its own memory structures.
c. The VM flow is obfuscated, with junk operations unrelated to the real logic mixed in.
d. Internal methods are called dynamically; their addresses are stored encrypted and decrypted at call time.
e. Collected fields are split into 10 groups, each encrypted with a different algorithm whose variation is controlled server-side.
f. The encryption is white-box and computed inside the VMP layer.
Colin Xiao — I take on contract reverse-engineering work, and writeups like this are how I show what I can do. If you need help with anything in this space — including but not limited to the areas I cover above — I’m available. No project is too big or too small — if it’s reverse engineering and I can do it, I’ll take it. DM me on X (@colinxiao_lab) or Telegram (@ColinXiao666).
Get in touch