用户态程序在运行过程中可能会出现异常的工作状态,此时通过特定的方式可以定位程序出错的原因,分析到原因后可能需要进行验证从而判断原因分析是否解决问题,这时候就可以使用程序动态注入进行验证。
linux下有一个环境变量叫LD_PRELOAD,该变量指向具体的动态库地址,动态链接器在载入一个程序所需的所有动态库之前,会先载入LD_PRELOAD环境变量所指定的动态库。运用这个机制,我们可以替换已有动态库中的方法,加入我们自己的逻辑,从而改变程序的执行行为。不过该方法只对动态链接的程序有效,对静态链接的程序无效。因为该方法需要重新载入动态库,所以需要重启程序才能生效。
执行代码(main.c):
#include <stdio.h>
#include "test.h"
int main(int argc, char *argv[])
{
printf("1 + 1 = %d\n", add(1, 1));
return 0;
}
头文件代码(test.h):
#ifndef __TEST_H__
#define __TEST_H__
int add(int a, int b);
#endif
原始库代码(test.c):
#include "test.h"
int add(int a, int b)
{
return a + b;
}
注入库代码(fake.c):
#include "test.h"
int add(int a, int b)
{
return a + b + 100;
}
生成执行文件和相应的库文件:
gcc test.c -o libtest.so -fPIC -shared
gcc fake.c -o libfake.so -fPIC -shared
gcc main.c -o main -L./ -ltest
export LD_LIBRARY_PATH=./;ldd main

从此处可以看到main文件依赖于libtest.so库
export LD_LIBRARY_PATH=./;./main

可以看到当前是libtest.so中add的执行结果
export LD_LIBRARY_PATH=./; export LD_PRELOAD=./libfake.so;ldd main

此时在依赖libtest.so之前添加了依赖库lbfake.so
export LD_LIBRARY_PATH=./; export LD_PRELOAD=./libfake.so;./main

此时执行了fake库中的add函数,修改掉了test库中的函数
readelf --dyn-syms libfake.so

readelf --dyn-syms libtest.so

由于动态链接器是按照库的载入顺序进行符号解析的,当libfake.so首先载入之后,动态链接器已经找到了add函数,所以会忽略libtest.so库中的add函数实现。