LIEF
If the binary is a PIE, exporting functions via the LIEF binary instrumentation framework should allow you to call the function you are interested in as if it was a function in a shared object.
LD_PRELOAD
If the binary is dynamically linked and contains code for setting up the standard C runtime environment e.g. __libc_start_main
calling main()
, you can hook these functions with LD_PRELOAD and interpose your own code via shared library injection which calls the target function directly with arguments of your choosing.
Qiling emulator
Using the Qiling emulator, you can record the state of the program and then replay the target function in GDB. Since the code is being emulated, it is straightforward to manipulate any aspect of the process' state (registers, memory, etc.)
DBI
Using Frida, Pin, DynamoRIO etc. you can basically make the program do what you want at run time, in this case hook a function, manipulate its arguments and observe the subsequent behavior.
Trampolining with e9patch
e9patch is a static binary rewriting tool that allows one to change/insert code prior to run time.
There are probably even more ways to do this, such as process snapshotting with ptrace and /proc and then manipulating registers and memory with ptrace, emulation with PANDA, emulation with Unicorn, emulation with QEMU, possibly even ELF parasite code or inserting code that calls the target function using LD_PRELOAD together with __attribute__ ((constructor)) injected_function()
. You have a lot of options.