动态链接技巧:使用LD_PRELOAD来欺骗,注入新特征和探索程序

Linux让你对系统有全面的掌控,这并不是所有人都会这么认为,但是厉害的人都喜欢全面掌控的感觉。我将会向你展示一些基础技巧,这些技巧能极大的影响大多数程序的行为,不仅仅是好玩,而且有用。

一个简单的例子

先玩玩,原理后面再聊。

random_num.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    srand(time(NULL));
    int i = 0;
	while( i--) printf("%d \n", rand()%100);
	return 0;
}

我觉得这足够简单,我编译它不用什么特殊flag,仅仅:

gcc random_num.c -o random_num

我希望结果很明显—不同时间不同的10个随机数从0-99中选出来了。

现在我盟假装我盟并没有这个程序的源码。不管是删除还是将它移动到另外文件夹,我们就是不需要。我们将显著的修改这个程序的行为,甚至不需要了解修改它的源代码,然后重新编译它。

接下来,我们新建另外一个C文件:

unrandom.c

int rand() {
	reutrn 42;
}

我将编译他成为一个shared library。

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

所以现在我们有:一个输出随机数的程序,和定制了一个返回固定42的rand()函数动态库(shared library)。现在,我们就跑一下,random_num, 用这种方式,并观察他的结果、

LD_PRELOAD=$PWD/unrandom.so ./random_nums

如果你太懒了,不自己做(猜测会发生什么,失败的)。我将会让你知道,这个结果将会是固定的42.或许这将会更让你惊讶。

export LD_PRELOAD=$PWD/unrandom.so

然后正常跑这个程序。一个未曾修改的app被我们一个小小的library很明显的影响了。

等等这是发生了什么??
是的,你是对的,我们的程序并没有产生随机数,因为他并没有使用 real "rand()",而是我们提供的42的函数。

但是我们告诉它使用真实的那个。我们写下它,并使用它。除非,在某个时间,我们新建一个程序,那个假函数,甚至还没曾在。

这并不是真的,我们确实没有选择执行哪个我们想要执行的rand。我们仅仅告诉它,使用rand。

当我们程序启动起来,确定的library(提供我们程序所需要的功能)被载入。我们能够看到哪些会被用到使用lld。

$ldd random_nums
.......

注意在这个list中有我们定制的library。确实这就是为什么代码被执行 random_num call rand(),但是如果 unrandom.so 被载入,是我们的库,提供rand的实现。 是吗?

Being Transparent

这不够,我想要能够注入一些code在app中,用同样的方式,但是用这种方式会让功能正常。如果我们实现了 一个"return 0" 的open(),这个程序我们将会

posted @ 2021-05-13 10:37  uttep  阅读(327)  评论(0)    收藏  举报