QBDIPreload API

Introduction

QBDIPreload is a small utility library that provides code injection capabilities using dynamic library injection. It currently only works under Linux using the LD_PRELOAD mechanism and macOS using the DYLD_INSERT_LIBRARIES mechanism. For other platforms please check out Frida/QBDI API instead.

QBDIPreload exploits these library injection mechanisms to hijack the normal program startup. During the hijacking process QBDIPreload will call your code allowing you to setup and start your instrumentation. The compilation should produce a dynamic library (.so under Linux, .dylib under macOS) which should then be added to the matching environment variable (LD_PRELOAD under Linux and DYLD_INSERT_LIBRARIES under macOS) when running the target binary.

You can look at Generate a template for a working example with build and usage instructions.

Note

QBDIPreload automatically takes care of blacklisting instrumentation of the C standard library and the OS loader as described in Limitations.

Note

Please note that QBDIPreload does not allow instrumenting a binary before the main function (inside the loader and the library constructors / init) as explained in Limitations.

Note

QBDIPreload is supposed to be used with LD_PRELOAD or DYLD_INSERT_LIBRARIES mechanisms to inject some code into the target process. Hence, the limitations of these also affect QBDIPreload (cannot inject suid binary, …).

Initialisation

QBDIPRELOAD_INIT

A C pre-processor macro declaring a constructor.

Warning

QBDIPRELOAD_INIT must be used once in any project using QBDIPreload. It declares a constructor, so it must be placed like a function declaration on a single line.

Return codes

QBDIPRELOAD_NO_ERROR

No error.

QBDIPRELOAD_NOT_HANDLED

Startup step not handled by callback.

QBDIPRELOAD_ERR_STARTUP_FAILED

Error in the startup (preload) process.

User callbacks

int qbdipreload_on_start(void *main)

Function called when preload is on a program entry point (interposed start or an early constructor). It provides the main function address, that can be used to place a hook using the qbdipreload_hook_main API.

Parameters:

main[in] Address of the main function

Returns:

int QBDIPreload state

int qbdipreload_on_premain(void *gprCtx, void *fpuCtx)

Function called when preload hook on main function is triggered. It provides original (and platforms dependent) GPR and FPR contexts. They can be converted to QBDI states, using qbdipreload_threadCtxToGPRState and qbdipreload_floatCtxToFPRState APIs.

Parameters:
  • gprCtx[in] Original GPR context

  • fpuCtx[in] Original FPU context

Returns:

int QBDIPreload state

int qbdipreload_on_main(int argc, char **argv)

Function called when preload has successfully hijacked the main thread and we are in place of the original main function (with the same thread state).

Parameters:
  • argc[in] Original argc

  • argv[in] Original argv

Returns:

int QBDIPreload state

int qbdipreload_on_run(VMInstanceRef vm, rword start, rword stop)

Function called when preload is done and we have a valid QBDI VM object on which we can call run (after some last initializations).

Parameters:
  • vm[in] VM instance.

  • start[in] Start address of the range (included).

  • stop[in] End address of the range (excluded).

Returns:

int QBDIPreload state

int qbdipreload_on_exit(int status)

Function called when process is exiting (using _exit or exit).

Parameters:

status[in] exit status

Returns:

int QBDIPreload state

Helpers

int qbdipreload_hook_main(void *main)

Enable QBDIPreload hook on the main function (using its address)

Warning

It MUST be used in qbdipreload_on_start if you want to handle this step. The assumed main address is provided as a callback argument.

Parameters:

main[in] Pointer to the main function

void qbdipreload_threadCtxToGPRState(const void *gprCtx, GPRState *gprState)

Convert a QBDIPreload GPR context (platform dependent) to a QBDI GPR state.

Parameters:
  • gprCtx[in] Platform GPRState pointer

  • gprState[in] QBDI GPRState pointer

void qbdipreload_floatCtxToFPRState(const void *fprCtx, FPRState *fprState)

Convert a QBDIPreload FPR context (platform dependent) to a QBDI FPR state.

Parameters:
  • fprCtx[in] Platform FPRState pointer

  • fprState[in] QBDI FPRState pointer