-
Notifications
You must be signed in to change notification settings - Fork 193
Library Injection
Library injection loads your own compiled code into the attached process. Use it when a normal memory edit is not enough and you want code running inside the target itself.
Common reasons to use it:
- Hooking functions from inside the process
- Calling game or engine code from your own helper code
- Logging internal state that is annoying to inspect from outside
- Applying patches that need more logic than a few overwritten bytes
For simpler stuff like changing values, NOPing instructions or making a small code cave, Libpince Engine is usually easier than building an external library.
PINCE supports two injection paths:
-
.soinjection: Linux-sidedlopen, works with native Linux processes and WINE/Proton processes - DLL injection: Windows-side
LoadLibraryW, only works with WINE/Proton processes
Open the Memory Viewer window and use the Tools menu:
-
Inject .so file: injects a Linux shared object into the target -
Inject DLL file: injects a Windows DLL into a WINE/Proton target
Your code runs inside the target process. If your constructor, hook or DllMain crashes, the target probably crashes too.
Keep this in mind:
- Match the loader architecture. A DLL must match the Windows PE bitness, while a
.somust match the Linux-side inferior bitness. Under New-WoW64, this normally means a 32-bit DLL but a 64-bit.so - Avoid doing heavy work directly in a
.soconstructor orDllMain. Start a thread or do the minimum setup if you need anything complicated - Make sure the target can access the file path. PINCE can see the file from your desktop session, but the target may be inside a sandbox or a WINE prefix with different path rules
- Do not inject random libraries you do not trust. This is code execution inside the target process
Use this for Linux shared objects.
Basic steps:
- Attach to a process.
- Open
Tools -> Inject .so file. - Select a
.sofile. - PINCE calls
dlopenin the target process.
If it succeeds, PINCE shows:
The shared object (.so) file has been injected
If your .so has a constructor like this, it runs when dlopen loads the library:
__attribute__((constructor))
static void init(void) {
/* your setup */
}If it fails, PINCE shows:
Failed to inject the shared object (.so) file
That failure is generic. It can mean dlopen could not be resolved, the file could not be loaded, the wrong architecture was used, a dependency was missing or the constructor failed.
PINCE first asks GDB to call one of these in the target:
dlopen(path, 2)__libc_dlopen_mode(path, 2)
The 2 is RTLD_NOW, meaning symbols are resolved immediately.
If GDB cannot resolve those symbols, PINCE falls back to manual symbol lookup:
- Reads
/proc/<pid>/maps - Looks for
libc,libc-musl,ld-muslorlibdl - Resolves sandboxed mapped paths through
/proc/<pid>/root - Parses the ELF
.dynsym/.dynstrtables on disk - Calls the resolved
dlopenaddress with a temporary interruption
This fallback handles 32-bit and 64-bit ELF files, little endian and big endian.
Use this for Windows DLLs in WINE/Proton targets.
Basic steps:
- Attach to a WINE or Proton process
- Open
Tools -> Inject DLL file - Select a
.dllfile - PINCE converts the Linux path to a WINE path and starts a bootstrap that calls
LoadLibraryW
If you try this on a native Linux process, PINCE shows:
DLL injection is only supported for WINE/Proton processes
If setup succeeds, PINCE shows:
DLL injection thread started. The DLL may still fail to load due to bitness mismatch or missing dependencies.
This only confirms that PINCE started the injection path. It does not wait for LoadLibraryW to finish or verify a returned module handle. If the Windows loader succeeds, your DLL's DllMain runs with DLL_PROCESS_ATTACH like a normal DLL load.
DLL injection is more involved than .so injection because GDB cannot resolve Windows PE exports by name.
PINCE first:
- Finds mapped
.exeand DLL images in/proc/<pid>/maps - Determines the Windows bitness from the main executable's PE header
- Parses the in-memory PE exports of
kernel32.dll,kernelbase.dllandntdll.dll - Waits up to 10 seconds for a target thread to reach
NtWaitForSingleObjectorNtDelayExecution, providing a safe Windows-side context for setup calls
For pure 32-bit and 64-bit WINE processes, PINCE resolves LoadLibraryW, VirtualAlloc, VirtualFree, CreateThread and CloseHandle. It allocates one Windows-side buffer for the UTF-16LE path and bootstrap code, then starts the bootstrap with CreateThread. The bootstrap calls LoadLibraryW, closes its thread handle and frees the buffer.
For a 32-bit target under New-WoW64, the GDB inferior is 64-bit while the Windows program is 32-bit. PINCE uses the 64-bit NtAllocateVirtualMemory to allocate memory reachable by guest code, finds the 32-bit guest context with RtlWow64GetCurrentCpuArea, then redirects the guest EIP through a 32-bit LoadLibraryW helper before returning to the original code. This path does not create a Windows thread.
The path conversion is simple:
/home/user/mod.dll -> Z:\home\user\mod.dll
That assumes the WINE Z: drive maps to /, which is the default setup.
During DLL injection, PINCE sets an internal driving_inferior flag. This suppresses normal stop/run UI updates and blocks user pause/continue/step controls while PINCE is steering the target.
If injection fails, check these first:
- The target is not attached anymore
- The DLL does not match the Windows PE bitness or the
.sodoes not match the Linux-side inferior bitness - The file exists for PINCE, but not for the target process namespace
- A
.sodependency is missing from the target environment - The
.soconstructor or DLLDllMaincrashed during load -
dlopen,LoadLibraryW,mallocorVirtualAlloccould not be resolved - The WINE
Z:drive does not map to/ - The WINE target did not hit
NtWaitForSingleObjectorNtDelayExecutionwithin 10 seconds - The target is paused in a bad state for making function calls
For WINE/Proton DLL injection, also make sure kernel32.dll and ntdll.dll are mapped. They should be in normal WINE processes, but if they are missing or the export tables cannot be read, PINCE cannot call LoadLibraryW.
Use .so injection when your payload is Linux code. This is often useful even for WINE/Proton games if you want to hook Linux-side libraries, libc calls or WINE itself.
Use DLL injection when your payload is Windows code and should live in the Windows side of the WINE process. This is the path you usually want for Windows game mods or Windows hooks.
They are not interchangeable. A .so is loaded by Linux dlopen. A .dll is loaded by WINE's Windows loader through LoadLibraryW.