My goal is to call a function that gets the current visitor count, but I can’t quite figure out how to do it with it not crashing the game. I’m okayish with c++ but am noob with reverse engineering and working with the stack.
Here is the function I’m looking to use:
"Signature": "int32_t User__get_VisitorsCount (User_o* __this, const MethodInfo* method);",
When I hook the function, and print the values, it works:
void Mods::HookGetShoppingVisitorsCount(void* thisPtr) {
Utils::HookData& hook = hooks[1];
// Unhook
Unhook(hook.address, hook.originalBytes, 5);
WriteToConsole("VisitorsCount getter accessed");
uintptr_t ebpValue;
uintptr_t valueAtEBPPlus8;
__asm {
mov ebpValue, ebp // Capture the current EBP
mov eax, [ebp + 0x8] // Capture the value at EBP + 0x8
mov valueAtEBPPlus8, eax // Store it in valueAtEBPPlus8
}
// Log EBP
WriteToConsole("EBP Value: %p", FOREGROUND_GREEN | FOREGROUND_INTENSITY, ebpValue);
WriteToConsole("Value at [EBP + 0x8]: %p", FOREGROUND_GREEN | FOREGROUND_INTENSITY, valueAtEBPPlus8);
// Capture the this pointer
userPointer = static_cast<User*>(thisPtr);
// Print the user pointer
if (userPointer) {
WriteToConsole("User pointer: %p", FOREGROUND_GREEN | FOREGROUND_INTENSITY, userPointer);
} else {
WriteToConsole("User pointer null", FOREGROUND_RED | FOREGROUND_INTENSITY);
}
if (!originalShoppingVisitorsCount) {
originalShoppingVisitorsCount = reinterpret_cast<int(*)(void*)>(hook.address);
}
// Call the original function
int visitorsCount = originalShoppingVisitorsCount(thisPtr);
// Log the visitor count
WriteToConsole("Shopping Visitors Count: %d", FOREGROUND_GREEN | FOREGROUND_INTENSITY, visitorsCount);
// Re-hook
// Hook(hook.address, (void*)(&Mods::HookGetShoppingVisitorsCount), 5, hook.originalBytes);
}
This value returns:
ShoppingVisitorsCount getter accessed! at [2024-09-09 04:53:52]
EBP Value: 00F2E7DC at [2024-09-09 04:53:52]
Value at [EBP + 0x8]: 48C40AA0 at [2024-09-09 04:53:52]
User pointer captured: 48C40AA0 at [2024-09-09 04:53:52]
Visitors Count: 2 at [2024-09-09 04:53:52]
but when calling it the function, it crashes the game
Calling code:
void Hacks::CallUserFunction() {
if (userPointer) {
WriteToConsole("Gold: %ld", FOREGROUND_GREEN | FOREGROUND_INTENSITY, userPointer->gold->_value);
WriteToConsole("Gems: %ld", FOREGROUND_GREEN | FOREGROUND_INTENSITY, userPointer->gems->_value);
WriteToConsole("Coins: %ld", FOREGROUND_GREEN | FOREGROUND_INTENSITY, userPointer->coins->_value);
WriteToConsole("XP: %ld", FOREGROUND_GREEN | FOREGROUND_INTENSITY, userPointer->xp->_value);
// Get the base addy of dll
uintptr_t baseAddress = BaseAddy;
if (!baseAddress) {
WriteToConsole("Failed to get base address!", FOREGROUND_RED | FOREGROUND_INTENSITY);
return;
}
// base address
WriteToConsole("Base Address: %p", FOREGROUND_GREEN | FOREGROUND_INTENSITY, baseAddress);
// real address of the VisitorsCount function
uintptr_t realAddress = baseAddress + 0xC810E0;
// MethodInfo pointer
uintptr_t methodInfoAddress = baseAddress + 0x263CCA8;
// Read the MethodInfo pointer
const void* methodInfo = nullptr;
try {
methodInfo = *reinterpret_cast<void**>(methodInfoAddress); // Deref
if (!methodInfo) {
WriteToConsole("MethodInfo pointer null", FOREGROUND_RED | FOREGROUND_INTENSITY);
return;
}
} catch (...) {
WriteToConsole("Exception while dereferencing MethodInfo!", FOREGROUND_RED | FOREGROUND_INTENSITY);
return;
}
// Log MethodInfo addresses
WriteToConsole("Real Address: %p", FOREGROUND_GREEN | FOREGROUND_INTENSITY, realAddress);
WriteToConsole("MethodInfo Address: %p", FOREGROUND_GREEN | FOREGROUND_INTENSITY, methodInfo);
typedef int32_t(__thiscall* ShoppingVisitorsCountFunc)(User* user, const void* methodInfo);
ShoppingVisitorsCountFunc GetShoppingVisitorsCount = reinterpret_cast<ShoppingVisitorsCountFunc>(realAddress);
WriteToConsole("User Pointer: %p", FOREGROUND_GREEN | FOREGROUND_INTENSITY, userPointer);
if (!GetShoppingVisitorsCount) {
WriteToConsole("Function pointer is null!", FOREGROUND_RED | FOREGROUND_INTENSITY);
return;
}
// Log all
std::ofstream logFile(R"(C:Users****DocumentsCodelog.txt)", std::ios::app); // Append mode
if (logFile.is_open()) {
logFile << std::hex << std::uppercase; // Set output to hexadecimal and uppercase
logFile << "User Pointer: 0x" << (uintptr_t)userPointer << "n";
logFile << "Base Address: 0x" << (uintptr_t)baseAddress << "n";
logFile << "Real Address: 0x" << (uintptr_t)realAddress << "n";
logFile << "MethodInfo Address: 0x" << (uintptr_t)methodInfoAddress << "n";
logFile.close(); // Close the file after writing
} else {
WriteToConsole("Failed to open log file!", FOREGROUND_RED | FOREGROUND_INTENSITY);
}
// Call the function
try {
int visitorsCount = GetShoppingVisitorsCount(userPointer, methodInfo);
WriteToConsole("Visitors Count: %d", FOREGROUND_GREEN | FOREGROUND_INTENSITY, visitorsCount);
} catch (...) {
WriteToConsole("Exceptionwhile calling GetShoppingVisitorsCount", FOREGROUND_RED | FOREGROUND_INTENSITY);
}
} else {
WriteToConsole("User pointer null", FOREGROUND_RED | FOREGROUND_INTENSITY);
}
}
this is the stack of the function:
il2cpp:5E0B10E0 sub_5E0B10E0 proc near ; CODE XREF: sub_5D7D07E0+C3↑p
il2cpp:5E0B10E0 ; sub_5D7D16C0+C3↑p ...
il2cpp:5E0B10E0
il2cpp:5E0B10E0 var_30 = dword ptr -30h
il2cpp:5E0B10E0 var_2C = dword ptr -2Ch
il2cpp:5E0B10E0 var_28 = dword ptr -28h
il2cpp:5E0B10E0 var_24 = dword ptr -24h
il2cpp:5E0B10E0 var_20 = dword ptr -20h
il2cpp:5E0B10E0 var_1C = dword ptr -1Ch
il2cpp:5E0B10E0 var_18 = dword ptr -18h
il2cpp:5E0B10E0 var_14 = dword ptr -14h
il2cpp:5E0B10E0 var_10 = dword ptr -10h
il2cpp:5E0B10E0 var_C = dword ptr -0Ch
il2cpp:5E0B10E0 var_4 = dword ptr -4
il2cpp:5E0B10E0 arg_0 = dword ptr 8
il2cpp:5E0B10E0
il2cpp:5E0B10E0 push ebp
il2cpp:5E0B10E1 mov ebp, esp
il2cpp:5E0B10E3 push 0FFFFFFFFh
il2cpp:5E0B10E5 push offset SEH_10C810E0
il2cpp:5E0B10EA mov eax, large fs:0
il2cpp:5E0B10F0 push eax
il2cpp:5E0B10F1 mov large fs:0, esp
il2cpp:5E0B10F8 sub esp, 24h
il2cpp:5E0B10FB cmp byte_6033548E, 0
il2cpp:5E0B1102 push ebx
il2cpp:5E0B1103 push esi
il2cpp:5E0B1104 push edi
il2cpp:5E0B1105 mov [ebp+var_10], esp
il2cpp:5E0B1108 jnz short loc_5E0B1146
il2cpp:5E0B110A push offset dword_6026D180
il2cpp:5E0B110F call sub_5D650490
il2cpp:5E0B1114 push offset dword_60232A1C
il2cpp:5E0B1119 call sub_5D650490
il2cpp:5E0B111E push offset dword_6023A3E0
il2cpp:5E0B1123 call sub_5D650490
il2cpp:5E0B1128 push offset dword_6026DFC4
il2cpp:5E0B112D call sub_5D650490
il2cpp:5E0B1132 push offset dword_60260B1C
il2cpp:5E0B1137 call sub_5D650490
il2cpp:5E0B113C add esp, 14h
il2cpp:5E0B113F mov byte_6033548E, 1
il2cpp:5E0B1146
il2cpp:5E0B1146 loc_5E0B1146: ; CODE XREF: sub_5E0B10E0+28↑j
il2cpp:5E0B1146 mov eax, [ebp+arg_0]
il2cpp:5E0B1149 xor edi, edi
il2cpp:5E0B114B mov [ebp+var_14], 0
il2cpp:5E0B1152 mov [ebp+var_18], edi
il2cpp:5E0B1155 mov eax, [eax+134h]
il2cpp:5E0B115B test eax, eax
il2cpp:5E0B115D jz loc_5E0B12CD
il2cpp:5E0B1163 push dword_60260B1C
il2cpp:5E0B1169 push eax
il2cpp:5E0B116A call sub_5EDBA970
il2cpp:5E0B116F add esp, 8
il2cpp:5E0B1172 test eax, eax
il2cpp:5E0B1174 jz loc_5E0B12CD
il2cpp:5E0B117A push eax
il2cpp:5E0B117B push dword_60232A1C
il2cpp:5E0B1181 push edi
il2cpp:5E0B1182 call sub_5D4328F0
il2cpp:5E0B1187 add esp, 0Ch
il2cpp:5E0B118A mov [ebp+var_14], eax
il2cpp:5E0B118D xor ebx, ebx
il2cpp:5E0B118F lea esi, [ebp+var_14]
il2cpp:5E0B1192 mov [ebp+var_30], ebx
il2cpp:5E0B1195 mov [ebp+var_2C], esi
il2cpp:5E0B1198 mov [ebp+var_4], ebx
il2cpp:5E0B119B mov byte ptr [ebp+var_4], 1
il2cpp:5E0B119F nop
il2cpp:5E0B11A0
il2cpp:5E0B11A0 loc_5E0B11A0: ; CODE XREF: sub_5E0B10E0+15F↓j
il2cpp:5E0B11A0 ; sub_5E0B10E0+167↓j ...
il2cpp:5E0B11A0 mov eax, [ebp+var_14]
il2cpp:5E0B11A3 test eax, eax
il2cpp:5E0B11A5 jz loc_5E0B12CD
il2cpp:5E0B11AB push eax
il2cpp:5E0B11AC push dword_6026DFC4
il2cpp:5E0B11B2 push 0
il2cpp:5E0B11B4 call sub_5D4328F0
il2cpp:5E0B11B9 add esp, 0Ch
il2cpp:5E0B11BC test al, al
il2cpp:5E0B11BE jz loc_5E0B1267
il2cpp:5E0B11C4 mov ebx, [ebp+var_14]
il2cpp:5E0B11C7 mov [ebp+var_20], ebx
il2cpp:5E0B11CA test ebx, ebx
il2cpp:5E0B11CC jz loc_5E0B12CD
il2cpp:5E0B11D2 mov ecx, [ebx]
il2cpp:5E0B11D4 xor eax, eax
il2cpp:5E0B11D6 mov [ebp+var_1C], ecx
il2cpp:5E0B11D9 mov [ebp+arg_0], eax
il2cpp:5E0B11DC movzx edx, word ptr [ecx+0B6h]
il2cpp:5E0B11E3 mov [ebp+var_24], edx
il2cpp:5E0B11E6 cmp ax, dx
il2cpp:5E0B11E9 jnb short loc_5E0B1213
il2cpp:5E0B11EB nop dword ptr [eax+eax+00h]
il2cpp:5E0B11F0
il2cpp:5E0B11F0 loc_5E0B11F0: ; CODE XREF: sub_5E0B10E0+131↓j
il2cpp:5E0B11F0 mov edx, [ebp+var_1C]
il2cpp:5E0B11F3 mov ebx, dword_6023A3E0
il2cpp:5E0B11F9 movzx ecx, ax
il2cpp:5E0B11FC mov esi, [edx+58h]
il2cpp:5E0B11FF mov edx, [ebp+var_24]
il2cpp:5E0B1202 cmp [esi+ecx*8], ebx
il2cpp:5E0B1205 lea esi, [ebp+var_14]
il2cpp:5E0B1208 mov ebx, [ebp+var_20]
il2cpp:5E0B120B jz short loc_5E0B1256
il2cpp:5E0B120D inc eax
il2cpp:5E0B120E cmp ax, dx
il2cpp:5E0B1211 jb short loc_5E0B11F0
il2cpp:5E0B1213
il2cpp:5E0B1213 loc_5E0B1213: ; CODE XREF: sub_5E0B10E0+109↑j
il2cpp:5E0B1213 push 0
il2cpp:5E0B1215 push dword_6023A3E0
il2cpp:5E0B121B push ebx
il2cpp:5E0B121C call sub_5D5DC9E0
il2cpp:5E0B1221 add esp, 0Ch
il2cpp:5E0B1224 mov ecx, eax
il2cpp:5E0B1226
il2cpp:5E0B1226 loc_5E0B1226: ; CODE XREF: sub_5E0B10E0+185↓j
il2cpp:5E0B1226 push dword ptr [ecx+4]
il2cpp:5E0B1229 mov eax, [ecx]
il2cpp:5E0B122B push ebx
il2cpp:5E0B122C call eax
il2cpp:5E0B122E add esp, 8
il2cpp:5E0B1231 test eax, eax
il2cpp:5E0B1233 jz loc_5E0B12CD
il2cpp:5E0B1239 mov eax, [eax+28h]
il2cpp:5E0B123C cmp eax, 4
il2cpp:5E0B123F jz loc_5E0B11A0
il2cpp:5E0B1245 test eax, eax
il2cpp:5E0B1247 jz loc_5E0B11A0
il2cpp:5E0B124D inc edi
il2cpp:5E0B124E mov [ebp+var_18], edi
il2cpp:5E0B1251 jmp loc_5E0B11A0
il2cpp:5E0B1256 ; ---------------------------------------------------------------------------
il2cpp:5E0B1256
il2cpp:5E0B1256 loc_5E0B1256: ; CODE XREF: sub_5E0B10E0+12B↑j
il2cpp:5E0B1256 mov edx, [ebx]
il2cpp:5E0B1258 mov eax, [edx+58h]
il2cpp:5E0B125B mov ecx, [eax+ecx*8+4]
il2cpp:5E0B125F add ecx, 18h
il2cpp:5E0B1262 lea ecx, [edx+ecx*8]
il2cpp:5E0B1265 jmp short loc_5E0B1226
il2cpp:5E0B1267 ; ---------------------------------------------------------------------------
il2cpp:5E0B1267
il2cpp:5E0B1267 loc_5E0B1267: ; CODE XREF: sub_5E0B10E0+DE↑j
il2cpp:5E0B1267 mov [ebp+var_4], 0FFFFFFFFh
il2cpp:5E0B126E mov eax, [esi]
il2cpp:5E0B1270 test eax, eax
il2cpp:5E0B1272 jz short loc_5E0B1285
il2cpp:5E0B1274 push eax
il2cpp:5E0B1275 push dword_6026D180
il2cpp:5E0B127B push 0
il2cpp:5E0B127D call sub_5D432A20
il2cpp:5E0B1282 add esp, 0Ch
il2cpp:5E0B1285
il2cpp:5E0B1285 loc_5E0B1285: ; CODE XREF: sub_5E0B10E0+192↑j
il2cpp:5E0B1285 xor ebx, ebx
il2cpp:5E0B1287 mov eax, edi
il2cpp:5E0B1289 mov ecx, [ebp+var_C]
il2cpp:5E0B128C mov large fs:0, ecx
il2cpp:5E0B1293 pop edi
il2cpp:5E0B1294 pop esi
il2cpp:5E0B1295 pop ebx
il2cpp:5E0B1296 mov esp, ebp
il2cpp:5E0B1298 pop ebp
il2cpp:5E0B1299 retn
il2cpp:5E0B129A ; ---------------------------------------------------------------------------
il2cpp:5E0B129A
il2cpp:5E0B129A loc_5E0B129A: ; DATA XREF: .rdata:stru_600DD290↓o
il2cpp:5E0B129A mov eax, [ebp+var_28]
il2cpp:5E0B129D mov eax, [eax]
il2cpp:5E0B129F mov [ebp+var_30], eax
il2cpp:5E0B12A2 mov eax, offset loc_5E0B12A8
il2cpp:5E0B12A7 retn
il2cpp:5E0B12A8 ; ---------------------------------------------------------------------------
il2cpp:5E0B12A8
il2cpp:5E0B12A8 loc_5E0B12A8: ; CODE XREF: sub_5E0B10E0+1C7↑j
il2cpp:5E0B12A8 ; DATA XREF: sub_5E0B10E0+1C2↑o
il2cpp:5E0B12A8 lea ecx, [ebp+var_30]
il2cpp:5E0B12AB mov [ebp+var_4], 0FFFFFFFFh
il2cpp:5E0B12B2 call sub_5D4326B0
il2cpp:5E0B12B7 mov edi, [ebp+var_18]
il2cpp:5E0B12BA mov ecx, [ebp+var_C]
il2cpp:5E0B12BD mov eax, edi
il2cpp:5E0B12BF pop edi
il2cpp:5E0B12C0 pop esi
il2cpp:5E0B12C1 mov large fs:0, ecx
il2cpp:5E0B12C8 pop ebx
il2cpp:5E0B12C9 mov esp, ebp
il2cpp:5E0B12CB pop ebp
il2cpp:5E0B12CC retn
il2cpp:5E0B12CD ; ---------------------------------------------------------------------------
il2cpp:5E0B12CD
il2cpp:5E0B12CD loc_5E0B12CD: ; CODE XREF: sub_5E0B10E0+7D↑j
il2cpp:5E0B12CD ; sub_5E0B10E0+94↑j ...
il2cpp:5E0B12CD call sub_5D6506A0
il2cpp:5E0B12CD sub_5E0B10E0 endp
Am I just too noobish to figure out where to find the methodInfo*? Is it a Call Convention issue? All input is useful to my lil journey, thank you all in advance
I went through multiple calling conventions, tried each of the addresses pushed onto stack as references for MethodInfo*, I’m just a little lost for this part
1