理解PLT、GOT及其挂钩技术(Linux与Android平台)
PLT与GOT相关问题解答
1. 单个进程中是否存在多组PLT与GOT?
没错,单个进程里会有多组PLT和GOT。进程的地址空间里不只有主可执行文件,还加载了所有依赖的共享库(比如libc.so、libpthread.so这类),每个可执行文件(包括主程序和每个共享库)都自带独立的PLT和GOT段。
举个实际的例子:主程序调用printf时,走的是主程序自己的PLT条目,跳转到对应的GOT表项;如果某个共享库也调用printf,它会用自己的PLT和GOT来处理,和主程序的那套完全独立。
2. PLT/GOT挂钩指的是哪部分?是否为主可执行文件的PLT和GOT?
不一定局限于主可执行文件,完全看你要拦截的目标:
- 如果只想拦截主程序对某个函数的调用,就修改主程序的PLT或GOT条目;
- 如果要拦截整个进程内所有模块对该函数的调用(包括各个共享库的调用),通常会修改该函数所在共享库的GOT条目(比如
libc.so里printf对应的GOT项),或者直接修改共享库的PLT。
实际场景里,全局拦截的话修改共享库的GOT更常见,因为动态链接器会把所有对该函数的引用,最终都绑定到共享库的实际函数地址对应的GOT条目上。
3. PLT挂钩的实际工作原理是什么?PLT挂钩和GOT挂钩的区别是?
先回顾下基础逻辑:PLT是一段跳转代码,每个PLT条目里的汇编指令会跳转到对应GOT条目存储的地址;GOT是存储函数实际地址的表项,第一次调用前可能指向PLT里的“跳板”代码,第一次调用后会被动态链接器更新为函数的真实地址。
- GOT挂钩:直接修改GOT条目里的地址值,把它换成你的钩子函数地址。这样不管是PLT跳转过来,还是其他直接引用GOT的地方,都会跑到你的钩子函数里。这种方式操作简单,因为只是修改一个内存地址的数据。
- PLT挂钩:修改PLT条目里的汇编指令。比如原本PLT里是
jmp *GOT_ENTRY,你把它改成直接jmp YOUR_HOOK_ADDRESS,或者插入跳转指令到你的钩子函数。需要注意的是,PLT属于代码段,默认是只读的,修改前得先用mprotect调整内存权限。
核心区别就是:GOT挂钩改的是数据(地址表项),PLT挂钩改的是代码(跳转指令)。实际使用中GOT挂钩更常用,因为操作更简单,不用处理代码段的权限问题。
内容的提问来源于stack exchange,提问作者localacct
相关产品推荐
相关产品推荐

