Files
2026-04-15 22:24:44 -07:00

97 lines
3.1 KiB
JavaScript

// capture_session_key.js - Capture keystream by XORing ciphertext with plaintext
// Write keystream blocks to file so the proxy can use them.
// Also capture the plaintext for analysis.
(function() {
'use strict';
var BASE = Process.getModuleByName('Paralogue-Win64-Shipping.exe').base;
var GAME_WRAPPER = BASE.add(0x49A2EB0);
var callCount = 0;
// Track keystream per direction (we need to figure out which calls are recv vs send)
var totalOffset = 0;
function toHex(ptr, len) {
try {
var arr = new Uint8Array(ptr.readByteArray(len));
var hex = '';
for (var i = 0; i < arr.length; i++)
hex += ('0' + arr[i].toString(16)).slice(-2);
return hex;
} catch(e) { return 'ERR'; }
}
Interceptor.attach(GAME_WRAPPER, {
onEnter: function(args) {
callCount++;
var thisPtr = this.context.rcx;
var dataPtr = this.context.r9;
var dataLen = this.context.r8.toInt32();
if (dataLen <= 0) return;
var streamOff = 0;
try { streamOff = Number(thisPtr.add(0xA0).readU64()); } catch(e) {}
// Determine direction: check [this+0x60] byte (encrypt flag?)
var encFlag = 0;
try { encFlag = thisPtr.add(0x60).readU8(); } catch(e) {}
this._n = callCount;
this._dataPtr = dataPtr;
this._dataLen = dataLen;
this._offset = streamOff;
this._encFlag = encFlag;
// Read input (before processing)
try {
this._inputData = dataPtr.readByteArray(dataLen);
} catch(e) {
this._inputData = null;
}
},
onLeave: function(retval) {
if (!this._inputData || !this._dataLen) return;
// Read output (after processing)
var outputData = null;
try {
outputData = this._dataPtr.readByteArray(this._dataLen);
} catch(e) { return; }
var input = new Uint8Array(this._inputData);
var output = new Uint8Array(outputData);
// Compute keystream = input XOR output
var keystream = new Uint8Array(this._dataLen);
for (var i = 0; i < this._dataLen; i++) {
keystream[i] = input[i] ^ output[i];
}
// Send plaintext + keystream + metadata
send({
t: 'packet',
n: callCount,
offset: this._offset,
len: this._dataLen,
enc: this._encFlag,
input: toHex(ptr(0), 0), // placeholder
}, outputData); // send plaintext as binary
// Also send keystream
send({
t: 'keystream',
offset: this._offset,
len: this._dataLen,
}, keystream.buffer);
}
});
setInterval(function() {
send({t: 'status', calls: callCount});
}, 5000);
send({t: 'ready', msg: 'Capturing plaintext + keystream from game wrapper.'});
})();