From 2a836ea6cb1e5ec5f0d6786443be35538a26d744 Mon Sep 17 00:00:00 2001 From: Andrii Dokhniak Date: Thu, 14 Aug 2025 18:04:12 +0200 Subject: [PATCH] Manuall frida --- android/code/index.mjs | 137 +++++++++++++++++------ android/conf/docker-entrypoint.sh | 8 +- android/conf/get_installed_apps.sh | 2 + android/conf/get_ports.sh | 2 +- android/conf/start_frida_app.sh | 15 +++ http_server/code/a.out | Bin 0 -> 15472 bytes http_server/code/index.html | 8 ++ http_server/code/src/main.ts | 51 ++++++++- http_server/code/src/shared.ts | 4 + http_server/code/test.c | 6 + pre_android/Dockerfile | 3 +- pre_android/preconf/docker-entrypoint.sh | 2 + pre_android/preconf/install_frida.sh | 13 +++ 13 files changed, 212 insertions(+), 39 deletions(-) create mode 100644 android/conf/get_installed_apps.sh create mode 100644 android/conf/start_frida_app.sh create mode 100755 http_server/code/a.out create mode 100644 http_server/code/test.c create mode 100644 pre_android/preconf/install_frida.sh diff --git a/android/code/index.mjs b/android/code/index.mjs index d20898c..86f8717 100644 --- a/android/code/index.mjs +++ b/android/code/index.mjs @@ -21,24 +21,45 @@ async function spawnPromise(program, args) { let io = new Server(); async function send_private_data() { - let adid = await spawnPromise("bash", ["/conf/get_adid.sh"]) + let adid = await spawnPromise("bash", ["/conf/get_adid.sh"]); adid = adid.output; - let gps_coords = await spawnPromise("bash", ["/conf/get_location.sh"]) + let gps_coords = await spawnPromise("bash", ["/conf/get_location.sh"]); gps_coords = gps_coords.output; - gps_coords = gps_coords.trim().split(','); - io.emit("private_info", {adid, latitude: gps_coords[0], longitude: gps_coords[1]}) + gps_coords = gps_coords.trim().split(","); + io.emit("private_info", { + adid, + latitude: gps_coords[0], + longitude: gps_coords[1], + }); } async function send_open_ports() { - let ports = new Set((await spawnPromise("bash", ["/conf/get_ports.sh"])).output.trim().split(' ')); + let ports = new Set( + (await spawnPromise("bash", ["/conf/get_ports.sh"])).output + .trim() + .split(" ") + ); - let start_ports = fs.readFileSync("/ports").toString().trim().split(' '); + let start_ports = fs.readFileSync("/ports").toString().trim().split(" "); for (let port of start_ports) { ports.delete(port); } io.emit("open_ports", [...ports]); } +async function send_installed_apps() { + let out = await spawnPromise("bash", ["/conf/get_installed_apps.sh"]); + if (out.code != 0) { + send_notification( + io, + false, + "Listing installed apps with frida", + out.output + ); + } + io.emit("installed_apps", JSON.parse(out.output)); +} + function send_notification(socket, is_ok, context, message) { socket.emit("notification", { is_ok, @@ -55,14 +76,18 @@ io.on("connection", (socket) => { console.log("server got: ", ev, ...args); }); socket.on("screenshot", async () => { - if (screenshot_in_flight) - return; + if (screenshot_in_flight) return; screenshot_in_flight = true; let screen; try { - screen = await fetch("http://localhost:9987/v2/uiDevice/screenshot"); - } catch(err) { - console.error("Failed to get the screenshot from culebra, the emulator probably died", err); + screen = await fetch( + "http://localhost:9987/v2/uiDevice/screenshot" + ); + } catch (err) { + console.error( + "Failed to get the screenshot from culebra, the emulator probably died", + err + ); screenshot_in_flight = false; return; } @@ -73,37 +98,66 @@ io.on("connection", (socket) => { socket.on("private_info_req", async () => { await send_private_data(); - }) + }); socket.on("open_ports_req", async () => { await send_open_ports(); - }) + }); + + socket.on("installed_apps_req", async () => { + await send_installed_apps(); + }); + + socket.on("start_frida_app", async (app_id) => { + await spawnPromise("bash", ["/conf/start_frida_app.sh", app_id]); + send_notification( + socket, + true, + "Frida intercepting stopped", + "the traffic of " + app_id + " is no longer being intercepted" + ); + }); socket.on("reset_adid", async () => { await spawnPromise("bash", ["/conf/reset_adid.sh"]); await send_private_data(); - }) + }); socket.on("back", async () => { if (gps_setting_in_progress) { - send_notification(socket, false, "Interactions not allowed when setting gps coordinates", ""); - return ; + send_notification( + socket, + false, + "Interactions not allowed when setting gps coordinates", + "" + ); + return; } await spawnPromise("bash", ["/conf/back.sh"]); }); socket.on("recent", async () => { if (gps_setting_in_progress) { - send_notification(socket, false, "Interactions not allowed when setting gps coordinates", ""); - return ; + send_notification( + socket, + false, + "Interactions not allowed when setting gps coordinates", + "" + ); + return; } await spawnPromise("bash", ["/conf/recent.sh"]); }); socket.on("home", async () => { if (gps_setting_in_progress) { - send_notification(socket, false, "Interactions not allowed when setting gps coordinates", ""); - return ; + send_notification( + socket, + false, + "Interactions not allowed when setting gps coordinates", + "" + ); + return; } await spawnPromise("bash", ["/conf/home.sh"]); }); @@ -121,22 +175,32 @@ io.on("connection", (socket) => { // drag handles both drag and click socket.on("motionevent", async (data) => { if (gps_setting_in_progress) { - send_notification(socket, false, "Interactions not allowed when setting gps coordinates", ""); - return ; + send_notification( + socket, + false, + "Interactions not allowed when setting gps coordinates", + "" + ); + return; } await spawnPromise("bash", [ "/conf/motionevent.sh", data.motionType, data.x + "", - data.y + "" + data.y + "", ]); }); // drag handles both drag and click socket.on("drag", async (data) => { if (gps_setting_in_progress) { - send_notification(socket, false, "Interactions not allowed when setting gps coordinates", ""); - return ; + send_notification( + socket, + false, + "Interactions not allowed when setting gps coordinates", + "" + ); + return; } await spawnPromise("bash", [ "/conf/drag.sh", @@ -150,19 +214,26 @@ io.on("connection", (socket) => { socket.on("key", async (data) => { if (gps_setting_in_progress) { - send_notification(socket, false, "Interactions not allowed when setting gps coordinates", ""); - return ; + send_notification( + socket, + false, + "Interactions not allowed when setting gps coordinates", + "" + ); + return; } - await spawnPromise("bash", [ - "/conf/press_key.sh", - data.key - ]); + await spawnPromise("bash", ["/conf/press_key.sh", data.key]); }); socket.on("setcoord", async (data) => { if (gps_setting_in_progress) { - send_notification(socket, false, "Interactions not allowed when setting gps coordinates", ""); - return ; + send_notification( + socket, + false, + "Interactions not allowed when setting gps coordinates", + "" + ); + return; } gps_setting_in_progress = true; const res = await spawnPromise("bash", [ diff --git a/android/conf/docker-entrypoint.sh b/android/conf/docker-entrypoint.sh index 12996b6..3446143 100644 --- a/android/conf/docker-entrypoint.sh +++ b/android/conf/docker-entrypoint.sh @@ -1,6 +1,10 @@ bash /conf/start_culebra.sh & npm i -C /code bash /conf/wait_for_sd.sh -node /code/index.mjs -#tail -f /dev/null +adb shell su root /tmp/frida-server & + +cd /frida-scripts && perl -i -0777p -e 's|CERT_PEM = .*?;|CERT_PEM = `'"$(cat /certificates/ca.pem | sed -z 's/\n/\\n/g')"'`;|gsm' config.js +adb reverse tcp:8000 tcp:8000 + +node /code/index.mjs diff --git a/android/conf/get_installed_apps.sh b/android/conf/get_installed_apps.sh new file mode 100644 index 0000000..1fdc397 --- /dev/null +++ b/android/conf/get_installed_apps.sh @@ -0,0 +1,2 @@ +set -e +frida-ps -Uai --json diff --git a/android/conf/get_ports.sh b/android/conf/get_ports.sh index 72c8030..94762ba 100644 --- a/android/conf/get_ports.sh +++ b/android/conf/get_ports.sh @@ -1,4 +1,4 @@ -out=$(adb shell su root "ss -tunlp | tail -n+2 | awk -F \" \" '{print \$5}' | awk -F ':' '{print \$NF}' | sort -n | uniq") +out=$(adb shell su root "ss -tunlp | tail -n+2 | grep -v users:\(\(\\\"frida-server | awk -F \" \" '{print \$5}' | awk -F ':' '{print \$NF}' | sort -n | uniq") if [ ! -f /ports ]; then echo -n $out > /ports diff --git a/android/conf/start_frida_app.sh b/android/conf/start_frida_app.sh new file mode 100644 index 0000000..dfa4b89 --- /dev/null +++ b/android/conf/start_frida_app.sh @@ -0,0 +1,15 @@ +set -e + +cd /frida-scripts + +frida -U \ + -l ./config.js \ + -l ./native-connect-hook.js \ + -l ./native-tls-hook.js \ + -l ./android/android-proxy-override.js \ + -l ./android/android-system-certificate-injection.js \ + -l ./android/android-certificate-unpinning.js \ + -l ./android/android-certificate-unpinning-fallback.js \ + -l ./android/android-disable-root-detection.js \ + -l ./android/android-disable-flutter-certificate-pinning.js \ + -f $1 diff --git a/http_server/code/a.out b/http_server/code/a.out new file mode 100755 index 0000000000000000000000000000000000000000..81714b2eca850c7651f8a92a948399f24a1709cb GIT binary patch literal 15472 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 literal 0 HcmV?d00001 diff --git a/http_server/code/index.html b/http_server/code/index.html index 4e96a1f..3ac14b2 100644 --- a/http_server/code/index.html +++ b/http_server/code/index.html @@ -129,6 +129,14 @@ + +

Lanuch app

+
+ + +
+

Open ports

diff --git a/http_server/code/src/main.ts b/http_server/code/src/main.ts index 5747ff0..c20b4c5 100644 --- a/http_server/code/src/main.ts +++ b/http_server/code/src/main.ts @@ -12,8 +12,10 @@ import { adid_priv_info_table, lat_priv_info_table, lon_priv_info_table, - recentButton, - open_ports, + recentButton, + open_ports, + app_id_select, + launch_app_form, } from "./shared"; import { start_notifications } from "./notifications"; @@ -122,6 +124,50 @@ socket.on("open_ports", (data: string[]) => { open_ports.textContent = data.toString(); }); +async function installed_apps_loop() { + var before; + + while (true) { + before = performance.now(); + socket.emit("installed_apps_req"); + while (performance.now() - before < 2000) await sleep(100); + } +} + +socket.on("installed_apps", (data) => { + let all_ids = new Set(); + let all_inserted_ids = new Set(); + + for (let app of data) { + all_ids.add(app.identifier); + } + + // remove all the elements that are no longer in the set + for (const el of app_id_select.children) { + const opt = el as HTMLOptionElement; + if (!all_ids.has(opt.value)) opt.remove(); + else all_inserted_ids.add(opt.value); + } + + for (let app of data) { + if (all_inserted_ids.has(app.identifier)) + continue; + let app_opt = document.createElement("option"); + app_opt.value = app.identifier; + app_opt.innerText = app.name; + app_id_select.appendChild(app_opt); + } +}); + + +(launch_app_form as HTMLFormElement).addEventListener("submit", (event) => { + event.preventDefault(); + event.stopImmediatePropagation(); + + const form_data = new FormData(event.target as HTMLFormElement); + socket.emit("start_frida_app", form_data.get("appid")); +}) + socket.emit("private_info_req"); socket.onAny((ev, ...args) => { @@ -244,6 +290,7 @@ async function open_ports_loop() { } } +installed_apps_loop(); open_ports_loop(); screenshot_loop(); start_notifications(); diff --git a/http_server/code/src/shared.ts b/http_server/code/src/shared.ts index c103cc2..2e98685 100644 --- a/http_server/code/src/shared.ts +++ b/http_server/code/src/shared.ts @@ -13,4 +13,8 @@ export const lat_priv_info_table = document.getElementById("lat_priv_info_table" export const lon_priv_info_table = document.getElementById("lon_priv_info_table")!; export const open_ports = document.getElementById("open-ports")!; + +export const app_id_select = document.getElementById("app_id_select")!; +export const launch_app_form = document.getElementById("launch_app_form")!; + export const socket = io(); diff --git a/http_server/code/test.c b/http_server/code/test.c new file mode 100644 index 0000000..5fdf8e4 --- /dev/null +++ b/http_server/code/test.c @@ -0,0 +1,6 @@ +#include +#include + +int main () { + printf("%p", realloc(0, 10)); +} diff --git a/pre_android/Dockerfile b/pre_android/Dockerfile index ccc4972..b3c5238 100644 --- a/pre_android/Dockerfile +++ b/pre_android/Dockerfile @@ -4,6 +4,7 @@ ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/andro RUN sdkmanager --channel=2 "system-images;android-35;google_apis;x86_64" \ && echo no | avdmanager create avd -n virtual_dev -b google_apis/x86_64 -k "system-images;android-35;google_apis;x86_64" \ - && apt-get update && apt-get install -y iproute2 iputils-ping npm git libxml2-utils telnet bc + && apt-get update && apt-get install -y iproute2 iputils-ping npm git libxml2-utils telnet bc aapt python3 python3-pip \ + && pip install frida-tools && git clone https://github.com/httptoolkit/frida-interception-and-unpinning /frida-scripts CMD bash /preconf/docker-entrypoint.sh diff --git a/pre_android/preconf/docker-entrypoint.sh b/pre_android/preconf/docker-entrypoint.sh index e288388..cb0d222 100644 --- a/pre_android/preconf/docker-entrypoint.sh +++ b/pre_android/preconf/docker-entrypoint.sh @@ -2,6 +2,8 @@ adb start-server emulator -avd virtual_dev -writable-system -no-window -no-audio -memory 4096 & +adb wait-for-device +bash /preconf/install_frida.sh bash /preconf/install_adidreader.sh bash /preconf/install_culebra.sh diff --git a/pre_android/preconf/install_frida.sh b/pre_android/preconf/install_frida.sh new file mode 100644 index 0000000..50fd283 --- /dev/null +++ b/pre_android/preconf/install_frida.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -xe + +cd /tmp + +wget https://github.com/frida/frida/releases/download/17.2.15/frida-server-17.2.15-android-x86_64.xz + +xz -d frida-server-17.2.15-android-x86_64.xz +adb push frida-server-17.2.15-android-x86_64 /tmp/frida-server + +adb shell su root 'chmod +x /tmp/frida-server' + +cd /frida-scripts && perl -i -0777p -e 's|CERT_PEM = .*?;|CERT_PEM = `'"$(cat /certificates/ca.pem | sed -z 's/\n/\\n/g')"'`;|gsm' config.js