ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

利用LD_PRELOAD 分析HACK Linux用户态内存使用问题

2022-02-08 13:33:40  阅读:223  来源: 互联网

标签:PRELOAD __ LD abcdef void malloc DBG HACK include


LD_PRELOAD是个环境变量,用于动态库的加载,动态库加载的优先级最高,一般情况下,其加载顺序为LD_PRELOAD > LD_LIBRARY_PATH > /etc/ld.so.cache > /lib>/usr/lib。程序中我们经常要调用一些外部库的函数.

以malloc/free为例,如果我们有个自定义的rand函数,把它编译成动态库后,通过LD_PRELOAD加载,当程序中调用malloc/free函数时,调用的其实是我们自定义的函数,下面以一个例子说明。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <sys/ioctl.h>
 
#define DBG(fmt, ...)   do { printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)

//extern unsigned int abcdef;
int main(void)
{
	void *p = malloc(256);
	//DBG("abcdef = 0x%x", abcdef);
	if(p == NULL)
	{
	    DBG("malloc p is null.");
	}
	else
	{
	    DBG("p = %p.", p);
	}

	free(p);
	//DBG("abcdef = 0x%x", abcdef);
	p = NULL;

	return 0;
}

编译后运行,结果如下:

结果不出所料,当前的调用逻辑可以图形化表示如下,main.c直接调用到C库里面。

利用LD_PRELOAD加入HOOK:

创建一个新的wrapper.so文件,内部实现malloc/free,并保证函数原型和C库完全一致.

#define _GNU_SOURCE

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <dlfcn.h>
 
#define DBG(fmt, ...)   do { printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)

unsigned int abcdef = 0;
void *malloc(size_t size)
{
	void *ret;

	static void* (*realmalloc)(size_t size) = NULL;

	if(realmalloc == NULL)
	{
		realmalloc = dlsym(RTLD_NEXT, "malloc");
	}

	if(realmalloc == NULL)
	{
		return NULL;
	}

	//DBG("malloc");
	ret = realmalloc(size);
	abcdef = 0xdeadbeef;

	return ret;
}

void free(void *p)
{
	static void* (*realfree)(void* p) = NULL;

	if(realfree == NULL)
	{
		realfree = dlsym(RTLD_NEXT, "free");
	}

	if(realfree == NULL)
	{
		return;
	}

	realfree(p);
	abcdef = 0xbeefdead;

    return;
}

修改main.c,加上对abcdef变量的打印逻辑,目的是验证流程是否走到我们期望的HOOK库里面,经过测试,wrapper.c中如果添加打印语句,在运行时会出现段错误,所以这也是不得已而为之。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <sys/ioctl.h>
 
#define DBG(fmt, ...)   do { printf("%s line %d, "fmt"\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)

extern unsigned int abcdef;
int main(void)
{
	void *p = malloc(256);
	DBG("abcdef = 0x%x", abcdef);
	if(p == NULL)
	{
	    DBG("malloc p is null.");
	}
	else
	{
	    DBG("p = %p.", p);
	}

	free(p);
	DBG("abcdef = 0x%x", abcdef);
	p = NULL;

	return 0;
}

编译wrapper.so,必须添加-ldl选项,否则会出现段错误,原因后面解释,也必须添加-fPIC,因为wrapper.so中有对全局变量的引用。

gcc --shared wrapper.c -o wrapper.so -ldl -fPIC

编译主函数,导出环境变量

$ gcc main.c -L./ wrapper.so
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/caozilong/Workspace/hook
$ LD_PRELOAD=./wrapper.so ./a.out

根据程序流程以及打印可以看出,主程序首先进入的是wrapper.c中的malloc/free实现,之后再通过后者调用C库中真正的malloc/free实现,由于中间多了一层中转,我们可以在此做手脚,加入一些调试,分析信息,解决具体的问题。图形表示如下:

为何不加-ldl会段错误?

 如下图所示,如果编译wrapper.so不加入-ldl库,运行例子会出现段错误:

分析原因,很可能是dlsym函数在两种情况下,绑定的地址不同导致,出错的时候,绑定的是错误的地址。

而正常情况下,绑定到了GLIBC库中的符号:

在错误的情况下,dlsym绑定地址为0,导致执行出现段错误。


结束!

标签:PRELOAD,__,LD,abcdef,void,malloc,DBG,HACK,include
来源: https://blog.csdn.net/tugouxp/article/details/122821586

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有