The second day of the Dragon Boat Festival was still spent in the dormitory. Taking advantage of the free time to write a blog is quite enjoyable. Coincidentally, I came across some articles yesterday about implementing function hooking using the LD_PRELOAD environment variable in Linux, which piqued my interest. So, I decided to experiment based on othersâ ideas. Since Iâm also learning this for the first time, Iâll quote an introduction from the internet.

LD_PRELOAD is an environment variable used for loading dynamic libraries. It has the highest priority in the loading sequence, which is generally as follows: LD_PRELOAD > LD_LIBRARY_PATH > /etc/ld.so.cache > /lib > /usr/lib. In programs, we often need to call functions from external libraries.
Why should we be cautious about the LD_PRELOAD environment variable? Letâs first explain program linking. Linking refers to the process where the compiler locates the functions or global variables referenced in the program.
Generally, program linking is divided into static linking and dynamic linking. Static linking compiles all referenced functions or variables directly into the executable file. Dynamic linking, on the other hand, does not compile the functions into the executable file but dynamically loads the libraries at runtime, which is known as runtime linking. Therefore, dynamic linking necessarily requires a dynamic library.
The advantage of dynamic libraries is that any changes to the functions in the library are transparent to the executable program, which doesnât need to be recompiled. This greatly facilitates program release, maintenance, and updates. In contrast, for statically linked programs, even a minor change in the library requires the entire program to be recompiled and released, increasing the maintenance workload.
We know that Linux uses glibc, which includes a file called libc.so.6. This file is part of the dynamic linking for almost all Linux commands and contains various standard C functions. For GCC, by default, programs compiled with standard C functions are dynamically linked to the libc.so.6 library.
Take the `rand` function as an example. If we define a custom `rand` function, compile it into a dynamic library, and load it using LD_PRELOAD, any calls to the `rand` function in the program will actually invoke our custom function. Letâs illustrate this with an example.
First, we write a piece of C code to generate 10 random numbers.

Next, we compile and execute it.

Now, we compile our custom `rand` function into a dynamic library using the following command.

At this point, the `unrandom.so` file has been generated. Add it to the LD_PRELOAD environment variable and re-execute the program. Using LD_PRELOAD, we can hack the original random program. Now, itâs time to witness the magic.

The above example shows that we successfully replaced the `rand` function with our custom version.
Using the `ldd` command, we can view the dynamic libraries loaded in both execution modes. When running the program directly without loading `unrandom.so`, the original `rand` function is used. If we specify `LD_PRELOAD=unrandom.so`, the `ldd` command will show that the loaded libraries include our custom `unrandom.so`. Since LD_PRELOAD has the highest loading priority, the `rand` function in `unrandom.so` will be used first.

This fully demonstrates that when LD_PRELOAD is specified, the program prioritizes our dynamic library during execution, thereby achieving function hooking.
Although there are other examples online, due to current limitations in my abilities, I only experimented with this one. Below is a simple summary of LD_PRELOAD usage.
- Define a function identical to the target function, including its name, variables, types, return value, and type.
- Compile the source code containing the replacement function into a dynamic library.
- Use the command `export LD_PRELOAD=âpath_to_libraryâ` to set the dynamic library to be prioritized.
- If the replacement library cannot be found, use `export LD_LIBRARY_PATH=path_to_library_directory` to set the systemâs library search path.
- To restore the original function call relationship, use the command `unset LD_PRELOAD` to remove the setting.
- To check dependencies, use the `ldd` command followed by the program name.
Iâve packaged the above code and program. Interested friends can download and experiment with it themselves.