Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F10360204
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/android/conf/start_culebra.sh b/android/conf/start_culebra.sh
index 98931e2..ec941ad 100644
--- a/android/conf/start_culebra.sh
+++ b/android/conf/start_culebra.sh
@@ -1,18 +1,18 @@
set -x
function culebra_loop() {
export PATH=$PATH:/root/culebraDependencies
cd /root/culebra
while true; do
./culebratester2 start-server
done
}
rm -f /opt/android-sdk-linux/.android/avd/virtual_dev.avd/*.lock
adb start-server
-emulator -avd virtual_dev -writable-system -no-window -no-audio &
+emulator -avd virtual_dev -writable-system -no-window -no-audio -memory 4096 &
adb wait-for-device
adb emu avd snapshot load configured
culebra_loop
diff --git a/http_server/code/index.mjs b/http_server/code/index.mjs
index a60e24e..222f219 100644
--- a/http_server/code/index.mjs
+++ b/http_server/code/index.mjs
@@ -1,111 +1,110 @@
import express from "express";
import { readFile } from "node:fs/promises";
import { execSync } from "node:child_process";
import { Server } from "socket.io";
import { io } from "socket.io-client";
import { build_html } from "./har-analyzer/build_html.js"
import fileUpload from "express-fileupload";
const app = express();
async function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
console.log("Waiting for full boot...");
// bidirectional forwarding
// Wait untill the connection
const back = io("ws://android:3000", {
reconnectionAttempts: 1000000,
reconnectionDelay: 100,
});
while (!back.connected) {
await sleep(100);
}
console.log("Boot detected! activating endpoints");
app.use(express.urlencoded({ extended: false }));
app.use(express.static("/code/dist"));
//GET
app.get("/favicon.ico", function (_req, res) {
res.sendFile("/code/favicon.ico");
});
app.get("/htmx.js", function (_req, res) {
res.sendFile("/code/node_modules/htmx.org/dist/htmx.min.js");
});
app.get("/socket.io.js", function (_req, res) {
res.sendFile("/code/node_modules/socket.io/client-dist/socket.io.js");
});
app.get("/", async function (req, res) {
let fileData = (await readFile("/code/index.html")).toString();
fileData = fileData.replace(
"___screenshotDelayMs___",
process.env.screenshotDelayMs
);
res.setHeader("Content-Type", "text/html");
res.setHeader("Content-Disposition", "inline");
res.send(fileData);
});
//POST
app.use(express.text({limit: "100mb"}));
app.post("/inspect_har", function (req, res) {
let body = JSON.parse(req.body);
let har = JSON.stringify(body.har);
- console.log(har);
let private_data;
if (body.private_data)
- private_data = JSON.stringify(body.private_data);
+ private_data = body.private_data;
res.setHeader("Content-Type", "text/html");
res.send(build_html(har, private_data, "/code/har-analyzer/"));
});
app.use(fileUpload());
app.post("/upload_apk", async function (req, res) {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send("No files were uploaded.");
}
execSync("rm -rf /shared_buffer/*");
if (Array.isArray(req.files.app)) {
for (const [idx, file] of req.files.app.entries()) {
let uploadPath = "/shared_buffer/app" + idx + ".apk";
await file.mv(uploadPath);
}
} else {
let uploadPath = "/shared_buffer/app" + 0 + ".apk";
await req.files.app.mv(uploadPath);
}
back.emit("install");
res.send("Files uploaded!");
});
let server = app.listen(8080, () => console.log("Listening in port 8080"));
const front = new Server(server);
// forwarding the messages
front.on("connection", (socket) => {
socket.onAny((event, ...args) => {
if (back.connected) {
back.emit(event, ...args);
} else {
console.log("Front tried to send: ", event, ...args);
}
});
});
back.onAny((event, ...args) => {
front.emit(event, ...args);
});
diff --git a/http_server/code/src/notifications.jsx b/http_server/code/src/notifications.jsx
index 5105dc3..edfe1b8 100644
--- a/http_server/code/src/notifications.jsx
+++ b/http_server/code/src/notifications.jsx
@@ -1,68 +1,67 @@
import { render, Component } from "preact";
import { io } from "socket.io-client";
function rand_num() {
return Math.floor(Math.random() * Number.MAX_VALUE);
}
class Notifications extends Component {
constructor() {
super();
this.state = { notifications: [] };
}
remove_notification(id) {
const newNotifications = this.state.notifications.filter(
(notification) => notification.id !== id
);
this.setState({ notifications: newNotifications });
}
componentDidMount() {
// This should also be dynamic
io().on("notification", (data) => {
let new_id = rand_num();
this.setState({
notifications: [
{ id: new_id, notification: data },
...this.state.notifications,
],
});
// a 10 sec timeout
setTimeout(() => {
this.remove_notification(new_id);
}, 10000);
});
}
render() {
- console.log("Render", this.state.notifications);
return this.state.notifications.map(({ id, notification }) => (
<div
onClick={() => this.remove_notification(id)}
style={`
background-color: ${notification.is_ok ? "#66ff99" : "#ff5c33"};
border-radius: 5px;
border-width: 2px;
border-style: solid;
border-color: ${notification.is_ok ? "#369648" : "#a23915"};
padding: 5px;
margin-top: 2px;
margin-bottom: 2px;
`}
>
<div>
<b>{notification.context}</b>
</div>
<div>
{notification.message.split("\n").map((line) => (
<p>{line}</p>
))}
</div>
</div>
));
}
}
render(<Notifications />, document.getElementById("notifications"));
diff --git a/http_server/code/src/trafficLog.tsx b/http_server/code/src/trafficLog.tsx
index c90b3ba..461648e 100644
--- a/http_server/code/src/trafficLog.tsx
+++ b/http_server/code/src/trafficLog.tsx
@@ -1,237 +1,253 @@
import { Entry, Har, PostData, Request, Response } from "har-format";
import { render, Component } from "preact";
type MyState = {
finished_entries: Entry[];
unfinished_entries: Map<string, Entry>;
};
class TrafficLog extends Component {
connection: WebSocket | undefined;
state: MyState = { finished_entries: [], unfinished_entries: new Map() };
constructor() {
super();
}
componentDidMount() {
// This should also be dynamic
this.connection = new WebSocket("ws://localhost:10001");
this.connection.onmessage = (msg) => {
this.process_msg(msg.data);
this.setState({
finished_entries: this.state.finished_entries,
unfinished_entries: this.state.unfinished_entries,
});
};
this.connection.onclose = this.connection.onerror = () => {
window.location.reload();
};
}
render() {
const download_har = () => {
var tempLink = document.createElement("a");
var taBlob = new Blob([JSON.stringify(this.export_har())], {
type: "text/plain",
});
tempLink.setAttribute("href", URL.createObjectURL(taBlob));
tempLink.setAttribute("download", `rentgendroid-capture.har`);
tempLink.click();
URL.revokeObjectURL(tempLink.href);
};
const inspect_har = async () => {
const req_body = {
har: this.export_har(),
- private_data: undefined,
+ private_data: [
+ [
+ "adid",
+ document.getElementById("adid_priv_info_table")!
+ .textContent,
+ ],
+ [
+ "latitude",
+ document.getElementById("lat_priv_info_table")!
+ .textContent,
+ ],
+ [
+ "longitude",
+ document.getElementById("lon_priv_info_table")!
+ .textContent,
+ ],
+ ],
};
+
const resp = await fetch("/inspect_har", {
- method: "POST",
- body: JSON.stringify(req_body),
- })
+ method: "POST",
+ body: JSON.stringify(req_body),
+ });
const resp_text = await resp.text();
const newWindow = window.open();
newWindow?.document.write(resp_text);
newWindow?.document.close();
-
- }
+ };
const contentWithLineBreaks = this.state.finished_entries.map((req) => {
return (
<span>
{req.request.url}
<br />
</span>
);
});
return (
<div>
<button onClick={download_har}>Download HAR</button>
<button onClick={inspect_har}>Inspect HAR</button>
<div>
<h2>stats: </h2>
<p>
Request + responce pairs:{" "}
{this.state.finished_entries.length}
</p>
<p>
Waiting for the responce:{" "}
{this.state.unfinished_entries.size}
</p>
</div>
<div>{contentWithLineBreaks}</div>
</div>
);
}
process_msg(s: string) {
let obj = JSON.parse(s);
console.log(obj);
if (obj.type !== "data") return;
if (obj.payload && obj.payload.data && obj.payload.data.requestReceived)
this.process_req(obj.payload.data.requestReceived);
if (
obj.payload &&
obj.payload.data &&
obj.payload.data.responseCompleted
)
this.process_res(obj.payload.data.responseCompleted);
}
process_res(res: any) {
let entry = this.state.unfinished_entries.get(res.id)!;
let content_type = "application/text";
let headers = JSON.parse(res.rawHeaders).map(
(header: [string, string]) => {
if (header[0].toLowerCase() === "content-type")
content_type = header[1];
return { name: header[0], value: header[1], comment: "" };
}
);
//'{"startTime":1751745139334,
// "startTimestamp":347666.762487,
// "bodyReceivedTimestamp":347667.529477,
// "headersSentTimestamp":347906.038202,
// "responseSentTimestamp":347906.616067}'
let timing_events = JSON.parse(res.timingEvents);
let start_ts = timing_events.startTimestamp;
let got_headers_ts = timing_events.headersSentTimestamp;
let end_ts = timing_events.responseSentTimestamp;
let wait_time = got_headers_ts - start_ts;
let recieve_time = end_ts - got_headers_ts;
let response: Response = {
status: res.statusCode,
statusText: res.statusMessage,
httpVersion: entry.request.httpVersion,
cookies: [],
headers,
content: {
size: 0,
mimeType: content_type,
text: res.body,
encoding: "base64",
},
redirectURL: "",
headersSize: -1,
bodySize: -1,
};
entry.response = response;
entry.timings.wait = wait_time;
entry.timings.receive = recieve_time;
this.state.unfinished_entries.delete(res.id);
this.state.finished_entries.push(entry);
}
process_req(req: any) {
let content_type = "application/text";
let headers = JSON.parse(req.rawHeaders).map(
(header: [string, string]) => {
if (header[0].toLowerCase() === "Content-Type")
content_type = header[1];
return { name: header[0], value: header[1], comment: "" };
}
);
let timing_events = JSON.parse(req.timingEvents);
let start_time: number = timing_events.startTime!;
let start_datetime = new Date(start_time).toISOString();
let request: Request = {
method: req.method,
url: req.url,
httpVersion: req.httpVersion,
cookies: [],
headers,
queryString: [],
postData: req.body
? ({ text: req.body, mimeType: content_type } as PostData)
: undefined,
headersSize: -1,
bodySize: -1,
comment: "",
};
//'{"startTime":1751745139334,"startTimestamp":347666.762487,"bodyReceivedTimestamp":347667.529477,"headersSentTimestamp":347906.038202,"responseSentTimestamp":347906.616067}'
let entry: Entry = {
startedDateTime: start_datetime,
time: 0,
request: request,
response: {
status: 0,
statusText: "",
httpVersion: "",
cookies: [],
headers: [],
content: {
size: 0,
mimeType: "",
},
redirectURL: "",
headersSize: 0,
bodySize: 0,
},
cache: {},
timings: {
wait: 0,
receive: 0,
},
};
this.state.unfinished_entries.set(req.id, entry);
}
export_har(): Har {
let ret: Har = {
log: {
version: "1.2",
creator: {
name: "Rentgendroid",
version: "0.0.1",
},
entries: [
...this.state.finished_entries,
...this.state.unfinished_entries.values(),
],
},
};
return ret;
}
}
render(<TrafficLog />, document.getElementById("traffic-log")!);
diff --git a/pre_android/preconf/docker-entrypoint.sh b/pre_android/preconf/docker-entrypoint.sh
index 8b20b68..e288388 100644
--- a/pre_android/preconf/docker-entrypoint.sh
+++ b/pre_android/preconf/docker-entrypoint.sh
@@ -1,23 +1,25 @@
adb start-server
-emulator -avd virtual_dev -writable-system -no-window -no-audio &
+
+emulator -avd virtual_dev -writable-system -no-window -no-audio -memory 4096 &
+
bash /preconf/install_adidreader.sh
bash /preconf/install_culebra.sh
# Open google maps once, skip all the screens, and give it gps permissions
adb shell am start-activity com.google.android.apps.maps
sleep 8
adb shell input tap 268 49
sleep 4
adb shell input tap 290 323
sleep 6
adb shell input tap 147 413
sleep 10
adb shell am stop-app com.google.android.apps.maps
adb emu avd snapshot save configured
adb emu kill
#to let the host know it finished installing
install -m 777 /dev/null /preconf/finished
tail -f /dev/null
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 8, 05:30 (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034053
Default Alt Text
(12 KB)
Attached To
Mode
R134 rentgen-android
Attached
Detach File
Event Timeline
Log In to Comment