Skip to content

Library Injection

brkzlr edited this page Jun 25, 2026 · 4 revisions

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:

  • .so injection: Linux-side dlopen, works with native Linux processes and WINE/Proton processes
  • DLL injection: Windows-side LoadLibraryW, only works with WINE/Proton processes

How to Access It

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

Before Injecting Anything

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 target architecture. A 64-bit target needs a 64-bit library. A 32-bit target needs a 32-bit library
  • Avoid doing heavy work directly in a .so constructor or DllMain. 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

.so Injection

Use this for Linux shared objects.

Basic steps:

  1. Attach to a process
  2. Open Tools -> Inject .so file
  3. Select a .so file
  4. PINCE calls dlopen in 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.

.so Technical Details

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-musl or libdl
  • Resolves sandboxed mapped paths through /proc/<pid>/root
  • Parses the ELF .dynsym / .dynstr tables on disk
  • Calls the resolved dlopen address with a temporary interruption

This fallback handles 32-bit and 64-bit ELF files, little endian and big endian.

DLL Injection

Use this for Windows DLLs in WINE/Proton targets.

Basic steps:

  1. Attach to a WINE or Proton process
  2. Open Tools -> Inject DLL file
  3. Select a .dll file
  4. PINCE converts the Linux path to a WINE path and calls LoadLibraryW

If you try this on a native Linux process, PINCE shows:

DLL injection is only supported for WINE/Proton processes

If it succeeds, PINCE shows the returned module handle:

The DLL has been injected at 0x7f1234560000

Your DLL's DllMain runs with DLL_PROCESS_ATTACH like a normal Windows DLL load.

DLL Technical Details

DLL injection is more involved than .so injection because GDB cannot resolve Windows PE exports by name.

PINCE does this:

  1. Finds kernel32.dll, ntdll.dll and sometimes kernelbase.dll in /proc/<pid>/maps
  2. Parses PE export tables in memory to find LoadLibraryW
  3. Falls back to kernelbase.dll if kernel32.dll forwards LoadLibraryW
  4. Resolves NtWaitForSingleObject or NtDelayExecution from ntdll.dll
  5. Waits for the target to reach one of those hot ntdll.dll wrapper functions, up to 10 seconds
  6. Allocates memory for the DLL path
  7. Writes the DLL path as UTF-16LE
  8. Calls LoadLibraryW from that cleaner Windows-side context

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.

For allocation, PINCE uses the path that fits the target:

  • Normal 64-bit and pure 32-bit cases use the target's libc malloc
  • Newer WoW64-style cases use Windows-side VirtualAlloc

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.

Common Failure Reasons

If injection fails, check these first:

  • The target is not attached anymore
  • The library architecture does not match the target
  • The file exists for PINCE, but not for the target process namespace
  • A .so dependency is missing from the target environment
  • The .so constructor or DLL DllMain crashed during load
  • dlopen, LoadLibraryW, malloc or VirtualAlloc could not be resolved
  • The WINE Z: drive does not map to /
  • The WINE target did not hit NtWaitForSingleObject or NtDelayExecution within 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.

.so vs DLL

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.

Clone this wiki locally