2

Currently we're working on the subject of manually loading DLL in lower 4Gbs of process' virtual address space on x64 platform. It is needed because DLL is written with explicit usage of 32-bit types everywhere and cannot be rewritten. So we are to use this peculiarity in the project and we are to make sure DLL uses only lower 4Gbs to stay workable.

There are some links across the web with implementation of manual DLL loading, we've taken this one as a base: link

This variant works. There are only some issues detected so far:

  1. No debug with sources is possible now, OS just doesn't see this module, it is a merely memory region for it and nothing else, so no PDB is loaded.
  2. Our project is implemented in such a way that DLL calls function from external framework where some payload is located. Then exception is raised in the framework (on purpose, not occasionally) and here is where problem occurs. This exception remains unhandled but handler is present in the code of the framework.

When DLL is loaded via LoadLibrary on x86 or x64 (and we're lucky it loads in lower 4Gbs region) everything works just fine. We can see the whole SEH chain (in WinDbg, for example) and exception is handled fine.

When loading DLL manually WinDbg shows something like this:

>!exchain
Frame 0x01: MSVCR120D!__ExceptionPtr::_RethrowException+0x1e1 (000007fe`d9cf4281)
ehandler MSVCR120D!__GSHandlerCheck (000007fe`d9e11eb0)
Frame 0x0b: error getting module for 000000000214daa1
Frame 0x0c: error getting module for 0000000000000003
Frame 0x0d: error getting module for 0000000100000000
Frame 0x0e: error getting module for 0000000002ffa420
Frame 0x0f: error getting module for 0000000100000000
Frame 0x10: error getting module for 0000000000000004

We've tried turning /SafeSEH option off but with the same result. We've done it because one guess was that OS can refuse to process exception handlers which are not in protected modules.

Current guess on why it happens is that OS needs so to say internally visible module (with some kernel objects created in the process of DLL loading via legal system function LoadLibrary) where exception chain can go through.

What do you think about possible solutions to this issue?

Edit: answered below.

greenpiece
  • 621
  • 8
  • 20
  • I'd like to know the reason of minuses for this question. Is it written in a too complicated way? Is it dumb? Please feel free to share your thoughts instead of simple click. – greenpiece Oct 26 '15 at 15:37
  • Does the .dll you're trying to load have image base specified? I'm not real familiar with loading a 32 bit module on 64 bit windows but my guess would be that you could use the rebase.exe SDK tool to provide your module with an image base below 4GB and Windows would try to load it there for you. – JJF Oct 26 '15 at 16:52
  • 1
    You forgot to add the unwind tables via [RtlAddFunctionTable](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680588(v=vs.85).aspx). – Raymond Chen Oct 27 '15 at 02:19

2 Answers2

2

Actually we've found the solution with "legal" OS functions.

Keep in mind that DLL we try to load is actually an x64 module but it is written the way that it works like an x86 one. It is able to deal only with lower 4 GBs of the whole virtual address space as it has explicit casts to 32-bit types.

So if you want to load a DLL at specified address, you are to do the following:

  1. Check for enough free memory as a block for DLL to fit there (loop with VirtualQueryEx function inside does it).
  2. Align got image base to 0x10000 (otherwise ERROR_BAD_EXE_FORMAT error will be got after trying to load such a module).
  3. Override default image base with the new value (do what linker /BASE option does).
  4. Patch relocations (they will be traversed after LoadLibrary call with offsets calculated from the original base address, not explicitly set one. So we are to patch these offsets for OS to load image properly, with new image base and relocations calculated accordingly). If not done then ERROR_NOACCESS error will be got after trying to load such a module.
  5. Reset ASLR flag which allows DLL loading at dynamic image base despite any preset one (do what linker /DYNAMICBASE:NO option does).
  6. Call LoadLibrary.

After completing steps in this algorithm we are able to work with loaded module as usually, it has no differences from any other loaded DLL, can be debugged with sources and raised exceptions are being processed correctly.

greenpiece
  • 621
  • 8
  • 20
  • Also found this link: http://stackoverflow.com/questions/19808172/struct-runtime-function – greenpiece Nov 18 '15 at 11:18
  • 1
    For the sake of completeness: there is a function [RebaseImage](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363364(v=vs.85).aspx) within `Imagehlp.dll` which can be used to patch an image. – greenpiece Mar 27 '17 at 15:36
0

Instead of storing 32 bit pointer, you could store an unsigned int and use a global std::map. This would make your code using 32 bit "pointer" which are mapped to void*. Potentially you would also need a reverse map of void* to unsigned int. This code would work on both OSs. You would also need a std::set of unsigned int containing the free IDs.