- Notifications
You must be signed in to change notification settings - Fork2
A tool, similar to patchelf, making DLL FS location changes possible for EXE files using rel/abs paths.
License
nixcloud/fixPath
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
fixPath is a tool to modify the path to a certain DLLs (Dynamic Shared Objects) forMicrosoft WindowsExecutables by rewriting parts of the executable's PEheader, when the.fixPath section is present and indicates support for such rewrite, butwithout having to realignthe PE headers. In concept, it is similar topatchelf but instead ofchanging search paths, fixPath hard-codes each DLL to a particular filepath.
The 'fix' in fixPath as in:
fix - fasten (something) securely in a particular place or position.
List all imports:
.\fixPath.exe list-imports ..\..\tests\program_with_lib\build\test_mylib.exeTARGET:- ..\..\tests\program_with_lib\build\test_mylib.exe- fixPath version: 2- fix_path_size: 301IMPORTS- 1, mylib.dll @ 0x4274- 2, KERNEL32.dll @ 0x43c1- 3, VCRUNTIME140D.dll @ 0x450e- 4, ucrtbased.dll @ 0x465b DELAYED IMPORTS- 1, delayedlib.dll @ 0x3894Change thedelayedlib.dll import location to an absolute path:
.\fixPath.exe set-import ..\..\tests\program_with_lib\build\test_mylib.exe delayedlib.dll c:\delayedlib.dllTARGET: - ..\..\tests\program_with_lib\build\test_mylib.exeCHANGE DELAYED IMPORTS - delayedlib.dll @ 0x3894 -> c:\delayedlib.dllDONEUsefixPath to modify the library search path:
- Microsoft's linker default search path(s)., i.e. c:\Windows\System32 and similar
- relative path to the executable: lib\delayedlib.dll
- absoluate path in filesystem: c:\lib\delayedlib.dll
Note:fixPath preserves the original library name and appends this information to the.idata section of the PE header.
fixPath requires special support from the linkerlld -the LLVM linker. It can't be applied to already existing binaries.
ThefixPath tool relies on a custom PE extension section called.fixPath (a section like.idata or.didata).
A patched version of theldd linker orld linker will create this section:
- when passing
/useFixPathon the command line the.fixPathsection is created - when passing the
/fixPathSize:33on the command line, thefixPathSizecan be set
ThefixPath tool will check if the.fixPath field exists and if so one can use it to change the loader order from:
- Thelibrary filename, for instance
KERNEL32.dllwill be searched in the default locations, likeC:\Windows\System32. - However, it can be arelative filepath like
..\foo.dllor - It can be anabsolute filepath like
c:\bar.dll
The motivation of the.fixPath section is to have a place with the original dll namesin case the user needs to revert.
This.fixPath section contains:
version field[u32],fixPathSize[u32]idata_name_table_size[u32]didata_name_table_size[u32]- array [
idataNameTable dllname] [ascii] - array [
didataNameTable dllname] [ascii], - bytes padding [u32]
- URL of fixPathhttps://github.com/nixcloud/fixPath
The motivation of the.fixPath section is to have a place with the original dll namesin case the user needs to revert.
This.fixPath section contains:
- a
version field[u32],fixPathSize[u32], empty spacer [u64] idata_name_table_size[u32]- array [
idataNameTable dllname] [ascii] - bytes padding [u32]
didata_name_table_size[u32]- array [
didataNameTable dllname] [ascii], - bytes padding [u32]
- URL of fixPathhttps://github.com/nixcloud/fixPath
- bytes padding [u32]
Seehttps://github.com/qknight/llvm-project/tree/libnix_PE-fixPath
Features:
- Reserving 300 chars dllname space
- Adding
.fixPathsection withversion anddllname size - Adding
.fixPathsection withdllnames for dll loading - Adding
.fixPathsection withdllnames for delayed dll loading - Using llm options to represent defaults
- Command line switches for cmake & similar
- Command line switches for clang-cl
- ImHex: add support
delayload parsing - ImHex: add support
.fixPath parsing
- GNU LD (GNU compiler) support
- GNU gold (GNU compiler) support
- Visual Studio linker support
No prototypes yet.
Thetests/ directory contains a set of executables which were used for verifying the fixPath execution.
It usesCMake with these settings:
set (CMAKE_CPP_FLAGS "-Xlinker /useFixPath") set (CMAKE_C_FLAGS "-Xlinker /useFixPath")Optionally one can override the reserved fixPath size default of 300 chars to 333 chars:
set (CMAKE_CPP_FLAGS "-Xlinker /useFixPath -Xlinker /fixPathSize:333") set (CMAKE_C_FLAGS "-Xlinker /useFixPath -Xlinker /fixPathSize:333")A verbose ninja run:
$ cmake -G "Ninja" -D_CMAKE_TOOLCHAIN_PREFIX=llvm- .. && ninja --verbose-- The C compiler identification is Clang 18.1.6 with GNU-like command-line-- The CXX compiler identification is Clang 18.1.6 with GNU-like command-line-- Detecting C compiler ABI info-- Detecting C compiler ABI info - done-- Check for working C compiler: C:/Program Files/LLVM/bin/clang.exe - skipped-- Detecting C compile features-- Detecting C compile features - done-- Detecting CXX compiler ABI info-- Detecting CXX compiler ABI info - done-- Check for working CXX compiler: C:/Program Files/LLVM/bin/clang++.exe - skipped-- Detecting CXX compile features-- Detecting CXX compile features - done-- Configuring done-- Generating done-- Build files have been written to: C:/Users/joschie/Desktop/Projects/binutils-ld-experiments/build[1/4] C:\PROGRA~1\LLVM\bin\clang.exe -IC:/Users/joschie/Desktop/Projects/binutils-ld-experiments/include -Xlinker /useFixPath -Xlinker /fixPathSize:333 -g -Xclang -gcodeview -O0 -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd -MD -MT CMakeFiles/test_mylib.dir/src/main.c.obj -MF CMakeFiles\test_mylib.dir\src\main.c.obj.d -o CMakeFiles/test_mylib.dir/src/main.c.obj -c C:/Users/joschie/Desktop/Projects/binutils-ld-experiments/src/main.cclang: warning: -Xlinker /useFixPath: 'linker' input unused [-Wunused-command-line-argument]clang: warning: -Xlinker /fixPathSize:333: 'linker' input unused [-Wunused-command-line-argument][2/4] C:\PROGRA~1\LLVM\bin\clang.exe -DMYLIB_EXPORTS -Dmylib_EXPORTS -IC:/Users/joschie/Desktop/Projects/binutils-ld-experiments/include -Xlinker /useFixPath -Xlinker /fixPathSize:333 -g -Xclang -gcodeview -O0 -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd -MD -MT CMakeFiles/mylib.dir/src/mylib.c.obj -MF CMakeFiles\mylib.dir\src\mylib.c.obj.d -o CMakeFiles/mylib.dir/src/mylib.c.obj -c C:/Users/joschie/Desktop/Projects/binutils-ld-experiments/src/mylib.cclang: warning: -Xlinker /useFixPath: 'linker' input unused [-Wunused-command-line-argument]clang: warning: -Xlinker /fixPathSize:333: 'linker' input unused [-Wunused-command-line-argument][3/4] cmd.exe /C "cd . && C:\PROGRA~1\LLVM\bin\clang.exe -fuse-ld=lld-link -nostartfiles -nostdlib -Xlinker /useFixPath -Xlinker /fixPathSize:333 -g -Xclang -gcodeview -O0 -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd -shared -o mylib.dll -Xlinker /MANIFEST:EMBED -Xlinker /implib:mylib.lib -Xlinker /pdb:mylib.pdb -Xlinker /version:1.0 CMakeFiles/mylib.dir/src/mylib.c.obj -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames && cd ."[4/4] cmd.exe /C "cd . && C:\PROGRA~1\LLVM\bin\clang.exe -fuse-ld=lld-link -nostartfiles -nostdlib -Xlinker /useFixPath -Xlinker /fixPathSize:333 -g -Xclang -gcodeview -O0 -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd -Xlinker /subsystem:console CMakeFiles/test_mylib.dir/src/main.c.obj -o test_mylib.exe -Xlinker /MANIFEST:EMBED -Xlinker /implib:test_mylib.lib -Xlinker /pdb:test_mylib.pdb -Xlinker /version:0.0 mylib.lib -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames && cd ."Running the test program:
./test_mylib.exeHello from my_function!Hello from the delayed loaded library!Looking at sections:
objdump.exe -h .\test_mylib.exe.\test_mylib.exe: file format pei-x86-64Sections:Idx Name Size VMA LMA File off Algn0 .text 00002366 0000000140001000 0000000140001000 00000400 2**4CONTENTS, ALLOC, LOAD, READONLY, CODE1 .rdata 00001334 0000000140004000 0000000140004000 00002800 2**4CONTENTS, ALLOC, LOAD, READONLY, DATA2 .data 00000200 0000000140006000 0000000140006000 00003c00 2**4CONTENTS, ALLOC, LOAD, DATA3 .pdata 0000039c 0000000140007000 0000000140007000 00003e00 2**2CONTENTS, ALLOC, LOAD, READONLY, DATA4 .fixPath 0000007b 0000000140008000 0000000140008000 00004200 2**2CONTENTS, ALLOC, LOAD, DATA5 .rsrc 000001a8 0000000140009000 0000000140009000 00004400 2**2CONTENTS, ALLOC, LOAD, READONLY, DATA6 .reloc 00000030 000000014000a000 000000014000a000 00004600 2**2CONTENTS, ALLOC, LOAD, READONLY, DATAModifying main.exe's library entry (without extending the .rdata)
- dll import supports absolute paths
- dll import supports relative paths like
lib\lib.dll(also checkt that it will uselib\lib.dlloverlib.dllin same dir) - works with long filename : "c:\t\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.dll"
- works with long directory: "c:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\t.dll"
- works with "C:\t\nix\store\zxxialnsgv0ahms5d35sivqzxqg1kicf-libiec61883-1.2.0\lib\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.dll" 213 chars
- works with "C:\t\nix\store\zxxialnsgv0ahms5d35sivqzxqg1kicf-libiec61883-1.2.0\lib\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.dll" 269 chars
this needs checking still:
- works with relative path ../zxxialnsgv0ahms5d35sivqzxqg1kicf-libiec61883-1.2.0\lib\lib.dll to symlinked library pointing to C:\nix\store\zxxialnsgv0ahms5d35sivqzxqg1kicf-libiec61883-1.2.0\lib\lib.dll
- works with relative path to symlinked library, which points also to a relative path ... and so on
/nix/store as path:
- one can use fixPath --set-import test.exe mylib.dll /nix/store/zxxialnsgv0ahms5d35sivqzxqg1kicf-libiec61883-1.2.0/lib/mylib.dll and executed in a shell from c: this will work (form d: it won't)
- A single leading slash means "whichever drive is the current one". There is no "drive root" like the Unix "/" on Windows. If C: is the active drive than "/" is C:, if D: is the active drive than "/" is D:\ which is why it's considered relative on Windows.
When compiling software using thenix package manager, it is required to build the software from adifferent folder than the final location of the software. UsingfixPath, which is similar to therpath featurefrom Linux/Unix the developer can hard-code the paths where the libraries are loaded from.
It basically prevents DLL-Hell by making it possible to use absolute paths for certain libraries and not rely ontheMicrosoft's linker default search path(s).
Modifyingdll paths of arbitrary executables proved way too complicated and often times resulted in corruptprograms, because the required relocations of sections and addresses inside the sections is undocumentedand not wanted.
https://discourse.llvm.org/t/build-lld-on-windows-10-using-ninja-llvm-18-1-6-cmake/79318/5
- 'fixPath' will force the Windows loader to use a 'fixed' down version of the library in an absolute or relative path
- 'rpath' sets search directories hierarchies thus works on paths. On Windows there is no such concept yet
See:
- https://developercommunity.visualstudio.com/idea/566616/support-rpath-for-binaries-during-development.html
- https://stackoverflow.com/questions/107888/is-there-a-windows-msvc-equivalent-to-the-rpath-linker-flag
Instead of using only fixPath it might be interesting to modifylld to write absolute library paths,i.e. c:\nix\store...\lib.dll' into the binary bydefault instead of just 'lib.dll' and hope forthe best.
- Martin Storsjö -https://github.com/mstorsjo
- John Ericson -https://github.com/ericson2314
- bring lld upstream
- bring object changes upstream
- imhex
- donate
- write fixpath section support
About
A tool, similar to patchelf, making DLL FS location changes possible for EXE files using rel/abs paths.
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors2
Uh oh!
There was an error while loading.Please reload this page.