Skip to content

Commit

Permalink
process scanning
Browse files Browse the repository at this point in the history
  • Loading branch information
wont-stream committed Sep 25, 2024
1 parent f3cd00e commit 4aaab69
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 9 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@
| bunRPC-darwin-x64 | macOS | x64 |||
| bunRPC-darwin-arm64 | macOS | arm64 || N/A |

On x64 platforms, bunRPC uses SIMD optimizations which require a modern CPU supporting AVX2 instructions. The `baseline` build of bunRPC is for older CPUs that don't support these optimizations. You usually don't need to worry about it on Darwin x64, but it is relevant for Windows x64 and Linux x64. If you or your users see `"Illegal instruction"` errors, you might need to use the baseline version.
On x64 platforms, bunRPC uses SIMD optimizations which require a modern CPU supporting AVX2 instructions. The `baseline` build of bunRPC is for older CPUs that don't support these optimizations. You usually don't need to worry about it on Darwin x64, but it is relevant for Windows x64 and Linux x64. If you or your users see `"Illegal instruction"` errors, you might need to use the baseline version.

# Help wanted
Someone please ensure src/process/native/darwin/index.js works, I don't have macos installed on my mac mini, and hackintosh is not worth setting up for this.
103 changes: 103 additions & 0 deletions src/process/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import * as Natives from './native/index.js';
const Native = Natives[process.platform];

const timestamps = {};
const names = {};
const pids = {};

export default class {
constructor(handlers) {
if (!Native) return;

this.handlers = handlers;

this.scan = this.scan.bind(this);

this.getDB();

this.scan();
setInterval(this.scan, 10000); // every 10 seconds instead of 5
}

async getDB() {
if (this.DetectableDB) return this.DetectableDB;

const data = await fetch("https://discord.com/api/v9/applications/detectable")

this.DetectableDB = await data.json();

return this.DetectableDB;
}

async scan() {
const processes = await Native.getProcesses();
const ids = [];

const DetectableDB = await this.getDB();

for (const [pid, _path, args] of processes) {
const path = _path.toLowerCase().replaceAll('\\', '/');
const toCompare = [];
const splitPath = path.split('/');
for (let i = 1; i < splitPath.length; i++) {
toCompare.push(splitPath.slice(-i).join('/'));
}

for (const p of toCompare.slice()) {
toCompare.push(p.replace('64', ''));
toCompare.push(p.replace('.x64', ''));
toCompare.push(p.replace('x64', ''));
toCompare.push(p.replace('_64', ''));
}

for (const { executables, id, name } of DetectableDB) {
if (executables?.some(x => {
if (x.is_launcher) return false;
if (x.name[0] === '>' ? x.name.substring(1) !== toCompare[0] : !toCompare.some(y => x.name === y)) return false;
if (args && x.arguments) return args.join(" ").indexOf(x.arguments) > -1;
return true;
})) {
names[id] = name;
pids[id] = pid;

ids.push(id);
if (!timestamps[id]) {
timestamps[id] = Date.now();
}

this.handlers.message({
socketId: id
}, {
cmd: 'SET_ACTIVITY',
args: {
activity: {
application_id: id,
name,
timestamps: {
start: timestamps[id]
}
},
pid
}
});
}
}
}

for (const id in timestamps) {
if (!ids.includes(id)) {
delete timestamps[id];

this.handlers.message({
socketId: id
}, {
cmd: 'SET_ACTIVITY',
args: {
activity: null,
pid: pids[id]
}
});
}
}
}
}
21 changes: 21 additions & 0 deletions src/process/native/darwin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { exec } from 'node:child_process';

export const getProcesses = () => {
return new Promise((resolve, reject) => {
exec("ps -axo pid,comm", (error, stdout) => {
if (error) {
return reject(error); // Handle errors
}

const processes = stdout
.toString()
.split('\n') // Split by new lines
.slice(1) // Skip the header line
.map(line => line.trim().split(/\s+/, 2)) // Split into PID and command
.filter(parts => parts.length === 2) // Ensure both PID and command exist
.map(([pid, command]) => [Number(pid), command]);

resolve(processes);
});
});
};
3 changes: 3 additions & 0 deletions src/process/native/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * as darwin from './darwin/index.js';
export * as linux from './linux/index.js';
export * as win32 from './win32/index.js';
21 changes: 21 additions & 0 deletions src/process/native/linux/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { readdir } from "node:fs/promises";
import { file } from "bun"

export const getProcesses = async () => {
const directories = await readdir("/proc");

const processPromises = directories
.filter(pid => +pid > 0) // Filter valid PIDs upfront
.map(async (pid) => {
try {
const cmdline = await file(`/proc/${pid}/cmdline`).text();
const [command, ...args] = cmdline.split("\0"); // Destructure for clarity
return [+pid, command, args];
} catch {
return null; // Return null on failure
}
});

const processes = await Promise.all(processPromises);
return processes.filter(Boolean); // Filter out null entries
};
18 changes: 18 additions & 0 deletions src/process/native/win32/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { exec } from 'node:child_process';

export const getProcesses = () => {
return new Promise((resolve) => {
exec("wmic process get ProcessID,ExecutablePath /format:csv", (error, output) => {

const processes = output
.toString()
.split('\r\n') // Split by new lines
.slice(2) // Remove headers
.map(line => line.trim().split(',').reverse()) // Split, reverse, and trim
.filter(parsed => parsed[1]) // Filter out invalid paths
.map(([executablePath, processId]) => [Number(processId) || processId, executablePath]); // Parse IDs

resolve(processes);
});
});
};
4 changes: 4 additions & 0 deletions src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { EventEmitter } from "node:events";
import ipc from "./transports/ipc.js";
import ws from "./transports/ws.js";

import process from "./process/index.js"

let socketId = 0;

export default class extends EventEmitter {
Expand All @@ -19,6 +21,8 @@ export default class extends EventEmitter {
// Ensure you have the latest bun version installed if you encounter issues.
new ipc(handlers);
new ws(handlers);

new process(handlers);
}

onConnection(socket) {
Expand Down
15 changes: 7 additions & 8 deletions src/transports/ipc.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { join } from "node:path";
import { platform, env } from "node:process";
import { unlinkSync } from "node:fs";

import { createServer, createConnection } from "node:net";

const SOCKET_PATH =
platform === "win32"
process.platform === "win32"
? "\\\\?\\pipe\\discord-ipc"
: join(
env.XDG_RUNTIME_DIR || env.TMPDIR || env.TMP || env.TEMP || "/tmp",
"discord-ipc",
);
process.env.XDG_RUNTIME_DIR || process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp",
"discord-ipc",
);

const Types = {
HANDSHAKE: 0,
Expand Down Expand Up @@ -116,7 +115,7 @@ const socketIsAvailable = async (socket) => {
try {
socket.end();
socket.destroy();
} catch {}
} catch { }
};

const possibleOutcomes = Promise.race([
Expand Down Expand Up @@ -145,10 +144,10 @@ const getAvailableSocket = async (tries = 0) => {
const socket = createConnection(path);

if (await socketIsAvailable(socket)) {
if (platform !== "win32")
if (process.process.process.process.process.process.process.process.process.process.process.platform !== "win32")
try {
unlinkSync(path);
} catch {}
} catch { }

return path;
}
Expand Down

0 comments on commit 4aaab69

Please sign in to comment.