Skip to content

Instantly share code, notes, and snippets.

@branw
Created September 2, 2020 23:23
Show Gist options
  • Save branw/a9f88e588b3e2946ae48ed0cb3eb35fe to your computer and use it in GitHub Desktop.
Save branw/a9f88e588b3e2946ae48ed0cb3eb35fe to your computer and use it in GitHub Desktop.
Adjust GTA 5/Online car values while on the Los Santos Custom's Sell Vehicle screen (GTA 1.50)
#include <Windows.h>
#include <iomanip>
#include <iostream>
#include <optional>
#include <psapi.h>
#include <tlhelp32.h>
DWORD find_process_by_name(const std::wstring &processName) {
PROCESSENTRY32 process_info;
process_info.dwSize = sizeof(process_info);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (snapshot == INVALID_HANDLE_VALUE) {
return 0;
}
if (Process32First(snapshot, &process_info)) {
while (Process32Next(snapshot, &process_info)) {
if (!processName.compare(process_info.szExeFile)) {
CloseHandle(snapshot);
return process_info.th32ProcessID;
}
}
}
CloseHandle(snapshot);
return 0;
}
HMODULE get_base_module(HANDLE process_handle) {
HMODULE modules[1024];
DWORD bytes_used;
unsigned int i;
if (EnumProcessModules(process_handle, modules, sizeof(modules),
&bytes_used)) {
for (i = 0; i < (bytes_used / sizeof(HMODULE)); i++) {
TCHAR module_name[MAX_PATH];
if (GetModuleFileNameEx(process_handle, modules[i], module_name,
sizeof(module_name) / sizeof(TCHAR))) {
if (std::wstring(module_name).find(L"GTA5.exe") != std::wstring::npos) {
return modules[i];
}
}
}
}
return nullptr;
}
uintptr_t find_pattern(HANDLE process_handle, uintptr_t start, uintptr_t size,
char const *sig, char const *mask) {
auto data = new uint8_t[size];
SIZE_T bytes_read;
if (!ReadProcessMemory(process_handle, (LPVOID)start, data, size,
&bytes_read)) {
return NULL;
}
auto block_matches = [](auto data, auto bMask, auto szMask) -> bool {
for (; *szMask; ++szMask, ++data, ++bMask)
if (*szMask == 'x' && *data != *bMask)
return FALSE;
return (*szMask == NULL);
};
for (size_t i = 0; i < size; i++) {
if (block_matches(reinterpret_cast<uint8_t const *>(data + i),
reinterpret_cast<uint8_t const *>(sig), mask)) {
return start + i;
}
}
delete[] data;
return NULL;
}
DWORD get_module_size(HANDLE process_handle, HMODULE module_handle) {
MODULEINFO module_info;
if (!GetModuleInformation(process_handle, module_handle, &module_info,
sizeof(module_info))) {
return 0;
}
return module_info.SizeOfImage;
}
template <typename T> T read(HANDLE process_handle, uintptr_t addr) {
T buffer;
if (!ReadProcessMemory(process_handle, (LPVOID)addr, &buffer, sizeof(T),
nullptr)) {
return T{};
}
return buffer;
}
template <typename T>
bool write(HANDLE process_handle, uintptr_t addr, T value) {
return WriteProcessMemory(process_handle, reinterpret_cast<LPVOID>(addr),
&value, sizeof(value), nullptr);
}
int main() {
std::cout << "Waiting for GTA5...";
DWORD process_id;
while ((process_id = find_process_by_name(L"GTA5.exe")) == 0) {
Sleep(500);
}
std::cout << " done (pid=" << process_id << ")" << std::endl;
auto const process_handle =
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION |
PROCESS_VM_READ | PROCESS_VM_WRITE,
0, process_id);
if (process_handle == nullptr) {
std::cerr << "Failed to open process handle" << std::endl;
return EXIT_FAILURE;
}
auto const base_module = get_base_module(process_handle);
if (base_module == nullptr) {
std::cerr << "Failed to find base module" << std::endl;
return EXIT_FAILURE;
}
auto const module_size = get_module_size(process_handle, base_module);
if (module_size == 0) {
std::cerr << "Failed to find base module size" << std::endl;
return EXIT_FAILURE;
}
auto const base_addr = reinterpret_cast<uintptr_t>(base_module);
auto const global_ptr_deref = find_pattern(
process_handle, base_addr, module_size,
"\x4C\x8D\x05\x00\x00\x00\x00\x4D\x8B\x08\x4D\x85\xC9\x74\x11",
"xxx????xxxxxxxx");
if (global_ptr_deref == 0) {
std::cerr << "Failed to find global pointer dereference" << std::endl;
return EXIT_FAILURE;
}
auto const global_ptrs =
global_ptr_deref + read<uint32_t>(process_handle, global_ptr_deref + 3) +
7;
auto write_global = [=](uint64_t index, uint64_t value) {
auto const page = read<uint64_t>(
process_handle, global_ptrs + (8 * (index >> 0x12 & 0x3F)));
write<uint64_t>(process_handle, page + (8 * (index & 0x3FFFF)), value);
};
std::cout
<< "Put a Tracker on the car, then go to Sell and enter a value below\n"
<< "You should see the new value reflected on the Sell screen"
<< std::endl;
while (!std::cin.fail()) {
std::cout << "Enter a new vehicle value: $";
uint64_t value;
std::cin >> value;
if (value > 67'000'000) {
std::cout
<< "Warning: selling a car for this price will cause an error\n"
<< "Press ALT+F4 and close the game instead of accepting the error!"
<< std::endl;
}
// Visual sell value
write_global(26269, value);
// Actual sell value (Global_98796.f_963)
write_global(98796 + 963, value);
}
CloseHandle(process_handle);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment