97 lines
3.1 KiB
JavaScript
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.'});
|
|
})();
|