New hook for ConCommandBase::IsFlagSet(...)

Updated signatures
Code cleanup and improvements
Fixd some bugs and crashes
This commit is contained in:
Amos 2021-04-25 14:36:55 -07:00
parent c53ba3f31e
commit c8a682ddaa
11 changed files with 180 additions and 107 deletions

View File

@ -1,8 +1,8 @@
#include <string>
#include <iostream>
#include <sstream>
#include <Windows.h>
#include <Windows.h>
#include <detours.h>
#include "hooks.h"
@ -23,13 +23,14 @@ void SetupConsole()
// Set the window title
FILE* sBuildTxt;
CHAR sBuildBuf[1024];
#pragma warning(suppress : 4996)
sBuildTxt = fopen("build.txt", "r");
CHAR sBuildBuf[1024] = { 0 };
fopen_s(&sBuildTxt, "build.txt", "r");
if (sBuildTxt)
{
while (fgets(sBuildBuf, sizeof(sBuildBuf), sBuildTxt) != NULL)
{
fclose(sBuildTxt);
}
}
SetConsoleTitle(sBuildBuf);
@ -39,25 +40,59 @@ void SetupConsole()
freopen_s(&fDummy, "CONOUT$", "w", stdout);
freopen_s(&fDummy, "CONOUT$", "w", stderr);
// Create a worker thread to process console commands.
// Create a worker thread to process console commands
DWORD threadId;
DWORD __stdcall ProcessConsoleWorker(LPVOID);
HANDLE hThread = CreateThread(NULL, NULL, ProcessConsoleWorker, NULL, NULL, NULL);
CloseHandle(hThread);
HANDLE hThread = CreateThread(NULL, 0, ProcessConsoleWorker, NULL, 0, &threadId);
if (hThread)
{
printf("THREAD ID: %ld\n\n", threadId);
CloseHandle(hThread);
}
}
bool Hook_Cvar_IsFlagSet(int ** cvar, int flag)
static bool b_DebugConsole = true;
bool Hook_ConVar_IsFlagSet(int** cvar, int flag)
{
int real_flags = *(*(cvar + (72/(sizeof(void*)))) + (56/sizeof(int)));
int real_flags = *(*(cvar + (72 / (sizeof(void*)))) + (56 / sizeof(int)));
if (!b_DebugConsole)
{
printf("----------------------------------------------\n");
printf(" Flaged: %08X\n", real_flags);
}
printf("----------------------------------------------\n");
printf("Real flags: %08X\n", real_flags);
// Mask off FCVAR_CHEATS and FCVAR_DEVELOPMENTONLY
// Mask off FCVAR_CHEATS and FCVAR_DEVELOPMENTONLY
real_flags &= 0xFFFFBFFD;
if (!b_DebugConsole)
{
printf(" Masked: %08X\n", real_flags);
printf(" Verify: %08X\n", flag);
}
if (flag & 0x80000)
{
return true;
}
printf(" Masked: %08X\n", real_flags);
printf(" Checking: %08X\n", flag);
return (real_flags & flag) != 0;
}
bool Hook_ConCommand_IsFlagSet(int* cmd, int flag)
{
int real_flags = *((cmd + (56 / sizeof(int))));
if (!b_DebugConsole)
{
printf("----------------------------------------------\n");
printf(" Flaged: %08X\n", real_flags);
}
// Mask off FCVAR_CHEATS and FCVAR_DEVELOPMENTONLY
real_flags &= 0xFFFFBFFD;
if (!b_DebugConsole)
{
printf(" Masked: %08X\n", real_flags);
printf(" Verify: %08X\n", flag);
}
if (flag & 0x80000)
{
return true;
@ -86,12 +121,21 @@ DWORD __stdcall ProcessConsoleWorker(LPVOID)
ToggleDevCommands();
continue;
}
if (sCommand == "toggle net")
{
ToggleNetHooks();
continue;
}
if (sCommand == "pattern test")
{
PrintHAddress();
continue;
}
if (sCommand == "console test")
{
b_DebugConsole = !b_DebugConsole;
continue;
}
// Execute the command in the r5 SQVM
CommandExecute(NULL, sCommand.c_str());

View File

@ -6,11 +6,6 @@
#include "utilities.h"
#include "hooks.h"
__declspec(dllexport) void DummyExport()
{
// Required for detours.
}
//---------------------------------------------------------------------------------
// Main
//---------------------------------------------------------------------------------
@ -19,7 +14,10 @@ void InitializeR5Dev()
{
SetupConsole();
InstallHooks();
printf("R5 Dev -- Initialized...\n");
printf("+-----------------------------------------------------------------------------+\n");
printf("| R5 DEV -- INITIALIZED ------------------------------------------------- |\n");
printf("+-----------------------------------------------------------------------------+\n");
printf("\n");
}
void TerminateR5Dev()

View File

@ -7,59 +7,37 @@
#include "utilities.h"
#include "hooks.h"
#include "patterns.h"
#include "structs.h"
//---------------------------------------------------------------------------------
// Engine Hooks
//---------------------------------------------------------------------------------
struct __declspec(align(8)) netpacket_t
{
DWORD family_maybe;
sockaddr_in sin;
WORD sin_port;
BYTE gap16;
BYTE byte17;
DWORD source;
double received;
unsigned __int8* data;
QWORD label;
BYTE byte38;
QWORD qword40;
QWORD qword48;
BYTE gap50[8];
QWORD qword58;
QWORD qword60;
QWORD qword68;
int less_than_12;
DWORD wiresize;
BYTE gap78[8];
QWORD qword80;
};
bool Hook_NET_ReceiveDatagram(int sock, void* inpacket, bool raw)
{
bool result = NET_ReceiveDatagram(sock, inpacket, raw);
if (result)
{
netpacket_t* pkt = (netpacket_t *)inpacket;
int i = NULL;
netpacket_t* pkt = (netpacket_t*)inpacket;
// TODO: print the rest of the data..
printf("Got packet! Len %u\n -- ", pkt->wiresize);
for (int i = 0; i < 16 && i < pkt->wiresize; i++)
{
printf("%02X ", pkt->data[i]);
}
printf("\n");
// Log received packet data
HexDump("", "", "", 0, &pkt->data[i], pkt->wiresize);
}
return result;
}
unsigned int Hook_NET_SendDatagram(SOCKET s, const char* ptxt, int len, void* netchan_maybe, bool raw)
unsigned int Hook_NET_SendDatagram(SOCKET s, const char* buf, int len, int flags)
{
// TODO print ptxt[...] up to len bytes
printf("Sending packet! %u bytes @ %p\n", len, ptxt);
return NET_SendDatagram(s, ptxt, len, netchan_maybe, raw);
unsigned int result = NET_SendDatagram(s, buf, len, flags);
if (result)
{
// Log transmitted packet data
HexDump("", "", "", 0, buf, len);
}
return result;
}
void* Hook_SQVM_Print(void* sqvm, char* fmt, ...)
@ -73,7 +51,7 @@ void* Hook_SQVM_Print(void* sqvm, char* fmt, ...)
bool Hook_SQVM_LoadScript(void* sqvm, const char* script_path, const char* script_name, int flag)
{
char filepath[MAX_PATH] = {0};
char filepath[MAX_PATH] = { 0 };
sprintf_s(filepath, MAX_PATH, "platform\\%s", script_path);
// Flip forward slashes in filepath to windows-style backslash
@ -126,6 +104,10 @@ void RemoveHooks()
// Unhook Functions
DetourDetach((LPVOID*)&SQVM_Print, &Hook_SQVM_Print);
DetourDetach((LPVOID*)&SQVM_LoadScript, &Hook_SQVM_LoadScript);
DetourDetach((LPVOID*)&ConVar_IsFlagSet, &Hook_ConVar_IsFlagSet);
DetourDetach((LPVOID*)&ConCommand_IsFlagSet, &Hook_ConCommand_IsFlagSet);
DetourDetach((LPVOID*)&NET_SendDatagram, &Hook_NET_SendDatagram);
DetourDetach((LPVOID*)&NET_ReceiveDatagram, &Hook_NET_ReceiveDatagram);
// Commit the transaction
DetourTransactionCommit();
@ -133,18 +115,20 @@ void RemoveHooks()
void ToggleDevCommands()
{
bool g_dev = false;
static bool g_dev = false;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
if (!g_dev)
{
DetourAttach((PVOID*)&Cvar_IsFlagSet, &Hook_Cvar_IsFlagSet);
DetourAttach((LPVOID*)&ConVar_IsFlagSet, &Hook_ConVar_IsFlagSet);
DetourAttach((LPVOID*)&ConCommand_IsFlagSet, &Hook_ConCommand_IsFlagSet);
}
else
{
DetourDetach((PVOID*)&Cvar_IsFlagSet, &Hook_Cvar_IsFlagSet);
DetourDetach((LPVOID*)&ConVar_IsFlagSet, &Hook_ConVar_IsFlagSet);
DetourDetach((LPVOID*)&ConCommand_IsFlagSet, &Hook_ConCommand_IsFlagSet);
}
if (DetourTransactionCommit() != NO_ERROR)
@ -152,25 +136,25 @@ void ToggleDevCommands()
TerminateProcess(GetCurrentProcess(), 0xBAD0C0DE);
}
g_dev = ~g_dev;
g_dev = !g_dev;
}
void ToggleNetHooks()
{
bool g_net = false;
static bool g_net = false;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
if (!g_net)
{
DetourAttach((PVOID*)&NET_SendDatagram, &Hook_NET_SendDatagram);
DetourAttach((PVOID*)&NET_ReceiveDatagram, &Hook_NET_ReceiveDatagram);
DetourAttach((LPVOID*)&NET_SendDatagram, &Hook_NET_SendDatagram);
DetourAttach((LPVOID*)&NET_ReceiveDatagram, &Hook_NET_ReceiveDatagram);
}
else
{
DetourDetach((PVOID*)&NET_SendDatagram, &Hook_NET_SendDatagram);
DetourDetach((PVOID*)&NET_ReceiveDatagram, &Hook_NET_ReceiveDatagram);
DetourDetach((LPVOID*)&NET_SendDatagram, &Hook_NET_SendDatagram);
DetourDetach((LPVOID*)&NET_ReceiveDatagram, &Hook_NET_ReceiveDatagram);
}
if (DetourTransactionCommit() != NO_ERROR)
@ -178,5 +162,5 @@ void ToggleNetHooks()
TerminateProcess(GetCurrentProcess(), 0xBAD0C0DE);
}
g_net = ~g_net;
g_net = !g_net;
}

View File

@ -5,4 +5,5 @@ void RemoveHooks();
void ToggleDevCommands();
void ToggleNetHooks();
bool Hook_Cvar_IsFlagSet(int** cvar, int flag);
bool Hook_ConVar_IsFlagSet(int** cvar, int flag);
bool Hook_ConCommand_IsFlagSet(int* cmd, int flag);

View File

@ -6,34 +6,40 @@ namespace
{
SigScan fScanner;
LONGLONG hGameConsole = fScanner.FindPattern("r5apex.exe", "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x8D\x0D\x27\x61\xa5\x1e\x41\x8B\xD8", "xxxx?xxxxxxxx????xxx");
void (*CommandExecute)(void* self, const char* cmd) = (void (*)(void*, const char*))hGameConsole;
LONGLONG p_GameConsole = fScanner.FindPattern("r5apex.exe", "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x8D\x0D\x27\x61\xa5\x1e\x41\x8B\xD8", "xxxx?xxxxxxxx????xxx");
void (*CommandExecute)(void* self, const char* cmd) = (void (*)(void*, const char*))p_GameConsole;
LONGLONG hGameConsoleFlag = fScanner.FindPattern("r5apex.exe", "\x48\x8B\x41\x48\x85\x50\x38", "xxxxxxx");
bool (*Cvar_IsFlagSet)(int** cvar, int flag) = (bool (*)(int**, int))hGameConsoleFlag;
LONGLONG p_ConVarFlag = fScanner.FindPattern("r5apex.exe", "\x48\x8B\x41\x48\x85\x50\x38", "xxxxxxx");
bool (*ConVar_IsFlagSet)(int** cvar, int flag) = (bool (*)(int**, int))p_ConVarFlag;
LONGLONG hSquirrelVMPrint = fScanner.FindPattern("r5apex.exe", "\x48\x8B\xC4\x48\x89\x50\x10\x4C\x89\x40\x18\x4C\x89\x48\x20\x53\x56\x57\x48\x81\xEC\x30\x08\x00\x00\x48\x8B\xDA\x48\x8D\x70\x18\x48\x8B\xF9\xE8\x00\x00\x00\xff\x48\x89\x74\x24\x28\x48\x8d\x54\x24\x30\x33", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx???xxxxxxxxxxxx");
void* SQVM_Print = (void*)hSquirrelVMPrint;
LONGLONG p_ConCommandFlag = fScanner.FindPattern("r5apex.exe", "\x85\x51\x38\x0f\x95\xc0\xc3", "xxxxxxx");
bool (*ConCommand_IsFlagSet)(int* cmd, int flag) = (bool (*)(int*, int))p_ConCommandFlag;
LONGLONG hSquirrelVMScript = fScanner.FindPattern("r5apex.exe", "\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x48\x89\x4C\x24\x08\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\x6C", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); // Uncomment for S0 and S1
//LONGLONG hSquirrelVMScript = fScanner.FindPattern("r5apex.exe", "\x48\x8B\xC4\x48\x89\x48\x08\x55\x41\x56\x48\x8D\x68", "xxxxxxxxxxxxx"); // Uncomment for anything S2 and above (current S8)
bool (*SQVM_LoadScript)(void* sqvm, const char* script_path, const char* script_name, int flag) = (bool (*)(void*, const char*, const char*, int))hSquirrelVMScript;
LONGLONG p_SquirrelVMPrint = fScanner.FindPattern("r5apex.exe", "\x48\x8B\xC4\x48\x89\x50\x10\x4C\x89\x40\x18\x4C\x89\x48\x20\x53\x56\x57\x48\x81\xEC\x30\x08\x00\x00\x48\x8B\xDA\x48\x8D\x70\x18\x48\x8B\xF9\xE8\x00\x00\x00\xff\x48\x89\x74\x24\x28\x48\x8d\x54\x24\x30\x33", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx???xxxxxxxxxxxx");
void* SQVM_Print = (void*)p_SquirrelVMPrint;
LONGLONG hNetRXDatagram = fScanner.FindPattern("r5apex.exe", "\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x50\xeb", "xxxxxxxxxxxxxxxxxxxxxxxxx");
bool (*NET_ReceiveDatagram)(int, void*, bool) = (bool (*)(int, void*, bool))hNetRXDatagram;
//LONGLONG p_SquirrelVMScript = fScanner.FindPattern("r5apex.exe", "\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x48\x89\x4C\x24\x08\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\x6C", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); // Uncomment for S0 and S1
LONGLONG p_SquirrelVMScript = fScanner.FindPattern("r5apex.exe", "\x48\x8B\xC4\x48\x89\x48\x08\x55\x41\x56\x48\x8D\x68", "xxxxxxxxxxxxx"); // Uncomment for anything S2 and above (current S8)
bool (*SQVM_LoadScript)(void* sqvm, const char* script_path, const char* script_name, int flag) = (bool (*)(void*, const char*, const char*, int))p_SquirrelVMScript;
LONGLONG hNetTXDatagram = fScanner.FindPattern("r5apex.exe", "\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x10\x48\x89\x74\x24\x18\x57\x48\x83\xEC\x20\x48\x8B\xF9\x41\xb8\x2d", "xxxxxxxxxxxxxxxxxxxxxxxxxx");
unsigned int (*NET_SendDatagram)(SOCKET s, const char* ptxt, int len, void* netchan_maybe, bool raw) = (unsigned int (*)(SOCKET, const char*, int, void*, bool))hNetTXDatagram;
LONGLONG p_NetRXDatagram = fScanner.FindPattern("r5apex.exe", "\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x50\xeb", "xxxxxxxxxxxxxxxxxxxxxxxxx");
bool (*NET_ReceiveDatagram)(int, void*, bool) = (bool (*)(int, void*, bool))p_NetRXDatagram;
LONGLONG p_NetTXDatagram = fScanner.FindPattern("r5apex.exe", "\x48\x89\x5c\x24\x08\x48\x89\x6c\x24\x10\x48\x89\x74\x24\x18\x57\x41\x56\x41\x57\x48\x81\xec\x00\x05\x00\x00", "xxxxxxxxxxxxxxxxxxxxxxx?xxx");
unsigned int (*NET_SendDatagram)(SOCKET s, const char* buf, int len, int flags) = (unsigned int (*)(SOCKET, const char*, int, int))p_NetTXDatagram;
void PrintHAddress() // Test the sigscan results
{
printf("%lld\n", hGameConsole);
printf("%lld\n", hGameConsoleFlag);
printf("%lld\n", hSquirrelVMPrint);
printf("%lld\n", hSquirrelVMScript);
printf("%lld\n", hNetRXDatagram);
printf("%lld\n", hNetTXDatagram);
printf("\n");
printf("0x%llx = GameConsole\n", p_GameConsole);
printf("0x%llx = GameConsoleFlag\n", p_ConCommandFlag);
printf("0x%llx = GameConsoleFlag\n", p_ConVarFlag);
printf("0x%llx = SquirrelVMPrint\n", p_SquirrelVMPrint);
printf("0x%llx = SquirrelVMScript\n", p_SquirrelVMScript);
printf("0x%llx = NetRXDatagram\n", p_NetRXDatagram);
printf("0x%llx = NetTXDatagram\n", p_NetTXDatagram);
printf("\n");
// TODO implement error handling when sigscan fails/result is 0
// TODO implement error handling when sigscan fails or result is 0
}
}

View File

@ -3,3 +3,8 @@
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
__declspec(dllexport) void DummyExport()
{
// Required for detours.
}

View File

@ -176,6 +176,7 @@
<ClInclude Include="patterns.h" />
<ClInclude Include="r5dev.h" />
<ClInclude Include="sigscan.h" />
<ClInclude Include="structs.h" />
<ClInclude Include="utilities.h" />
</ItemGroup>
<ItemGroup>

View File

@ -44,10 +44,13 @@
<ClInclude Include="sigscan.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="structs.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="r5dev.def">
<Filter>Header Files</Filter>
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
</Project>

28
r5dev/structs.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
// Define structures/types
typedef unsigned __int64 QWORD;
struct __declspec(align(8)) netpacket_t
{
DWORD family_maybe;
sockaddr_in sin;
WORD sin_port;
BYTE gap16;
BYTE byte17;
DWORD source;
double received;
unsigned __int8* data;
QWORD label;
BYTE byte38;
QWORD qword40;
QWORD qword48;
BYTE gap50[8];
QWORD qword58;
QWORD qword60;
QWORD qword68;
int less_than_12;
DWORD wiresize;
BYTE gap78[8];
QWORD qword80;
};

View File

@ -1,10 +1,19 @@
#pragma once
#include <Windows.h>
#include <stdio.h>
#include <string>
#include "hooks.h"
namespace
{
BOOL FileExists(LPCTSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
static void DbgPrint(LPCSTR Format, ...)
{
CHAR Buffer[512] = { 0 };
@ -21,17 +30,7 @@ namespace
OutputDebugString(Buffer);
}
typedef unsigned __int64 QWORD;
BOOL FileExists(LPCTSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
static void HexDump(char* data, int len)
static void HexDump(const char* header, const char* file, const char* mode, int func, const void* data, int size)
{
// todo..
}

View File

@ -8,7 +8,9 @@ void PrintLastError()
//Get the error message, if any.
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0)
{
return;
}
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
@ -21,12 +23,12 @@ void PrintLastError()
bool LaunchR5Apex()
{
FILE* sLaunchParams;
CHAR sArgumentBuffer[1024];
CHAR sArgumentBuffer[1024] = { 0 };
CHAR sCommandDirectory[MAX_PATH];
LPSTR sCommandLine = sCommandDirectory;
#pragma warning(suppress : 4996)
sLaunchParams = fopen("launchparams.txt", "r"); // "+exec autoexec -dev -fnf -noplatform"
// '+exec autoexec -dev -fnf -noplatform'
fopen_s(&sLaunchParams, "launchparams.txt", "r");
BOOL result;
@ -44,7 +46,9 @@ bool LaunchR5Apex()
if (sLaunchParams)
{
while (fgets(sArgumentBuffer, sizeof(sArgumentBuffer), sLaunchParams) != NULL)
{
fclose(sLaunchParams);
}
}
// Format the file paths for the game exe and dll.