62 lines
2.2 KiB
JavaScript
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()});
|
|
})();
|