【发布时间】:2018-03-05 21:39:11
【问题描述】:
我正在尝试解决的一个有趣的学术问题:
在 C 代码中,我试图在运行时动态重新绑定符号,就像 Facebook's fishhook repo 重新绑定函数符号一样。我主要关心的是,在 Mach-O 可执行文件的 __DATA.__la_symbol_ptr 部分中引用的符号。使用fishhook 实现,您可以提供新函数来替换原始函数、指示要替换哪个函数的字符串以及一个全局函数指针,该指针将代替调用原始替换函数的位置。
例如,取自 fishhook repo 中的 README...
static int (*orig_close)(int);
int my_close(int fd) {
return orig_close(fd);
}
...然后在main
rebind_symbols((struct rebinding[1]){{"close", my_close, (void *)&orig_close}}, 1);
这太棒了,但我希望能够在我的模块中将所有调用完全切换到my_close,并将所有调用切换到close,反之亦然。例如,不是指向原始close 的全局函数指针,我希望我的实现看起来像这样:
int my_close(int fd) {
return my_close(fd);
}
不幸的是,由于这个符号在同一个模块中被引用,这个符号将通过直接调用而不是符号存根来调用。这是从main调用此函数时的程序集
0x100001e00 <+0>: push rbp
0x100001e01 <+1>: mov rbp, rsp
0x100001e04 <+4>: sub rsp, 0x20
0x100001e08 <+8>: xor eax, eax
0x100001e0a <+10>: mov dword ptr [rbp - 0x4], 0x0
0x100001e11 <+17>: mov dword ptr [rbp - 0x8], edi
0x100001e14 <+20>: mov qword ptr [rbp - 0x10], rsi
0x100001e18 <+24>: mov edi, eax
0x100001e1a <+26>: call 0x100001da0 ; my_close at main.m:42
0x100001e1f <+31>: xor edi, edi
0x100001e21 <+33>: mov dword ptr [rbp - 0x14], eax
0x100001e24 <+36>: mov eax, edi
0x100001e26 <+38>: add rsp, 0x20
0x100001e2a <+42>: pop rbp
0x100001e2b <+43>: ret
好的,很容易修复,我可以使用汇编指令将函数标记为弱,并使用弱引用来关闭编译器以防止潜在的堆栈溢出。将my_close 更改为:
static int f(int) __attribute__ ((weakref ("my_close")));
__attribute__((weak))
int my_close(int fd) {
return f(fd);
}
然后将在main 中生成以下程序集:
0x100001df0 <+0>: push rbp
0x100001df1 <+1>: mov rbp, rsp
0x100001df4 <+4>: sub rsp, 0x20
0x100001df8 <+8>: xor eax, eax
0x100001dfa <+10>: mov dword ptr [rbp - 0x4], 0x0
0x100001e01 <+17>: mov dword ptr [rbp - 0x8], edi
0x100001e04 <+20>: mov qword ptr [rbp - 0x10], rsi
0x100001e08 <+24>: mov edi, eax
0x100001e0a <+26>: call 0x100001e5e ; symbol stub for: my_close
0x100001e0f <+31>: xor edi, edi
0x100001e11 <+33>: mov dword ptr [rbp - 0x14], eax
0x100001e14 <+36>: mov eax, edi
0x100001e16 <+38>: add rsp, 0x20
0x100001e1a <+42>: pop rbp
0x100001e1b <+43>: ret
所以这是我坚持的部分:当在 my_close 中引用 my_close 时,它总是会导致直接调用。例如:这是my_close 的程序集
0x100001dd0 <+0>: push rbp
0x100001dd1 <+1>: mov rbp, rsp
0x100001dd4 <+4>: sub rsp, 0x10
0x100001dd8 <+8>: mov dword ptr [rbp - 0x4], edi
0x100001ddb <+11>: mov edi, dword ptr [rbp - 0x4]
0x100001dde <+14>: call 0x100001dd0 ; <+0> at main.m:44
0x100001de3 <+19>: add rsp, 0x10
0x100001de7 <+23>: pop rbp
0x100001de8 <+24>: ret
在my_close 内部调用时,我可以使用(我错过的)任何汇编程序指令告诉my_close 被视为存根吗?是的,我知道我可以使用dlsym 来获取原件,但我很固执:]
【问题讨论】:
-
再回头看看
weakref__attribute__似乎无论如何都无法工作,因为该函数需要声明为静态。我会保留这个问题。 -
只是一个想法...为什么不将
my_call声明为全局函数指针类型(甚至可以使用volatile属性,最好确保它是原子的且对齐的),所以每次引用symbol 实际上是对全局变量的引用(您可以随时更新)....? -
对于替代路线,您可能对此感兴趣:stackoverflow.com/a/34120249/5329717
-
@Sozin'sComet 谢谢,但这有点不公平,因为我没有想出它,只是不久前才发现的。
-
@Kamil.S 很公平,再次感谢您对此的帮助
标签: c macos linker stub mach-o