Tutorial Get Module Base Address Tutorial dwGetModuleBaseAddress

Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,061
78,998
2,370
How long you been coding/hacking?
7 years
This tutorial will teach you how to get the module base address of any module. dwGetModuleBaseAddress is the function that most people are familiar with in the past. Our tutorial uses uintptr_t which will resolve to a x86 or x64 address depending what architecture you build for. This makes it work on both, so you only need one function. The old function uses DWORD so it only works on x86.

This tutorial will show you how to find the moduel base address in Cheat Engine, and then how to find it using C+++.

Video tutorial covering this code:

All .exe and .dll files when loaded into memory are referred to as "modules".

When adding addresses to your Cheat Engine table, and especially when using pointers you will often find the address listed like this:


Or maybe like this:
server.dll + 004EE83

This is using relative offset from the address of a module. Too see if an address is offset from a certain module make sure you enable this:


Then in memory viewer use "Go To Address" to the address. Regardless of if it is data or code, this will tell you what module it is offset from.

To view all the modules loaded by the process in Cheat Engine and view their addresses do this:


Also you can use Dissect PE Headers to view relative information:

MZ-Start is the address of the module as it is currently loaded into memory. Preferred ImageBase is parsed straight from the PE Header and is the location that it prefers to be loaded into. If this memory address is already taken, it will relocate.

When an .exe is executed, the windows loader create a process for it and give it it's own virtual memory space. The loader loads the executable into memory and then any .dlls that are called by the process. The PE header for the .dll defines a ImageBase address. The windows loader will try to load the .dll into the virtual memory space of the process that requires it. If that space is already occupied, it will be loaded into a different location. If this happens hardcodes addresses in our hacks will not work.

Now let's say we have a pointer:
ac_client.exe + 109B74

Now the ImageBase pulled from the PE header of ac_client.exe is "00400000"
We can only have one executable for each process which is an empty memory space until ac_client.exe is loaded. There is nothing blocking ac_client.exe from loading into it's ImageBase. So the base address of a .exe is always the same.

The ONLY time when a .exe isn't loaded into the imagebase stored in the PE headers is when ASLR(Address Space Layout Randomization) is enabled on the OS and the DynamicBase flag is set to enable the OS to randomize virtual address of the module.

We can just evaluate this before placing it in the code.
ac_client.exe + 109B74
00400000 + 109B74
509B74

This is the definition of a static address, it may be relative to the base address of an executable in the binary on disk, but it is always static in memory after relocations have occured.

But for .DLL's that can be relocated:

"server.dll + 004EE83" works in Cheat Engine because Cheat Engine evaluates the address of server.dll. CE will get the address of server.dll and replace it with the adress that the module is loaded.
So lets say the address of module server.dll is 0x10000000, cheat Engine will evaluate:

server.dll + 004EE83
0x10000000 + 004EE83
1004EE83

The above evaluation is done by cheat engine while the program is running.

But when you are trying to use this in an external trainer you need to evaluate "server.dll" + 004EE83 yourself. There are multiple ways of doing this and we will discuss one of them now.

To do this externally you can use this function that has been widely used named dwGetModuleBaseAddress.

Basically it uses the windows API CreateToolhelp32Snapshot to get a snapshot of all loaded modules for the given process, it then iterates through all the loaded modules and finds the module with the module name you give it. It returns a uintptr_t to the module address. You input the ProcessID and the name of the module and it ouputs the address of the module.
You must set your project to UNICODE for this to work, if you're not a noob you can easily change this to work with MBCS.

Function:
C++:
//Place this anywhere in the global namespace
#include <windows.h>
#include <TlHelp32.h>

uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)
{
    uintptr_t modBaseAddr = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 modEntry;
        modEntry.dwSize = sizeof(modEntry);
        if (Module32First(hSnap, &modEntry))
        {
            do
            {
                if (!_wcsicmp(modEntry.szModule, modName))
                {
                    modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnap, &modEntry));
        }
    }
    CloseHandle(hSnap);
    return modBaseAddr;
}
The Function Call
C++:
uintptr_t serverdllBaseAddress = GetModuleBaseAddress(ProcId, L"server.dll");
You can learn more about ToolHelp32Snapshot:
Taking a Snapshot and Viewing Processes (Windows)
Traversing the Module List (Windows)

Want to do it internally?
Don't worry, we got you: Solved - [INTERNAL HACKS HELP]Is there a fastest way to get an module base address?
 
Last edited:

zepixx

Newbie
Full Member
Aug 29, 2014
27
168
0
Thanks pal, very useful! :) I'm sure others will appreciate this too.
 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,061
78,998
2,370
I updated this tutorial making it alot easier to understand. While doing so I had a question:

When an .exe is executed, the windows loader create a process for it and give it it's own virtual memory space. The loader loads any .dlls that are called by the process. The PE header for the .dll defines a ImageBase address. The windows loader will try to load the .dll into the virtual memory space of the process that requires it. If that space is already occupied, it will be loaded into a different location. If this happens hardcodes addresses in our hacks will not work.

Now let's say we have a pointer:
ac_client.exe + 109B74

Now the ImageBase pulled from the PE header of ac_client.exe is "00400000"
We can only have one executable for each process which is an empty memory space until ac_client.exe is loaded. There is nothing blocking ac_client.exe from loading into it's ImageBase.

We can just evaluate this before placing it in the code.
ac_client.exe + 109B74
00400000 + 109B74
509B74

This is the definition of a static address.
So is there anytime when an .exe is not loaded into it's imagebase?


Interesting Article: Why is 0x00400000 the default imagebase?
 
Last edited:

squeenie

Hacker
Meme Tier VIP
Dank Tier Donator
Mar 6, 2013
677
5,478
37
I updated this tutorial making it alot easier to understand. While doing so I had a question:

When an .exe is executed, the windows loader create a process for it and give it it's own virtual memory space. The loader loads any .dlls that are called by the process. The PE header for the .dll defines a ImageBase address. The windows loader will try to load the .dll into the virtual memory space of the process that requires it. If that space is already occupied, it will be loaded into a different location. If this happens hardcodes addresses in our hacks will not work.

Now let's say we have a pointer:
ac_client.exe + 109B74

Now the ImageBase pulled from the PE header of ac_client.exe is "00400000"
We can only have one executable for each process which is an empty memory space until ac_client.exe is loaded. There is nothing blocking ac_client.exe from loading into it's ImageBase.

We can just evaluate this before placing it in the code.
ac_client.exe + 109B74
00400000 + 109B74
509B74

This is the definition of a static address.
So is there anytime when an .exe is not loaded into it's imagebase?


Interesting Article: Why is 0x00400000 the default imagebase?
Nice tut, should help people grasp the what's going on behind the scenes. btw your link is broken
 

Solaire

Respected Hacker
Dank Tier VIP
Dec 15, 2013
1,051
16,353
62
Just thought I'd add to the thread by going step by step through grabbing a module's base address function. Mine slightly differs from Anomander's, but they do the same exact thing.

C++:
DWORD GetModuleBase(const wchar_t * ModuleName, DWORD ProcessId){
    // This structure contains lots of goodies about a module
    MODULEENTRY32 ModuleEntry = { 0 };
    // Grab a snapshot of all the modules in the specified process
    HANDLE SnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);

    if (!SnapShot)
        return NULL;

    // You have to initialize the size, otherwise it will not work
    ModuleEntry.dwSize = sizeof(ModuleEntry);

    // Get the first module in the process
    if (!Module32First(SnapShot, &ModuleEntry))
        return NULL;

    do{
        // Check if the module name matches the one we're looking for
        if (!wcscmp(ModuleEntry.szModule, ModuleName)){
            // If it does, close the snapshot handle and return the base address
            CloseHandle(SnapShot);
            return (DWORD)ModuleEntry.modBaseAddr;
        }
    // Grab the next module in the snapshot
    } while (Module32Next(SnapShot, &ModuleEntry));

    // We couldn't find the specified module, so return NULL
    CloseHandle(SnapShot);
    return NULL;
}
MSDN links to all of the functions and the struct. I recommend you read them for a better understanding of what's going on.

MODULEENTRY32
CreateToolhelp32Snapshot
Module32First
Module32Next
wcscmp
CloseHandle
 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,061
78,998
2,370
small update:

[GH] Rake;33046 said:
So is there anytime when an .exe is not loaded into it's imagebase?
The ONLY time when a .exe isn't loaded into the imagebase stored in the PE headers is when ASLR(Address Space Layout Randomization) is enabled on the OS and the DynamicBase flag is set to enable the OS to randomize virtual address of the module.
 

MasterG

Coder
Dank Tier Donator
Nobleman
Mar 14, 2015
102
888
1
Bookmarked.. will be useful for my own memoryclass..
 

ChickenWeed

Newbie
Full Member
Jan 6, 2017
10
194
0
Do you need this for like Rainbow Six Siege, because the offsets/pointer goes rainbowsix.exe +.... and Battleye blocks normal RPM/WPM
 

EugenioH

Newbie
Full Member
Apr 2, 2016
7
248
0
I'm trying to get a base from a module, but it usually returns a value of type 10000000, a base and "mono.dll", and when I add "mono.dll" + 0x020A13C it is not a final basis of the address.

Look here in the forum something about ASLR (Address Space Layout Randomization) is that this could be it?
I just do not know what else to do.
follow the code:

C++:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <TlHelp32.h>
#include <tchar.h>

using namespace std;
//-----------Prototipos ----------//
DWORD dwGetModule(DWORD dwProcID, TCHAR *cModuleName);

int main() {
	LPCSTR GameName = "Cuphead";
	HANDLE hProcHandle = NULL;
	HWND hJanela = NULL;
	DWORD dwProcID = NULL;
	int valor = 1;
	hJanela = FindWindow(NULL, GameName);
	GetWindowThreadProcessId(hJanela, &dwProcID);

	hProcHandle = OpenProcess(PROCESS_ALL_ACCESS, NULL, dwProcID);
	DWORD BaseAddress = 0;
	BaseAddress = dwGetModule(dwProcID, "mono.dll");

	if (hProcHandle == INVALID_HANDLE_VALUE || hProcHandle == NULL)
		cout << "Não foi possível abrir um handle válido" << endl;
	else
	{
		cout << "Pronto para hackear!" << endl;
		

	};
	cout << "Modulo " << hex << BaseAddress << endl;
	cout << "Endereco FInal " << BaseAddress + 0x0020A13C << endl;

	WriteProcessMemory(hProcHandle, (LPVOID*)BaseAddress + 0x0020A13C, &valor, sizeof(valor), NULL);
	system("pause");



}
DWORD dwGetModule(DWORD dwProcID, TCHAR *cModuleName) {

	DWORD dwModuleBase = 0;
	HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwProcID);

		MODULEENTRY32 Me32;
		Me32.dwSize = sizeof(MODULEENTRY32);

		if (Module32First(hSnapShot, &Me32)) {
			do
			{
				if (_tcsicmp(Me32.szModule, cModuleName) == 0) {
					dwModuleBase = (DWORD)Me32.modBaseAddr;
					break;
				}
			} while (Module32Next(hSnapShot, &Me32));
		}

		CloseHandle(hSnapShot);

		return dwModuleBase;

}
 

ryuiijin

Banned
Silenced
Oct 14, 2017
16
47
0
so i see they are using a different address and offset in c++. so how can i convert my ce adress to c++ adress.

ex i have this
"ac_client.exe"+0010F4F4+f18

how can i convert this into the c++ offset?
 

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,744
40,528
316
You first have to read the base address and then the offset. Depening on wether you're making an internal or an external hack you have to either dereference addresses or use ReadProcessMemory.

Internal would look like this:
C++:
DWORD ac_client = (DWORD)GetModuleHandleA("ac_client.exe"); //getting the base address of the process
DWORD base = ac_client + 0x10F4F4; //calculate the full base address
DWORD address = *(DWORD*)base + 0xF8; //dereference ("read") the base address and add the offset
//now you can write to the address:
*(DWORD*)address = 1337;
External (assuming you already got the process handle):
C++:
DWORD ac_client = dwGetModuleBaseAddress(pid, "ac_client.exe"); //check https://guidedhacking.com/getmodulebase for this function
DWORD base = ac_client + 0x10F4F4; //calculate the full base address

DWORD address = 0;
ReadProcessMemory(hProc, (void*)base, &address, sizeof(address), nullptr); //read the base address
address += 0xF8; //add the offset

DWORD value = 1337;
WriteProcessMemory(hProc, (void*)address, &value, sizeof(value), nullptr); //write
Keep in mind that you should add error checking to the code above (eg. if ReadProcessMemory fails or *(DWORD*)base returns 0). Otherwise you will probably crash the process.
 

ryuiijin

Banned
Silenced
Oct 14, 2017
16
47
0
You first have to read the base address and then the offset. Depening on wether you're making an internal or an external hack you have to either dereference addresses or use ReadProcessMemory.

Internal would look like this:
C++:
DWORD ac_client = (DWORD)GetModuleHandleA("ac_client.exe"); //getting the base address of the process
DWORD base = ac_client + 0x10F4F4; //calculate the full base address
DWORD address = *(DWORD*)base + 0xF8; //dereference ("read") the base address and add the offset
//now you can write to the address:
*(DWORD*)address = 1337;
External (assuming you already got the process handle):
C++:
DWORD ac_client = dwGetModuleBaseAddress(pid, "ac_client.exe"); //check https://guidedhacking.com/getmodulebase for this function
DWORD base = ac_client + 0x10F4F4; //calculate the full base address

DWORD address = 0;
ReadProcessMemory(hProc, (void*)base, &address, sizeof(address), nullptr); //read the base address
address += 0xF8; //add the offset

DWORD value = 1337;
WriteProcessMemory(hProc, (void*)address, &value, sizeof(value), nullptr); //write
Keep in mind that you should add error checking to the code above (eg. if ReadProcessMemory fails or *(DWORD*)base returns 0). Otherwise you will probably crash the process.
very clear tut! ty so much bro! :)
 

ryuiijin

Banned
Silenced
Oct 14, 2017
16
47
0
You first have to read the base address and then the offset. Depening on wether you're making an internal or an external hack you have to either dereference addresses or use ReadProcessMemory.

Internal would look like this:
C++:
DWORD ac_client = (DWORD)GetModuleHandleA("ac_client.exe"); //getting the base address of the process
DWORD base = ac_client + 0x10F4F4; //calculate the full base address
DWORD address = *(DWORD*)base + 0xF8; //dereference ("read") the base address and add the offset
//now you can write to the address:
*(DWORD*)address = 1337;
External (assuming you already got the process handle):
C++:
DWORD ac_client = dwGetModuleBaseAddress(pid, "ac_client.exe"); //check https://guidedhacking.com/getmodulebase for this function
DWORD base = ac_client + 0x10F4F4; //calculate the full base address

DWORD address = 0;
ReadProcessMemory(hProc, (void*)base, &address, sizeof(address), nullptr); //read the base address
address += 0xF8; //add the offset

DWORD value = 1337;
WriteProcessMemory(hProc, (void*)address, &value, sizeof(value), nullptr); //write
Keep in mind that you should add error checking to the code above (eg. if ReadProcessMemory fails or *(DWORD*)base returns 0). Otherwise you will probably crash the process.
hey. what library should i use to register "pid, dwGetModuleBaseAdress and hProc"?
 
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods