首页
社区
课程
招聘
[原创]解答andwei关于android平台通过dlsym来hook模块方法的原理的疑问
发表于: 2020-3-21 15:20 6644

[原创]解答andwei关于android平台通过dlsym来hook模块方法的原理的疑问

2020-3-21 15:20
6644

原文参考在android平台通过dlsym来hook模块方法的原理是?
作者有两个疑问:

因为私信了,在原评论区无法给作者详细的解释,这里是我验证的几个点,希望andwei能够有所启发吧:
写了一个demo,平台为debian linux 10,x64,只在linux平台做了验证,因为android的底层即为linux,所以这里认为平台是一致的。

程序运行的结果为:

首先可以看出函数指针的解引用依然是它本身,所以
p =*p, 这样可以解答作者的

疑问1:为啥可以修改函数地址指向的地方,这个地方难道不是在代码段吗?

可以看到函数指针是个比较特殊的指针,*函数指针并未指向代码段,还是指向自己,也可以理解成相当于没有发生解引用。

至于作者的疑问2:修改了以后为啥备份的原函数地址还可以调用原函数,代码段原函数的首地址指向的地方的内容不是已经改成跳转方法的首地址了吗?
备份的原函数地址保存在一个全局的结构体中,这样到了跳转函数依然可以拿到原函数的地址进行调用。而代码段的原函数的首地址的指向的地方的内容依然没有做任务修改。

眼见为实,做一次简单的debug,以便能更好的理解:
第一段程序:

main反汇编
disas
Max函数的首地址
Max
执行完指令:printf("p_max=%p,p_max=%p,**p=%p\n",p_max,p_max,**p_max);
看到输出内容p_max=0x55b1862551df就是Max函数的首地址
debug
接下来执行到这里printf("Max=%p,&Max= %p\n",Max,&Max);
寄存器RDX=RSI,即地址Max,&Max,虽然使用的寄存器不同。
debug

为了验证dlsym跟上述函数的效果一样,产生第二段程序:

在这里下断点:p_strcat(arr,"hhee");可以看到调试内容的输出结果
p_strcat=0x7f1f4ba230f0,*p_strcat=0x7f1f4ba230f0
strcat=0x7f1f4ba230f0

debug

继续执行到call ax ,开始调用p_strcat(arr,"hhee");
debug

可以看到rax=strcat=0x7f1f4ba230f0
strcat

进入strcat即rax即可以看到rax的函数指令。
strcat

 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (8)
雪    币: 330
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
非常感谢大神这么上心!!!我仔细研究研究。
2020-3-21 17:03
0
雪    币: 251
活跃值: (513)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习了 !!!
2020-3-21 18:22
0
雪    币: 330
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
版主,我同事用dlsym是将返回的函数地址转成二级指针使用的,但是我理解转成函数指针和转成二级指针都是指针,做左值都是修改指针指向的内容。看了版主的分析原来编译器对函数指针是有特殊处理的。dlsym返回的函数地址强转二级指针就可以做左值,但是在ubuntu上无法正常执行。

版主你的代码编译有问题,我修改了一下:

#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>

static char *testChar = "test hook!!";

typedef char* (*p_strcat)(void *dest, const void *src);

static p_strcat _p_s = NULL;

void call_strcat() {
	char test[100];
	strcat(test, "test");
	printf("call_strcat -> test=%s\n", test);
}

char* my_strcat(void *dest, const void *src) {
	printf("testChar=%s\n", testChar);
	return testChar;
}

int main(void) {

	printf("my_strcat=%p,&my_strcat= %p\n", my_strcat, &my_strcat);

	printf("address of strcat=%p\n", (int*) strcat);

	void *handle;

	//strcat
	handle = dlopen(" /lib/x86_64-linux-gnu/libc.so.6",
			RTLD_LAZY | RTLD_GLOBAL);

	p_strcat p_s_aa = (p_strcat)dlsym(handle, "strcat");

	printf("to p  -> p_s_aa=%p,*p_s_aa=%p\n", p_s_aa, *p_s_aa);

	// 不能做左值,编译器提示 read - only
	// *p_s_aa = my_strcat;

	p_strcat *p_s_bb = (p_strcat*) dlsym(handle, "strcat");

	printf("to p* -> p_s_bb=%p,*p_s_bb=%p\n", p_s_bb, *p_s_bb);

	p_strcat * p_p_s = &_p_s;

	*p_p_s = *p_s_bb;

	char arr[20];
	_p_s(arr, "hhee");

	printf("arr=%s\n", arr);

	*p_s_bb = my_strcat;

	printf("bb p_s_bb=%p,*p_s_bb=%p\n", p_s_bb, *p_s_bb);

	call_strcat();

	dlclose(handle);

	return 0;
}

执行结果:

my_strcat=0x400803,&my_strcat= 0x400803
address of strcat=0x400680
to p  -> p_s_aa=0x400680,*p_s_aa=0x400680
to p* -> p_s_bb=0x400680,*p_s_bb=0x668002009c225ff

后面的没有打印,应该是段错误

2020-3-21 22:02
0
雪    币: 330
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
多谢版主,我搞明白啦~
2020-3-21 22:47
0
雪    币: 6573
活跃值: (3893)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
6
andwei 多谢版主,我搞明白啦~[em_13]
哈哈  ,明白就好
2020-3-21 22:58
0
雪    币: 26205
活跃值: (63302)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
7
赞!
2021-1-23 09:38
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
学习了
2023-7-8 17:29
0
雪    币: 3090
活跃值: (30881)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
感谢分享
2023-7-8 22:41
1
游客
登录 | 注册 方可回帖
返回
//