Modifying the stack on Windows, TIB and exceptions - c++

The origin of my question effectively stems from wanting to provide an implementation of pthreads on Windows which supports user provide stacks. Specifically, pthread_attr_setstack should do something meaningful. My actual requirements are a bit more involved than this but this is good enough for the purpose of the post.
There are no public Win APIs for providing a stack in either the Fiber or Thread APIs. I've searched around for sneaky backdoors, workarounds and hacks, there's nothing going. In fact, I looked that the winpthread source for inspiration and that ignores any stack provided to pthread_attr_setstack.
Instead I tried the following "solution" to see if it would work. I create a Fiber using the usual combination of ConvertThreadToFiber, CreateFiberEx and SwitchToFiber. In CreateFiberEx I provide a minimal stack size. In the entry point of the fibre I then allocate memory for a stack, change the TIB fields: "Stack Base" and "Stack Limit" appropriately (see here: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block) and then set ESP to the high address of my stack.
(In a real world case I would setup the stack better than this and change EIP as well so that this step behaves more like the posix funciton swapcontext, but you get the idea).
If I make any OS calls when on this different stack then I'm pretty much screwed (printf for example dies). However this isn't an issue for me. I can ensure that I never make sure calls when on my custom stack (hence why I said my actual requirements are a bit more involved). Except...I need exceptions to work. And they don't! Specifically, if I try to throw and catch an exception on my modified stack then I get an assert
Unhandled exception at 0xXXXXXXXX ....
So my (vague) question is, does anyone have any insight as to how exceptions and a custom stack might not be playing nicely together? I appreciate that this is totally unsupported and can happily except nil response or "go away". In fact, I've pretty much decided that I need a different solution and, despite this involving compromise, I'm likely to use one. However, curiosity gets the better of me so I'd like to know why this doesn't work.
On a related note, I wondered how Cygwin dealt with this for ucontext. The source here http://szupervigyor.ddsi.hu/source/in/openjdk-6-6b18-1.8.13/cacao-0.99.4/src/vm/jit/i386/cygwin/ucontext.c uses GetThreadContext/SetThreadContext to implement ucontext. However, from experimentation I see that this also fails when an exception is thrown from inside a new context. In fact the SetThreadContext call doesn't even update the TIB block!
EDIT (based on the answer from #avakar)
The following code, which is very similar to yours, demonstrates the same failure. The difference is that I don't start the second thread suspended but suspend it then try to change context. This code exhibits the error I was describing when the try-catch block is hit in foo. Perhaps this simply isn't legal. One notable thing is that in this situation the ExceptionList member of the TIB is a valid pointer when modifyThreadContext is called, whereas in your example it's -1. Manually editing this doesn't help.
As mentioned in my comment to your answer. This isn't precisely what I need. I would like to switch contexts from the thread I'm current on. However, the docs for SetThreadContext warn not to call this on an active thread. So I'm guessing that if the below code doesn't work then I have no chance of making it work on a single thread.
namespace
{
HANDLE ghSemaphore = 0;
void foo()
{
try
{
throw 6;
}
catch(...){}
ExitThread(0);
}
void modifyThreadContext(HANDLE thread)
{
typedef NTSTATUS WINAPI NtQueryInformationThread_t(HANDLE ThreadHandle, DWORD ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);
HMODULE hNtdll = LoadLibraryW(L"ntdll.dll");
auto NtQueryInformationThread = (NtQueryInformationThread_t *)GetProcAddress(hNtdll, "NtQueryInformationThread");
DWORD stackSize = 1024 * 1024;
void * mystack = VirtualAlloc(0, stackSize, MEM_COMMIT, PAGE_READWRITE);
DWORD threadInfo[7];
NtQueryInformationThread(thread, 0, threadInfo, sizeof threadInfo, 0);
NT_TIB * tib = (NT_TIB *)threadInfo[1];
CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_ALL;
GetThreadContext(thread, &ctx);
ctx.Esp = (DWORD)mystack + stackSize - ((DWORD)tib->StackBase - ctx.Esp);
ctx.Eip = (DWORD)&foo;
tib->StackBase = (PVOID)((DWORD)mystack + stackSize);
tib->StackLimit = (PVOID)((DWORD)mystack);
SetThreadContext(thread, &ctx);
}
DWORD CALLBACK threadMain(LPVOID)
{
ReleaseSemaphore(ghSemaphore, 1, NULL);
while (1)
Sleep(10000);
// Never gets here
return 1;
}
} // namespace
int main()
{
ghSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
HANDLE th = CreateThread(0, 0, threadMain, 0, 0, 0);
while (WaitForSingleObject(ghSemaphore, INFINITE) != WAIT_OBJECT_0);
SuspendThread(th);
modifyThreadContext(th);
ResumeThread(th);
while (WaitForSingleObject(th, 10) != WAIT_OBJECT_0);
return 0;
}

Both exceptions and printf work for me, and I don't see why they shouldn't. If you post your code, we can try to pinpoint what's going on.
#include <windows.h>
#include <stdio.h>
DWORD CALLBACK ThreadProc(LPVOID)
{
try
{
throw 1;
}
catch (int i)
{
printf("%d\n", i);
}
return 0;
}
typedef NTSTATUS WINAPI NtQueryInformationThread_t(HANDLE ThreadHandle, DWORD ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength, PULONG ReturnLength);
int main()
{
HMODULE hNtdll = LoadLibraryW(L"ntdll.dll");
auto NtQueryInformationThread = (NtQueryInformationThread_t *)GetProcAddress(hNtdll, "NtQueryInformationThread");
DWORD stackSize = 1024 * 1024;
void * mystack = VirtualAlloc(0, stackSize, MEM_COMMIT, PAGE_READWRITE);
DWORD dwThreadId;
HANDLE hThread = CreateThread(0, 0, &ThreadProc, 0, CREATE_SUSPENDED, &dwThreadId);
DWORD threadInfo[7];
NtQueryInformationThread(hThread, 0, threadInfo, sizeof threadInfo, 0);
NT_TIB * tib = (NT_TIB *)threadInfo[1];
CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_ALL;
GetThreadContext(hThread, &ctx);
ctx.Esp = (DWORD)mystack + stackSize - ((DWORD)tib->StackBase - ctx.Esp);
tib->StackBase = (PVOID)((DWORD)mystack + stackSize);
tib->StackLimit = (PVOID)((DWORD)mystack);
SetThreadContext(hThread, &ctx);
ResumeThread(hThread);
WaitForSingleObject(hThread, INFINITE);
}

Related

Resize a memory mapped file on windows without invalidating pointers

I would like to resize a memory mapped file on windows, without invalidating the pointer retrieved from a previous call to MapViewOfFileEx. This way, all pointers to any file data that are stored throughout the application are not invalidated by the resize operation.
I found a solution for the problem but im not sure whether this approach is actually guaranteed to work in all cases.
This is my approach:
I reserve a large memory region with VirtualAlloc:
reserved_pages_ptr = (char*)VirtualAlloc(nullptr, MAX_FILE_SIZE, MEM_RESERVE, PAGE_NOACCESS);
base_address = reserved_pages_ptr;
Every time the memory map is resized, I close the old file mapping, release the reserved pages and reserve the rest pages, that are not needed for the current size of the file:
filemapping_handle = CreateFileMappingW(...);
SYSTEM_INFO info;
GetSystemInfo(&info);
const DWORD page_size = info.dwAllocationGranularity;
const DWORD pages_needed = file_size / page_size + size_t(file_size % page_size != 0);
// release reserved pages:
VirtualFree(reserved_pages_ptr, 0, MEM_RELEASE);
// reserve rest pages:
reserved_pages_ptr = (char*)VirtualAlloc(
base_address + pages_needed * page_size,
MAX_FILE_SIZE - pages_needed * page_size,
MEM_RESERVE, PAGE_NOACCESS
);
if(reserved_pages_ptr != base_address + pages_needed * page_size)
{
//I hope this never happens...
}
Then i can map the view with MapViewOfFileEx:
data_ = (char*)MapViewOfFileEx(filemapping_handle, ... , base_address);
if (data_ != base_address)
{
//I hope this also never happens...
}
Is this approach stable enough to guarantee, that the potential problems never occur?
Do I need any synchronization to avoid problems with multithreading?
EDIT: I know that the most stable approach would be to change the rest of the application to allow invalidating all the file data pointers, but this solution could be an easy approach that mirrors the behavior of mmap on Linux.
The solution depends on whether you use file mapping object is backed by the operating system paging file (the hFile parameter is INVALID_HANDLE_VALUE), or by some file on disk.
In this case, you use file mapping object is backed by the operating system paging file, you need use the SEC_RESERVE flag:
specifies that when a view of the file is mapped into a process
address space, the entire range of pages is reserved for later use by
the process rather than committed. Reserved pages can be committed to
subsequent calls to the VirtualAlloc function. After the pages are
committed, they cannot be freed or decommitted with the VirtualFree
function.
The code can look like:
#define MAX_FILE_SIZE 0x10000000
void ExtendInMemorySection()
{
if (HANDLE hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0,
PAGE_READWRITE|SEC_RESERVE, 0, MAX_FILE_SIZE, NULL))
{
PVOID pv = MapViewOfFile(hSection, FILE_MAP_WRITE, 0, 0, 0);
CloseHandle(hSection);
if (pv)
{
SYSTEM_INFO info;
GetSystemInfo(&info);
PBYTE pb = (PBYTE)pv;
int n = MAX_FILE_SIZE / info.dwPageSize;
do
{
if (!VirtualAlloc(pb, info.dwPageSize, MEM_COMMIT, PAGE_READWRITE))
{
break;
}
pb += info.dwPageSize;
} while (--n);
UnmapViewOfFile(pv);
}
}
}
But from SEC_RESERVE
This attribute has no effect for file mapping objects that are backed
by executable image files or data files (the hfile parameter is a
handle to a file).
For this (and only this) case exists undocumented API:
NTSYSCALLAPI
NTSTATUS
NTAPI
NtExtendSection(
_In_ HANDLE SectionHandle,
_Inout_ PLARGE_INTEGER NewSectionSize
);
This API lets you extend section size (and backed file). Also, SectionHandle must have SECTION_EXTEND_SIZE access right in this case, but CreateFileMapping creates a section handle without this access. So we need use only NtCreateSection here, then we need use ZwMapViewOfSection api with AllocationType = MEM_RESERVE and ViewSize = MAX_FILE_SIZE - this reserve ViewSize region of memory but not commit it, but after calling NtExtendSection the valid data (commit pages) in view will be auto extended.
Before win 8.1, the MapViewOfFile not such functionality for the pass MEM_RESERVE allocation type to ZwMapViewOfSection, but begin from win 8 (or 8.1) exist undocumented flag FILE_MAP_RESERVE which let do this.
In general, demonstration code can look like:
#define MAX_FILE_SIZE 0x10000000
void ExtendFileSection()
{
HANDLE hFile = CreateFile(L"d:/ee.tmp", GENERIC_ALL, 0, 0, CREATE_ALWAYS, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
HANDLE hSection;
SYSTEM_INFO info;
GetSystemInfo(&info);
// initially only 1 page in the file
LARGE_INTEGER SectionSize = { info.dwPageSize };
NTSTATUS status = NtCreateSection(&hSection,
SECTION_EXTEND_SIZE|SECTION_MAP_READ|SECTION_MAP_WRITE, 0,
&SectionSize, PAGE_READWRITE, SEC_COMMIT, hFile);
CloseHandle(hFile);
if (0 <= status)
{
PVOID BaseAddress = 0;
SIZE_T ViewSize = MAX_FILE_SIZE;
//MapViewOfFile(hSection, FILE_MAP_WRITE|FILE_MAP_RESERVE, 0, 0, MAX_FILE_SIZE);
status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0,
&ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE);
if (0 <= status)
{
SIZE_T n = MAX_FILE_SIZE / info.dwPageSize - 1;
do
{
SectionSize.QuadPart += info.dwPageSize;
if (0 > NtExtendSection(hSection, &SectionSize))
{
break;
}
} while (--n);
UnmapViewOfFile(BaseAddress);
}
CloseHandle(hSection);
}
}
}

64-bit Code Cave Returning Incorrect Entry Point Location

I have been attempting to run a 64-bit DLL purely in a processes virtual memory without 'manually mapping' it (i.e. manually resolving relocations/imports).
The plan was to inject code into the target application and load the module via conventional means, such as LoadLibrary.
I was under the assumption LoadLibrary would fix the module relocations/imports on it's own, as that's what it is designed to do.
After loading the module, the injected code would obtain information regarding the module with GetModuleInformation, transfer it to a temporary memory buffer, free the module, allocate memory at the same address it was originally loaded at, write it back, and execute the entry point.
That last step is where I believe the error is occurring.
In order to test this theory, I have hard-coding entry point addresses, debugged the remote application via Visual Studio's 'Attach to Process' feature, emulated a similar environment to correct bad pointer arithmetic, all in order to gain a bit more information on what the error might be.
Here is some general information which may or may not be useful:
Both applications (the injector, and DLL) are compiled to run in 64-bit architectures
The test application I have been using to test the injection method is the windows update applicaiton (wuauclt.exe - located in /System32/), it is of course compiled to run as a 64-bit PE
Host machine: Windows 7 Home Premium (system type: 64-bit operating system)
As far as information relating directly to the injector goes:
The primary code injection method works (as far as I can tell), and I have proven this via caveman debugging with MessageBoxA
The project is using a multi-byte character set with code optimizations disabled. The code was compiled using VS 2013 Ultimate (both projects built for Release x64)
SDL checks are off since unsafe functions are used (strcpy and friends)
The injector is debugged with elevated privileges (as high as SE_DEBUG_PRIVILEGES) every time its ran.
Code Preface:
The code exhibited below is not in any which way meant to look pretty or exhibit good programming practices. Keep this in mind when viewing the code. It was specifically designed to test a code-injection method to verify it works. If you have issues with the program layout, structure, etc, feel free to correct them and/or restructure them on your own. It's not the reason I'm here. Unless it is what resulted in the error, then it is entirely the reason I'm here :)
The code for the injector: http://pastebin.com/FF5G9nnR
/*
Some of the code was truncated (functions not pertaining to the injection), but
I have verified the code compiles and works correctly with it's injeteme.dll counterpart
*/
#include <Windows.h>
#include <Psapi.h>
#define TARGET_PID 1124
typedef BOOL(WINAPI* pFreeLibrary)(HMODULE);
typedef HMODULE(WINAPI* pLoadLibraryA)(LPCSTR);
typedef HANDLE(WINAPI* pGetCurrentProcess)(void);
typedef BOOL(WINAPI* DLL_MAIN)(HMODULE, DWORD, LPVOID);
typedef HANDLE(WINAPI* pOpenProcess)(DWORD, BOOL, DWORD);
typedef BOOL(WINAPI* pVirtualFree)(LPVOID, SIZE_T, DWORD);
typedef int(__stdcall* pMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
typedef LPVOID(WINAPI* pVirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD);
typedef BOOL(WINAPI* pGetModuleInformation)(HANDLE, HMODULE, LPMODULEINFO, DWORD);
typedef BOOL(WINAPI* pWriteProcessMemory)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*);
//////////////////////////////////////////////////////////////////
struct IINFO
{
LPVOID stubAddr;
LPVOID retStatusPtr;
char fullModulePath[MAX_PATH];
DWORD pId, sizeOfCurrStruct;
// DEBUG
pMessageBoxA messageBox;
pOpenProcess openProcess;
pVirtualFree virtualFree;
pFreeLibrary freeLibrary;
pLoadLibraryA loadLibrary;
pVirtualAlloc virtualAlloc;
pGetCurrentProcess getCurrProc;
pWriteProcessMemory writeMemory;
pGetModuleInformation getModInfo;
};
static DWORD WINAPI stub(IINFO *iInfo)
{
HMODULE hMod;
MODULEINFO mInfo;
DLL_MAIN dllMain;
LPVOID lpNewMod, lpTempModBuff;
PIMAGE_DOS_HEADER pIDH;
PIMAGE_NT_HEADERS pINH;
iInfo->messageBox(NULL, iInfo->fullModulePath, NULL, 0);
hMod = iInfo->loadLibrary(iInfo->fullModulePath);
if (!hMod)
return 0;
if (!iInfo->getModInfo(iInfo->getCurrProc(), hMod, &mInfo, sizeof(MODULEINFO)))
return 0;
lpTempModBuff = iInfo->virtualAlloc(NULL, mInfo.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpTempModBuff)
return 0;
if (!iInfo->writeMemory(iInfo->getCurrProc(), lpTempModBuff, mInfo.lpBaseOfDll, mInfo.SizeOfImage, NULL))
return 0;
if (!iInfo->freeLibrary(hMod))
return 0;
lpNewMod = iInfo->virtualAlloc(mInfo.lpBaseOfDll, mInfo.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpNewMod)
return 0;
// using wpm since we have already acquired the function
if (!iInfo->writeMemory(iInfo->getCurrProc(), lpNewMod, lpTempModBuff, mInfo.SizeOfImage, NULL))
return 0;
if (!iInfo->virtualFree(lpTempModBuff, 0, MEM_RELEASE))
return 0;
/*if (!iInfo->virtualFree(iInfo, 0, MEM_RELEASE))
return 0;
iInfo->messageBox(NULL, NULL, NULL, 0); */
pIDH = (PIMAGE_DOS_HEADER)lpNewMod;
if (!pIDH)
return 0;
pINH = (PIMAGE_NT_HEADERS)((LPBYTE)lpNewMod + pIDH->e_lfanew);
if (!pINH)
return 0;
dllMain = (DLL_MAIN)((LPBYTE)lpNewMod + pINH->OptionalHeader.AddressOfEntryPoint);
if (!dllMain)
return 0;
iInfo->messageBox(NULL, NULL, NULL, 0);
dllMain((HINSTANCE)lpNewMod, DLL_PROCESS_ATTACH, NULL);
return 1;
}
static DWORD WINAPI stubEnd(){ return 0; }
//////////////////////////////////////////////////////////////////
int main()
{
HANDLE hThread = 0;
DWORD dwStubSize = 0;
int sucResp = 0, count = 0;
HMODULE hUser32 = 0, hNtdll = 0;
char fullPathName[] = "C:\\injectme.dll";
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, TARGET_PID);
if (!hProc || hProc == INVALID_HANDLE_VALUE)
return 0;
__int64 SizeOfStub = (LPBYTE)stubEnd - (LPBYTE)stub;
LPVOID lpStub = VirtualAllocEx(hProc, NULL, SizeOfStub, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpStub)
return 0;
hUser32 = LoadLibraryA("user32.dll");
if (!hUser32)
return 0;
hNtdll = LoadLibraryA("kernel32.dll");
if (!hNtdll)
return 0;
IINFO iInfo = {};
iInfo.retStatusPtr = &sucResp;
strcpy(iInfo.fullModulePath, fullPathName);
iInfo.sizeOfCurrStruct = sizeof(IINFO);
iInfo.stubAddr = lpStub;
iInfo.pId = GetCurrentProcessId();
iInfo.messageBox = (pMessageBoxA)GetProcAddress(hUser32, "MessageBoxA");
iInfo.openProcess = (pOpenProcess)GetProcAddress(hNtdll, "OpenProcess");
iInfo.virtualFree = (pVirtualFree)GetProcAddress(hNtdll, "VirtualFree");
iInfo.freeLibrary = (pFreeLibrary)GetProcAddress(hNtdll, "FreeLibrary");
iInfo.loadLibrary = (pLoadLibraryA)GetProcAddress(hNtdll, "LoadLibraryA");
iInfo.virtualAlloc = (pVirtualAlloc)GetProcAddress(hNtdll, "VirtualAlloc");
iInfo.getCurrProc = (pGetCurrentProcess)GetProcAddress(hNtdll, "GetCurrentProcess");
iInfo.writeMemory = (pWriteProcessMemory)GetProcAddress(hNtdll, "WriteProcessMemory");
iInfo.getModInfo = (pGetModuleInformation)GetProcAddress(hNtdll, "K32GetModuleInformation");
LPVOID lpStubInfo = VirtualAllocEx(hProc, NULL, sizeof(IINFO), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpStubInfo)
return 0;
if (!WriteProcessMemory(hProc, lpStub, stub, SizeOfStub, NULL))
return 0;
if (!WriteProcessMemory(hProc, lpStubInfo, &iInfo, sizeof(iInfo), NULL))
return 0;
hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpStub, lpStubInfo, 0, NULL);
if (!hThread || hThread == INVALID_HANDLE_VALUE)
return 0;
WaitForSingleObject(hThread, INFINITE);
return 1;
}
The code for the DLL to be injected: http://pastebin.com/8WXxcpu1
#include <Windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpParam)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
MessageBoxA(NULL, "Hello from injectme.dll!", "", MB_OK | MB_ICONINFORMATION);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
The error when running the code above verbatim (assuming you also applied the settings above and have a similar environment) in VS2013's debugger is as follows:
"Unhandled exception at 0x000007FEEA5125D4 in wuauclt.exe: 0xC0000005: Access violation executing location 0x000007FEEA5125D4."
Upon viewing the process "wuauclt.exe" in Process Hacker, I can clearly see the module was allocated originally (upon being loaded via LoadLibrary) at 0x7fef67c0000. This is shown in the context menu->under miscellaneous->unloaded modules.
Once double-clicking "wuauclt.exe", you can browse over the application's virtual memory to ensure everything is working as it should be. I can confirm for this current session, an RWX memory buffer has been allocated at 0x7fef67c0000 with the exact size of the unloaded module, containing the injectme.dll module. When digging into injectme.dll with CFF Explorer, then entry point RVA seems to be 0x132C, which does not add up, considering the error is much further away in memory. Additionally, I can verify two more RWX memory buffers containing the code injection stub, and information structure. Looking back the information structure probably doesn't need RWX. Anyway, I can't for the life of me figure out the error.
I'm hoping one you may be able to assist me. I am extremely grateful for your time.
My gut feeling is that you're lacking the fundamental understanding for such a challenging project. You're mixing concepts from rather distinct realms.
Windows itself cares very, very little about the programming language you used in development. Either you get CLR code (.Net) or native code. In this case it's x64. But Windows really doesn't care about strcpy or SDL checks. That's for the compiler to deal with, not the OS. Chances are strcpy wouldn't even survive, when its code is fully inlined. But you apparently have optimizations turned off, for some strange reason - again a compiler versus OS confusion.
However, Windows does care about other concepts that you don't mention. Chiefly those would be ASLR and DEP - Address Space Layout Randomization and Data Execution Prevention. They're techniques to keep hackers out, and you're hacking. So that's not really a surprise.
I'm not sure if by "RWX" you mean Read Write Execute" because you should know that's asking for problems. DEP is inspired by the more aptly named W^X, Write XOR eXecute.
The more likely culprit is ASLR, though. Windows by design tries to load DLL's at unpredicatble addresses, as that eliminates an entire class of hacks. It appears you're assuming a load address, while Windows really is using another address.
A final mistake might be that you're failing to understand where the relocations are done. To improve the amount of shareable pages, relocations are done on the Import Address Table, not the code itself. The IAT is a trampoline table, and therefore executable. Your failure might also be a missing IAT.

Stack Corruption With SetupDiXxx structures

I am having some trouble with the structures used to obtain device information. From what I understand it is somewhat tricky to set the cbSize correctly, and thus the API is writing data beyond where it is supposed to (causing the stack corruption). So far I have the following code:
GUID guid;
HidD_GetHidGuid(&guid);
HDEVINFO info;
info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
SP_DEVINFO_DATA DeviceInfoData;
memset(&DeviceInfoData, 0, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
int deviceIndex = 0;
while (SetupDiEnumDeviceInfo(info, deviceIndex++, &DeviceInfoData))
{
SP_INTERFACE_DEVICE_DATA data;
data.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
int interfaceIndex = 0;
while (SetupDiEnumDeviceInterfaces(info, &DeviceInfoData, &guid, interfaceIndex++, &data))
{
//https://msdn.microsoft.com/en-us/library/windows/hardware/ff551120%28v=vs.85%29.aspx
//Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with a NULLDeviceInterfaceDetailData pointer,
//a DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize variable. In response to such a call, this function
//returns the required buffer size at RequiredSize and fails with GetLastError returning ERROR_INSUFFICIENT_BUFFER.
SP_DEVICE_INTERFACE_DETAIL_DATA interfaceData;
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
DWORD bufferSize = 0;
SetupDiGetDeviceInterfaceDetail(info, &data, NULL, 0, &bufferSize, nullptr);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
//Call the function again
SetupDiGetDeviceInterfaceDetail(info, &data, &interfaceData, bufferSize, NULL, &DeviceInfoData);
DWORD error = GetLastError();
if (error != ERROR_SUCCESS)
{
printf("Could not obtain device interface details. Error: %d \n", error);
}
}
}
The error which I get is:
Run-Time Check Failure #2 - Stack around the variable 'DeviceInfoData' was corrupted.
though I have seen SP_INTERFACE_DEVICE_DATA and SP_DEVICE_INTERFACE_DETAIL_DATA cause the same error
Any help is greatly appreciated!
It looks like your interfaceData buffer is too small.
Check the documentation for the DeviceInterfaceDetailData argument to SetupDiGetDeviceInterfaceDetail again.
If you want to get more info about driver development, I recommend the book USB Complete. I fixed the issue based on their explanation. The issue is as follows:
First, get the buffer size:
SetupDiGetDeviceInterfaceDetail(info, &data, NULL, 0, &bufferSize, nullptr);
Then, allocate the PSP_DEVICE_INTERFACE_DETAIL_DATA structure manually using malloc based on the size that was returned:
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceData;
interfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
notice the P in front of PSP_DEVICE_INTERFACE_DETAIL_DATA. This is Microsofts semantics for this API. It stands for pointer; something really easy to miss when looking at the documentation (if you also miss the ->)
The SetupDiGetDeviceInterfaceDetail function returns the size of the entire structure, so you need to allocate it to that size. I've seen examples that attempt to increment size until the error goes away. That approach is wrong... for alot of reasons. Obtain the size from SetupDiGetDeviceInterfaceDetail and then allocate the entire PSP_DEVICE_INTERFACE_DETAIL_DATA memory block based on that size. Don't forget to set cbSize to the size of the struct SP_DEVICE_INTERFACE_DETAIL_DATA
Once again, pay attention to the P in the naming conventions because it's easy to get the sizeof(PSP_DEVICE_INTERFACE_DETAIL_DATA) by mistake.

WIN API ReadFile() returns GetLastError() ERROR_INVALID_PARAMETER

I wrote this code below and it worked fine under code::blocks using mingw gcc 4.7 to compile it. I have since decided to start using Visual Studio 2013 express. Now I am getting an error when ReadFile() is called. Which seems to be an invalid parameter. I can't see the error hoping someone here can spot it.
This is all wrapped inside a class Serial. From what I can see in the IDE the memory reference for m_hSerial is correct when compared to the reference CreateFile() returns to the handle.
m_hSerial = CreateFile(m_pchPort,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
I call the WorkThread like so
m_hThread = (HANDLE)_beginthreadex(0, 0, &WorkThread, (void*) this, 0, 0);
Here is the WorkThread code
unsigned int __stdcall Serial::WorkThread(void* pvParam)
{
// This is a pointer to the 'this' serial class.
// Needed to be able to set members of the class in a static class function
Serial * cThis = (Serial*) pvParam;
// Set up the overlapped event
OVERLAPPED ov;
memset(&ov, 0, sizeof(ov));
ov.hEvent = CreateEvent(0, true, 0, 0);
DWORD dwEventMask = 0;
DWORD dwWait;
HANDLE aHandles[2];
aHandles[0] = cThis->m_hThreadTerminator;
aHandles[1] = ov.hEvent;
SetEvent(cThis->m_hThreadRunning);
while (true)
{
if (!WaitCommEvent(cThis->m_hSerial, &dwEventMask, &ov))
{
assert(GetLastError() == ERROR_IO_PENDING);
}
dwWait = WaitForMultipleObjects(2, aHandles, FALSE, INFINITE);
switch(dwWait)
{
case WAIT_OBJECT_0:
{
_endthreadex(1);
}
case WAIT_OBJECT_0 + 1:
{
if (dwEventMask & EV_TXEMPTY)
{
ResetEvent(ov.hEvent);
}
else if (dwEventMask & EV_RXCHAR)
{
// read data here
DWORD dwBytesRead = 0;
DWORD dwErrors;
COMSTAT cStat;
OVERLAPPED ovRead;
ovRead.hEvent = CreateEvent(0, true, 0, 0);
// Get the Bytes in queue
ClearCommError(cThis->m_hSerial, &dwErrors, &cStat);
DWORD nSize = cStat.cbInQue;
// EM_REPLACESEL needs a LPARAM null terminated string, make room and set the CString NULL
char *szBuf = new char[nSize+1];
memset(szBuf, 0x00, sizeof(szBuf));
if (!ReadFile(cThis->m_hSerial, &szBuf, nSize, &dwBytesRead, &ovRead))
DWORD err = GetLastError();
if (dwBytesRead == nSize)
SendMessage(cThis->m_hHwnd, WM_SERIAL, 0, LPARAM(&szBuf));
CloseHandle(ovRead.hEvent); // clean up!!!
delete[] szBuf;
}
// Reset the overlapped event
ResetEvent(ov.hEvent);
}
break;
}//switch
}
return 0;
}
ReadFile(cThis->m_hSerial, &szBuf, nSize, &dwBytesRead, &ovRead)
You are asking for an asynchronous operation, but also asking the function to tell you how many bytes have been read. You passed &dwBytesRead as the penultimate parameter. When you are performing overlapped reading, pass NULL for this parameter. The documentation says:
Use NULL for this parameter if this is an asynchronous operation to avoid potentially erroneous results.
It is also a mistake to pass &szBuf in the code above. You mean to pass szBuf.
You also fail to initialize the OVERLAPPED struct. Do so like this:
OVERLAPPED ovRead = {};
A bigger problem is that you ask for asynchronous access, but then write the code as it it were synchronous. As soon as ReadFile returns you attempt to get meaningful information out of dwBytesRead and you close the event that you put in the overlapped struct.
If you are really going code this asynchronously, you need to re-write the code to be asynchronous. On the face of it, it looks as though you have not fully understood the implications of overlapped I/O and you should perhaps switch to non-overlapped, synchronous I/O.

c++ Run-Time Check Failure #0 - The value of ESP was not properly saved across ... Points to check for simple worker thread

I have a dialog. in this dialog ::OnInitDialog() I create a thread AfxBeginThread((AFX_THREADPROC)MyThreadProc, NULL); It crashes when I close the dialog with run time check failure, and it is pointing to thrdcore.cpp file (Microsoft Foundation Classes C++ library)
// first -- check for simple worker thread
DWORD nResult = 0;
if (pThread->m_pfnThreadProc != NULL)
{
nResult = (*pThread->m_pfnThreadProc)(pThread->m_pThreadParams);
ASSERT_VALID(pThread);
}
I have a code to kill the thread OnClose function, but it doesn't solve the issue. Can some help, what I am missing? My code for
HANDLE m_hExit;
DWORD dwResult = 0;
unsigned threadID = 0;
...
OnInitDialog()
{...
m_hExit = (HANDLE)AfxBeginThread((AFX_THREADPROC)MyThreadProc, NULL);
}
OnClose()
{
dwResult = WaitForSingleObject(m_hExit, 0);
if (dwResult == WAIT_TIMEOUT)
{
printf("The thread is still running...\n");
}
else
{
printf("The thread is no longer running...\n");
}
Sleep(10000);
dwResult = WaitForSingleObject(m_hExit, 0);
if (dwResult == WAIT_TIMEOUT)
{
printf("The thread is still running...\n");
}
else
{
printf("The thread is no longer running...\n");
}
CDialog::OnClose();
}
thread function is very big((((
AfxBeginThread is documented as requiring the threadproc to be
UINT __cdecl MyControllingFunction( LPVOID pParam );
Your comment says your function is
UINT WINAPI MyThreadProc( LPVOID pParam )
WINAPI is defined as _stdcall (see here)
So you have a mismatch of calling conventions. As others already commented, the cast is suspicious. In fact, that's the only reason your code is compiling. If you remove the cast, the compiler should show an error.
The solution is to remove the cast and then fix the calling convention of your function. Once that code compiles correctly without the cast, it should run properly without corrupting the stack.