PRELOAD 去欺骗、注入特性和研究程序

动态连接的诀窍:使用 LD_PRELOAD 去欺骗、注入特性和研究程序

本文假设你具备基本的 C 技能

Linux 完全在你的控制之中。虽然从每个人的角度来看似乎并不总是这样,但是高级用户喜欢去控制它。我将向你展示一个基本的诀窍,在很大程度上你可以去影响大多数程序的行为,它并不仅是好玩,在有时候也很有用。

一个让我们产生兴趣的示例

让我们以一个简单的示例开始。先乐趣,后科学。

random_num.c:

#include<stdio.h>

#include<stdlib.h>

#include<time.h>

int main(){

srand(time(NULL));

int i =10;

while(i--)printf("%d\n",rand()%100);

return0;

}

我相信,它足够简单吧。我不使用任何参数来编译它,如下所示:

gcc random_num.c -o random_num

我希望它输出的结果是明确的:从 0-99 中选择的十个随机数字,希望每次你运行这个程序时它的输出都不相同。

现在,让我们假装真的不知道这个可执行程序的出处。甚至将它的源文件删除,或者把它移动到别的地方 —— 我们已不再需要它了。我们将对这个程序的行为进行重大的修改,而你并不需要接触到它的源代码,也不需要重新编译它。

因此,让我们来创建另外一个简单的 C 文件:

unrandom.c:

int rand(){

return42;//the most random number in the universe

}

我们将编译它进入一个共享库中。

gcc-shared -fPIC unrandom.c -o unrandom.so

因此,现在我们已经有了一个可以输出一些随机数的应用程序,和一个定制的库,它使用一个常数值 42 实现了一个 rand() 函数。现在 …… 就像运行 random_num 一样,然后再观察结果:

LD_PRELOAD=$PWD/unrandom.so ./random_nums

如果你想偷懒或者不想自动亲自动手(或者不知什么原因猜不出发生了什么),我来告诉你 —— 它输出了十次常数 42。

如果先这样执行

export LD_PRELOAD=$PWD/unrandom.so

然后再以正常方式运行这个程序,这个结果也许会更让你吃惊:一个未被改变过的应用程序在一个正常的运行方式中,看上去受到了我们做的一个极小的库的影响 ……

等等,什么?刚刚发生了什么?

是的,你说对了,我们的程序生成随机数失败了,因为它并没有使用 “真正的” rand(),而是使用了我们提供的的那个 —— 它每次都返回 42。

但是,我们告诉过它去使用真实的那个。我们编程让它去使用真实的那个。另外,在创建那个程序的时候,假冒的 rand() 甚至并不存在!

这句话并不完全正确。我们只能告诉它去使用 rand(),但是我们不能去选择哪个 rand() 是我们希望我们的程序去使用的。

当我们的程序启动后,(为程序提供所需要的函数的)某些库被加载。我们可以使用 ldd 去学习它是怎么工作的:

$ ldd random_nums

linux-vdso.so.1=>(0x00007fff4bdfe000)

libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007f48c03ec000)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b1d2aed790ac3b2e0320209dc9ef7dbc.html