CasualX / pelite

Lightweight, memory-safe, zero-allocation library for reading and navigating PE binaries.
MIT License
280 stars 42 forks source link

Incorrect module base address used for PE32 mapped images using ASLR #266

Closed tremwil closed 1 year ago

tremwil commented 1 year ago

When Windows maps a PE32+ executable in memory and ASLR is enabled, OptionalHeader.ImageBase is relocated to the virtual address at which the image is loaded. However, this does not happen for PE32 executables (at least under WoW64); OptionalHeader.ImageBase is still the preferred virtual address. Hence when creating a Pe object via PeView::module, for example, the Pe methods that perform VA to RVA translation using this value may end up reading unnacessible or out-of-bounds memory.

I have encountered this issue while trying to use the provided pe32::msvc RTTI structs to extract class names and virtual function tables from a loaded DLL in the same 32-bit process, as these structs have Ptr<T> fields (whose values have been adjusted by the OS due to ASLR).

EDIT: After more testing, it appears that OptionalHeader.ImageBase is normally relocated for 32-bit DLLs as well. I checked a couple 32-bit DLLs but only the one I was initially working with, steamclient.dll from Steam, had this weird behaviour. After inspecting steam_api.dll, which is responsible for loading steamclient.dll, it does so by using a call to LoadLibraryEx with only the LOAD_WITH_ALTERED_SEARCH_PATH flag set. I doubt this should affect how the ImageBase value behaves under ASLR, but did not find any difference in the DLL's headers that should do so either.