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

62 lines
2.2 KiB
JavaScript

// item_table_dump.js - dump every valid item id from the client's
// BagItemSubsystem local ItemTable.
//
// Technique: hook sub_1449639C0 (LookupItemRecordById), grab `rcx` =
// subsystem pointer on first natural call during login, then walk its
// internal table in-place.
//
// Layout recovered from IDA:
// subsystem + 56..168 -> 7 block descriptors, 16 bytes each:
// [0] qword ptr to items[0]
// [8] int32 item count
// [12] int32 padding
// each item record = 120 bytes; first 4 bytes = itemId (uint32).
// The table's effective size = sum of counts across the 7 blocks.
(function () {
'use strict';
var MOD = 'Paralogue-Win64-Shipping.exe';
var mod = Process.getModuleByName(MOD);
if (!mod) { send({t:'error', msg:'module not found'}); return; }
var LOOKUP = mod.base.add(0x49639C0);
var dumped = false;
function walk(subsystem) {
try {
var base = subsystem.add(56);
var end = subsystem.add(168);
var total = 0;
var emitted = 0;
for (var slot = base; !slot.equals(end); slot = slot.add(16)) {
var ptr = slot.readPointer();
var count = slot.add(8).readS32();
if (ptr.isNull() || count <= 0 || count > 200000) continue;
send({t:'item_block', ptr: ptr.toString(), count: count});
total += count;
for (var i = 0; i < count; i++) {
var rec = ptr.add(i * 120);
var id = rec.readU32();
send({t:'item_id', id: id});
emitted++;
}
}
send({t:'item_dump_done', total: total, emitted: emitted});
} catch (e) {
send({t:'error', msg:'walk failed: '+e.message});
}
}
Interceptor.attach(LOOKUP, {
onEnter: function (args) {
if (dumped) return;
dumped = true;
var subsystem = this.context.rcx;
send({t:'item_subsystem', addr: subsystem.toString()});
walk(subsystem);
}
});
send({t:'ready', msg:'item_table_dump hook installed at '+LOOKUP.toString()});
})();