逆向Linux导出函数,Linux下入门级导出函数截获-使用LD_PRELOAD环境变量

博文篇首要感谢我的同事zxb,他曾经提示我有这种简便的截获方法。

近期要做Linux下libvirt事件审计,原计划是分析libvirt的通信数据从而进一步分析libvirt事件。尼玛,这怎么看都觉得工作量浩大,第一反应就是能不能偷懒。对于一般的审计事件,首先想到的是函数截获:遍历ELF文件的导出函数,然后替换之。顺带一提,现在安卓上的进程注入就这么做的,哪天有空了我也放一篇Linux ELF文件注入的博文。不过这个工程也不小(相比原计划已经很小了),而且我也没十足的把握稳定代码。于是,退而求其次想到标题中这种方法,此法,也是首次尝试。

1)    先来整理下当时的处理思路:libvirt提供了一个命令行客户端工具--virsh,通过virsh可以使用libvirt提供的功能,如创建域。首先,可以肯定的是libvirt是个成功的项目,所以,客户端代码肯定和实际虚拟化操作是分开的,他们的唯一结合处一定是调用libvirt某个动态库导出的函数,来找一下他们的契合处:

root@ubuntu:~# which virsh

/usr/local/bin/virsh

root@ubuntu:~# ldd /usr/local/bin/virsh

linux-gate.so.1 => (0xb770d000)

libvirt.so.0 => /usr/lib/libvirt.so.0 (0xb743d000)

libvirt-qemu.so.0 => /usr/lib/libvirt-qemu.so.0 (0xb7439000)

libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb741d000)可以看到virsh依赖于libvirt.so这个动态库。再来看看这个动态库是否提供了virsh命令行所需要的接口:

virsh创建域会调用virDomainCreateXML这个API,来看下virDomainCreateXML在virsh中的符号形式:

root@ubuntu:~# nm /usr/local/bin/virsh|grep virDomainCreateXML

U virDomainCreateXML@@LIBVIRT_0.5.0nm显示virDomainCreateXML在virsh中是未解析的符号名,意味着,virsh中没有对应的实现,那必须在其他模块中实现否则都不会通过链接的步骤。可以猜测,virDomainCreateXML肯定在libvirt中实现(我看了源码,当然知道在这个so中实现。你不服,可在ldd virsh输出的所有动态库中搜索这个API)。

root@ubuntu:~# nm /usr/lib/libvirt.so.0 | grep virDomainCreateXML

000f7c40 T virDomainCreateXMLnm显示virDomainCreateXML的确在libvirt.so中实现。如此可以确定virsh以至于其他客户端工具,要使用libvirt提供的虚拟化操作,都依赖这个库的实现。咩哈哈哈哈哈,后面都用LD_PRELOAD来截获对该动态库的调用了,以此来实现对libvirt的审计。

2)    扯了这么久,还没怎么利用LD_PRELOAD。这不,思路很重要么,至少看到这知道了审计事件时,可以用这种方式去实现么。好,先放个链接:http://blog.csdn.net/haoel/article/details/1602108  这位博主详细介绍了什么是LD_PRELOAD以及如何利用。但是,这位博主只做了一半,还有一半没做:就是,你把水截流了,还得把水放到下游去啊,要不然下游人民怎么生活!光简单粗暴的截获了strcmp,然后return 0这不是改的strcmp他妈都不认识他了么?为了实现strcmp的原有功能,这里我用到了dlopen/dlsym,用来加载动态库和获得导出函数。类似于windows的LoadLibrary和GetProcAddr。值得一提的事,linux的进程加载器也是使用这两个函数加载所依赖的so库。

下面来看下我对那位博主代码的扩充:

hack.c

#define _GNU_SOURCE

#include

#include

#include

typedef int (*detour_strcmp)(const char*,const char*);

detour_strcmp g_Strcmp;

int strcmp(const char *s1, const char *s2)

{

int res=0;

printf("hack function invoked. s1= s2=\n", s1, s2);

g_Strcmp = dlsym(RTLD_NEXT, "strcmp");

if(g_Strcmp==NULL)

{

printf("load strcmp failed\n");

return 0;

}

res = (*g_Strcmp)(s1,s2);

printf("compare result:%d\n",res);

return res;

}因为使用了dlopen和dlsym编译连接时,需要加上-ldl

gcc -shared -o hack.so hack.c -ldl

最后,来看下新strcmp的输出:

root@ubuntu:~/Desktop# export LD_PRELOAD="./hack.so"

root@ubuntu:~/Desktop# ./verifypasswd

usage: ./verifypasswd /nroot@ubuntu:~/Desktop# ./verifypasswd 1

hack function invoked. s1= s2=<1>/ncompare result:1

Invalid Password!/n输出无效的密码!至少可以知道strcmp是被调用过了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值