From aa096fe6886681d3338573cd3af779b57a5b56ab Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 30 Aug 2026 03:32:59 +0200 Subject: init --- src/cinput.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/cinput.cpp (limited to 'src/cinput.cpp') diff --git a/src/cinput.cpp b/src/cinput.cpp new file mode 100644 index 0000000..7c40b3b --- /dev/null +++ b/src/cinput.cpp @@ -0,0 +1,142 @@ +// cinput.cpp — CInput discovery, usercmd CRC, get/fix helpers +#include "hl2h.h" + +// --------------------------------------------------------------------------- +// CRC-32 (standard IEEE reflected, matches Valve's implementation) +// --------------------------------------------------------------------------- + +static uint32_t g_crc_table[256]; +static bool g_crc_inited = false; + +static void crc32_init_table() { + if (g_crc_inited) + return; + for (uint32_t i = 0; i < 256; i++) { + uint32_t c = i; + for (int k = 0; k < 8; k++) + c = (c & 1) ? 0xEDB88320u ^ (c >> 1) : c >> 1; + g_crc_table[i] = c; + } + g_crc_inited = true; +} + +// field set verified from client.so GetChecksum disassembly +uint32_t usercmd_checksum(const CUserCmd *c) { + crc32_init_table(); + uint32_t crc = 0xFFFFFFFFu; + auto upd = [&crc](const void *p, size_t n) { + const uint8_t *b = (const uint8_t *)p; + while (n--) + crc = g_crc_table[(crc ^ *b++) & 0xFF] ^ (crc >> 8); + }; + upd(&c->command_number, 4); + upd(&c->tick_count, 4); + upd(&c->viewangles, 12); + upd(&c->forwardmove, 4); + upd(&c->sidemove, 4); + upd(&c->upmove, 4); + upd(&c->buttons, 4); + upd(&c->impulse, 1); + upd(&c->weaponselect, 4); + upd(&c->weaponsubtype, 4); + upd(&c->random_seed, 4); + upd(&c->mousedx, 2); + upd(&c->mousedy, 2); + return ~crc; +} + +// CInput: +0xE4 = m_pCommands, +0xE8 = m_pVerifiedCommands +static constexpr size_t CMDOFF_M_PCOMMANDS = 0xE4; +static constexpr size_t CMDOFF_M_PVERIFIED = 0xE8; +static constexpr size_t VERIFIED_STRIDE = 0x58; +static constexpr size_t VERIFIED_CRC_OFF = 0x54; + +CUserCmd *get_usercmd(int seq) { + if (!g_input) + return nullptr; + uintptr_t cmds = *(uintptr_t *)(g_input + CMDOFF_M_PCOMMANDS); + if (!cmds) + return nullptr; + auto *cmd = (CUserCmd *)(cmds + (size_t)(seq % 90) * 0x54); + if (cmd->command_number != seq) + return nullptr; + return cmd; +} + +void fix_verified_crc(int seq, uint32_t crc) { + if (!g_input) + return; + uintptr_t verified = *(uintptr_t *)(g_input + CMDOFF_M_PVERIFIED); + if (verified) + *(uint32_t *)(verified + (size_t)(seq % 90) * VERIFIED_STRIDE + + VERIFIED_CRC_OFF) = crc; +} + +// --------------------------------------------------------------------------- +// CInput discovery: byte-scan of CHLClient::CreateMove prologue +// --------------------------------------------------------------------------- + +bool find_input_global() { + void **vt = VTABLE(g_iface.client); + uintptr_t cm = (uintptr_t)vt[21]; // CreateMove slot + if (!g_client.contains(cm)) { + logf("CreateMove %p outside client module", (void *)cm); + return false; + } + const uint8_t *b = (const uint8_t *)cm; + + // 1) PIC anchor: call __x86.get_pc_thunk + add $imm,%esi + uintptr_t anchor = 0; + for (int i = 0; i <= 0x100 - 11; i++) { + if (b[i] == 0xE8 && b[i + 5] == 0x81 && b[i + 6] == 0xC6) { + uint32_t imm; + memcpy(&imm, b + i + 7, 4); + anchor = cm + (uintptr_t)(i + 5) + imm; + break; + } + } + if (!anchor || !g_client.contains(anchor)) { + logf("PIC anchor not found in CreateMove"); + return false; + } + + // 2) the input->CreateMove call: "ff 51 0c" preceded by "52", scan back + // for "8d 86 imm32" with "8b 10" between + for (int c = 3; c <= 0x100 - 3; c++) { + if (!(b[c] == 0xFF && b[c + 1] == 0x51 && b[c + 2] == 0x0C && + b[c - 1] == 0x52)) + continue; + for (int i = c - 8; i > c - 44 && i > 2; i--) { + if (b[i] != 0x8D || b[i + 1] != 0x86) + continue; + bool has_mov = false; + for (int j = i + 6; j < c - 1; j++) + if (b[j] == 0x8B && b[j + 1] == 0x10) { + has_mov = true; + break; + } + if (!has_mov) + continue; + uint32_t disp; + memcpy(&disp, b + i + 2, 4); + uintptr_t var = anchor + disp; + if (!g_client.contains(var)) + continue; + uintptr_t input = *(uintptr_t *)var; + if (!input || !g_client.contains(input)) + continue; + uintptr_t vtbl = *(uintptr_t *)input; + if (!vtbl || !g_client.contains(vtbl)) + continue; + uintptr_t f3 = *(uintptr_t *)(vtbl + 3 * sizeof(void *)); + if (!g_client.contains(f3)) + continue; + logf("CInput* = %#lx (ptr var %#lx, vfunc[3] %#lx)", (unsigned long)input, + (unsigned long)var, (unsigned long)f3); + g_input = input; + return true; + } + } + logf("CInput pointer variable not found in CreateMove scan"); + return false; +} -- cgit v1.2.3