{
	"id": "35bac2af-0e23-4385-a894-c7d5ce038be8",
	"created_at": "2026-04-06T01:31:49.944558Z",
	"updated_at": "2026-04-10T03:20:25.764271Z",
	"deleted_at": null,
	"sha1_hash": "ec98c2264976d5f79544fae08df7e1159e711fc7",
	"title": "reversing an Android anti-analysis native library",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2274322,
	"plain_text": "reversing an Android anti-analysis native library\r\nArchived: 2026-04-06 00:07:03 UTC\r\nVB2018 paper: Unpacking the packed unpacker: reversing an Android anti-analysis native library\r\nMaddie Stone\r\nGoogle, USA\r\nCopyright © 2018 Virus Bulletin\r\nTable of contents\r\nAbstract\r\nMalware authors implement many different techniques to frustrate analysis and make reverse engineering\r\nmalware more difficult. Many of these anti-analysis and anti-reverse engineering techniques attempt to send a\r\nreverse engineer down a different investigation path or require them to invest large amounts of time reversing\r\nsimple code. This talk analyses one of the most interesting anti-analysis native libraries we've seen in the Android\r\necosystem. No previous references to this library have been found. We've named this anti-analysis library\r\n'WeddingCake' because it has lots of layers.\r\nThis paper covers four techniques the malware authors used in the WeddingCake anti-analysis library to prevent\r\nreverse engineering. These include: manipulating the Java Native Interface, writing complex algorithms for simple\r\nfunctionality, encryption, and run-time environment checks. This paper discusses the steps and the process\r\nrequired to proceed through the anti-analysis traps and expose what the developers are trying to hide.\r\nIntroduction\r\nTo protect their code, authors may implement obfuscation, encryption, and anti-analysis techniques. There are\r\nboth legitimate and malicious reasons why developers may want to prevent analysis and reverse engineering of\r\ntheir code. Legitimate developers may want to protect their intellectual property, while malicious developers may\r\nwant to prevent detection. This paper details an Android anti-analysis native library used by multiple malware\r\nfamilies to prevent analysis and detection of their malicious behaviours. Some variants of the Chamois malware\r\nfamily [1] use this anti-analysis library, which has been seen in over 5,000 unique Android APKs. The APK with\r\nSHA256 hash e8e1bc048ef123a9757a9b27d1bf53c092352a26bdbf9fbdc10109415b5cadac is used as the sample\r\nfor this paper.\r\nIntroduction to the Java Native Interface (JNI)\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 1 of 19\n\nThe sample Android application includes a native library to hide the contents and functionality of native code. The\r\nJava Native Interface (JNI) allows developers to define Java native methods that run in other languages, such as C\r\nor C++, in the application. This allows bytecode and native code to interface with each other. In Android, the\r\nNative Development Kit (NDK) is a toolset that permits developers to write C and C++ code for their Android\r\napps [2]. Using the NDK, Android developers can include native shared libraries in their Android applications.\r\nThese native shared libraries are .so files, a shared object library in the ELF format. In this paper, the terms 'native\r\nlibrary', 'ELF', and '.so file' are used interchangeably to refer to the anti-analysis library. The anti-analysis library\r\nthat is detailed in this paper is one of these Android native shared libraries.\r\nThe bytecode in the .dex file of the Android application defines the native methods [3]. These native method\r\ndefinitions pair with a subroutine in the shared library. Before the native method can be run from the Java code,\r\nthe Java code must call System.loadLibrary or System.load on the shared library (.so file). When the Java code\r\ncalls one of the two load methods, the JNI_OnLoad() function is called from the shared library. The shared library\r\nneeds to export the JNI_OnLoad() function.\r\nIn order to run a native method from Java, the native method must be 'registered', meaning that the JNI knows\r\nhow to pair the Java method definition with the correct function in the native library. This can be done either by\r\nleveraging the RegisterNatives JNI function or through 'discovery' based on the function names and function\r\nsignatures matching in both Java and the .so [4]. For either method, a string of the Java method name is required\r\nfor the JNI to know which native function to call.\r\nCharacteristics of the anti-analysis library\r\nWeddingCake, the anti-analysis library discussed in this paper, is an Android native library, an ELF file, included\r\nin the APK. In the sample, the anti-analysis library is named lib/armeabi/libdxarq.so. The name of the anti-analysis library differs in each APK, as explained in the following section.\r\nNaming\r\nWithin the classes.dex of the APK, there is a package of classes whose whole name is random characters. For the\r\nsample described in this paper, the class name is ses.fdkxxcr.udayjfrgxp.ojoyqmosj.xien.xmdowmbkdgfgk. This\r\nclass declares three native methods: quaqrd, ixkjwu, and vxeg.\r\nThe native library discussed in this paper is usually named lib[3-8 random lowercase characters].so. However,\r\nwe've encountered a few samples whose name does not match this convention. All APK samples that include\r\nWeddingCake use different random characters for their class and function names. It is likely that WeddingCake\r\nprovides tooling that generates new random names each time it is compiled.\r\nVariants\r\nThe most common version of the library is a 32-bit 'generic' ARM (armeabi) ELF, but I've also identified 32-bit\r\nARMv7 (armeabi-v7a), ARM64 (arm64-v8a), and x86 (x86) versions of the library. All of the variants include the\r\nsame functionality. If not otherwise specified, this paper focuses on the 32-bit 'generic' ARM implementation of\r\nWeddingCake because this is the most common variant.\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 2 of 19\n\nAs an example, the APK with SHA256 hash\r\n92e80872cfd49f33c63993d52290afd2e87cbef5db4adff1bfa97297340f23e0, which is different from the one\r\nanalysed in this paper, includes three variants of the anti-analysis library: generic ARM, ARMv7, and x86.\r\nAnti-analysis lib file paths Anti-analysis library 'type'\r\nlib/armeabi/librxovdx.so 32-bit 'generic' ARM\r\nlib/armeabi-v7a/librxovdx.so 32-bit ARMv7\r\nlib/x86/libaojjp.so x86\r\nTable 1: Anti-analysis lib paths in 92e80872cfd49f33c63993d52290afd2e87cbef5db4adff1bfa97297340f23e0.\r\nKey signatures of the ELF\r\nThere are some signatures that help identify ELF files as a WeddingCake anti-analysis library:\r\nTwo strings under the .comment section in the ELF:\r\n- Android clang version 3.8.275480 (based on LLVM 3.8.275480)\r\n- GCC: (GNU) 4.9.x 20150123 (prerelease)\r\nThe native function names defined in the APK do not exist in the shared library\r\nFor the 32-bit generic ARM version of the library, when loaded into IDA Pro, JNI_OnLoad (Figure 1) is an\r\nexported function name, but does not exist in 'functions' because there are 12 bytes (three words) that are\r\ndefined as data, which inhibit IDA's ability to identify the function. The bytes defined as data are always at\r\noffsets +0x24, +0x28, and +0x44 from the beginning of the JNI_OnLoad function.\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 3 of 19\n\nFigure 1: JNI_OnLoad in IDAPro.\r\nAnalysing the library\r\nThe JNI_OnLoad function is the starting point for analysis because there are no references to the native methods\r\nthat were defined in the APK. For this sample, the following three methods were defined as native methods in\r\nses.fdkxxcr.udayjfrgxp.ojoyqmosj.xien.xmdowmbkdgfgk:\r\npublic static native String quaqrd(int p0);\r\npublic native Object ixkjwu(Object[] p0);\r\npublic native int vxeg(Object[] p0);\r\nThere are no instances of these strings existing in the native library being analysed. As described in the\r\n'Introduction to JNI' section, in order to call a native function from the Java code in the APK, the ELF must know\r\nhow to match a Java method (as listed previously) to the native function in the ELF file. This is done by\r\nregistering the native function using RegisterNatives() and the JNINativeMethod struct [5]. We would normally\r\nexpect to see the Java native method name and its associated function signature ([Ljava/lang/Object;)I) as strings\r\nin the ELF file. Since we do not, the ELF file is probably using an anti-analysis technique.\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 4 of 19\n\nBecause JNI_OnLoad must be executed prior to the application calling one of its defined native methods, I began\r\nanalysis in the JNI_OnLoad function.\r\nIn the sample, the JNI_OnLoad() function ends with many calls to the same function. This is shown in Figure 2.\r\nEach call takes a different block of memory as its argument, which is often a signal of decryption. In this sample,\r\nthe subroutine at 0x2F30 (sub_2F30) is the in-place decryption function.\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 5 of 19\n\nFigure 2: Calls to the decryption subroutine in JNI_OnLoad in IDA Pro.\r\nIn-place decryption\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 6 of 19\n\nTo obscure its functionality, this library's contents are decrypted dynamically when the library is loaded. The\r\ndecryption algorithm used in this library was not matched to a known encryption/decryption algorithm. The\r\ndecryption function, found at sub_2F30 in this sample, takes the following arguments:\r\nencrypted_array: Pointer to the encrypted byte array (bytes to be decrypted)\r\nlength: Length of the encrypted byte array\r\nword_seed_array: Word (each value in array is 4 bytes) seed array\r\nbyte_seed_array: Byte (each value in array is 1 byte) seed array\r\nsub_2F30(Byte[] encrypted_array, int length, Word[] word_seed_array, Byte[] byte_seed_array)\r\nGenerating the seed arrays\r\nThe decryption function takes two seed arrays as arguments each time it is called: the word seed array and the byte\r\nseed array. These two arrays are generated once, beginning at 0x1B58 in this sample, prior to the first call to the\r\ndecryption function. The byte array is created first; in this sample, it's generated at 0x1B58. The word array is\r\ncreated immediately after the byte array initialization at 0x1BD0. The word seed array and byte seed array are the\r\nsame for every call to the decryption function within the ELF and are never modified.\r\nThe author of this code obfuscated the generation of the seed arrays. The IDA decompiled code for the generation\r\nof the two arrays, byte_seed_array and word_seed_array, is shown in Listing 1.\r\nbyte_seed_array = malloc(0x100u);\r\nindex = 0;\r\n do\r\n {\r\n byte_seed_array[index] = index;\r\n ++index;\r\n }\r\n while ( 256 != index );\r\n v4 = 0x2C09;\r\n curr_count = 256;\r\n copy_byte_seed_array = byte_seed_array\r\n do\r\n {\r\n v6 = 0x41C64E6D * v4 + 0x3039;\r\n v7 = v6;\r\n v8 = copy_byte_seed_array[v6];\r\n v9 = 0x41C64E6D * (v6 \u0026 0x7FFFFFFF) + 0x3039;\r\n copy_byte_seed_array[v7] = copy_byte_seed_array[v9];\r\n copy_byte_seed_array[v9] = v8;\r\n --curr_count;\r\n v4 = v9 \u0026 0x7FFFFFFF;\r\n }\r\n while ( curr_count );\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 7 of 19\n\nword_seed_array = malloc(0x400u);\r\n index = 0;\r\n do\r\n {\r\n word_seed_array[byte_seed_array[index]] = index;\r\n ++index;\r\n }\r\n while ( 256 != index );\r\nListing 1: The IDA decompiled code for the generation of the two arrays, byte_seed_array and word_seed_array.\r\nThese algorithms output the byte_seed_array and word_seed_array shown in Listing 2. The author of this code\r\ntried to frustrate the reverse engineering process of this library by writing complex algorithms which would\r\nrequire more investment of effort, time and skill to reverse engineer. Using a complex algorithm to accomplish a\r\nsimple task is a common anti-reverse engineering technique.\r\nbyte_seed_array =\r\n[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x\r\nword_seed_array =\r\n[0x0000000, 0x0000001, 0x0000002, 0x0000003, 0x0000004, 0x0000005, 0x0000006, 0x0000007, 0x0000008, 0\r\nListing 2: The byte_seed_array and word_seed_array.\r\nKnowing that these arrays are static, an analyst could dump the arrays any time post-initialization, thus bypassing\r\nthis anti‑reversing technique.\r\nDecryption algorithm\r\nThe overall framework of the in-place decryption process is:\r\n1. Decryption function is called on an array of encrypted bytes.\r\n2. Decryption is performed.\r\n3. Encrypted bytes are overwritten by the decryption bytes.\r\nThis process is repeated in JNI_OnLoad() for each encrypted array. I did not identify the decryption algorithm\r\nused in the library as being a variation of a known encryption algorithm. The Python code I wrote to implement\r\nthe decryption algorithm is shown in Listing 3.\r\ndef decrypt(encrypted_bytes, length, byte_seed_array, word_seed_array):\r\n if (encrypted_bytes is None):\r\n print ( \"encrypted_bytes is null. -- Exiting \")\r\n return\r\n if (length \u003c 1):\r\n print ( \"encrypted_bytes len \u003c 1 -- Exiting \")\r\n return\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 8 of 19\n\nreg_4 = ~(0x00000004)\r\n reg_0 = 4\r\n reg_2 = 0\r\n reg_5 = 0\r\n do_loop = True\r\n# Address 0x2F58 in Sample e8e1bc048ef123a9757a9b27d1bf53c092352a26bdbf9fbdc10109415b5cadac\r\n while (do_loop):\r\n reg_6 = length + reg_0\r\n reg_6 = encrypted_bytes[reg_6 + reg_4]\r\n if (reg_6 \u0026 0x80):\r\n if (reg_5 \u003e 3):\r\n return\r\n reg_6 = reg_6 \u0026 0x7F\r\n reg_2 = reg_2 \u0026 0xFF\r\n reg_2 = reg_2 \u003c\u003c 7\r\n reg_2 = reg_2 | reg_6\r\n reg_0 = reg_0 + reg_4 + 4\r\n reg_3 = length + reg_0 + reg_4 + 2\r\n reg_5 += 1\r\n if (reg_3 \u0026 0x80000000 or reg_3 \u003c= 1):\r\n return\r\n else:\r\n do_loop = False\r\n reg_5 = 0xF0 \u0026 reg_6\r\n reg_3 = length + reg_0 + reg_4\r\n reg_1 = reg_3 + 1\r\n if (reg_0 == 0 and reg_5 != 0):\r\n return\r\n# Address 0x2F9A in Sample e8e1bc048ef123a9757a9b27d1bf53c092352a26bdbf9fbdc10109415b5cadac\r\n reg_5 = reg_1\r\n reg_1 = (reg_2 \u003c\u003c 7) + reg_6\r\n byte_FF = 0xFF\r\n reg_1 = reg_1 \u0026 byte_FF\r\n last_byte = reg_1\r\n if (reg_5 == 0 or reg_5 \u0026 0x80000000 or last_byte == 0 or signed_ble(reg_3, last_byte)):\r\n return\r\n reg_1 = (reg_4 + 4)\r\n reg_1 = (reg_1 * last_byte)\r\n reg_1 += length\r\n crazy_num = reg_1 + reg_0 + reg_4\r\n if (crazy_num \u003c 1):\r\n return\r\n new_index = reg_1 + reg_0\r\n reg_5 = 0\r\n# Address 0x2FD8 in Sample e8e1bc048ef123a9757a9b27d1bf53c092352a26bdbf9fbdc10109415b5cadac\r\nwhile (1):\r\n byte = encrypted_bytes[reg_5]\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 9 of 19\n\nreg_0 = byte \u003c\u003c 2\r\n reg_6 = word_seed_array[byte]\r\n reg_0 = 0xFF - reg_6\r\n if (not reg_6 \u0026 0x80000000):\r\n reg_6 = reg_0\r\n reg_0 = reg_5\r\n reg_1 = reg_0 % last_byte\r\n reg_0 = new_index + reg_1\r\n reg_0 = encrypted_bytes[(reg_0 + reg_4) \u0026 0xFF]\r\n reg_1 = word_seed_array[reg_0]\r\n reg_2 = reg_1 | reg_6\r\n index_reg_0 = reg_5\r\n if (reg_2 \u0026 0x80000000):\r\n break\r\n# Address 0x3012 in Sample e8e1bc048ef123a9757a9b27d1bf53c092352a26bdbf9fbdc10109415b5cadac\r\n reg_1 = reg_6 + reg_1 + reg_5\r\n reg_2 = arith_shift_rt(reg_1, 0x1F)\r\n reg_2 = reg_2 \u003e\u003e 0x18\r\n reg_2 = reg_2 \u0026 ~0x000000FF\r\n reg_1 -= reg_2\r\n reg_1 = 0x000000FF - reg_1\r\n reg_1 = byte_seed_array[reg_1 \u0026 0xFF]\r\n encrypted_bytes[index_reg_0] = reg_1 \u0026 0xFF\r\n reg_5 += 1\r\n if (reg_5 \u003e= crazy_num):\r\n break\r\n print \"*********** FINISHED DECRYPT *************** \"\r\nListing 3: Python code to implement the decryption algorithm.\r\nI wrote an IDAPython script to statically decrypt the contents of the ELF so that reverse engineering could\r\ncontinue. This script and description is provided in the Appendix.\r\nDecrypted contents\r\nEach of the encrypted arrays decrypts to a string. Before-and-after samples of the encrypted bytes and the\r\ndecrypted bytes at 0x9480 are shown in Figures 3 and 4. The bytes were decrypted using the IDAPython\r\ndecryption script described in the Appendix.\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 10 of 19\n\nFigure 3: Encrypted bytes in ELF beginning at 0x9480.\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 11 of 19\n\nFigure 4: Decrypted bytes in ELF beginning at 0x9480.\r\nWithin the decrypted strings of the ELF, we see the names of the native functions defined in the Java code at the\r\nfollowing locations in the ELF file:\r\nquaqrd (0xA107)\r\nvxeg (0x936E)\r\nixkjwu (0x9330)\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 12 of 19\n\nNow that these strings are decrypted, we can see which subroutines in the ELF are called when the native function\r\nis called from the APK. Table 2 shows the native functions defined for this sample in the anti-analysis ELF.\r\nNative\r\nfunction\r\nname\r\nNative\r\nsubroutine\r\naddress\r\nSignature\r\nHuman-readable\r\nsignature\r\nvxeg 0x30D4 ([Ljava/lang/Object;)I\r\npublic native int\r\nvxeg(Object[] p0);\r\nquaqrd 0x4814 (I)Ljava/lang/String;\r\npublic static native String\r\nquaqrd(int p0);\r\nixkjwu ---- ([Ljava/lang/Object;)Ljava/lang/Object;\r\npublic native Object\r\nixkjwu(Object[] p0);\r\nTable 2: Native functions in the anti-analysis library.\r\nThe Java-declared native method that has the same signature as vxeg has in this sample (([Ljava/lang/Object;)I), is\r\nresponsible for doing all of the run-time environment checks described in the next section. In each sample, this\r\nfunction is named differently due to the automatic obfuscator run on the Java code, but it always has this\r\nsignature. For clarity, the rest of this paper will refer to the native subroutine that performs all of the run-time\r\nchecks as vxeg().\r\nThe Java-declared native method that has the same signature as quarqrd has in this sample ((I)Ljava/lang/String;)\r\nreturns a string from an array. The argument to the method is the index into the array and the address of the array\r\nis hard coded into the native subroutine. The strings in this array are decrypted by the decryption function\r\ndescribed above.\r\nVia static reverse engineering, I did not determine the native subroutine corresponding to the ixkjwu method. In\r\nthe Java code, the ixkjwu method is only called in one place and is only called based on the value of a variable. It\r\nis possible that this method is never called based on the value of that variable and thus the ixkjwu native\r\nsubroutine does not exist.\r\nvxeg and quarqrd are registered with the RegisterNatives JNI method at 0x2B60 in this sample. The array at\r\n0x9048 is used for this call to RegisterNatives. It includes the native method name, signature, and pointer to the\r\nnative subroutine as shown below. The code at 0x2B42, prior to the call to RegisterNatives, shows that this\r\nsubroutine can support the following array entries for three native methods instead of the two that exist in this\r\ninstance.\r\n0x9048: Pointer to vxeg string\r\n0x904C: Pointer to vxeg signature string\r\n0x9050: 0x30D5 (Pointer to subroutine)\r\n0x9054: Pointer to quarqrd string\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 13 of 19\n\n0x9058: Pointer to quarqrd signature string\r\n0x905C: 0x4815 (Pointer to subroutine)\r\nThe rest of this paper will focus on the functionality found in vxeg() because it contains the anti-analysis run-time\r\nenvironment checks.\r\nRun-time environment checks\r\nThe Java classes associated with WeddingCake in the APK define three native functions in the Java code. In this\r\nsample vxeg()performs all of the run-time environment checks prior to performing the hidden behaviour. This\r\nfunction performs more than 45 different run-time checks. They can be grouped as follows:\r\nChecking system properties\r\nVerifying CPU architecture by reading the /system/lib/libc.so ELF header\r\nLooking for Monkey [6] by iterating through all PIDs in /proc/\r\nEnsuring the Xposed Framework [7] is not mapped to the application process memory\r\nIf the library detects any of the conditions outlined in this section, the Linux exit(0) function is called, which\r\nterminates the Android application [8]. The application stops running if any of the 45+ environment checks fail.\r\nSystem properties checks\r\nThe vxeg() subroutine begins by checking the values of the listed system properties. The system_property_get()\r\nfunction is used to get the value of each system property checked. The code checks if the value matches the listed\r\nvalue for each property. If any one of the system properties matches the listed value, the Android application exits.\r\nTable 3 lists each of the system properties that is checked and the value which will trigger an exit.\r\nSystem property checked Value(s) that trigger exit\r\ninit.svc.gce_fs_monitor running\r\ninit.svc.dumpeventlog running\r\ninit.svc.dumpipclog running\r\ninit.svc.dumplogcat running\r\ninit.svc.dumplogcat-efs running\r\ninit.svc.filemon running\r\nro.hardware.virtual_device gce_x86\r\nro.kernel.androidboot.hardware gce_x86\r\nro.hardware.virtual_device gce_x86\r\nro.boot.hardware gce_x86\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 14 of 19\n\nro.boot.selinux disable\r\nro.factorytest true, 1, y\r\nro.kernel.android.checkjni true, 1, y\r\nro.hardware.virtual_device vbox86\r\nro.kernel.androidboot.hardware vbox86\r\nro.hardware vbox86\r\nro.boot.hardware vbox86\r\nro.build.product google_sdk\r\nro.build.product Droid4x\r\nro.build.product sdk_x86\r\nro.build.product sdk_google\r\nro.build.product vbox86p\r\nro.product.manufacturer Genymotion\r\nro.product.brand generic\r\nro.product.brand generic_x86\r\nro.product.device generic\r\nro.product.device generic_x86\r\nro.product.device generic_x86_x64\r\nro.product.device Droid4x\r\nro.product.device vbox86p\r\nro.kernel.androidboot.hardware goldfish\r\nro.hardware goldfish\r\nro.boot.hardware goldfish\r\nro.hardware.audio.primary goldfish\r\nro.kernel.androidboot.hardware ranchu\r\nro.hardware ranchu\r\nro.boot.hardware ranchu\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 15 of 19\n\nTable 3: System properties checked and the values that trigger exit.\r\nThe anti-analysis library also checks if any of five system properties exist on the device using the\r\nsystem_property_find() function. If any of these five system properties exist, the Android application exits. The\r\nproperties that the library searches for are listed in Table 4. The presence of any of these properties usually\r\nindicates that the application is running on an emulator.\r\nIf any of these system properties exist, the application exits\r\ninit.svc.vbox86-setup\r\nqemu.sf.fake_camera\r\ninit.svc.goldfish-logcat\r\ninit.svc.goldfish-setup\r\ninit.svc.qemud\r\nTable 4: System properties checked for using system_property_find.\r\nVerifying CPU architecture\r\nIf the library has passed all of the system property checks, it (still in vxeg()) then verifies the CPU architecture of\r\nthe phone on which the application is running. In order to verify the CPU architecture, the code reads 0x14 bytes\r\nfrom the beginning of the /system/lib/libc.so file on the device. If the read is successful, the code looks at the bytes\r\ncorresponding to the e_ident[EI_CLASS] and e_machine fields of the ELF header. e_ident[EI_CLASS] is set to 1\r\nto signal a 32-bit architecture and set to 2 to signal a 64-bit architecture. e_machine is a 2-byte value identifying\r\nthe instruction set architecture. The code will only continue if one of the following statements is true. Otherwise,\r\nthe application exits:\r\ne_ident[EI_CLASS] == 0x01 (32-bit) AND e_machine == 0x0028 (ARM)\r\ne_ident[EI_CLASS] == 0x02 (64-bit) AND e_machine == 0x00B7 (AArch64)\r\nUnable to read 0x14 bytes from /system/lib/libc.so\r\nThe anti-analysis library is verifying that it is only running on a 32-bit ARM or 64-bit AArch64 CPU. Even when\r\nthe library is running its x86 variant, it still checks whether the CPU is ARM and will exit if the detected CPU is\r\nnot ARM or AArch64.\r\nIdentifying if Monkey is running\r\nAfter the CPU architecture check, the library attempts to iterate through every PID directory under /proc/ to\r\ndetermine if com.android.commands.monkey is running [6]. The code does this by opening the /proc/ directory\r\nand iterating through each entry in the directory, completing the following steps. If any step fails, execution moves\r\nto the next entry in the directory.\r\n1. Verifies d_type from the dirent struct == DT_DIR\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 16 of 19\n\n2. Verifies that d_name from the dirent struct is an integer\r\n3. Constructs path strings: /proc/[pid]/comm and /proc/[pid]/cmdline where [pid] is the directory entry name\r\nthat has been verified to be an integer\r\n4. Attempts to read 0x7F bytes from both comm and cmdline constructed path strings\r\n5. Stores the data from whichever attempt (comm or cmdline) reads more data\r\n6. Checks if the read data equals com.android.commands.monkey, meaning that package is running.\r\nIf the check for Monkey is ever true, exit() is called, closing the Android application (see Figure 5).\r\nFigure 5: Check for Monkey.\r\nThis method of iterating through each directory in /proc/ doesn't work in Android N and above [9]. If the library is\r\nnot able to iterate through the directories in /proc/ it will continue executing.\r\nCurrent process not hooked with Xposed Framework\r\nThe Xposed Framework allows hooking and modifying of the system code running on an Android device. This\r\nlibrary ensures that the Xposed Framework is not currently mapped to the application process. If Xposed is\r\nrunning the process, it could allow for some of the anti-analysis techniques to be bypassed. If the library did not\r\ncheck for Xposed and allowed the application to continue running when Xposed was hooked to the process, an\r\nanalyst could instrument the application to bypass the anti-analysis hurdles and uncover the functionality that the\r\napplication author is trying to hide.\r\nIn order to determine if Xposed is running, the library, checks if 'LIBXPOSED_ART.SO' or\r\n'XPOSEDBRIDGE.JAR' exist in /proc/self/maps. If either of them exist, then the application exits.\r\n/proc/self/maps lists all of the memory pages mapped into the process memory. Therefore, you can see any\r\nlibraries loaded by the process by reading its contents.\r\nTo further verify that the Xposed Framework is not running, the code will check if either of the following two\r\nclasses can be found using the JNI FindClass() function [10]. If either class can be found, the application exits:\r\nXC_MethodHook: de/robv/android/xposed/XC_MethodHook\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 17 of 19\n\nXposedBridge: de/robv/android/xposed/XposedBridge\r\nIf the Xposed library is not found, the execution continues to the behaviour that the anti-analysis techniques were\r\ntrying to protect. This behaviour continues in vxeg(). In the case of this sample, it was another unpacker that\r\npreviously had not been protected by the anti-reversing and analysis techniques described in this paper.\r\nConclusion\r\nThis paper detailed the operation of WeddingCake, an Android native library using extensive anti-analysis\r\ntechniques. Unlike previous packers' anti-emulation techniques, this library is written in C/C++ and runs as a\r\nnative shared library in the application. Once an analyst understands the anti-reversing and anti-analysis\r\ntechniques utilized by an application, they can more effectively understand its logic and analyse and detect\r\npotentially malicious behaviours.\r\nReferences\r\n[1] Detecting and eliminating Chamois, a fraud botnet on Android. Android Developers Blog. https://android-developers.googleblog.com/2017/03/detecting-and-eliminating-chamois-fraud.html.\r\n[2] Getting Started with the NDK. Android. https://developer.android.com/ndk/guides/.\r\n[3] JNI Tips. Android. https://developer.android.com/training/articles/perf-jni.\r\n[4] Resolving Native Method Names. Oracle.\r\nhttps://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp615.\r\n[5] Registering Native Methods in JNI. Stack Overflow. https://stackoverflow.com/questions/1010645/what-does-the-registernatives-method-do.\r\n[6] UI/Application Exerciser Monkey. Android. https://developer.android.com/studio/test/monkey.\r\n[7] Xposed General. XDA Developers Forum. https://forum.xda-developers.com/xposed.\r\n[8] EXIT(3). Linux Programmer's Manual. http://man7.org/linux/man-pages/man3/exit.3.html.\r\n[9] Enable hidepid=2 on /proc. Android Open Source Project. https://android-review.googlesource.com/c/platform/system/core/+/181345.\r\n[10] JNI Functions. Oracle.\r\nhttps://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#FindClass.\r\nAppendix: IDAPython decryption script\r\nIn order to decrypt the encrypted portions of the ELF library that the decryption function (for this sample,\r\nsub_2F30) decrypts during execution, I created an IDAPython script to decrypt the ELF. This script is available at\r\nhttp://www.github.com/maddiestone/IDAPythonEmbeddedToolkit/Android/WeddingCake_decrypt.py. By\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 18 of 19\n\ndecrypting the ELF with the IDAPython script, it's possible to statically reverse engineer the behaviour that is\r\nhidden under the anti-analysis techniques. This section describes how the script works.\r\nThe IDAPython decryption script runs the following steps:\r\n1. Identifies the JNI_OnLoad function\r\n2. Identifies the decryption function\r\n3. Generates the two seed arrays\r\n4. Identifies memory addresses of arrays to be decrypted and their lengths from the ELF loaded into the IDA\r\nPro database\r\n5. Decrypts each array and writes the decrypted bytes back to the IDA database, defining the decrypted bytes\r\nas strings.\r\nThe script was written to dynamically identify each of the encrypted arrays and their lengths from an IDA Pro\r\ndatabase. This allows it to be run on many different samples without an analyst having to define the encrypted\r\nbyte arrays. Therefore, the IDAPython script is dependent on the library's architecture. This script will run on the\r\n32-bit 'generic' ARM versions of the library. For the other variants of the library mentioned in the 'Variants' section\r\n(ARMv7, ARM64, and x86), the same decryption algorithm in the script can be used, but the code to find the\r\nencrypted arrays and lengths will not run.\r\nOnce the script has finished running, the analyst can reverse engineer the native code as it lives when executing\r\nwith the decrypted string.\r\nSource: https://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native\r\n-library/\r\nhttps://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/\r\nPage 19 of 19\n\nVariants The most common version of the library is a 32-bit 'generic' ARM (armeabi) ELF, but I've also identified 32-bit\nARMv7 (armeabi-v7a), ARM64 (arm64-v8a), and x86 (x86) versions of the library. All of the variants include the\nsame functionality. If not otherwise specified, this paper focuses on the 32-bit 'generic' ARM implementation of\nWeddingCake because this is the most common variant.    \n   Page 2 of 19",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.virusbulletin.com/virusbulletin/2019/01/vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library/"
	],
	"report_names": [
		"vb2018-paper-unpacking-packed-unpacker-reversing-android-anti-analysis-native-library"
	],
	"threat_actors": [],
	"ts_created_at": 1775439109,
	"ts_updated_at": 1775791225,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/ec98c2264976d5f79544fae08df7e1159e711fc7.pdf",
		"text": "https://archive.orkl.eu/ec98c2264976d5f79544fae08df7e1159e711fc7.txt",
		"img": "https://archive.orkl.eu/ec98c2264976d5f79544fae08df7e1159e711fc7.jpg"
	}
}