469 lines
12 KiB
HTML
469 lines
12 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head style="height: 100vh">
|
|
<meta charset="UTF-8" />
|
|
<title>Rentgen android</title>
|
|
<script src="/htmx.js"></script>
|
|
<style>
|
|
main {
|
|
display: flex;
|
|
}
|
|
|
|
.log-section {
|
|
height: auto;
|
|
width: 400px;
|
|
overflow: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-left: 20px;
|
|
}
|
|
|
|
.screen {
|
|
display: inline-block;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.screen-buttons {
|
|
display: flex;
|
|
justify-content: space-around;
|
|
margin-top: 5px;
|
|
gap: 10px;
|
|
}
|
|
|
|
.screen-buttons button {
|
|
font-size: 1.1rem;
|
|
padding: 10px 20px;
|
|
width: 100%;
|
|
cursor: pointer;
|
|
background-color: transparent;
|
|
}
|
|
|
|
.screen-buttons button:hover {
|
|
background-color: aqua;
|
|
}
|
|
|
|
#clicks-log {
|
|
font-family:
|
|
Menlo,
|
|
Consolas,
|
|
Monaco,
|
|
Liberation Mono,
|
|
Lucida Console,
|
|
monospace;
|
|
}
|
|
|
|
.tab {
|
|
border: 1px solid #ccc;
|
|
background-color: #f1f1f1;
|
|
}
|
|
|
|
/* Style the buttons that are used to open the tab content */
|
|
.tab button {
|
|
background-color: inherit;
|
|
float: left;
|
|
border: none;
|
|
outline: none;
|
|
cursor: pointer;
|
|
padding: 14px 16px;
|
|
transition: 0.3s;
|
|
}
|
|
|
|
/* Change background color of buttons on hover */
|
|
.tab button:hover {
|
|
background-color: #ddd;
|
|
}
|
|
|
|
/* Create an active/current tablink class */
|
|
.tab button.active {
|
|
background-color: #ccc;
|
|
}
|
|
.tabcontent.active {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-grow: 1;
|
|
}
|
|
|
|
/* Style the tab content */
|
|
.tabcontent {
|
|
display: none;
|
|
padding: 6px 12px;
|
|
border: 1px solid #ccc;
|
|
border-top: none;
|
|
}
|
|
html,
|
|
body,
|
|
main {
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
margin: 0;
|
|
}
|
|
main {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: stretch;
|
|
}
|
|
#logs-tab {
|
|
overflow: auto;
|
|
text-wrap: wrap;
|
|
}
|
|
.screen-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.screen-section #screen,
|
|
.screen-section.screen_buttons {
|
|
flex-grow: 0;
|
|
}
|
|
#screen {
|
|
user-select: none;
|
|
}
|
|
.tab-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-grow: 1;
|
|
}
|
|
#resp {
|
|
display: none;
|
|
}
|
|
#upload_form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
#upload_form button,
|
|
#upload_form label {
|
|
border: 2px solid #ccc;
|
|
background-color: #f1f1f1;
|
|
cursor: pointer;
|
|
padding: 3px 10px;
|
|
transition: 0.3s;
|
|
}
|
|
#upload_form button:hover,
|
|
#upload_form label:hover {
|
|
background-color: #ddd;
|
|
}
|
|
#notifications {
|
|
width: 40%;
|
|
margin-left: 60%;
|
|
position: absolute;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="notifications"></div>
|
|
<div id="resp" style="display: none"></div>
|
|
<main>
|
|
<section class="screen-section">
|
|
<img
|
|
id="screen"
|
|
alt="android screen"
|
|
src=""
|
|
draggable="false"
|
|
class="screen"
|
|
style="flex-grow: 0"
|
|
tabindex="0"
|
|
/>
|
|
<div class="screen-buttons" style="flex-grow: 0">
|
|
<button class="screen-buttons-home">home</button>
|
|
<button class="screen-buttons-back">back</button>
|
|
</div>
|
|
<form
|
|
id="upload_form"
|
|
hx-post="/upload_apk"
|
|
enctype="multipart/form-data"
|
|
hx-target="#resp"
|
|
>
|
|
<label id="upload_input" for="app"
|
|
>Select file
|
|
<input
|
|
type="file"
|
|
id="app"
|
|
name="app"
|
|
accept=".apk"
|
|
required
|
|
multiple
|
|
/>
|
|
</label>
|
|
<button type="submit">Install the app</button>
|
|
</form>
|
|
</section>
|
|
|
|
<div class="tab-section">
|
|
<div class="tab">
|
|
<button
|
|
class="tablinks active"
|
|
onclick="open_tab(event, 'httptoolkit-tab')"
|
|
>
|
|
HttpToolkit UI
|
|
</button>
|
|
<button class="tablinks" onclick="open_tab(event, 'logs-tab')">
|
|
Logs
|
|
</button>
|
|
<button class="tablinks" onclick="open_tab(event, 'controls-tab')">
|
|
Device Controls
|
|
</button>
|
|
</div>
|
|
|
|
<div class="tabcontent" id="logs-tab">
|
|
<p id="clicks-log" class="log-section"></p>
|
|
<p id="traffic-log" class="log-section"></p>
|
|
</div>
|
|
|
|
<div class="tabcontent active" id="httptoolkit-tab">
|
|
<iframe
|
|
id="httptoolkit-frame"
|
|
style="flex-grow: 1"
|
|
src="http://localhost:9080/"
|
|
title="httptoolkit"
|
|
></iframe>
|
|
</div>
|
|
<div class="tabcontent" id="controls-tab">
|
|
<form id="set_coords" onsubmit="coords_handler(event)">
|
|
<label>
|
|
Latitude:
|
|
<input type="text" name="lat" />
|
|
</label>
|
|
<label>
|
|
Longitude:
|
|
<input type="text" name="lon" />
|
|
</label>
|
|
<button type="submit">Submit coords</button>
|
|
</form>
|
|
<button id="reset_adid_btn" onclick="reset_adid_handler(event)">Reset ADID</button>
|
|
<table>
|
|
<thead></thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>ADID:</td>
|
|
<td id="adid_priv_info_table">UNKNOWN</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Longitude:</td>
|
|
<td id="lon_priv_info_table">UNKNOWN</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Latitude:</td>
|
|
<td id="lat_priv_info_table">UNKNOWN</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
<script src="/socket.io.js"></script>
|
|
<script>
|
|
var socket = io();
|
|
|
|
function reset_adid_handler(e) {
|
|
socket.emit("reset_adid");
|
|
}
|
|
|
|
function coords_handler(e) {
|
|
e.preventDefault();
|
|
const form_data = new FormData(e.target);
|
|
console.log(form_data);
|
|
socket.emit("setcoord", {
|
|
lon: Number.parseFloat(form_data.get("lon")),
|
|
lat: Number.parseFloat(form_data.get("lat")),
|
|
});
|
|
}
|
|
|
|
function open_tab(evt, tab_name) {
|
|
let i, tabcontent, tablinks;
|
|
|
|
// Get all elements with class="tabcontent" and hide them
|
|
tabcontent = document.getElementsByClassName("tabcontent");
|
|
for (i = 0; i < tabcontent.length; i++) {
|
|
if (tabcontent[i].id != tab_name) {
|
|
tabcontent[i].classList.remove("active");
|
|
} else {
|
|
tabcontent[i].classList.add("active");
|
|
}
|
|
}
|
|
|
|
// Get all elements with class="tablinks" and remove the class "active"
|
|
tablinks = document.getElementsByClassName("tablinks");
|
|
for (i = 0; i < tablinks.length; i++) {
|
|
tablinks[i].classList.remove("active");
|
|
}
|
|
|
|
// Show the current tab, and add an "active" class to the button that opened the tab
|
|
evt.currentTarget.classList.add("active");
|
|
}
|
|
var screen = document.getElementById("screen");
|
|
var clicksLog = document.getElementById("clicks-log");
|
|
const homeButton = document.querySelector(".screen-buttons-home");
|
|
const backButton = document.querySelector(".screen-buttons-back");
|
|
|
|
let lastTouch = new Date().getTime();
|
|
|
|
const calculateElapsedTime = (last) => {
|
|
const currentTouch = new Date().getTime();
|
|
const elapsedTime = currentTouch - lastTouch;
|
|
const elapsedSec = Math.round(elapsedTime / 1000);
|
|
lastTouch = currentTouch;
|
|
return elapsedSec;
|
|
};
|
|
|
|
const waitToLog = (clickInfoText) => {
|
|
const clickInfo = document.createElement("span");
|
|
const waitInfo = document.createElement("span");
|
|
waitInfo.textContent = `await wait(${calculateElapsedTime(
|
|
lastTouch
|
|
)});`;
|
|
clicksLog.appendChild(waitInfo);
|
|
clickInfo.textContent = clickInfoText;
|
|
clicksLog.appendChild(clickInfo);
|
|
};
|
|
|
|
const registerClick = ({ path, logText, body }) => {
|
|
const clicksLog = document.getElementById("clicks-log");
|
|
const span = document.createElement("span");
|
|
|
|
waitToLog(logText);
|
|
socket.emit(path, body ? body : {});
|
|
};
|
|
|
|
homeButton.addEventListener("click", () =>
|
|
registerClick({ path: "home", logText: "await homeButton();" })
|
|
);
|
|
|
|
backButton.addEventListener("click", () =>
|
|
registerClick({ path: "back", logText: "await backButton();" })
|
|
);
|
|
|
|
socket.on("screenshot_data", (data) => {
|
|
try {
|
|
const blob = new Blob([data]);
|
|
screen.src = URL.createObjectURL(blob);
|
|
} catch (error) {
|
|
console.error("Error fetching image: ", error);
|
|
}
|
|
});
|
|
|
|
socket.on("private_info", (data) => {
|
|
console.log("private_info");
|
|
adid_priv_info_table.textContent = data.adid;
|
|
lat_priv_info_table.textContent = data.latitude;
|
|
lon_priv_info_table.textContent = data.longitude;
|
|
});
|
|
|
|
socket.emit("private_info_req");
|
|
|
|
socket.onAny((ev, ...args) => {
|
|
console.log("ev: ", ev, args);
|
|
});
|
|
|
|
async function displayImage() {
|
|
socket.emit("screenshot");
|
|
}
|
|
|
|
let isDragging = false;
|
|
const screenSize = [320, 640];
|
|
|
|
function calcMousePos(event) {
|
|
let rect = screen.getBoundingClientRect();
|
|
let x = ((event.clientX - rect.left) / rect.width) * screenSize[0];
|
|
let y = ((event.clientY - rect.top) / rect.height) * screenSize[1];
|
|
x = Math.min(Math.max(x, 0), screenSize[0]);
|
|
y = Math.min(Math.max(y, 0), screenSize[1]);
|
|
return { x, y };
|
|
}
|
|
|
|
screen.addEventListener(
|
|
"mousemove",
|
|
(event) => {
|
|
if (!isDragging) return;
|
|
let pos = calcMousePos(window.event);
|
|
|
|
if (isDragging) {
|
|
registerClick({
|
|
path: "motionevent",
|
|
logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
|
|
body: {
|
|
motionType: "MOVE",
|
|
x: pos.x,
|
|
y: pos.y,
|
|
},
|
|
});
|
|
}
|
|
},
|
|
false
|
|
);
|
|
|
|
const handleDraggStart = (event) => {
|
|
isDragging = true;
|
|
let pos = calcMousePos(event);
|
|
registerClick({
|
|
path: "motionevent",
|
|
logText: `await motionevent({motionType: "DOWN", x:${pos.x},y:${pos.y}}});`,
|
|
body: {
|
|
motionType: "DOWN",
|
|
x: pos.x,
|
|
y: pos.y,
|
|
},
|
|
});
|
|
};
|
|
|
|
screen.addEventListener("mousedown", handleDraggStart);
|
|
|
|
document.addEventListener("mouseup", (e) => {
|
|
if (!isDragging) return;
|
|
isDragging = false;
|
|
let pos = calcMousePos(e);
|
|
registerClick({
|
|
path: "motionevent",
|
|
logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
|
|
body: {
|
|
motionType: "MOVE",
|
|
x: pos.x,
|
|
y: pos.y,
|
|
},
|
|
});
|
|
registerClick({
|
|
path: "motionevent",
|
|
logText: `await motionevent({motionType: "UP", x:${pos.x},y:${pos.y}}});`,
|
|
body: {
|
|
motionType: "UP",
|
|
x: pos.x,
|
|
y: pos.y,
|
|
},
|
|
});
|
|
});
|
|
|
|
window.addEventListener("keydown", (event) => {
|
|
let key = event.key;
|
|
if (key === "Space") key = " ";
|
|
else if (key !== "Enter" && key !== "Backspace" && key.length !== 1)
|
|
return;
|
|
console.log(event.key, key);
|
|
if (document.getElementById("screen").matches(":hover")) {
|
|
registerClick({
|
|
path: "key",
|
|
logText: `await key(${event.key});`,
|
|
body: { key },
|
|
});
|
|
}
|
|
});
|
|
|
|
async function sleep(time) {
|
|
return new Promise((resolve) => setTimeout(resolve, time));
|
|
}
|
|
|
|
async function screenshot_loop() {
|
|
var before;
|
|
|
|
while (true) {
|
|
before = performance.now();
|
|
await displayImage();
|
|
while (performance.now() - before < ___screenshotDelayMs___)
|
|
await sleep(50);
|
|
}
|
|
}
|
|
screenshot_loop();
|
|
</script>
|
|
<script src="/trafficLog.js"></script>
|
|
<script src="/notifications.js"></script>
|
|
</body>
|
|
</html>
|