
Choosing a Game
Let’s start by choosing a game. I’ve selected Hyper Light Drifter (referred to as HLD). If you plan to experiment with a commercial game, check out the PCGamingWiki website as well as games with open source code.
warning
Since I will be using a commercial game to write this article, I need to make sure that the End User License Agreement (EULA) permits this.
When I started the installation and carefully read through the EULA text, I noticed that it explicitly prohibits the creation and distribution of cheats and trainers only if they interfere with the service’s operations. Since nothing of that sort is planned in our case, we can confidently proceed with the installation.

Value Search
To find the values that the cheat will modify, we will use Cheat Engine (hereafter referred to as CE).
Start the game and select windowed mode in the settings. This allows space on the screen for other content aside from the game.

As we can see, in windowed mode, there is no title bar that allows us to drag the game window across the screen. To fix this issue, we will open the debugger x64dbg, specifically its 32-bit version (x32dbg
), and run HLD under it.
Let’s set breakpoints on the functions CreateWindowExA
and CreateWindowExW
, which are responsible for creating a window. You can find these functions under the Symbols tab by selecting the user32.
library.

We see that our window is created with the parameter dwStyle
, which has the value WS_POPUP
.

Change this value to WS_OVERLAPPED
.

And here’s the result: we can now move the window.

After setting up the game window using the debugger, we’ll set it aside for a bit. To find the necessary values in Cheat Engine, let’s delve into some theory.
What is a Static Address?
A static address is one that changes predictably relative to the module it belongs to. If a variable is global, it can typically be found in the data segment.
Static addresses are specified in the format [
. For example, in library.
, we might find a value at the address 0x700004C0
(base
). Since library.
can be relocated and its base loading address might change, we don’t use this address directly to access our value. Instead, we use the address [library.
]. Consequently, when library.
loads at the base address 0x10000000
, [library.
] translates to 0x100004C0
, allowing us to access our value.
If the variable is local, it should be sought in the stack. To do this, obtain the TebBaseAddress
of a specific thread, and then the second pointer from this structure (FS:[
or GS:[
, depending on the process’s architecture), which contains the stack’s top. The TebBasePointer
can be acquired using NtQueryInformationThread
(for a 64-bit process) or by using Wow64GetThreadSelectorEntry
(for a 32-bit process in a 64-bit system).
Finding Health Values
Launch Cheat Engine and connect to the game’s process.

Since the type in which the health metric is stored is unknown, we set the following parameters for the initial scan.

Next, we continue scanning, while intentionally losing health points (HP) in the game. We do this to monitor the changes in the HP value in the game’s memory using Cheat Engine (CE) and to reduce the value in subsequent scans. We will keep doing this until we reach a manageable number of values in the CE window. In this context, a manageable number means a number of addresses that can be checked in about five minutes.

I found these two addresses interesting and added them to the lower window by double-clicking on them. They caught my attention primarily because the values at these addresses have the largest data type — double. It’s always important to check from the largest type to the smallest. So, first we check addresses holding the double type, then float, followed by integer, and so on. For more detailed information on data type sizes, you can refer to the Microsoft documentation.

If we change the value at address 0x36501940
, a health bar will appear on the screen, but the amount of health will not change.

If we now change the value at the address 0x36501A30
, an HP bar will appear on the screen and the value will change. This means we have found the address where the health value in the game is stored. The value is stored in double format, following the IEEE 754 standard.

Let’s name the addresses we found as hp_bar
and hp
, respectively. However, as I mentioned in the section about static addresses, the address we found will become useless once we return to the menu or restart the game.
Searching for a Static Address for the Health Indicator
To continue searching for the static address, let’s go back to the debugger. In the dump window, navigate to the previously obtained address 0x36501A30
, where the value of hp is stored.

Set a hardware breakpoint at address 0x36501A34
to trigger on write operations and then lose some health in the game. When the breakpoint is activated, we observe that the new health value is taken from the EDI
register. This value is the first parameter of the current function.

After exiting this function, let’s trace where it gets its first parameter from. We will see that the parameter being passed is the return value of the function located at address 0x003EFCE9
.

Let’s set a breakpoint at the function call located at 0x003EFCE9
, and then continue debugging until the call is reached. Once inside the function, execute it to the end. When we reach address 0x00F88E19
, we’ll see that the EAX
register contains the address of the hp value. It’s clear that this function accesses our address through pointer arithmetic involving structures, specifically by adding offsets to a pointer and subsequently dereferencing it. You can read more about this process here. We will need to step through this function again to determine the exact address and offsets it uses to obtain the hp value address.

Once we discover the address 0x353F9BB0
, which leads us to the address storing the value of hp, we begin unwinding from the functions. During this process, we carefully monitor the parameters being passed to them. After a few exits, we’ll encounter the following.

We’ve located a static address! If you examine its position in memory, you’ll find it in the .
section.

Knowing all the offsets, add them to Cheat Engine by clicking Add
.

Finding the Ammo Count Value
Now let’s proceed to finding the ammo value. Conduct the first scan using the same search parameters we used when searching for health.

In this case, we were only able to identify one value, which is the indicator displaying the number of ammunition rounds.

In the game, this indicator did not appear. Unlike the health bar, it only shows up after pressing the E button or during shooting.

Finding a Static Address for Ammo
We understand that the readings of the indicators in the game are always compared with actual values. If one of the bars doesn’t display the correct value, its length is adjusted. Therefore, we return to the debugger and start with a hardware breakpoint on write at the address 0x365014C4
. As noted in the comments, we have encountered this function before.

Similarly to how we handle the search for hp, we exit the function.

Since we already know that the indicator must derive its value from somewhere earlier, we’ll need to scroll up in the disassembler window until we find a function that likely obtains the actual ammo value.

We can observe that we’ve already been in this function, which means it’s receiving a value as well, but in this case, it’s ammo
. However, this value seems a bit unusual.

By adding this “strange” value in Cheat Engine and then changing it, say, to 100, you’ll notice the on-screen ammo indicator changes accordingly. This means we’ve identified the address where the ammo value is stored in the game.

Once you know all the offsets from the static address to the ammo values, you can add them in Cheat Engine by clicking on Add
.

info
Most likely, ammo in HLD represents a charge of energy and is stored as a percentage—when searching for it in the debugger, you could spot strings containing the word energy
. That’s a hint at how the value is stored in memory. For example, a game from a certain well-known Polish studio stored ammo in memory as a combined value, even though the UI showed it separately—as a magazine and remaining bullets. So searching for either value alone didn’t work; you had to look for their sum.
Verification of the Obtained Static Address
To verify if we have correctly identified the addresses, exit the game menu and return to the gameplay or restart the game.
Testing for HP
Here is our cheat table for HP.

This is what it looks like after restarting the game.

Ammo Check
Here is our cheat table for ammo.

Here’s how it looks after restarting the game.

What Will Our Pointer Look Like in C++
In our cheat, access to the discovered value addresses will be as follows.
static_addr = (DWORD)GetModuleHandle(0);
static_addr = *(DWORD*)(static_addr + 0x255AF150);
static_addr = *(DWORD*)(static_addr);
static_addr = *(DWORD*)(static_addr + 0xD48);
static_addr = *(DWORD*)(static_addr + 0x0C);
static_addr = (DWORD*)(static_addr + 0xC4);
static_addr = *(DWORD*)(*static_addr + 0x08);
static_addr = *(DWORD*)(static_addr + 0x44);
static_addr = *(DWORD*)(static_addr + 0x10);
drifter_hp = (double*)(DWORD*)*(DWORD*)(static_addr + 0x1FD8);
drifter_ammo = (double*)(DWORD*)*(DWORD*)(static_addr + 0x268C);
Developing a Game Trainer
Cheats can be divided into two categories based on their functionality: internal and external. External cheats are separate applications running in the system as a process. Internal cheats are typically implemented as dynamic libraries injected directly into the game’s process.
We will be developing an internal cheat, which means we’ll need not only the library itself but also an injector to insert our library into the game process. The injector will list the processes, identify the game process, allocate memory within it for our internal cheat, and then create a remote thread within the game to execute the cheat code.
Injector
Here’s what the code for our injector looks like.
#include <windows.h>#include <tlhelp32.h>// Name of the injected dllconst char* dll_path = "internal_trainer_hld.dll";int main(void) { HANDLE process; void* alloc_base_addr; HMODULE kernel32_base; LPTHREAD_START_ROUTINE LoadLibraryA_addr; HANDLE thread; HANDLE snapshot = 0; PROCESSENTRY32 pe32 = { 0 }; DWORD exitCode = 0; pe32.dwSize = sizeof(PROCESSENTRY32); // Get a snapshot of the current processes snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); Process32First(snapshot, &pe32); do { // We only want to work with the HyperLightDrifter process if (wcscmp(pe32.szExeFile, L"HyperLightDrifter.exe") == 0) { // First, we need to get the process handle to use for subsequent calls process = OpenProcess(PROCESS_ALL_ACCESS, true, pe32.th32ProcessID); // To avoid damaging memory, we'll allocate extra memory to store our DLL path alloc_base_addr = VirtualAllocEx(process, NULL, strlen(dll_path) + 1, MEM_COMMIT, PAGE_READWRITE); // Write the path to our DLL into the memory we just allocated inside the game WriteProcessMemory(process, alloc_base_addr, dll_path, strlen(dll_path) + 1, NULL); // Create a remote thread inside the game, which will execute LoadLibraryA // In this LoadLibraryA call, we will pass the full path to our DLL that we have injected into the game kernel32_base = GetModuleHandle(L"kernel32.dll"); LoadLibraryA_addr = (LPTHREAD_START_ROUTINE)GetProcAddress(kernel32_base, "LoadLibraryA"); thread = CreateRemoteThread(process, NULL, 0, LoadLibraryA_addr, alloc_base_addr, 0, NULL); // To ensure our DLL is injected, we can use these two calls for synchronization WaitForSingleObject(thread, INFINITE); GetExitCodeThread(thread, &exitCode); // Finally, free memory and clean up process handles VirtualFreeEx(process, alloc_base_addr, 0, MEM_RELEASE); CloseHandle(thread); CloseHandle(process); break; } // Iterate over processes from the snapshot } while (Process32Next(snapshot, &pe32)); return 0;}
DLL
Our library will consist of the following modules:
- Main module (
dllmain.
)cpp - Hook module (
directx_hook.
andcpp directx_hook.
)h - Callback module (
directx_hook_callbacks.
)h - Memory management module (
memory.
)h
Main Module
When our library is loaded via the LoadLibraryA
function, a thread is created where two functions will be executed. The first function sets up a hook, and the second one renders the cheat menu and alters previously found values through keyboard inputs.
#include "directx_hook.h"double full_health = 6;double full_ammo = 100;DWORD static_addr = 0;DWORD *drifter = 0;// Retrieve player classvoid get_player_class() { if (drifter == NULL) { static_addr = (DWORD)GetModuleHandle(0); static_addr = *(DWORD*)(static_addr + 0x255AF150); static_addr = *(DWORD*)static_addr; static_addr = *(DWORD*)(static_addr + 0xD48); static_addr = *(DWORD*)(static_addr + 0x0C); drifter = (DWORD*)(static_addr + 0xC4); }}// Render our menuvoid draw_menu(directx_hook* hook) { hook->draw_text(10, 70, D3DCOLOR_ARGB(255, 255, 255, 255), "Full health press F1"); hook->draw_text(10, 90, D3DCOLOR_ARGB(255, 255, 255, 255), "Full ammo press F2");}// Change values of hp and ammo when keys are pressedvoid run(directx_hook* hook) { double* drifter_hp; double* drifter_ammo; draw_menu(hook); get_player_class(); if (*drifter) { static_addr = *(DWORD*)(*drifter + 0x08); static_addr = *(DWORD*)(static_addr + 0x44); static_addr = *(DWORD*)(static_addr + 0x10); drifter_hp = (double*)(DWORD*)*(DWORD*)(static_addr + 0x1FD8); drifter_ammo = (double*)(DWORD*)*(DWORD*)(static_addr + 0x268C); if (GetAsyncKeyState(VK_F1) & 1) { *drifter_hp = full_health; } if (GetAsyncKeyState(VK_F2) & 1) { *drifter_ammo = full_ammo; } }}void injected_thread() { // Add our function that will be called during inline hook directx_hook::get_instance()->add_callback(&run); // Begin the setup of inline hook directx_hook::get_instance()->initialize();}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: CreateThread(0, 0, (LPTHREAD_START_ROUTINE)injected_thread, 0, 0, 0); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE;}
Hook Module
This module is designed to intercept the EndScene function, which is responsible for rendering scenes. This is necessary to render our menu.
Hooks
There are many types of hooks, but we will use the simplest one from this list—byte patching/inline hook. The choice is straightforward: our game only supports single-player mode, and other hooks are designed to bypass anti-cheat systems in multiplayer games, which we simply don’t need.
#pragma once
#include <windows.h>
#include <stdint.h>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
typedef HRESULT(WINAPI* _endscene)(LPDIRECT3DDEVICE9 pDevice);
class directx_hook;
typedef void (*_callback_run)(directx_hook* hook);
class directx_hook {
private:
static directx_hook* instance;
static uint8_t* orig_endscene_code;
static uint32_t endscene_addr;
static LPDIRECT3DDEVICE9 hooked_device;
static bool hook_ready_pre, hook_ready;
_callback_run callback_run;
LPD3DXFONT font;
void set_hooks();
uint32_t locate_endscene();
public:
static _endscene orig_endscene;
static directx_hook* get_instance() {
if (!directx_hook::instance) {
directx_hook::instance = new directx_hook();
}
return directx_hook::instance;
}
static void delete_instance() {
if (directx_hook::instance) {
delete directx_hook::instance;
directx_hook::instance = NULL;
}
}
void initialize();
void add_callback(_callback_run cb);
void draw_text(uint32_t x, uint32_t y, D3DCOLOR color, const char* text);
uint32_t init_hook_callback(LPDIRECT3DDEVICE9 device);
HRESULT WINAPI endscene_hook_callback(LPDIRECT3DDEVICE9 pDevice);
};
In the other modules, we will perform the following actions:
- Create a temporary Direct3D device and obtain its VF (Virtual Function) table to find the address of the
EndScene
function. - Set up a temporary hook on the
EndScene
function. - Upon executing the hook, perform a callback and pass the address of the device used to call the
EndScene
function. Then, remove the hook and restore normal execution of theEndScene
function. - Execute our
run
function. - Return to the second step.
The purpose of all this is to ensure that our code renders the cheat menu and allows changes in the values of HP and ammo when buttons are pressed.
#include "directx_hook.h"#include "directx_hook_callbacks.h"#include "memory.h"directx_hook* directx_hook::instance = NULL;uint8_t* directx_hook::orig_endscene_code = NULL;uint32_t directx_hook::endscene_addr = NULL;LPDIRECT3DDEVICE9 directx_hook::hooked_device = NULL;_endscene directx_hook::orig_endscene = NULL;bool directx_hook::hook_ready = false;bool directx_hook::hook_ready_pre = false;void directx_hook::initialize() { // Check if d3d9.dll is in the address space while (!GetModuleHandleA("d3d9.dll")) { Sleep(10); } // Obtain the address of the endscene function directx_hook::endscene_addr = this->locate_endscene(); // Check if the EndScene address was successfully obtained // If yes, set our inline hook if (directx_hook::endscene_addr) { directx_hook::orig_endscene_code = hook_jmp(directx_hook::endscene_addr, (uint32_t)&endscene_trampoline); } // Wait while (!directx_hook::hook_ready_pre) { Sleep(10); } // Signal that our hook is ready directx_hook::hook_ready = true;}// Replace with assignment// As soon as our hook is setvoid directx_hook::add_callback(_callback_run cb) { if (!directx_hook::hook_ready) callback_run = cb;}// Wrapper for text renderingvoid directx_hook::draw_text(uint32_t x, uint32_t y, D3DCOLOR color, const char* text) { RECT rect; rect.left = x + 1; rect.top = y + 1; rect.right = rect.left + 1000; rect.bottom = rect.top + 1000; this->font->DrawTextA(NULL, text, -1, &rect, 0, color);}uint32_t directx_hook::init_hook_callback(LPDIRECT3DDEVICE9 device) { directx_hook::hooked_device = device; while (directx_hook::orig_endscene_code == NULL) {} unhook_jmp(directx_hook::endscene_addr, orig_endscene_code); D3DXCreateFont(directx_hook::hooked_device, 15, 0, FW_BOLD, 1, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &this->font); this->set_hooks(); directx_hook::hook_ready_pre = true; return directx_hook::endscene_addr;}HRESULT WINAPI directx_hook::endscene_hook_callback(LPDIRECT3DDEVICE9 pDevice) { HRESULT result; callback_run(this); result = orig_endscene(pDevice); this->set_hooks(); return result;}void directx_hook::set_hooks() { uint32_t ret; // Set the hook ret = hook_vf((uint32_t)directx_hook::hooked_device, 42, (uint32_t)&my_endscene); if (ret != (uint32_t)&my_endscene) { *(uint32_t*)&directx_hook::orig_endscene = ret; }}uint32_t directx_hook::locate_endscene() { LPDIRECT3D9 pD3D; D3DPRESENT_PARAMETERS d3dpp; LPDIRECT3DDEVICE9 pd3dDevice; uint32_t endscene_addr; // Create a temporary D3D9 object and iterate through the virtual table to obtain the EndScene method address pD3D = Direct3DCreate9(D3D_SDK_VERSION); if (!pD3D) { return 0; } ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = GetForegroundWindow(); HRESULT result = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice); if (FAILED(result) || !pd3dDevice) { pD3D->Release(); return 0; } // Obtain the address stored in rdata endscene_addr = get_vf((uint32_t)pd3dDevice, 42); // Clean up pD3D->Release(); pd3dDevice->Release(); return endscene_addr;}
Callback Module
This module contains the function inline
called endscene_trampoline
, as well as the function init_endscene
, which is the target for the hook to transfer control to. This function, in turn, will launch init_hook_callback
to set up the hook. The function my_endscene
will call endscene_hook_callback
, which is responsible for executing the run
function.
#include "directx_hook.h"DWORD WINAPI init_endscene(LPDIRECT3DDEVICE9 device_addr) { return directx_hook::get_instance()->init_hook_callback(device_addr);}HRESULT WINAPI my_endscene(LPDIRECT3DDEVICE9 pDevice) { return directx_hook::get_instance()->endscene_hook_callback(pDevice);}// Our inline hook__declspec(naked) void endscene_trampoline() { __asm { MOV EAX, DWORD PTR SS:[ESP + 0x4] PUSH EAX CALL init_endscene JMP EAX }}
Memory Management Module
The Direct3DCreate9
function returns a pointer to the IDirect3D9
interface, which contains the virtual method table (VMT). The function we need, EndScene
, is located at index 42 in this table. Therefore, we’ll write several functions to obtain the VMT, as well as to read, write, and change memory access permissions. You can find more details about virtual method tables on Wikipedia.
#pragma once#include <windows.h>#include <stdint.h>// Read from memorytemplate<typename T>T read_memory(uint32_t address) { return *((T*)address);}// Write to memorytemplate<typename T>void write_memory(uint32_t address, T value) { *((T*)address) = value;}template<typename T>uint32_t protect_memory(uint32_t address, uint32_t prot) { DWORD old_prot; VirtualProtect((LPVOID)address, sizeof(T), prot, &old_prot); return old_prot;}// Get the address of EndScene in VMTuint32_t get_vf(uint32_t class_inst, uint32_t func_idx) { uint32_t vf_table; uint32_t hook_addr; vf_table = read_memory<uint32_t>(class_inst); hook_addr = vf_table + func_idx * sizeof(uint32_t); return read_memory<uint32_t>(hook_addr);}// Get the address of EndScene from VMTuint32_t hook_vf(uint32_t class_inst, uint32_t func_idx, uint32_t new_func) { uint32_t vf_table; uint32_t hook_addr; uint32_t old_prot; uint32_t orig_func; vf_table = read_memory<uint32_t>(class_inst); hook_addr = vf_table + func_idx * sizeof(uint32_t); old_prot = protect_memory<uint32_t>(hook_addr, PAGE_READWRITE); orig_func = read_memory<uint32_t>(hook_addr); write_memory<uint32_t>(hook_addr, new_func); protect_memory<uint32_t>(hook_addr, old_prot); return orig_func;}// Set a hookunsigned char* hook_jmp(uint32_t hook, uint32_t new_func) { uint32_t new_offest; uint32_t old_prot; uint8_t* originals = new uint8_t[5]; // Calculate the offset for our inline hook new_offest = new_func - hook - 5; // To avoid a crash, as all virtual functions // are stored in rdata, change access rights at the function address old_prot = protect_memory<uint8_t[5]>(hook, PAGE_EXECUTE_READWRITE); // Save the original address for (uint8_t i = 0; i < 5; i++) { originals[i] = read_memory<uint8_t>(hook + i); } // Overwrite it with our code write_memory<uint8_t>(hook, 0xE9); write_memory<uint32_t>(hook + 1, new_offest); // Restore previous rights protect_memory<uint8_t[5]>(hook + 1, old_prot); return originals;}// Remove a hookvoid unhook_jmp(uint32_t hook, uint8_t* originals) { uint32_t old_prot; // To avoid a crash, change access rights at the function address old_prot = protect_memory<uint8_t[5]>(hook, PAGE_EXECUTE_READWRITE); // Write the original address for (unsigned int i = 0; i < 5; i++) { write_memory<uint8_t>(hook + i, originals[i]); } // Restore previous rights protect_memory<uint8_t[5]>(hook + 1, old_prot); delete[] originals;}
Functionality Check
We activate our cheat, take some damage, spend some ammo, press F1-F2, and watch as the HP and ammo values are restored to maximum. This means the cheat is working!

Conclusions
Using Cheat Engine, we learned how to search for the actual value of the variable we want to modify. Then, by using a debugger, we found static addresses for the values determined with Cheat Engine, allowing us to understand how the game engine operates. For example, there is a general function for obtaining player values such as health (hp) and ammunition (ammo), as well as a general function for recording changes to these values. With this knowledge, searching for other values will be much easier and faster. The code we’ve written can serve as a foundation or base for cheats in other games.

2022.02.16 — Timeline of everything. Collecting system events with Plaso
As you are likely aware, forensic analysis tools quickly become obsolete, while hackers continuously invent new techniques enabling them to cover tracks! As…
Full article →
2022.01.12 — Post-quantum VPN. Understanding quantum computers and installing OpenVPN to protect them against future threats
Quantum computers have been widely discussed since the 1980s. Even though very few people have dealt with them by now, such devices steadily…
Full article →
2022.01.11 — Persistence cheatsheet. How to establish persistence on the target host and detect a compromise of your own system
Once you have got a shell on the target host, the first thing you have to do is make your presence in the system 'persistent'. In many real-life situations,…
Full article →
2022.01.13 — Step by Step. Automating multistep attacks in Burp Suite
When you attack a web app, you sometimes have to perform a certain sequence of actions multiple times (e.g. brute-force a password or the second authentication factor, repeatedly…
Full article →
2023.02.13 — Ethernet Abyss. Network pentesting at the data link layer
When you attack a network at the data link layer, you can 'leapfrog' over all protection mechanisms set at higher levels. This article will walk…
Full article →
2022.01.01 — It's a trap! How to create honeypots for stupid bots
If you had ever administered a server, you definitely know that the password-based authentication must be disabled or restricted: either by a whitelist, or a VPN gateway, or in…
Full article →
2023.07.20 — Evil modem. Establishing a foothold in the attacked system with a USB modem
If you have direct access to the target PC, you can create a permanent and continuous communication channel with it. All you need for this…
Full article →
2023.02.12 — Gateway Bleeding. Pentesting FHRP systems and hijacking network traffic
There are many ways to increase fault tolerance and reliability of corporate networks. Among other things, First Hop Redundancy Protocols (FHRP) are used for this…
Full article →
2023.02.21 — Herpaderping and Ghosting. Two new ways to hide processes from antiviruses
The primary objective of virus writers (as well as pentesters and Red Team members) is to hide their payloads from antiviruses and avoid their detection. Various…
Full article →
2022.06.02 — Climb the heap! Exploiting heap allocation problems
Some vulnerabilities originate from errors in the management of memory allocated on a heap. Exploitation of such weak spots is more complicated compared to 'regular' stack overflow; so,…
Full article →