So I am writing my very first trainer for Microsoft's Spider Solitaire. First I needed to backwards-engineer all memory adresses until I found a static one. I used offsets so I can easily revert them back.
I've found this:
1000157F78 <-- starting value(never changes)
+ E8 <-- offsets to pointers
+ 14
002DC3D4 <-- final adress(changes every time)
This is how my trainer gets his final memory address:
DWORD FindFinalAddr(HANDLE hProc, BYTE offsets[], DWORD baseAddress, unsigned char pointerLevel)
{
DWORD pointer = baseAddress;
DWORD pTemp = 0;
DWORD pointerAddr = 0;
// set base address
ReadProcessMemory(hProc, (LPCVOID)pointer, &pTemp, (DWORD)sizeof(pTemp), NULL);
for (int c = 0; c < pointerLevel; c++)
{
pointerAddr = pTemp + (DWORD)offsets[c];
ReadProcessMemory(hProc, (LPCVOID)pointerAddr, &pTemp, (DWORD)sizeof(pTemp), NULL);
}
return pointerAddr;
}
In this case, I do(roughly) this: FindFinalAddr(hProc, {0xE8, 0x14}, 0x1000157F78, 2);
This works fine when Spider Solitaire is open and I have just found the static value.
But when I close it and re-open it's no longer valid.
I found out that 1000157F78 is actually SpiderSolitaire.exe+B5F78 It's like a offset. If I enter this in cheat engine I get the right memory address, but I can't just simply enter it in my code.
Now is my question: How do I convert SpiderSolitaire.exe+B5F78 to the right memory adress?
Note: SpiderSolitaire.exe is 64 bit.
EDIT:
I've tried the following:
void * entryPoint = (void*) hProc;
DWORD base_addr = ((DWORD)(entryPoint) + 0xB5F78);
But that doesn't work, because the entry point is 5C. The adress it should give(in this session) is FF7A5F78, but what really happens is 5C + B5F78 = B5F4D.
I think you can query the load address using GetModuleInformation, passing NULL for the module handle parameter. If that doesn't work, you can take the longer route through EnumProcessModules and GetModuleBaseName.
After a long period of research I've found my own answer!
This piece of code gets the module base address(AKA entry point)(you need to include TlHelp32.h and tchar.h):
DWORD getModuleBaseAddr(DWORD procId, TCHAR * lpszModuleName)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, procId);
DWORD moduleBaseAddr = 0;
if (hSnapshot != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 mentry32 = { 0 };
mentry32.dwSize = sizeof(MODULEENTRY32);
if (Module32First(hSnapshot, &mentry32))
{
do
{
if (_tcscmp(mentry32.szModule, lpszModuleName) == 0)
{
moduleBaseAddr = (DWORD)mentry32.modBaseAddr;
break;
}
} while (Module32Next(hSnapshot, &mentry32));
}
}
else
{
std::cout << "Error on finding module base address: " << GetLastError() << "\n";
}
return moduleBaseAddr;
}
You give it the pid and the name of the module(like game.exe), then it browses through modules and check if they are the same, and then it returns the base address.
Now, I tested this with Spider Solitaire. It gave me an error.
That is because my compiled code was 32 bit and SpiderSolitaire.exe was 64 bit, which was caused because my Windows 7 was 64 bit.
So make sure your code has the same platform target as the code you're aiming for!
Related
I wanted to load a Windows PE file (a.k.a. EXE) from a memory buffer in C++ so I found this code. Using a simple hello world example, it works fine. However, when loading a more sophisticated EXE with static dependencies the code crashes instead of loading the PE file successfully. My updated PE loader code is the following:
#include <Windows.h>
#include <stdexcept>
inline auto fix_image_iat(PIMAGE_DOS_HEADER dos_header, PIMAGE_NT_HEADERS nt_header)
{
auto import_table = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].
VirtualAddress + reinterpret_cast<UINT_PTR>(dos_header));
const DWORD iat_loc = nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress ?
IMAGE_DIRECTORY_ENTRY_IAT : IMAGE_DIRECTORY_ENTRY_IMPORT;
const DWORD iat_rva = nt_header->OptionalHeader.DataDirectory[iat_loc].VirtualAddress;
const SIZE_T iat_size = nt_header->OptionalHeader.DataDirectory[iat_loc].Size;
const auto iat = reinterpret_cast<LPVOID>(iat_rva + reinterpret_cast<UINT_PTR>(dos_header));
DWORD op;
VirtualProtect(iat, iat_size, PAGE_READWRITE, &op);
PIMAGE_THUNK_DATA thunk;
while (import_table->Name)
{
const auto import_base = LoadLibraryA(
reinterpret_cast<LPCSTR>(import_table->Name + reinterpret_cast<UINT_PTR>(dos_header)));
auto fix_up = reinterpret_cast<PIMAGE_THUNK_DATA>(import_table->FirstThunk + reinterpret_cast<UINT_PTR>(
dos_header));
if (import_table->OriginalFirstThunk)
{
thunk = reinterpret_cast<PIMAGE_THUNK_DATA>(import_table->OriginalFirstThunk + reinterpret_cast<UINT_PTR>(dos_header));
}
else
{
thunk = reinterpret_cast<PIMAGE_THUNK_DATA>(import_table->FirstThunk + reinterpret_cast<UINT_PTR>(dos_header));
}
while (thunk->u1.Function)
{
if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
{
fix_up->u1.Function =
reinterpret_cast<UINT_PTR>(GetProcAddress(import_base, reinterpret_cast<LPCSTR>(thunk->u1.Ordinal & 0xFFFF)));
}
else
{
const PCHAR func_name = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(thunk->u1.AddressOfData)->Name + reinterpret_cast<
UINT_PTR>(dos_header);
fix_up->u1.Function = reinterpret_cast<UINT_PTR>(GetProcAddress(import_base, func_name));
}
fix_up++;
thunk++;
}
import_table++;
}
}
inline auto map_image_to_memory(const char* pe_buffer)
{
auto raw_image_base = PIMAGE_DOS_HEADER(pe_buffer);
if (IMAGE_DOS_SIGNATURE != raw_image_base->e_magic)
{
throw std::runtime_error(("Invalid DOS signature"));
}
auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>(raw_image_base->e_lfanew + reinterpret_cast<UINT_PTR>(raw_image_base));
if (IMAGE_NT_SIGNATURE != nt_header->Signature)
{
throw std::runtime_error(("Invalid NT header"));
}
if (IMAGE_FILE_MACHINE_AMD64 != nt_header->FileHeader.Machine)
{
throw std::runtime_error(("Not a 64-bit module"));
}
if (nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress)
{
throw std::runtime_error((".NET is not supported"));
}
auto section_header = reinterpret_cast<PIMAGE_SECTION_HEADER>(raw_image_base->e_lfanew + sizeof * nt_header
+ reinterpret_cast<UINT_PTR>(raw_image_base));
auto mem_image_base = VirtualAlloc(reinterpret_cast<LPVOID>(nt_header->OptionalHeader.ImageBase),
nt_header->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (mem_image_base == nullptr)
{
throw std::runtime_error(("VirtualAlloc() failed"));
}
memcpy(mem_image_base, raw_image_base, nt_header->OptionalHeader.SizeOfHeaders);
for (WORD section_index = 0; section_index < nt_header->FileHeader.NumberOfSections; section_index++)
{
memcpy(reinterpret_cast<LPVOID>(section_header->VirtualAddress + reinterpret_cast<UINT_PTR>(mem_image_base)),
reinterpret_cast<LPVOID>(section_header->PointerToRawData + reinterpret_cast<UINT_PTR>(raw_image_base)),
section_header->SizeOfRawData);
section_header++;
}
return static_cast<PIMAGE_DOS_HEADER>(mem_image_base);
}
//works with manually mapped files
HANDLE GetImageActCtx(HMODULE module)
{
WCHAR temp_path[MAX_PATH];
WCHAR temp_filename[MAX_PATH];
for (int i = 1; i <= 3; i++) {
HRSRC resource_info = FindResource(module, MAKEINTRESOURCE(i), RT_MANIFEST);
if (resource_info) {
HGLOBAL resource = LoadResource(module, resource_info);
DWORD resource_size = SizeofResource(module, resource_info);
const PBYTE resource_data = (const PBYTE)LockResource(resource);
if (resource_data && resource_size) {
FILE* fp;
errno_t err;
DWORD ret_val = GetTempPath(MAX_PATH, temp_path);
if (0 == GetTempFileName(temp_path, L"manifest.tmp", 0, temp_filename))
return NULL;
err = _wfopen_s(&fp, temp_filename, L"w");
if (errno)
return NULL;
fprintf(fp, (const char *)resource_data);
fclose(fp);
break;
}
else {
return NULL;
}
}
}
ACTCTXW act = { sizeof(act) };
act.lpSource = temp_filename;
return CreateActCtx(&act);
}
BOOL FixImageRelocations(PIMAGE_DOS_HEADER dos_header, PIMAGE_NT_HEADERS nt_header, ULONG_PTR delta)
{
ULONG_PTR size;
PULONG_PTR intruction;
PIMAGE_BASE_RELOCATION reloc_block =
(PIMAGE_BASE_RELOCATION)(nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress +
(UINT_PTR)dos_header);
while (reloc_block->VirtualAddress) {
size = (reloc_block->SizeOfBlock - sizeof(reloc_block)) / sizeof(WORD);
PWORD fixup = (PWORD)((ULONG_PTR)reloc_block + sizeof(reloc_block));
for (int i = 0; i < size; i++, fixup++) {
if (IMAGE_REL_BASED_DIR64 == *fixup >> 12) {
intruction = (PULONG_PTR)(reloc_block->VirtualAddress + (ULONG_PTR)dos_header + (*fixup & 0xfff));
*intruction += delta;
}
}
reloc_block = (PIMAGE_BASE_RELOCATION)(reloc_block->SizeOfBlock + (ULONG_PTR)reloc_block);
}
return TRUE;
}
void load_portable_executable(const char* pe_buffer)
{
const auto dos_header = map_image_to_memory(pe_buffer);
auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>(dos_header->e_lfanew + reinterpret_cast<UINT_PTR>(dos_header));
HANDLE actctx = NULL;
UINT_PTR cookie = 0;
BOOL changed_ctx = FALSE;
if (nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) {
actctx = GetImageActCtx(reinterpret_cast<HMODULE>(dos_header));
if (actctx)
changed_ctx = ActivateActCtx(actctx, &cookie);
}
fix_image_iat(dos_header, nt_header);
if (nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) {
ptrdiff_t delta = (ptrdiff_t)((PBYTE)dos_header - (PBYTE)nt_header->OptionalHeader.ImageBase);
if (delta)
FixImageRelocations(dos_header, nt_header, delta);
}
// Calculate the absolute entry point address
const auto entry_point_address = reinterpret_cast<LPVOID>(nt_header->OptionalHeader.AddressOfEntryPoint + reinterpret_cast<UINT_PTR>(dos_header));
// Launch the PE file
static_cast<void(*)()>(entry_point_address)(); // TODO Crashes here
}
Note that C++20 is required to successfully compile.
Any idea why it crashes at the last line of code when passing control to the entry point address? Is there any library or clean reference implementation for PE loading (on Windows)?
I am doing a similar thing, loading an exe file (with LoadLibraryEx flag LOAD_IGNORE_CODE_AUTHZ_LEVEL) into the address space of the loading application. In this way I can observe all the activities of the program from its inception.
The steps are:
LoadLibrary, and if successful then
Patch the IAT
Get the address of entry-point of the loaded program
CreateThread, CREATE_SUSPENDED with the thread-start-address being the address of entry-point.
ResumeThread and off she goes.
So far there are 2 types of files that can be loaded, those with relocation table and those without. The ones with the relocation table are the modern ones compiled with /DynamicBase and the older ones do not have this information.
I compiled the loader to have fixed-base address way above the default 0x140000000 for x64 to ensure that there is ample space below it for loaded exes that have no relocation and have to be loaded at the default address.
The OS loader applies relocation fixups but does not fix import addresses which we have to do manually.
Any dll we load to fix the imports need no further cooking as the OS loader takes care of that.
Now just like the experience BullyWiiPlaza had I found some programs can be loaded and run perfectly yet many others crash on startup. And the annoying feature that when you exit your loaded program it tends to take with it the loading application on its way out.
To fix this I intercepted the CRT functions abort, _cexit, _c_exit and the kernel ExitProcess
and just the sheer virtue of using these functions enables the loaded program to go out alone but I use the opportunity to UnregisterClass in case I have to re-load the previous not so well written app.
Remember the RegisterClass function can fail with an error message ERROR_CLASS_ALREADY_EXISTS which isn't a sufficient reason to abort the application.
Another important function to intercept is GetModuleHandle because when the loaded app uses this function as GetModuleHandle(0) to query its base address then without intercepting it and returning its hModule the OS will give it the Loader's base address which will cause a crash.
What I find confusing is that some lost versions of my applications could load apps that have no relocation info and run successfully but after ceaseless tweaking I could no longer run them.
The problem appears to be write access violation.
So I checked the protection parameters given to VirtualProtect and found from this following code that the iat_size is small and does not include the thunk I wish modify.
DWORD iat_loc = (nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress)
? IMAGE_DIRECTORY_ENTRY_IAT : IMAGE_DIRECTORY_ENTRY_IMPORT;
UINT_PTR iat_rva = nt_header->OptionalHeader.DataDirectory[iat_loc].VirtualAddress;
SIZE_T iat_size = nt_header->OptionalHeader.DataDirectory[iat_loc].Size;
LPVOID iat = (LPVOID)(iat_rva + (UINT_PTR)dos_header);
DWORD op;
VirtualProtect(iat, iat_size, PAGE_READWRITE, &op);
If anyone wants to recreate the problem then the specimen I used was Celemony Melodyne 5.
It does not have a relocation table and loads at address 0x140000000.
What is confusing is that other x64 applications such as DarkWave Studio run normally except it takes out the loader when it exits.
And by the way Microsoft has made a fine mess of the pragmas data_seg and data_section with respect to x64 altho they claim it works in the documentation.
Quick summary
In a nut shell i wish to access the debug information regarding the stack, preferably for passing information to Logger.
I wish for the information to tell me the Function Name, Line Number and File Name.
I've got the symbols and i'm attempting to access the junk values in them and turn them in to English. However nothing seems to work.
I have commented the code for people to read and see if they can help me effectively walk the stack to pull the information out i need.
So far i can point out SymGetModuleBase() does not return a positive number only 0, according to MSDN it fails if returns 0. Which is correct as it returns a memory address.
SymGetSymFromAddr() fails to return true, which i'm assuming gets the name of the stack frame/function
SymGetLineFromAddr() goes on to fail as well and doesn't return the line number location in the file and also doesn't gather the file path.
I believe this is due to the process parameter being invalid. I will elaborate below.
Attempts to locate and fix the problem
I have read the MSDN documentation repeatedly and feel like i'm banging my head off the wall, i've done pretty much what it said and i feel like it's just not working.
However i have noticed SymInitialize() should be called prior to attempting this, which i do call. This changed the GetLastError() value from 6 ERROR_INVALID_HANDLE to 0 ERROR_SUCCESS. Yet SymGetModuleBase() still returns 0 no matter if SymInitialize() although GetLastError() reports different error codes depending on SymInitialize() use. It should return a valid virtual memory address this is where i think the main problem lies in the code.
HANDLE process = ::GetCurrentProcess(); this line in the code below returns 0xffffffffffffffff very suspect if you ask me. This should return a pseudo virtual memory address but it to me anyway looks like a false result. This happens every time i run the program which leads me to think ::GetCurrentProcess() this is either got a bug, or doesn't work somehow. According to MSDN this is the correct a up to date way of getting the current process and i don't know how to get a valid HANDLE to a the process another way. So i can't pass the first parameter in SymGetModuleBase() the correct process, although i maybe wrong.
Full code for the function
void Logger::WriteStackFrames(log::TextColor tc)
{
// Initalize some memory
DWORD machine = IMAGE_FILE_MACHINE_AMD64;
HANDLE process = ::GetCurrentProcess();
HANDLE thread = GetCurrentThread();
// Initalize more memory
CONTEXT context;
STACKFRAME stack_frame;
// Set some memory
memset(&context, 0, sizeof(CONTEXT));
memset(&stack_frame, 0, sizeof(STACKFRAME));
// Capture the context
RtlCaptureContext(&context);
// Initalize a few things here and there
stack_frame.AddrPC.Offset = context.Rip;
stack_frame.AddrPC.Mode = AddrModeFlat;
stack_frame.AddrStack.Offset = context.Rsp;
stack_frame.AddrStack.Mode = AddrModeFlat;
stack_frame.AddrFrame.Offset = context.Rbp;
stack_frame.AddrFrame.Mode = AddrModeFlat;
// Randomly saw this was supposed to be called prior to StackWalk so tried it
if (!SymInitialize(process, 0, false))
{
wprintf(L"SymInitialize unable to find process!! Error: %d\r\n", GetLastError());
}
for (ULONG frame = 0; ; frame++)
{
// Set text color
SetTextColor(tc);
// Check for frames
BOOL result = StackWalk(machine, process, thread, &stack_frame, &context, 0,
SymFunctionTableAccess, SymGetModuleBase, 0);
// Get memory address of base module. Returns 0 although when SymInitialize is called before it the GetLastError returns 0 without return 6
DWORD64 module_base = SymGetModuleBase(process, stack_frame.AddrPC.Offset);
if (module_base == 0) {
wprintf(L"SymGetModuleBase is unable to get virutal address!! Error: %d\r\n", GetLastError());
}
// Initalize more memory
MODULEINFO module_info;
SecureZeroMemory(&module_info, sizeof(MODULEINFO));
// Get the file name of the file containing the function
TCHAR module_buffer[log::MaxPath];
DWORD mod_file = GetModuleFileName((HINSTANCE)module_base, module_buffer, log::MaxPath);
if ((module_base != 0) && (mod_file != 0))
{
module_info.module_name = module_buffer;
}
// Initalize more memory and clear it out
PIMAGEHLP_SYMBOL64 symbol;
IMAGEHLP_LINE64 line_num;
SecureZeroMemory(&symbol, sizeof(PIMAGEHLP_SYMBOL64));
SecureZeroMemory(&symbol, sizeof(IMAGEHLP_LINE64));
// Get the symbol
TCHAR symbol_buffer[log::MaxPath];
symbol = (PIMAGEHLP_SYMBOL)symbol_buffer;
symbol->SizeOfStruct = (sizeof(IMAGEHLP_SYMBOL) + log::MaxPath);
symbol->MaxNameLength = 254;
// Attempt to get name from symbol (fails)
LPSTR name_buffer = new CHAR[254];
if (SymGetSymFromAddr(process, stack_frame.AddrPC.Offset, 0, symbol))
{
name_buffer = symbol->Name;
}
// Set the size of something
DWORD offset = 0;
line_num.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
// Attempt to get the line and file name of where the symbol is
if (SymGetLineFromAddr(process, stack_frame.AddrPC.Offset, &offset, &line_num))
{
module_info.line = line_num.LineNumber;
module_info.file = line_num.FileName;
}
// Initalize memory
LPWSTR console_message = new TCHAR[log::MaxMsgLength];
LPWSTR file_message = new TCHAR[log::MaxMsgLength];
// Set some strings
swprintf(console_message, log::MaxMsgLength, L">> Frame %02lu: called from: %016X Stack: %016X Frame: %016X Address return: %016X\r\n",
frame, stack_frame.AddrPC.Offset, stack_frame.AddrStack.Offset, stack_frame.AddrFrame.Offset, stack_frame.AddrReturn.Offset);
swprintf(file_message, log::MaxMsgLength, L"Frame %02lu: called from: %016X Stack: %016X Frame: %016X Address return: %016X\r\n",
frame, stack_frame.AddrPC.Offset, stack_frame.AddrStack.Offset, stack_frame.AddrFrame.Offset, stack_frame.AddrReturn.Offset);
/* When the symbol can yield the name, line and file name the above strings
will also include that information */
// To go here . . .
// Write some strings
wprintf(console_message);
WriteAsync(file_message);
// Delete some memory
if (console_message) {
delete[] console_message; console_message = nullptr;
}
if (file_message) {
delete[] file_message; file_message = nullptr;
}
// If nothing else to do break loop
if (!result) {
break;
}
}
}
What i hope to achieve
Although i realize this will only work in debug mode that is fine, and i know i could write a macro using the __LINE__ __FUNCTION__ __FILE__ macros but that isn't what i'm looking for.
The results should be a wind up from the bottom stack showing the memory addresses of the calling PC, stack and frame. This works.
However it should also show me which the Name of the function, the Line number and the File path. This doesn't work.
FYI: I realize i need to add the code in to the generate the string and output it, but the code isn't capable of getting the information for the strings so that isn't coded in yet.
Please if anyone can help me, it would be fantastic all the code is focused around the "DbgHelp.h" windows file and most information is available on MSDN. So for the long question but i felt i should provide everything i know.
::GetCurrentProcess() = 0xffffffffffffffff
is not suspicious.
I tried a few variations on your code pulling bits from here and there - in the end I could not get it to work as I was using clang/mingw and it was not generating .pdb files. However, maybe the code will work for you as you are using MSVC. Anyway, here it is, in case it helps
I also noticed you hard coded machine type to AMD - I assume that is correct for you, but below I have an ifdef I found that sets it for other archs.
#include <windows.h>
#include <excpt.h>
#include <imagehlp.h>
#include <binutils/bfd.h>
#include <psapi.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdbool.h>
#include <psapi.h>
#include <dbghelp.h>
#define MAX_SYMBOL_LEN 1024
typedef struct CallstackEntry
{
DWORD64 offset; // if 0, we have no valid entry
CHAR name[MAX_SYMBOL_LEN];
CHAR undName[MAX_SYMBOL_LEN];
CHAR undFullName[MAX_SYMBOL_LEN];
DWORD64 offsetFromSmybol;
DWORD offsetFromLine;
DWORD lineNumber;
CHAR lineFileName[MAX_SYMBOL_LEN];
DWORD symType;
LPCSTR symTypeString;
CHAR moduleName[MAX_SYMBOL_LEN];
DWORD64 baseOfImage;
CHAR loadedImageName[MAX_SYMBOL_LEN];
} CallstackEntry;
typedef enum CallstackEntryType
{
firstEntry,
nextEntry,
lastEntry
} CallstackEntryType;
void _backtrace (void)
{
HANDLE process = ::GetCurrentProcess();
HANDLE thread = GetCurrentThread();
if (!SymInitialize(process, 0, true)) {
wprintf(L"SymInitialize unable to find process!! Error: %d\r\n",~
GetLastError());
}
DWORD symOptions = SymGetOptions();
symOptions |= SYMOPT_LOAD_LINES;
symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
symOptions = SymSetOptions(symOptions);
char szSearchPath[MAX_SYMBOL_LEN] = {0};
SymGetSearchPath(process, szSearchPath, MAX_SYMBOL_LEN);
char szUserName[MAX_SYMBOL_LEN] = {0};
DWORD dwSize = MAX_SYMBOL_LEN;
GetUserNameA(szUserName, &dwSize);
CHAR search_path_debug[MAX_SYMBOL_LEN];
size_t maxLen = MAX_SYMBOL_LEN;
#if _MSC_VER >= 1400
maxLen = _TRUNCATE;
#endif
_snprintf_s(search_path_debug, maxLen,~
"SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n",
szSearchPath, symOptions, szUserName);
search_path_debug[MAX_SYMBOL_LEN - 1] = 0;
printf(search_path_debug);
// Initalize more memory
CONTEXT context;
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
// Initalize a few things here and there
STACKFRAME stack;
memset(&stack, 0, sizeof(STACKFRAME));
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat;
#ifdef _M_IX86
auto machine = IMAGE_FILE_MACHINE_I386;
#elif _M_X64
auto machine = IMAGE_FILE_MACHINE_AMD64;
#elif _M_IA64
auto machine = IMAGE_FILE_MACHINE_IA64;
#else
#error "platform not supported!"
#endif
for (ULONG frame = 0; ; frame++) {
BOOL result = StackWalk(machine,~
process,~
thread,~
&stack,
&context,
0,
SymFunctionTableAccess,~
SymGetModuleBase,~
0);
CallstackEntry csEntry;
csEntry.offset = stack.AddrPC.Offset;
csEntry.name[0] = 0;
csEntry.undName[0] = 0;
csEntry.undFullName[0] = 0;
csEntry.offsetFromSmybol = 0;
csEntry.offsetFromLine = 0;
csEntry.lineFileName[0] = 0;
csEntry.lineNumber = 0;
csEntry.loadedImageName[0] = 0;
csEntry.moduleName[0] = 0;
IMAGEHLP_SYMBOL64 symbol {};
symbol.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbol.MaxNameLength = MAX_SYMBOL_LEN;
// Initalize more memory and clear it out
if (SymGetSymFromAddr64(process,~
stack.AddrPC.Offset,
&csEntry.offsetFromSmybol,~
&symbol)) {
}
IMAGEHLP_LINE64 line {};
line.SizeOfStruct = sizeof(line);
if (SymGetLineFromAddr64(process,~
stack.AddrPC.Offset,
&csEntry.offsetFromLine,~
&line)) {
}
printf("Frame %lu:\n"
" Symbol name: %s\n"
" PC address: 0x%08LX\n"
" Stack address: 0x%08LX\n"
" Frame address: 0x%08LX\n"
"\n",
frame,
symbol.Name,
(ULONG64)stack.AddrPC.Offset,
(ULONG64)stack.AddrStack.Offset,
(ULONG64)stack.AddrFrame.Offset
);
// If nothing else to do break loop
if (!result) {
break;
}
}
}
I am running a simple app and trying to read a specific offset within it's memory using Window's PSAPI.
when I run my debugger, I get the real value of the memory address, and the relative one to my ".exe" entry point.
yet, when I run the following code, the base module I get as an entry point together with my offset yields a different address(it's wrong, and off by a few (hexa)demical points).
what might be the problem?
ReadMemory is a template for ReadProcessMemory
HWND WINDOW_HANDLE;
HANDLE PROC_HANDLE;
DWORD PROC_ID;
DWORD address;
SIZE_T bytesRead;
int InitReadMemory(const char* windowClass,const char* caption, DWORD addressOffset)
{
DWORD cbNeeded;
DWORD dwdResult;
HMODULE mainModule;
BOOL enumResult;
//Get the window handle
WINDOW_HANDLE = FindWindow(windowClass, NULL);
if(WINDOW_HANDLE == NULL)
{
//Window was not foud
return 10;
}
//Get the process ID
dwdResult = GetWindowThreadProcessId(WINDOW_HANDLE, &PROC_ID);
if(dwdResult==0)
{
//Getting Process ID failed
return 20;
}
//Open the process
PROC_HANDLE = OpenProcess(PROCESS_ALL_ACCESS, false, PROC_ID);
if(PROC_HANDLE==NULL)
{
//Process failed to open
return 30;
}
/*
*Get the Main Module-
*first entry in the returned HMODULE array from
*EnumProcessModules
*/
enumResult = EnumProcessModules(PROC_HANDLE, &mainModule, sizeof(HMODULE), &cbNeeded);
if(enumResult != 0)
{
//Failed enumerating process modules
return 40;
}
//offset the requested memory address from the application's base address
address = (DWORD)((UINT_PTR)mainModule + addressOffset);
#ifdef DEBUG
using namespace std;
char filenameBuffer[64]="";
string number;
stringstream stristream;
stristream << address;
stristream >> number;
cout << number << "\r\n" << endl;
GetModuleFileNameEx(PROC_HANDLE, mainModule , filenameBuffer, 256);
cout << (byte)ReadMemory<byte>() << "\r\n" << number << "\r\n" << filenameBuffer << endl;
system("PAUSE");
#endif
return 1;}
thank you in advance :)
P.S. I'm mostly just looking for pointers ...
bah dum tsss
Update:
apparently, checking for GetLastError value, EnumProcessModules prompts a 299 error code after it is done. and debugging shows that mainModule holds nothing... yet EnumProcessModules returns 0 as in "no errors".
yesterday, I managed to get it AND get GetModuleFileName to work propery(same code, only added GetLastError).
Apparently, my problem was that I was running the tests with the snippet
enumResult = EnumProcessModules(PROC_HANDLE, &mainModule, sizeof(HMODULE), &cbNeeded)
if(enumResult != 0)
{
//Failed enumerating process modules
return 40;
}
and a successful run of EnumProcessModules yields a nonzero result! (thus causing me some confusion and faulted my whole debugging process)
after I figured this detail out, I ran some old tests again and found out that my target process is 64 bit, while I was running a 32 bit application.
changed to 64bit and now it works like a charm
The title explains my goal very well, it should be simple but my solution just doesn't seem to be functioning properly. Currently, the function always returns NULL. When I use another program to locate the string and manually point memcmp to it, it returns 0 as it should.
DWORD findString(const char *input)
{
DWORD address;
size_t length = strlen(input);
DWORD baseAddress = (DWORD)GetModuleHandle(NULL);
DWORD maxAddress = (baseAddress + 26480640)-length;//the large # is the approximate size of the base module of the executable
for (address = baseAddress; address < maxAddress; address++)
{
if (memcmp(input, (void *)address, length) == 0)
{
return address;
}
}
OutputDebugStringA("String not found!");
return NULL;
}
I'm making a Pixel-Cheat for a game. The program only works for 64bit currently and I'm trying to compile for 32bit.
I tried many ways of finding base address of process, but to no avail. Only the 64bit function works, and it will create a 64bit program.
Here's my 64bit working function:
DWORD64 GetModuleBase(HANDLE hProc, string &sModuleName)
{
HMODULE *hModules;
char szBuf[50];
DWORD cModules;
DWORD64 dwBase = -1;
//------
EnumProcessModulesEx(hProc, hModules, 0, &cModules, LIST_MODULES_ALL);
hModules = new HMODULE[cModules/sizeof(HMODULE)];
if(EnumProcessModulesEx(hProc, hModules,
cModules/sizeof(HMODULE), &cModules, LIST_MODULES_ALL)) {
for(int i = 0; i < cModules/sizeof(HMODULE); i++) {
if(GetModuleBaseName(hProc, hModules[i], szBuf, sizeof(szBuf))) {
if(sModuleName.compare(szBuf) == 0) {
dwBase = (DWORD64)hModules[i];
break;
}
}
}
}
delete[] hModules;
return dwBase;
}
All 32bit functions on google fails, with error:
21 59 C:\Users\Administrator\Documents\main.cpp [Error] cast from 'BYTE* {aka unsigned char*}' to 'DWORD {aka long unsigned int}' loses precision [-fpermissive]
How to get this code work in 32bit?
DWORD64 GetModuleBase(HANDLE hProc, string &sModuleName)
{
HMODULE *hModules;
char szBuf[50];
DWORD cModules;
DWORD64 dwBase = -1;
//------
EnumProcessModulesEx(hProc, NULL, 0, &cModules, LIST_MODULES_ALL);
hModules = new HMODULE[cModules/sizeof(HMODULE)];
if(EnumProcessModulesEx(hProc, hModules,
cModules/sizeof(HMODULE), &cModules, LIST_MODULES_ALL)) {
for(unsigned int i = 0; i < cModules/sizeof(HMODULE); i++) {
if(GetModuleBaseName(hProc, hModules[i], szBuf, sizeof(szBuf))) {
if(sModuleName.compare(szBuf) == 0) {
dwBase = (DWORD64)hModules[i];
break;
}
}
}
}
delete[] hModules;
return dwBase;
}
Your function as it stood compiled just fine in a 32bit exe on my machine with a few warnings which I corrected in the snippet above.
A few things you may want to do, is make sure your compiler is set to run in Multi-Byte Character Mode, and not Unicode if you're going to pass an 8bit char array(szBuf) to the function, otherwise use a 16bit wchar array. Also you passed hModules to EnumProcessModulesEx() on the first call which was where you were to get the number of modules, that would have generated an error since it has not yet been allocated, pass NULL on the first call to get the number of modules, then pass hModules.
Alas, the code should compile and run fine, but next time use GetModuleHandle() as mentioned before, will save you a headache.