WELCOME TO INFOCHEATS.NET

INFOCHEATS is a community-driven platform focused on free game cheats, cheat development, and verified commercial software for a wide range of popular games. We provide a large collection of free cheats shared by the community. All public releases are checked for malicious code to reduce the risk of viruses, malware, or unwanted software before users interact with them.

Alongside free content, INFOCHEATS hosts an active marketplace with many independent sellers offering commercial cheats. Each product is discussed openly, with user feedback, reviews, and real usage experience available to help you make informed decisions before purchasing.

Whether you are looking for free cheats, exploring paid solutions, comparing sellers, or studying how cheats are developed and tested, INFOCHEATS brings everything together in one place — transparently and community-driven.

Guide [Source] C&C Generals — Bypassing GenTool Hooks & Checksums

byte_corvus

Newbie
Newbie
Newbie
Newbie
Status
Offline
Joined
Mar 3, 2026
Messages
481
Reaction score
7
Tired of GenTool's d3d8.dll hooks clashing with your patches? For anyone digging into C&C: Generals or Zero Hour, GenTool is the main hurdle for internal cheats. It uses two primary methods to stop you from patching the .text section or applying VMT/IAT hooks:
  1. Inline hooks on VirtualProtect and ZwProtectVirtualMemory.
  2. Background .text section checksum validation.

Evading VirtualProtect Hooks
If you check your cheat in x64dbg, you'll see VirtualProtect calls jumping straight into a d3d8.dll subroutine. GenTool effectively gates unauthorized protection changes. Since VirtualProtect eventually hits ZwProtectVirtualMemory in ntdll, we can resolve the original syscall by calculating the jump offset GenTool uses to back up the original function.

Code:
using ZwProtectVirtualMemory_t = NTSTATUS(__stdcall*)(HANDLE, PVOID*, PULONG, ULONG, PULONG);

BOOL TrueVirtualProtect(LPVOID base, SIZE_T amount, DWORD newProtect, PDWORD oldProtect)
{
  static auto ZwProtectVirtualMemory = 
    reinterpret_cast<ZwProtectVirtualMemory_t>(GetProcAddress(LoadLibraryA("ntdll.dll"), "ZwProtectVirtualMemory"));

  if (ZwProtectVirtualMemory == NULL) return FALSE;

  static ZwProtectVirtualMemory_t OriginalZwProtectVirtualMemory = NULL;
  if (OriginalZwProtectVirtualMemory == NULL)
  {
    if (*reinterpret_cast<uint8_t*>(ZwProtectVirtualMemory) == 0xE9)
    {
      uintptr_t ZwProtectVirtualMemoryAddress = reinterpret_cast<uintptr_t>(ZwProtectVirtualMemory);
      int relativeJumpOffset = *reinterpret_cast<int*>(ZwProtectVirtualMemoryAddress + 1);
      int absoluteJumpOffset = relativeJumpOffset + ZwProtectVirtualMemoryAddress + sizeof(uint8_t) + sizeof(uintptr_t);
      // Skip to where GenTool backs up the original logic
      OriginalZwProtectVirtualMemory = **reinterpret_cast<ZwProtectVirtualMemory_t**>(absoluteJumpOffset + 130);
    }
    else
    {
      OriginalZwProtectVirtualMemory = ZwProtectVirtualMemory;
    }
  }
  return OriginalZwProtectVirtualMemory(GetCurrentProcess(), &base, &amount, newProtect, oldProtect) == 0;
}

You can then #define VirtualProtect to use this TrueVirtualProtect wrapper. This skips the hook and restores your ability to patch memory without GenTool blocking the API call.

Neutralizing Engine Checksums
Even with memory access, GenTool will black-screen you if it detects a .text mismatch. This check runs in separate threads at random intervals. If you inject and don't patch, nothing happens—confirming it's a checksum comparison. The solution is simple: find the thread entry point in d3d8.dll and terminate any thread running that subroutine.

Code:
Pattern patterns::gentool::ChecksumThread = Pattern(
  "\xA1\x00\x00\x00\x00\x33\xC4\x50\x8D\x44\x24\x18\x64\xA3\x00\x00\x00\x00\x00\x00\x00\x00\x8B",
  "x????xxxxxxxxx????????x"
);

const DWORD ThreadQuerySetWin32StartAddress = 9;

bool KillCodeChecksumThreads()
{
  HANDLE threadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
  if (threadSnapshot == INVALID_HANDLE_VALUE) return false;

  uintptr_t codeChecksumEntryPoint = patterns::gentool::ChecksumThread.FindInModule("./d3d8.dll");
  if (codeChecksumEntryPoint == NULL) { CloseHandle(threadSnapshot); return false; }
  
  codeChecksumEntryPoint -= 19;
  THREADENTRY32 currentThread { sizeof(currentThread) };

  if (Thread32First(threadSnapshot, &currentThread))
  {
    do {
      HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, currentThread.th32ThreadID);
      if (hThread)
      {
        PVOID threadEntryPoint = NULL;
        NtQueryInformationThread(hThread, (THREADINFOCLASS)ThreadQuerySetWin32StartAddress, &threadEntryPoint, sizeof(threadEntryPoint), NULL);
        if (threadEntryPoint == (PVOID)codeChecksumEntryPoint)
        {
          TerminateThread(hThread, 0);
        }
        CloseHandle(hThread);
      }
    } while (Thread32Next(threadSnapshot, &currentThread));
  }
  CloseHandle(threadSnapshot);
  return true;
}

Implementation Notes
  1. Inject your bypass early, ideally before applying any patches.
  2. Make sure to link ntdll.lib for NtQueryInformationThread.
  3. This method completely nukes the integrity checks, meaning you can run your internal hooks without the infamous GenTool black screen.

GenTool isn't that sophisticated; it's just a d3d8 wrapper. Once the threads are dead and the syscalls are clean, the game is wide open for reversing.

Have fun reversing, drop your crash logs below if you hit issues.
 
Top