Loading a 64-bit Windows PE file from memory - c++

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.

Related

Stackwalk get Function Name, Line number and File Name, in debug

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;
}
}
}

Ejecting dll by calling CreateRemoteThread : crash

I am trying to make for myself a tool for extracting/releasing dlls from processes. I have already experienced with LoadLibrary and injecting but this time the logic doesn't seem to apply.
This is my code:
HMODULE findModuleOffset(HANDLE proc, char *mod_name) {
//Finds module address in specified process. 0 if not found
HMODULE hMods[2048];
DWORD modules_byte_size;
if (EnumProcessModules(proc, hMods, sizeof(hMods), &modules_byte_size))
{
for (unsigned long i = 0; i < (modules_byte_size / sizeof(HMODULE)); i++) {
CHAR module_name[MAX_PATH];
// Get the full path to the module's file.
if (GetModuleFileNameExA(proc, hMods[i], module_name, sizeof(module_name))) {
if (strcmp(strrchr(module_name,'.')+1,"exe")!=0 && compareExeName(module_name, mod_name)) {
return hMods[i];
}
}
}
}
return 0;
}
bool compareExeName(char *path, char *partial_name) {
//This will substract the filename from path and compare it with partial_name
char *lastSlash = strrchr(path, '\\') + 1;
if (lastSlash != NULL && strstr(lastSlash, partial_name) == lastSlash) return 1;
return 0;
}
void unload_all_dll(char *dll_name) {
DWORD process_ids[2048];
DWORD process_byte_size; //size of filled process_ids in BYTES (after the call)
DWORD process_count; //count of all elements in process_ids
HMODULE ext_dll_module;
HANDLE opened_process;
HANDLE Hthread;
DWORD thread_exit_code = 1;
CHAR exe_path[1024];
if (EnumProcesses(process_ids, sizeof(process_ids), &process_byte_size)) {
process_count = process_byte_size / sizeof(DWORD);
for (int i = 0; i < process_count; i++) {
thread_exit_code = 0;
if ((opened_process = OpenProcess(PROCESS_ALL_ACCESS, false, process_ids[i])) == NULL) continue;
GetModuleFileNameExA(opened_process, 0, exe_path, MAX_PATH);
if ((ext_dll_module = findModuleOffset(opened_process, dll_name)) != 0) {
while (thread_exit_code == 0) {
if ((Hthread = CreateRemoteThread(opened_process, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("kernel32.dll"), "FreeLibrary"), (void*)ext_dll_module, 0, NULL)) == NULL) {
cout<<"Process closed meanwhile or dll unloaded";
break; //process has closed meanwhile
}
while (WaitForSingleObject(Hthread, 1000) == WAIT_TIMEOUT);
GetExitCodeThread(Hthread, &thread_exit_code);
}
cout << "Dll unloaded from " << exe_path << endl;
}
}
}
}
Warning:some variables names might be confusing(I am in hurry)
But every time I try to eject a dll everything crashes(of course,only the apps that contained the specfied dll). I tested everything I could and everything seems fine: the module address returned by findModuleOffset is good(checked against the value given by process explorer). I have no ideea what the return value of createremotethread or thread_exit_code is because the app crashes(it contasins the dll to be ejected..so...). Can you help me?
(moving from the comments)
Given that there are threads in the target process that are running code from the dll being unloaded, they are going to crash immediately after the dll gets freed - after all, the very pages of code that the CPU is executing are being unmapped!
To avoid the problem, the running threads have to be notified in some way, so they can terminate before unloading the dll; Windows provides many IPC methods, one rarely used is particularly well-fitted for this case, namely mailslots.
When the dll is injected, the "master" thread that gets created will create a mailslot with a well-known name, and periodically check if there's any message for him. When you want to unload the dlls, instead of brutally injecting a thread that forcefully frees the dll, just ask to your "inside man": post a message to the mailslot asking it to terminate1.
The thread will see that there's a message in the mailslot, take care to possibly terminate the other threads that were started inside the target process (a shared atomic variable + WaitForSingleObject can be used) and, when the cleanup is finished, call FreeLibraryAndExitThread to suicide both the last thread and the dll.
Notes
A particularly interesting peculiarity of mailslots is that, if they are created multiple times with the same name, messages sent to such a name will be delivered to all them, so if, as it seems, you want to shut down all the injected dlls at the same time, this greatly simplifies the controlling program - there's not even need to enumerate the running processes.

Converting "application's" memory address

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!

Reading Shared Memory from x86 to x64 and vice versa on OSX

If I create a SM from 64 bit application and open it on 32 bit application it fails.
//for 64 bit
shared_memory_object( create_only, "test" , read_write) ;
// for 32 bit
shared_memory_object (open_only, "test", read_write);
file created by 64bit application is at path as below:
/private/tmp/boost_interprocess/AD21A54E000000000000000000000000/test
where as file searched by 32 bit application is at path
/private/tmp/boost_interprocess/AD21A54E00000000/test
Thus 32 bit applications cannot read the file.
I am using boost 1.47.0 on Mac OS X.
Is it a bug? Do I have to do some settings use some Macros in order to fix it? Has any one encountered this problem before?
Is it important that the shared memory be backed by a file? If not, you might consider using the underlying Unix shared memory APIs: shmget, shmat, shmdt, and shmctl, all declared in sys/shm.h. I have found them to be very easy to use.
// create some shared memory
int id = shmget(0x12345678, 1024 * 1024, IPC_CREAT | 0666);
if (id >= 0)
{
void* p = shmat(id, 0, 0);
if (p != (void*)-1)
{
initialize_shared_memory(p);
// detach from the shared memory when we are done;
// it will still exist, waiting for another process to access it
shmdt(p);
}
else
{
handle_error();
}
}
else
{
handle_error();
}
Another process would use something like this to access the shared memory:
// access the shared memory
int id = shmget(0x12345678, 0, 0);
if (id >= 0)
{
// find out how big it is
struct shmid_ds info = { { 0 } };
if (shmctl(id, IPC_STAT, &info) == 0)
printf("%d bytes of shared memory\n", (int)info.shm_segsz);
else
handle_error();
// get its address
void* p = shmat(id, 0, 0);
if (p != (void*)-1)
{
do_something(p);
// detach from the shared memory; it still exists, but we can't get to it
shmdt(p);
}
else
{
handle_error();
}
}
else
{
handle_error();
}
Then, when all processes are done with the shared memory, use shmctl(id, IPC_RMID, 0) to release it back to the system.
You can use the ipcs and ipcrm tools on the command line to manage shared memory. They are useful for cleaning up mistakes when first writing shared memory code.
All that being said, I am not sure about sharing memory between 32-bit and 64-bit programs. I recommend trying the Unix APIs and if they fail, it probably cannot be done. They are, after all, what Boost uses in its implementation.
I found the solution to the problem and as expected it is a bug.
This Bug is present in tmp_dir_helpers.hpp file.
inline void get_bootstamp(std::string &s, bool add = false)
{
...
std::size_t char_counter = 0;
long fields[2] = { result.tv_sec, result.tv_usec };
for(std::size_t field = 0; field != 2; ++field){
for(std::size_t i = 0; i != sizeof(long); ++i){
const char *ptr = (const char *)&fields[field];
bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4];
bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)];
}
...
}
Where as it should have been some thing like this..
**long long** fields[2] = { result.tv_sec, result.tv_usec };
for(std::size_t field = 0; field != 2; ++field){
for(std::size_t i = 0; i != sizeof(**long long**); ++i)
I have created a ticket in boost for this bug.
Thank you.

How do I read from a version resource in Visual C++

I have a version resource in my resources in a C++ project which contains version number, copyright and build details. Is there an easy way to access this at run-time to populate my help/about dialog as I am currently maintaining seperate const values of this information. Ideally, the solution should work for Windows/CE mobile and earlier versions of Visual C++ (6.0 upwards).
This is an edited version of my original answer.
bool GetProductAndVersion(CStringA & strProductName, CStringA & strProductVersion)
{
// get the filename of the executable containing the version resource
TCHAR szFilename[MAX_PATH + 1] = {0};
if (GetModuleFileName(NULL, szFilename, MAX_PATH) == 0)
{
TRACE("GetModuleFileName failed with error %d\n", GetLastError());
return false;
}
// allocate a block of memory for the version info
DWORD dummy;
DWORD dwSize = GetFileVersionInfoSize(szFilename, &dummy);
if (dwSize == 0)
{
TRACE("GetFileVersionInfoSize failed with error %d\n", GetLastError());
return false;
}
std::vector<BYTE> data(dwSize);
// load the version info
if (!GetFileVersionInfo(szFilename, NULL, dwSize, &data[0]))
{
TRACE("GetFileVersionInfo failed with error %d\n", GetLastError());
return false;
}
// get the name and version strings
LPVOID pvProductName = NULL;
unsigned int iProductNameLen = 0;
LPVOID pvProductVersion = NULL;
unsigned int iProductVersionLen = 0;
// replace "040904e4" with the language ID of your resources
if (!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductName"), &pvProductName, &iProductNameLen) ||
!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen))
{
TRACE("Can't obtain ProductName and ProductVersion from resources\n");
return false;
}
strProductName.SetString((LPCSTR)pvProductName, iProductNameLen);
strProductVersion.SetString((LPCSTR)pvProductVersion, iProductVersionLen);
return true;
}
To get a language independent result to Mark's answer change :
// replace "040904e4" with the language ID of your resources
!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen))
{
TRACE("Can't obtain ProductName and ProductVersion from resources\n");
return false;
}
To
UINT uiVerLen = 0;
VS_FIXEDFILEINFO* pFixedInfo = 0; // pointer to fixed file info structure
// get the fixed file info (language-independent)
if(VerQueryValue(&data[0], TEXT("\\"), (void**)&pFixedInfo, (UINT *)&uiVerLen) == 0)
{
return false;
}
strProductVersion.Format("%u.%u.%u.%u",
HIWORD (pFixedInfo->dwProductVersionMS),
LOWORD (pFixedInfo->dwProductVersionMS),
HIWORD (pFixedInfo->dwProductVersionLS),
LOWORD (pFixedInfo->dwProductVersionLS));
Something like might get you started, perhaps:
TCHAR moduleName[MAX_PATH+1];
(void)GetModuleFileName(AfxGetInstanceHandle(), moduleName, MAX_PATH);
DWORD dummyZero;
DWORD versionSize = GetFileVersionInfoSize(moduleName, &dummyZero);
if(versionSize == 0)
{
return NULL;
}
void* pVersion = malloc(versionSize);
if(pVersion == NULL)
{
return NULL;
}
if(!GetFileVersionInfo(moduleName, NULL, versionSize, pVersion))
{
free(pVersion);
return NULL;
}
UINT length;
VS_FIXEDFILEINFO* pFixInfo;
VERIFY(VerQueryValue(pVersionInfo, const_cast<LPTSTR>("\\"), (LPVOID*)&pFixInfo, &length));
Something like this will give you raw access to the resource data and get you started:
HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(MY_VERSION_ID), RT_VERSION);
DWORD size = ::SizeofResource(NULL, res);
HGLOBAL mem = ::LoadResource(NULL, res);
LPVOID raw_data = ::LockResource(mem);
...
::FreeResource(mem);
Beware!
Using FindResource..LockResource is not correct. It will sometimes work (as it did in my small demo program) and sometimes cause access violations (example: the production code I was making the demo for).
The VerQueryValue() documentation states that you should call GetFileVersionInfoSize and GetFileVersionInfo instead.
Raymond Chen explains, see http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx
Ok, a bit more googleing found the following on CodeGuru. Basically this approach uses the CFileVersionInfo object to get on any given file. It should be interesting to see if it works on the currently running .EXE file and on Windows CE.
Sometimes I receive Access Violation when use VerQueryValueA. But I never got this error when use VerQueryValueW. I think something wrong with VerQueryValueA in version.dll. Therefore I use VerQueryValueW instead of VerQueryValueA even in projects Multi-byte Character Encoding. Here is my code of ReadVersion function