8

Does LoadLibraryEx function use side-by-side manifests? I have bar.dll with embedded SxS manifest, and that manifest describes version of this bar.dll, other dll file foo.dll has manifest that lists bar.dll as dependency, with specified version. But when I try to load bar.dll from foo.dll with LoadLibraryEx("bar.dll", NULL, 0) I see (with enabled sls with gflags) that it ignores these manifests, and loads first version of bar.dll that it sees in searchpath, if I define ISOLATION_AWARE_ENABLED and use LoadLibrary it finds right version, but this ISOLATION_AWARE_ENABLED doesn't affect behaviour of LoadLibraryEx, I need to load right version with LoadLibraryEx because LoadLibraryEx is used implicitly for delayed loading of dll's. Is LoadLibraryEx supposed to work like this, or is it some problem in my project configuration?

foo dll

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="foo" version="0.1.2.3" type="win32"/>
<dependency>
    <dependentAssembly>
        <assemblyIdentity name="bar" version="0.1.2.3" type="win32" />
    </dependentAssembly>
</dependency>
<file name="foo.dll">
</file>
</assembly> 

bar.dll

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="bar" version="0.1.2.3" type="win32"/>
<file name="bar.dll">
</file>
</assembly> 
Ibraim Ganiev
  • 8,934
  • 3
  • 33
  • 52
  • 2
    are you activate manifest from *foo.dll* before call `LoadLibrary` ? sure that no. by default active is exe manifest. you need activate you foo.dll manifest before call `LoadLibrary` and deactivate after. exactly this is do `IsolationAwareLoadLibraryA`. so you need in fooentry point save activation context - by call `GetCurrentActCtx` and then shell `LoadLibrary` call into `ActivateActCtx` `DeactivateActCtx` – RbMm Jan 17 '18 at 19:31
  • @RbMm, No, of course I don't touch any active context functions, because I want it to create new context implicitly, when I DelayLoad some dll (Call LoadLibraryEx) – Ibraim Ganiev Jan 17 '18 at 19:34
  • this and your error. you not need create new context but activate context from your foo.dll – RbMm Jan 17 '18 at 19:35
  • _"If you call LoadLibraryEx with the name of an assembly without a path specification and the assembly is listed in the system compatible manifest, the call is automatically redirected to the side-by-side assembly."_ https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx – Richard Critten Jan 17 '18 at 19:37
  • And you can use sxstrace to see exactly what the loader does. – SoronelHaetir Jan 17 '18 at 19:37
  • @RichardCritten I've seen that, I load it as LoadLibraryEx("bar.dll", NULL, 0), there is no path in first argument. – Ibraim Ganiev Jan 17 '18 at 19:41

1 Answers1

10

LoadLibrary used active activation context of the calling thread. but which is this context ? why it must be from your foo.dll ? why not from xyz.dll or from exe ? really most time active activation context was exactly from exe.

if dll have own manifest - system create activation context for this dll and save it (until dll will be unloaded) but not make it active. and this is obviously - we have multiple dlls in process, but active context only one - from which dll select it ? from exe. however system activate (make it current active) dll activation context before call it entry point. and deactivate it after entry point return. but say inside another dll functions - (who called it ?) the context already not from your dll.

so solution must be next:

define 2 global variables in dll:

BOOL gActCtx;
HANDLE ghActCtx

on DLL_PROCESS_ATTACH save current activation context (it from your dll manifest)

gActCtx = GetCurrentActCtx(&ghActCtx);

free it on DLL_PROCESS_DETACH

if (gActCtx) ReleaseActCtx(ghActCtx);

and when you need load bar.dll do next:

if (gActCtx)
{
    ULONG_PTR Cookie;

    if (ActivateActCtx(ghActCtx, &Cookie))
    {
        LoadLibraryExW(L"bar.dll", NULL, 0);

        DeactivateActCtx(0, Cookie);
    }
}
RbMm
  • 31,280
  • 3
  • 35
  • 56
  • But shouldn't /DELAYLOAD option of linker automatically take into account this context activation? It's weird that developers of linker didn't make such obvious feature. – Ibraim Ganiev Jan 17 '18 at 20:34
  • 1
    @IbraimGaniev - how `/DELAYLOAD` can do this ?! try set self on linker place. he generate link code, but it have no any knowledge of os. when you call function from delay load dll - linker simply call `__delayLoadHelper2` function. you must implement it yourself, or use some lib implementation. exactly here you need load correct dll as well. but this already your task, not linker – RbMm Jan 17 '18 at 20:42
  • @IbraimGaniev - you can for example, if use lib implementation for delayload - on `dliStartProcessing` yourself activate context by `ActivateActCtx` and on `dliNoteEndProcessing` deactivate it. or yourself implement dll load on `dliNotePreLoadLibrary` – RbMm Jan 17 '18 at 20:53
  • this works perfectly, but could you give me a link where this approach is described? I'm not sure if there are any guarantees that I'll be able to save handler to context of DLL in DLL_PROCESS_ATTACH. And is there a way to get this handler in other places of my dll's code? Thanks in advance, and thanks again for your answer. – Ibraim Ganiev Jan 19 '18 at 15:19
  • 1
    @IbraimGaniev - when system load dll it look for it manifest (`ISOLATIONAWARE_MANIFEST_RESOURCE_ID`) and if it present create activation context from it and save [here](http://processhacker.sourceforge.net/doc/ntldr_8h_source.html#l00155). before call dll entry point - loader activate this context. so you can got it and save by call `GetCurrentActCtx`. also possible at any time get it by undocumented `LdrFindEntryForAddress`. also look this - http://simon.rozman.si/computers/wxwidgets/wxwidgets-dll-plugin – RbMm Jan 19 '18 at 15:32