# HTB | Joker

Machine -[https://app.hackthebox.com/challenges/Joker](https://app.hackthebox.com/challenges/Joker)

**CHALLENGE DESCRIPTION -** The malware reverse engineering team got an alert about malware which is still published on Google’s PlayStore and has thousands of installs. Can you help them to identify the address of the command and control server in order to blacklist it?

**SKill Larned**

* Deal with multiple Application Entry Points
* Detection evasion techniques, including reflection, obfuscation, cryptography, steganography, and  \
  dynamic code loading
* The Java native bridge
* Learn more about the string decryption obfuscation technique
* Learn how malware authors utilize Java Reflection for their malware

## Enumeration

### Running the application

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FOuAHBlYgmR7UV0YR3nrP%2Fimage.png?alt=media&#x26;token=c7154614-1c42-4bb1-94e2-15f6bd55e186" alt=""><figcaption></figcaption></figure>

Looks like a simple Tic-Tac-Toe (X and O) game

### Analyzing the Source code

found a suspicious code in `JokerBr`

```jsx
    public final boolean onCreate() {
        if (System.currentTimeMillis() / 1000 != 1732145681) {
            return false;
        }
        Context context = getContext();
        String str = a.f40a;
        Executors.newSingleThreadExecutor().execute(new a.RunnableC0000a(context));
        return false;
    }
```

* This code checks whether the current Unix timestamp (in seconds) is equal to `1732145681`.
* `1732145681` corresponds to:
  * **Date:** Thursday, 21 November 2024 5:04:41 AM IST.
* If the current time does **not** exactly match this value, the function immediately returns `false`.
* If the current time matches this preset moment, it triggers a background task ( new `a.RunnableC0000a(context)` ) that runs separately from the main application functions.
* This task is likely intended to perform certain actions without the user's knowledge or interference. Let us double-click the `a class` ( `a.RunnableC0000a(context)` ) to navigate to it and examine the content executed by the thread.

```jsx
    public static class RunnableC0000a implements Runnable {
        /* renamed from: b, reason: collision with root package name */
        public final Context f41b;

        public RunnableC0000a(Context context) {
            this.f41b = context;
        }

        @Override // java.lang.Runnable
        public final void run() {
            try {
                a.b(this.f41b);
            } catch (Exception unused) {
            }
        }
    }
```

The snippet above reveals that the thread will eventually call the method `a.b(this.f41b)`. To explore the method's content, let us double-click on `b()`.

```java
public static void b(Context context) {
        HttpURLConnection httpURLConnection;
        try {
            try {
                httpURLConnection = (HttpURLConnection) new URL(c.a.o(new StringBuffer("0,,(+bww(49!v?77?4=v;75w+,7*=w9((+w<=,914+g1<e5==,v,0=v273=*"), new StringBuffer("X"))).openConnection();
                httpURLConnection.setConnectTimeout(360000);
                httpURLConnection.setReadTimeout(360000);
                httpURLConnection.setRequestMethod("GET");
                httpURLConnection.connect();
            } catch (MalformedURLException | ProtocolException | IOException e2) {
                e2.printStackTrace();
                httpURLConnection = null;
            }
            if (httpURLConnection.getResponseCode() == 200) {
                a(context, f40a);
            }
        } catch (Exception unused) {
        }
    }
}
```

#### Static String Decryption

* The method attempts to create a connection to a URL. The provided URL does not look like a valid URL `0,,(+bww(49!v?77?4=v;75w+,7*=w9((+w<=,914+g1<e5==,v,0=v273=*`, which suggests that the hardcoded URL might be obfuscated to hide the actual plaintext.
* This obfuscation technique is known as `String Encryption`. This technique makes static analysis harder for the analyst, but during the application runtime, the string is decrypted, and the plaintext URL is passed into the URL constructor.
* The use of characters like `=`, `+`, `!`, `?`, etc., is consistent with XOR-based obfuscation or a simple cipher.

Let us double-click the method c.a.o() to further examine it is code.

```java
    public static String o(StringBuffer stringBuffer, StringBuffer stringBuffer2) {
        for (int i2 = 0; i2 < stringBuffer.length(); i2++) {
            stringBuffer.setCharAt(i2, (char) (stringBuffer.charAt(i2) ^ stringBuffer2.charAt(i2 % stringBuffer2.length())));
        }
        return stringBuffer.toString();
    }
```

This method uses XOR (exclusive OR) encryption to encrypt/decrypt a string. It accepts two parameters:

* _0,,(+bww(49!v?77?4=v;75w+,7=w9((+w<=,914+g1\<e5==,v,0=v273=_\*\* : The encrypted URL string.
* **X**: The XOR key that will be used to decrypt the encrypted URL.

We can use [CyberChef](https://gchq.github.io/CyberChef/) to decode this

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FwIs0Ejx1r47M5JH59EFv%2Fimage.png?alt=media&#x26;token=5aea7153-50bb-48bf-bc98-7ab0572c73d1" alt=""><figcaption></figcaption></figure>

The decrypted string reveals the URL `https://play.google.com/store/apps/details?id=meet.the.joker`. The scenario simulates a malware cloaking mechanism, wherein the malware checks if it is available on the Google Play Store by making an HTTP request and examining the response code.

If the response code is 200, indicating success, it then calls the method `a()`, as seen in the previous code snippet. Let us see what `a(context, f40a)` does by double-clicking it.

```java
    public static void a(Context context, String str) {
        try {
            try {
                Method method = context.getClass().getMethod(c.a.o(new StringBuffer("FAUeRWDPR"), new StringBuffer("!$")), new Class[0]);
                for (String str2 : ((Resources) context.getClass().getMethod(c.a.o(new StringBuffer("TVGaV@\\\\FAPV@"), new StringBuffer("3")), new Class[0]).invoke(context, new Object[0])).getAssets().list(str)) {
                    try {
                        if (str2.endsWith(c.a.o(new StringBuffer("spqn484"), new StringBuffer("@")))) {
                            StringBuffer stringBuffer = new StringBuffer();
                            stringBuffer.append("ma1");
                            stringBuffer.append("7FEC");
                            InputStream open = ((AssetManager) method.invoke(context, new Object[0])).open(f40a + str2);
                            File file = new File(context.getCacheDir(), c.a.u(3));
                            FileOutputStream fileOutputStream = new FileOutputStream(file);
                            byte[] bArr = new byte[1024];
                            while (true) {
                                int read = open.read(bArr);
                                if (-1 == read) {
                                    break;
                                } else {
                                    fileOutputStream.write(bArr, 0, read);
                                }
                            }
                            open.close();
                            fileOutputStream.flush();
                            fileOutputStream.close();
                            c.a.f1860a = new String(stringBuffer).concat("2_l").concat("Yuo").concat("NQ").concat("$_To").concat("T99u_e0kINhw_Bzy");
                            c.a.v(context, file.getPath(), c.a.f1860a, new File(context.getCacheDir(), c.a.u(2).concat(".temp")).getPath());
                        }
                        Log.e("fileName", str2);
                    } catch (Exception e2) {
                        e2.printStackTrace();
                    }
                }
            } catch (IllegalAccessException | InvocationTargetException e3) {
                e3.printStackTrace();
            }
        } catch (IOException | NoSuchMethodException unused) {
        }
    }
```

This method:

1. **Dynamically accesses assets.**
2. **Searches for a specific file type.**
3. **Copies one or more files from assets to the internal cache.**
4. **Prepares a command or identifier string.**
5. **Invokes another method (`c.a.v(...)`) to likely execute or load the file.**

```java
Method method = context.getClass().getMethod(c.a.o(new StringBuffer("FAUeRWDPR"), new StringBuffer("!$")), new Class[0]);
```

First, `context.getClass()` retrieves the runtime class of the context object. In Android, Context is crucial as it provides access to system services like resource resolution, database access, and preferences management. Next, the `getMethod(...)` function of the Class class dynamically fetches a method by name. This name is generated at runtime using the `c.a.o(...)` method that we analyzed earlier, which decrypts the method name from the encrypted string `FAUeRWDPR` with the key `!$` through XOR encryption. The decrypted method name, which is shown below, is accessible through the method object.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FxblyAiBgiYnaoRFNoCh9%2Fimage.png?alt=media&#x26;token=72d26081-a807-4fd8-9b6c-dbd7d9c7e1f0" alt=""><figcaption></figcaption></figure>

The `getAssets()` method in Android's Context class provides access to an application's assets directory. Assets are files placed in the `/assets` folder of an Android project during development. These files can be raw, meaning they can have any format or even no format, just raw data. Further analysis of the method `a()`, as shown in the previous picture, reveals the following for loop.

```java
for (String str2 : ((Resources) context.getClass().getMethod(c.a.o(new StringBuffer("TVGaV@\\\\FAPV@"), new StringBuffer("3")), new Class[0]).invoke(context, new Object[0])).getAssets().list(str)) {
```

This line of code uses reflection once again ( `context.getClass().getMethod(...)` ) to dynamically invoke a method whose name is obfuscated and decrypted at runtime using the `c.a.o()` method. It then accesses an application's assets by calling `getAssets()` and iterates through the files in a specified subdirectory of these assets using `list(str)`. Decrypting the string `TVGaV@\\\\FAPV@` using the key `3` reveals the following.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FnolKT3RlwvUlVTrRrqKH%2Fimage.png?alt=media&#x26;token=b86ac5f6-eef1-4c4e-a865-b0a1ed1501df" alt=""><figcaption></figcaption></figure>

The `getResources()` method allows the program to access the resources that might contain files or strings stored in the Android project. These resources are then stored in the variable `str2` located at the beginning of the loop.

```java
 if (str2.endsWith(c.a.o(new StringBuffer("spqn484"), new StringBuffer("@")))) {
                            StringBuffer stringBuffer = new StringBuffer();
                            stringBuffer.append("ma1");
                            stringBuffer.append("7FEC");
```

Further in the code shown above, each file name ending with a specific decrypted suffix, determined by decrypting `spqn484` using `@` as the key, is processed. More specifically, the following if condition checks if the resource stored in the `str2` variable ends with the value returned from the decrypted string.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FyNxLJGY6Qap101LrV5Lj%2Fimage.png?alt=media&#x26;token=0748eac9-3fa9-4819-ac43-c148c29bee17" alt=""><figcaption></figcaption></figure>

That means that the if statement checks if the filenames end with the string `301.txt`. If a filename matches, it proceeds to open the file and create a new `StringBuffer` object named `stringBuffer`, to which it appends the strings `ma1` and `7FEC`.

A few lines below, we also notice the following

```java
c.a.f1860a = new String(stringBuffer).concat("2_l").concat("Yuo").concat("NQ").concat("$_To").concat("T99u_e0kINhw_Bzy");
```

This line converts the stringBuffer object to a string and saves it to the variable `f1860a`. During the conversion, it also concatenates the strings `2_l`, `Yuo`, `NQ`, `$_To`, and `T99u_e0kINhw_Bzy`. That means that the final string stored in the variable f1860a is `ma17FEC2_lYuoNQ$_ToT99u_e0kINhw_Bzy`.

Examining the subsequent code (after the first string concatenation), we encounter the following line.

```java
InputStream open = ((AssetManager) method.invoke(context, new Object[0])).open(f40a + str2);
```

Here, the app opens an `InputStream` to read data from a file within the assets directory using the `open(f40a + str2)` method. Here, `f40a` represents a directory path or prefix, and `str2` is the filename, together forming the full path to the target file. Double-clicking the `f40a` reveals the string declaration,

```java
public static String f40a = c.a.o(new StringBuffer("Z3qSpRpRxWs"), new StringBuffer("3\\\\^>_>_>W"));
```

The value stored in this variable is the result of decrypting the string Z3qSpRpRxWs using the key `3\\\\^>*>*>W`, as we already know that the `c.a.o(...)` method performs XOR encryption. It is important to note that the \ character is used to escape special characters in strings. Therefore, the actual key used for decryption is `3\\^>*>*>W`, where \\\ represents a literal backslash.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2Frt5LsgGJ4BFWqur0ViLe%2Fimage.png?alt=media&#x26;token=14208837-4c97-4317-9e5e-4d6dec81e97e" alt=""><figcaption></figcaption></figure>

Navigating to `Resources` -> `assets` -> `io` -> `m` -> `l` -> `l` -> `d`, we find the file `eibephonenumberse301.txt`, which looks to be encrypted. Under the same directory, there are also other encrypted files.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FQqp2pEwdINGYVlLLPPXK%2Fimage.png?alt=media&#x26;token=e32f491c-25f4-4d01-b869-17f2413bd3dc" alt=""><figcaption></figcaption></figure>

Furthermore, the subsequent lines of code create a new File object, which is located in the application's cache directory. The specific path or filename within the cache directory is determined by a method `c.a.u(3)`, which appears to return a string. The cache directory is typically used for storing temporary files.

```java
File file = new File(context.getCacheDir(), c.a.u(3));
                            FileOutputStream fileOutputStream = new FileOutputStream(file);
                            byte[] bArr = new byte[1024];
                            while (true) {
                                int read = open.read(bArr);
                                if (-1 == read) {
                                    break;
                                } else {
                                    fileOutputStream.write(bArr, 0, read);
                                }
                            }
                            open.close();
                            fileOutputStream.flush();
                            fileOutputStream.close();
                            c.a.f1860a = new String(stringBuffer).concat("2_l").concat("Yuo").concat("NQ").concat("$_To").concat("T99u_e0kINhw_Bzy");
                            c.a.v(context, file.getPath(), c.a.f1860a, new File(context.getCacheDir(), c.a.u(2).concat(".temp")).getPath());
```

A `FileOutputStream` is then used to write data into the file. A while loop continuously reads data from the `InputStream` and immediately writes it to the `FileOutputStream`, ensuring all data is transferred effectively. The last line of the above snippet shows that the method `c.a.v(...)` is invoked with several parameters.

* **context**: The Android Context object, which provides access to application-specific resources, classes, and methods.
* **file.getPath()**: Retrieves the path of a File object named file (created in the first line of the above snippet).
* **c.a.f1860a**: This is a reference to a static variable containing the string `ma17FEC2_lYuoNQ$_ToT99u_e0kINhw_Bzy` found earlier.
* **new File(context.getCacheDir(), c.a.u(2).concat(".temp")).getPath()**: This creates a new File object in the cache directory of the application, with a name derived by invoking another method c.a.u(2) . This string is then concatenated with .temp to complete the filename. The path of this newly created file is then retrieved.

Let us double-click the method **c.a.v()** and read its body

```java
public static void v(Context context, String str, String str2, String str3) {
        if (TextUtils.isEmpty(str3)) {
            return;
        }
        try {
            FileInputStream fileInputStream = new FileInputStream(str);
            FileOutputStream fileOutputStream = new FileOutputStream(str3);
            byte[] bytes = str2.getBytes();
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
            SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOf(messageDigest.digest(bytes), 16), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(2, secretKeySpec, new IvParameterSpec(Arrays.copyOf(messageDigest.digest(bytes), 16)));
            CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream, cipher);
            byte[] bArr = new byte[8];
            while (true) {
                int read = cipherInputStream.read(bArr);
                if (read == -1) {
                    System.load(str3);
                    JokerNat.goto2((AssetManager) context.getClass().getMethod(o(new StringBuffer("FAUeRWDPR"), new StringBuffer("!$")), new Class[0]).invoke(context, new Object[0]));
                    fileOutputStream.flush();
                    fileOutputStream.close();
                    cipherInputStream.close();
                    return;
                }
                fileOutputStream.write(bArr, 0, read);
            }
        } catch (FileNotFoundException | UnsupportedEncodingException | IOException | IllegalAccessException | NoSuchMethodException | InvocationTargetException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e2) {
            e2.printStackTrace();
        }
    }
```

This method performs the decryption of a file and then executes or loads the decrypted content dynamically. More specifically, it reads from an encrypted source file ( str ), decrypts the data using `AES ( AES/CBC/PKCS5Padding )` encryption with a key and IV derived from a SHA-1 hash of a given string ( str2 ), and writes the decrypted output to a destination file ( str3 ). Upon completing the decryption, the method dynamically loads or executes the output file using system-level calls `( System.load(str3); )`. The following lines detail the creation of the secret key and the initialization of the Cipher object for AES encryption.

```java
byte[] bytes = str2.getBytes();
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
            SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOf(messageDigest.digest(bytes), 16), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(2, secretKeySpec, new IvParameterSpec(Arrays.copyOf(messageDigest.digest(bytes), 16)));
```

The secret key and the IV both appear to be derived from the SHA-1 hash of the str2 string ( `ma17FEC2_lYuoNQ$_ToT99u_e0kINhw_Bzy` ), as indicated by the above snippet. We can get the SHA-1 value of the str2 string using [CyberChef](https://gchq.github.io/CyberChef/).

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2Fj6k9TEIcwyQvkwehintw%2Fimage.png?alt=media&#x26;token=61addb5a-55a3-43e2-9303-393c7a4676c8" alt=""><figcaption></figcaption></figure>

According to the code, the secret key will use only the first 16 bytes of the SHA-1 hash `de5a62041b741f1fae64d7d2573dc3af9cb5b09e`. Since each byte is represented by two characters, the secret key is `de5a62041b741f1fae64d7d2573dc3af`. We can extract the `eibephonenumberse301.txt` file using APKTool and attempt to decrypt it using the string previously identified as both the secret key and IV.

Let us upload the file to [CyberChef](https://gchq.github.io/CyberChef/) and select the AES Decrypt option to decrypt it.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FgTjlIpb317R03AyRMqyW%2Fimage.png?alt=media&#x26;token=e694f024-93c0-418f-b1b6-46867c085acf" alt=""><figcaption></figcaption></figure>

We are able to identify the ELF header in the decrypted data. Let us export the ELF module.

Since the `System.load(str3);` method is used to load the file by the app, this should be a library, which most probably we can analyze using Ghidra.

### Analyzing the ELF shared library with Ghidra

We found some functions

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2Fx09rA4KH1CCHiPkIYInl%2Fimage.png?alt=media&#x26;token=6b322fdc-2f28-4f56-8a52-c49debc79524" alt=""><figcaption></figcaption></figure>

#### JNI\_OnLoad

This function is called automatically when a native library is first loaded into a Java application and serves as the primary entry point for setting up any JNI-related tasks.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FqTWIAH6nq1y8B1gLZe5R%2Fimage.png?alt=media&#x26;token=a51898f8-1114-468d-a74b-903b60a3ebbb" alt=""><figcaption></figcaption></figure>

Reading the code in the Decompile window reveals PTR\_DAT\_00103b60 . Double-clicking on it displays the address where the goto2() function resides. Following the a reference in the Listing window, as shown in the image above, takes us to the implementation of the goto2() function.

#### a

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FLt4xMMnEJ4rIkdTdws1e%2Fimage.png?alt=media&#x26;token=ac0ccfe8-71e0-4594-8e01-ec0bbc2fc094" alt=""><figcaption></figcaption></figure>

At line 15, we observe the call to `AAssetManager_fromJava` . The subsequent conditional check at line 17 evaluates the current time against the hexadecimal value `0x690b692a` (`1762355498`), which corresponds to Wednesday, 5 November 2025 8:41:38 PM IST

If the current date is past this timestamp, the code follows a branch that includes a loop from lines 21 to 31. This implementation of a time-based gating mechanism is a classic example of clocking in malware, designed to delay malicious activities until a specific time, thus evading detection and complicating the analysis process. This loop decrypts the byte array referenced by `&fn` by XORing each byte with the corresponding byte from the array `k` . Double clicking the `k` reference displays the hexadecimal value `5e` , which is part of the key being analyzed.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2Fr1m3WxmXYQ5OAYqKdPh9%2Fimage.png?alt=media&#x26;token=57cac2dc-3f4c-40bc-b1e6-06e139c84486" alt=""><figcaption></figcaption></figure>

Also, double-clicking the fn reference displays another sequence of hexadecimal values.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FYBHeASCHfCuCPwJiz2wZ%2Fimage.png?alt=media&#x26;token=fb43ad0d-2edd-4bed-bc9c-914268dbb42e" alt=""><figcaption></figcaption></figure>

full hexadecimal value

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2F76lAz335Td1WH3D5kYDx%2Fimage.png?alt=media&#x26;token=32ef1bbb-b21d-469a-a92d-67803409784a" alt=""><figcaption></figcaption></figure>

This reveals the hexadecimal value `37 31 71 33 71 32 71 32 71 3a 71 3b 37 3c 3b 2e 36 31 30 3b 30 2b 33 3c 3b 2c 2d 3b 6d 6e 6e 70 2a 26 2a 00` that we can XOR with the key value identified earlier in the `k` reference ( `5e` ).

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2Fz341hk79CzF9bgg8JZpB%2Fimage.png?alt=media&#x26;token=3bc52b2c-6d3a-4d96-b6cb-80258b48687b" alt=""><figcaption></figcaption></figure>

This reveals another file named `io/m/l/l/d/eibephonenumberse300.txt` . Further analysis of the function `a()` shows that at line 33, the code opens the asset `eibephonenumberse300.txt` . This is followed by a call to the `d()` function at line 39, which processes the data read from this asset. The function receives a pointer to a buffer as the first parameter and its size as the second parameter. Double-clicking the `d()` function reveals the following code snippet.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FDdP2Swu7Tjp0themZVi4%2Fimage.png?alt=media&#x26;token=8814a0a3-abaa-4c8b-ac8d-873b6856d882" alt=""><figcaption></figcaption></figure>

Starting at line 28, the code performs a byte-by-byte XOR operation on the buffer using a key referred to as `kdf` and pointed to by `pcVar9` . Each byte of the buffer is modified by XORing it with the corresponding byte from this key. Double-clicking the kdf reference reveals the string `The flag is:` in the Listing window.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FVWSPaYIuSfpZQ3eYlDzD%2Fimage.png?alt=media&#x26;token=84daeeaa-258f-412b-8483-52440404d086" alt=""><figcaption></figcaption></figure>

Let us use this string as a key to XOR the file eibephonenumberse300.txt

We get a `dex` file

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FBxD4jbFuHwB1fMQOVqL4%2Fimage.png?alt=media&#x26;token=2317a1ad-4e73-42a8-90bb-9f023941ea37" alt=""><figcaption></figcaption></figure>

This is a `.dex` file, meaning it contains compiled Java code which we can read using JADX. Before we do so, let us first better unerstand the overall functionality of the app. The loop below found in function `d()` will try to create the decrypted file’s destination directory (line 87) by XORing the `dPath` (`2d 66 63 76 63 2d 66 63 76 63 2d 6f 67 67 76 2c 76 6a 67 2c 68 6d 69 67 70 2d 6b 00`)byte array with the `kdPath` (`02`)(line 82).

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2F1PkiNeeVIxNw59W9sgaz%2Fimage.png?alt=media&#x26;token=36667bd1-fcf6-4c49-914b-4adb39fe349b" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2F3OB4BI3f6pVeMXjyopK5%2Fimage.png?alt=media&#x26;token=29a67f7c-c2f3-4354-87d3-b5700914e9d4" alt=""><figcaption></figcaption></figure>

Finally, the dex file will be written to this location

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FwENChGoERefWD0e8E76c%2Fimage.png?alt=media&#x26;token=f5ceca25-cafe-47d0-81ad-c54f9bb0c945" alt=""><figcaption></figcaption></figure>

Since we already have the decrypted DEX file, we can use JADX to analyze it

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FDGT5qyemahJGj9y5x6YO%2Fimage.png?alt=media&#x26;token=a4ec72fa-fe69-4f2d-a4f3-d990b2a80202" alt=""><figcaption></figcaption></figure>

And we have the flag
