[llvm-dev] Get the delayed-load function binding correctly written into the image executable (dlltool)
Dmitry Mikushin via llvm-dev
llvm-dev at lists.llvm.org
Tue Aug 25 12:01:46 PDT 2020
Solved! Just for the records: everything is done right here, and the
BinUtils dlltool as of today is interoperable with Visual Studio 2019. The
only missing bit was that in the absence of MSVC-orchestrated delayed-load,
linker.exe defaults to read-only ".idata", which has to be altered by e.g.
set_target_properties(${PROJECT_NAME}_test_executable PROPERTIES LINK_FLAGS
"/SECTION:.idata,RW")
Note also the delayimp code for DloadObtainSection() must also be changed
slightly, as we don't have (and don't really need)
the IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:
_Success_(return != nullptr)
DLOAD_INLINE
PVOID
DloadObtainSection (
_Out_ PULONG SectionSize,
_Out_ PULONG SectionCharacteristics
)
{
PIMAGE_DATA_DIRECTORY DataDir;
ULONG Entries;
PUCHAR ImageBase;
ULONG Index;
PIMAGE_NT_HEADERS NtHeaders;
PIMAGE_SECTION_HEADER SectionHeader;
ImageBase = (PUCHAR)&__ImageBase;
NtHeaders = (PIMAGE_NT_HEADERS)(ImageBase + __ImageBase.e_lfanew);
SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
for (Index = 0;
Index < NtHeaders->FileHeader.NumberOfSections;
Index += 1, SectionHeader += 1) {
if (!__memcmp(SectionHeader->Name, ".idata", __strlen(".idata"))) {
*SectionSize = SectionHeader->Misc.VirtualSize;
*SectionCharacteristics = SectionHeader->Characteristics;
return ImageBase + SectionHeader->VirtualAddress;
}
}
return NULL;
}
пн, 24 авг. 2020 г. в 12:34, Dmitry Mikushin <dmitry at kernelgen.org>:
> Dear All,
>
> I've been studying the delayed-load (delayimp) pipeline as a possible
> backend for the missing RPATH functionality on Windows, by the following
> example:
>
> #include <stdio.h>
>
> int __declspec(dllimport) foo(int arg);
>
> int main(int argc, char* argv[])
> {
> printf("foo() = %d\n", foo(foo(argc)));
> return 0;
> }
>
> Both GNU and LLVM implement delayed loading similarly with the dlltool
> (yet, LLVM's dlltool seems to have merged into ld-link). Essentially, the
> task performed in LLVM's lld/COFF/DLL.cpp or BinUtil's dlltool.c is
> two-fold:
>
> 1) Generate jump table stub for a delayed-load function (see example below)
> 2) Generate a trampoline that shall deploy the __delayLoadHelper2 code
> (see example below)
>
> Upon the successful binding, the __delayLoadHelper2 seems to write a
> resolved function address right into the executable code section:
>
> extern "C"
> FARPROC WINAPI
> __delayLoadHelper2(
> PCImgDelayDescr pidd,
> FARPROC * ppfnIATEntry
> ) {
>
> SetEntryHookBypass:
> *ppfnIATEntry = pfnRet; // access violation
>
> }
>
> In order for executable image modification, Microsoft has developed some
> fancy functions that temporarily add write permissions to the corresponding
> memory region.
>
> Now the question is: the code to be modified is within the jump table stub
> that goes into ".idata" section, and it fails to get write permissions:
>
> if ((Characteristics & IMAGE_SCN_MEM_WRITE) == 0) {
>
> //
> // This delay load helper module does not support merging the
> delay
> // load section to a read only section because memory
> management
> // would not guarantee that there is commit available - and
> thus a
> // low memory failure path where the delay load failure hook
> could
> // not be safely invoked (the delay load section would still be
> // read only) might be encountered.
> //
> // It is a build time configuration problem to produce such a
> // binary so abort here and now so that the problem can be
> // identified & fixed.
> //
>
> /* Exception thrown at 0x000000013F3B3F3F in dlltool_test_executable.exe:
> 0xC0000005: Access violation reading */
> __fastfail(FAST_FAIL_DLOAD_PROTECTION_FAILURE);
> }
>
> So, currently the hard-binding does not work, and gives "write access
> violation". I'm wondering what kind of "build-time configuration" am I
> missing here?
>
> My test config: LLVM upstream from github, BinUtils upstream from git,
> MSVC2019, Windows 7.
>
> I'm posting this also to StackOverflow:
> https://stackoverflow.com/questions/63559263/
>
> Kind regards,
> - Dmitry.
>
> $ cat trampoline.s
> # Import trampoline
> .section .text
> .global
> __tailMerge_C__Users_marcusmae_dlltool_build_import_test_lib
> __tailMerge_C__Users_marcusmae_dlltool_build_import_test_lib:
> pushq %rcx
> pushq %rdx
> pushq %r8
> pushq %r9
> subq $40, %rsp
> movq %rax, %rdx
> leaq
> __DELAY_IMPORT_DESCRIPTOR_C__Users_marcusmae_dlltool_build_import_test_lib(%rip),
> %rcx
> call __delayLoadHelper2
> addq $40, %rsp
> popq %r9
> popq %r8
> popq %rdx
> popq %rcx
> jmp *%rax
>
> # DELAY_IMPORT_DESCRIPTOR
> .section .text$2
> .global
> __DELAY_IMPORT_DESCRIPTOR_C__Users_marcusmae_dlltool_build_import_test_lib
> __DELAY_IMPORT_DESCRIPTOR_C__Users_marcusmae_dlltool_build_import_test_lib:
> .long 1 # grAttrs
> .rva __C__Users_marcusmae_dlltool_build_import_test_lib_iname
> # rvaDLLName
> .rva
> __DLL_HANDLE_C__Users_marcusmae_dlltool_build_import_test_lib # rvaHmod
> .rva __IAT_C__Users_marcusmae_dlltool_build_import_test_lib #
> rvaIAT
> .rva __INT_C__Users_marcusmae_dlltool_build_import_test_lib #
> rvaINT
> .long 0 # rvaBoundIAT
> .long 0 # rvaUnloadIAT
> .long 0 # dwTimeStamp
>
> .section .data
> __DLL_HANDLE_C__Users_marcusmae_dlltool_build_import_test_lib:
> .long 0 # Handle
> .long 0
>
> #Stuff for compatibility
> .section .idata$5
> .long 0
> .long 0
> __IAT_C__Users_marcusmae_dlltool_build_import_test_lib:
> .section .idata$4
> .long 0
> .long 0
> .section .idata$4
> __INT_C__Users_marcusmae_dlltool_build_import_test_lib:
> .section .idata$2
>
> $ objdump -d dorks00000.o
>
> dorks00000.o: file format pe-x86-64
>
>
> Disassembly of section .text:
>
> 0000000000000000 <foo>:
> 0: ff 25 00 00 00 00 jmpq *0x0(%rip) # 6 <foo+0x6>
> 6: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # d <foo+0xd>
> d: e9 00 00 00 00 jmpq 12 <foo+0x12>
> ...
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200825/cb8838c7/attachment.html>
More information about the llvm-dev
mailing list