 |
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
dreamlane How do I cheat?
Reputation: 0
Joined: 13 Mar 2013 Posts: 3 Location: United States
|
Posted: Wed Mar 13, 2013 3:52 pm Post subject: Help with understanding "base address" |
|
|
Hey guys. I've been playing around with Cheat Engine, mostly as an exercise to augment an OS class I am currently taking as part of a CS degree.
I've tracked a multilevel pointer to its base address, but I am a little confused on one thing.
The first level of the pointer is Code: | "Client.exe"+0069C25C. |
How do i figure out in CE what the hex value of "Client.exe" is?
I understand the offsets and pointer arithmetic, but I'm lost in regards to getting the address of "Client.exe" wand what CE evaluates that string to be.
Description: |
|
Filesize: |
8.46 KB |
Viewed: |
16313 Time(s) |

|
|
|
Back to top |
|
 |
SteveAndrew Master Cheater
Reputation: 30
Joined: 02 Sep 2012 Posts: 323
|
Posted: Thu Mar 14, 2013 12:08 am Post subject: |
|
|
Well that's easy, "Client.exe" is the base address of "Client.exe" when its loaded in memory...
In previous versions of Windows the base address used to be pretty consistently located at: 0x00400000... So addresses used to be based off that and they would still work for everyone. In more recent versions of Windows: 7, 8, etc.. It's no longer the case...
So instead of using VA's (virtual addresses [image base included]) We use RVA's(relative virtual addresses)... As we know with the same version of the game (say your using v1.0), if everyone's using v1.0 the code/data is going to be located at the same offset from the start of the module/exe...
If you're working from the inside of the process it's really easy to get the base address of any module (a loaded DLL, or the process itself)
//Note this is C/C++ code
Code: |
ULONG EXEBaseAddr = (ULONG)GetModuleHandleW(0);
ULONG DLLBaseAddr = (ULONG)GetModuleHandleW(L"whatever.dll");
|
It's really that simple if on the inside of the process (with an injected dll for example) (don't get confused about a module handle [with that function] being the base address, a process handle is different as you'll see below (the handle you get from OpenProcess for example))
If working from the outside (externally, like CE)
There are several ways, but one easy way is to use the toolhelp APIs
Code: |
#include <tlhelp32.h>
//Get process ids/handles/modules functions
HANDLE GetProcessHandle(wchar_t *ProcessName, ULONG *ReturnedProcessId)
{
PROCESSENTRY32W *pe = new PROCESSENTRY32W;
HANDLE Snap;
pe->dwSize = sizeof(PROCESSENTRY32W);
Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(Snap == INVALID_HANDLE_VALUE)
{
delete pe;
return 0;
}
BOOL bProcess = Process32FirstW(Snap, pe);
while(bProcess)
{
if(_wcsicmp(pe->szExeFile, ProcessName) == 0)
{
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pe->th32ProcessID);
if(ReturnedProcessId)
*ReturnedProcessId = pe->th32ProcessID;
CloseHandle(Snap);
delete pe;
return ProcessHandle;
}
bProcess = Process32NextW(Snap, pe);
}
CloseHandle(Snap);
delete pe;
return 0;
}
ULONG GetModuleBase(wchar_t *ModuleName, ULONG ProcessId)
{
MODULEENTRY32W *me = new MODULEENTRY32W;
HANDLE Snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
me->dwSize = sizeof(MODULEENTRY32W);
if(Snap == INVALID_HANDLE_VALUE)
{
delete me;
return 0;
}
BOOL bModule = Module32First(Snap, me);
while(bModule)
{
if(!ModuleName|| _wcsicmp(me->szModule, ModuleName) == 0)
{
CloseHandle(Snap);
return (ULONG)me->modBaseAddr;
}
bModule = Module32Next(Snap, me);
}
CloseHandle(Snap);
delete me;
return 0;
}
///.... I'm using Crysis 3 as an example usage of those functions, lol!
ULONG RemoteProcessId = 0;
HANDLE RemoteProcessHandle = GetProcessHandle(L"Crysis3.exe", &RemoteProcessId);
//if 'ModuleName' passed is NULL just return EXE Base
ULONG EXEModuleBase = GetModuleBase(0, RemoteProcessId);
//or for a specific DLL of that process
ULONG DLLModuleBase = GetModuleBase(L"SomeDll.dll", RemoteProcessId);
printf("Remote EXE Base: %p; Remote DLL Base: %p\n", EXEModuleBase, DLLModuleBase);
|
However you said you're going to school so you may be interested in knowing the way Windows itself has that information stored... (how the toolhelp API's probably work internally)
It's part of the PEB of a process where this information can be accessed...
The following is a sort of 'undocumented' way of achieving the same thing... It requires a little bit of setup therefore, but this way is cooler
In your header file: .h
Code: |
typedef void** PPVOID;
typedef struct _UNICODE_STRING
{
WORD Length;
WORD MaximumLength;
WORD *Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID ModuleBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullModuleName;
UNICODE_STRING BaseModuleName;
ULONG Flags;
WORD LoadCount;
WORD TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
DWORD EntryPointActivationContext; //_ACTIVATION_CONTEXT * EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
BOOLEAN Spare;
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA LoaderData;
DWORD ProcessParameters; //PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
DWORD FastPebLockRoutine; //PPEBLOCKROUTINE FastPebLockRoutine;
DWORD FastPebUnlockRoutine; //PPEBLOCKROUTINE FastPebUnlockRoutine;
ULONG EnvironmentUpdateCount;
PPVOID KernelCallbackTable;
PVOID EventLogSection;
PVOID EventLog;
DWORD FreeList; //PPEB_FREE_BLOCK FreeList;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[0x2];
PVOID ReadOnlySharedMemoryBase;
PVOID ReadOnlySharedMemoryHeap;
PPVOID ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
BYTE Spare2[0x4];
LARGE_INTEGER CriticalSectionTimeout;
ULONG HeapSegmentReserve;
ULONG HeapSegmentCommit;
ULONG HeapDeCommitTotalFreeThreshold;
ULONG HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PPVOID *ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
PVOID GdiDCAttributeList;
PVOID LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
ULONG OSBuildNumber;
ULONG OSPlatformId;
ULONG ImageSubSystem;
ULONG ImageSubSystemMajorVersion;
ULONG ImageSubSystemMinorVersion;
ULONG GdiHandleBuffer[0x22];
ULONG PostProcessInitRoutine;
ULONG TlsExpansionBitmap;
BYTE TlsExpansionBitmapBits[0x80];
ULONG SessionId;
} PEB, *PPEB;
typedef struct _PROCESS_BASIC_INFORMATION {
long ExitStatus;
PPEB PebBaseAddress;
unsigned long AffinityMask;
long BasePriority;
unsigned long UniqueProcessId;
unsigned long InheritedFromUniqueProcessId;
}PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
typedef enum _PROCESSINFOCLASS {
ProcessBasicInformation = 0
} PROCESSINFOCLASS;
typedef ULONG (NTAPI *NTQUERYINFORMATIONPROCESS)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
HANDLE GetProcessHandle(wchar_t *ProcessName, ULONG *ReturnedProcessId); //lol still using toohelp to get the processid and handle
BOOL GetProcessPEB(HANDLE hProcess, PPEB pPeb);
BOOL GetProcessLoaderData(HANDLE hProcess, PEB peb, PPEB_LDR_DATA pPebLdrData);
ULONG GetModuleBaseEx(wchar_t *ModuleName, HANDLE hProcess);
|
In the source file (.cpp)
Code: |
BOOL GetProcessPEB(HANDLE hProcess, PPEB pPeb)
{
SetLastError(0);
NTQUERYINFORMATIONPROCESS NtQueryInformationProcess = 0;
PROCESS_BASIC_INFORMATION pbi = {0};
NTSTATUS NtStatus;
ULONG dwLength;
HMODULE NtDll;
NtDll = GetModuleHandleA("ntdll.dll");
if(!NtDll) return 0;
NtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)GetProcAddress(NtDll, "NtQueryInformationProcess");
if(!NtQueryInformationProcess) return 0;
NtStatus = NtQueryInformationProcess(hProcess, ProcessBasicInformation, (PVOID)&pbi, sizeof(PROCESS_BASIC_INFORMATION), &dwLength);
if(NtStatus != 0) return 0; //0 == STATUS_SUCCESS
ULONG dwBytesRead = 0;
if(!ReadProcessMemory(hProcess, pbi.PebBaseAddress, pPeb, sizeof(PEB), &dwBytesRead) || dwBytesRead < sizeof(PEB)) return 0;
//Successfully Got PEB!
return 1;
}
BOOL GetProcessLoaderData(HANDLE hProcess, PEB peb, PPEB_LDR_DATA pPebLdrData)
{
ULONG dwBytesRead = 0;
if(!ReadProcessMemory(hProcess, peb.LoaderData, pPebLdrData, sizeof(PEB_LDR_DATA), &dwBytesRead) || dwBytesRead < sizeof(PEB_LDR_DATA)) return 0;
return 1;
}
ULONG GetModuleBaseEx(wchar_t *ModuleName, HANDLE hProcess)
{
LDR_DATA_TABLE_ENTRY LoaderTable;
PLIST_ENTRY pCurrentList = 0, pStart = 0;
PEB ThePeb;
PEB_LDR_DATA PebLoaderData;
if(!GetProcessPEB(hProcess, &ThePeb)) return 0;
if(!GetProcessLoaderData(hProcess, ThePeb, &PebLoaderData)) return 0;
pStart = PebLoaderData.InLoadOrderModuleList.Blink;
pCurrentList = PebLoaderData.InLoadOrderModuleList.Flink;
wchar_t *RemoteModuleName = 0;
while(pCurrentList != pStart) //It's a doublely linked list
{
if(!ReadProcessMemory(hProcess, pCurrentList, &LoaderTable, sizeof(LDR_DATA_TABLE_ENTRY), 0)) return 0;
RemoteModuleName = new wchar_t[LoaderTable.BaseModuleName.Length+1];
ZeroMemory(RemoteModuleName, LoaderTable.BaseModuleName.Length+1);
if(!ReadProcessMemory(hProcess, LoaderTable.BaseModuleName.Buffer, RemoteModuleName, LoaderTable.BaseModuleName.Length, 0))
{
VirtualFree(RemoteModuleName, 0, MEM_RELEASE);
return 0;
}
if(!ModuleName || _wcsicmp(ModuleName, RemoteModuleName) == 0)
{
delete[] RemoteModuleName;
return (ULONG)LoaderTable.ModuleBase;
}
delete[] RemoteModuleName;
pCurrentList = LoaderTable.InLoadOrderLinks.Flink;
}
return 0;
}
|
Then where you're writing your code, usage is similar:
Code: |
ULONG RemoteProcessId = 0;
HANDLE RemoteProcessHandle = GetProcessHandle(L"Crysis3.exe", &RemoteProcessId);
ULONG EXEBaseFromPEB = GetModuleBaseEx(0, RemoteProcessHandle); //Will get Crysis3.exe's base address
//Gets the base address of the dll named 'WhateverTheDllIsCalled.dll'
ULONG DLLBaseFromPEB = GetModuleBaseEx(L"WhateverTheDllIsCalled.dll", RemoteProcessHandle);
printf("Remote EXE Base From PEB: %p; Remote Module: %08x", EXEBaseFromPEB, DLLBaseFromPEB);
|
Now it's probably better to use the toolhelp APIs or some other documented way... as it isn't depending on those structures being exactly the same in every version of windows as this is here, but these in particular don't really change very often so it's still pretty safe to use. If you did want to use some undocumented way of doing things and wanted to be safer about it you could just not even use defined structures! The just wouldn't look as pretty but you would have offsets into structures and sizes of structures defined for different versions of windows and play around with them in the code to get what you needed...
Man I guess I can't just explain something simply can I!! lol That's enough for now...
_________________
|
|
Back to top |
|
 |
dreamlane How do I cheat?
Reputation: 0
Joined: 13 Mar 2013 Posts: 3 Location: United States
|
Posted: Thu Mar 14, 2013 4:16 pm Post subject: |
|
|
Excellent answer SteveAndrew. If this were StackOverflow, you'd have earned yourself some points.
Thank you for taking the time to explain both the high level and low level parts!
|
|
Back to top |
|
 |
Crashix How do I cheat?
Reputation: 0
Joined: 10 Dec 2013 Posts: 1
|
Posted: Tue Dec 10, 2013 8:41 am Post subject: |
|
|
Thank you Steve Andrew and dreamlane this post really helped me =)
But i have one problem since a long time with this base adress! and i just registered to tell you that...
Your code below seems to work only for 32bit process and dll...
When i try to execute your code with 64bit process it didn't work and he send me a base adress of 0.
I know that CreateToolhelp32Snapshot( work only for 32bit. So, is there a way to make it work with 64 bit ? or am i missing something ?
thanks in advance =)
|
|
Back to top |
|
 |
Dark Byte Site Admin
Reputation: 470
Joined: 09 May 2003 Posts: 25796 Location: The netherlands
|
Posted: Tue Dec 10, 2013 9:00 am Post subject: |
|
|
Also or in
TH32CS_SNAPMODULE32 to createtoolhelp32snapshof
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|