Skip to content

Library Injection

brkzlr edited this page Jun 19, 2026 · 4 revisions

Library injection lets you load your own code into a running process. This is useful for hooking functions, modifying behavior at a deeper level or adding custom functionality that can't be achieved with simple memory edits.

PINCE supports two types of library injection:

  • .so files (shared objects): works on any Linux process, including WINE/Proton
  • DLL files: only works on WINE/Proton processes

How to Access It

Open the Memory Viewer window and go to Tools menu:

  • Inject .so file: for any Linux process (native or WINE/Proton)
  • Inject DLL file: for WINE/Proton processes only

.so Injection

To inject a shared object file:

  1. Make sure you're attached to a process
  2. Go to Tools -> Inject .so file
  3. Select your .so file from the file dialog (filter: Shared object library (*.so))
  4. PINCE will call dlopen() in the target process to load your library

If the injection succeeds, you'll see the message "The shared object (.so) file has been injected". Your library's constructor function (if you defined one with __attribute__((constructor))) will run automatically when loaded, since that's how dlopen() works.

If it fails, you'll see "Failed to inject the shared object (.so) file". Note that PINCE can't distinguish between "couldn't find dlopen" and "dlopen returned NULL because the .so file was invalid" so both cases show the same error.

How It Works

PINCE first tries to call dlopen() (or __libc_dlopen_mode() as a fallback) in the target process via GDB. The call uses RTLD_NOW (flag 2) so all symbols are resolved immediately.

If GDB can't resolve these symbols (like in stripped binaries), PINCE has a fallback mechanism that:

  • Scans /proc/<pid>/maps for libc, libc-musl, ld-musl or libdl mappings
  • Parses the ELF file's dynamic symbol tables on disk to find the dlopen address
  • Resolves sandboxed paths (Flatpak, Steam pressure-vessel) by going through /proc/<pid>/root so the file PINCE reads is the exact file the target process mapped
  • Manually calls dlopen at the resolved address with a temporary interrupt

This works on both native Linux and WINE/Proton processes and handles both 32-bit and 64-bit ELF files (little and big endian).

DLL Injection (WINE/Proton Only)

To inject a Windows DLL:

  1. Make sure you're attached to a WINE or Proton process
  2. Go to Tools -> Inject DLL file
  3. Select your DLL file from the file dialog (filter: Dynamic-link library (*.dll))
  4. PINCE will convert the path to WINE format and call LoadLibraryW in the target process

If you try this on a native Linux process, you'll get the error "DLL injection is only supported for WINE/Proton processes".

If the injection succeeds, you'll see a message like "The DLL has been injected at 0x7f1234560000" showing the module handle address returned by LoadLibraryW.

How It Works

DLL injection is more complex because WINE processes run Windows PE binaries and GDB can't resolve PE exports by symbol. The process:

  1. PINCE locates kernel32.dll and ntdll.dll in the process memory by scanning /proc/<pid>/maps
  2. Parses the PE export tables in memory to find LoadLibraryW in kernel32.dll. If LoadLibraryW turns out to be an export forwarder (which happens in some WINE versions), PINCE falls back to resolving it from kernelbase.dll
  3. Also resolves NtWaitForSingleObject (or NtDelayExecution as fallback) from ntdll.dll
  4. Resolves malloc from the target's libc (using the same ELF parsing fallback as .so injection) to allocate a buffer for the path string
  5. Finds a clean execution context by setting a temporary breakpoint at the entry of NtWaitForSingleObject or NtDelayExecution (these are hot ntdll syscall wrappers), letting the target run until it hits one (up to 10 seconds), then calling LoadLibraryW from that context. This is necessary because the call needs to run from a clean PE context, not a thread parked mid-syscall
  6. Converts your Linux path to WINE format: Z: + path with / replaced by \, encoded as UTF-16LE with a null terminator (e.g. /home/user/mod.dll becomes Z:\home\user\mod.dll)
  7. Allocates memory in the process via malloc, writes the UTF-16LE path string into it, then calls LoadLibraryW with a pointer to that buffer
  8. The call uses different argument signatures for 32-bit vs 64-bit targets (64-bit uses a 4-arg calling convention, 32-bit uses single-arg stdcall)

During injection, PINCE sets a driving_inferior flag that suppresses UI stop/run notifications and blocks user pause/continue/step controls so nothing interferes with the process.

Limitations

  • DLL injection only works on WINE/Proton processes. If you try to inject a DLL into a native Linux process, you'll get an error.
  • Your library must be compatible with the target process architecture (32-bit or 64-bit).
  • The library file must be accessible from the target process. For sandboxed environments, make sure the path is valid inside the sandbox.
  • DLL injection assumes the default WINE prefix where the Z: drive maps to /. If you remapped or removed the Z: drive in your WINE prefix, DLL injection won't find your file.
  • DLL injection requires both kernel32.dll and ntdll.dll to be mapped in the target, plus a resolvable malloc in the target's libc.
  • The clean context wait can time out. If the target doesn't call NtWaitForSingleObject or NtDelayExecution within 10 seconds, the injection fails with a generic error.
  • No file existence check is done before injection. If the path is wrong, dlopen or LoadLibraryW simply returns NULL and you get a generic failure message.

Use Cases

Common reasons to use library injection:

  • Function hooking: Replace or wrap game functions with your own code
  • Custom allocators: Intercept memory allocation calls
  • Logging: Add debug output to specific functions
  • Patches: Apply complex multi-step modifications atomically

For simpler patches like NOPing instructions or basic code injection, check out Modifying Game Code or Libpince Engine instead, which don't require creating external library files.

Clone this wiki locally