[fpc-devel] Manual reload of a DLL snapshot (with relocations) causes multiple AV
Gennadiy Poryev
core at barvinok.net
Fri Jan 6 15:07:31 CET 2012
= Preamble =
The task I'm working on is somewhat unorthodox, but I'd like to get some comments anyway.
I'm writing "semi-stealth" DLL which is one loaded by the process (and visible by others) while not residing on disk as a file. This is done by the following method:
1. Call LoadLibrary on an existing DLL file
2. Take memory snapshot of the loaded DLL
3. Call FreeLibrary on it and delete DLL file.
4. Create KnownDlls kernel section object, obtain its new base address.
5. Process relocations and imagebase fixups, write such patched image to kernel section.
Now whenever a process tries to load DLL normally by magic name, it is loaded from this kernel section, not from file.
= Problem =
As long as I use minimalistic DLL with single "invoke MessageBoxW" (written in masm) everything works just fine.
Then comes the following:
---
library demo;
uses Windows;
begin
MessageBoxW(GetDesktopWindow,'Demo window','Demo',MB_OK or MB_ICONINFORMATION);
end.
---
This one is failing by causing AV upon loading from kernel section. I narrowed down this problem as being caused by the implicitly linked code from _FPC_DLL_Entry as well as initialization section of system.pp. The first failure is caused by this:
---
{ pass dummy value }
StackLength := CheckInitialStkLen($1000000);
StackBottom := StackTop - StackLength;
---
These are threadvars, but the helper functions SysAllocateThreadVars() and suchlike are only initialized _later_ in the code with the call of InitSystemThreads(). Therefore, AV ensues since SysAllocateThreadVars() is being called by the now invalid absolute addresses. I wonder why it even works normally.
At first I thought InitSystemThreads() was the only culprit since it remembers the addresses of threadvar and other helper functions. But placing it prior to access to StackLength did not help much. There seems to be alot of other stuff that remembers other function's addresses in such a way that they are not recalculated upon DLL reload. I tried to figure out in what order the procedure calls between begin and end in system.pp should be rearranged but that didn't help either. Finally, as a last resort, I commented out everything that was in system.pp's begin-end section and now my "library" is “working” just fine. I understand though that this method implies stripping most of FPC juicy features like strings, memory management, maybe arrays etc and that I can't really do much without it.
= Question =
First, I'd like to know why calling of DLL entry point anew does not re-initialize _all_ RTL internals regardless of what was remembered prior to taking the snapshot. Is it just assuming good behavior of system loader that carefully zeroes data segment while I don't?
Second, I'd be glad to hear any suggestions of workarounds, such as:
a) is there a way to supply specially modified system.ppu/o compile-time depending on what source file is being compiled?
or
b) is there a way to somehow IFDEF the initialization section in system.pp so that my DLL code can not have it while everything else can?
or
c) should I take care to zero data segment after the relocations are processed?
or (in the ideal Universe)
d) is there a proper order of calling the initialization routines in the system.pp section that makes sure EVERY helper function gets its address variable updated prior to using?
Thank you all in advance.
Best Regards,
Gennadiy.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20120106/5daa8863/attachment.html>
More information about the fpc-devel
mailing list