Aaa*_*Bbb 1 linux memory paging x86-64 linux-kernel
我想过编写一个程序集存根来mprotect
使用页面地址进行调用,但随后我需要在进程的同一地址空间中运行此存根,而且我不知道该怎么做。还有其他方法吗?
是的,只要有适当的权限,您就可以。根据情况,您可能需要CAP_SYS_PTRACE
能力。请参阅此文档页面了解/proc/sys/kernel/yama/ptrace_scope
更多信息。
最简单的方法是使用调试器,例如GDB:
运行目标进程并获取其PID。ps
您可以使用、htop
、pidof
和类似命令查找进程的 PID 。
打开终端并将 GDB 连接到进程gdb --pid PID
。
在 GDB 提示符下,检查内存映射:
(gdb) info inferiors
Num Description Connection Executable
* 1 process 19433 2 (native) /usr/bin/ls
(gdb) !cat /proc/19433/maps
555555554000-555555558000 r--p 00000000 00:18 5154601 /usr/bin/ls
555555558000-55555556d000 r-xp 00004000 00:18 5154601 /usr/bin/ls
55555556d000-555555576000 r--p 00019000 00:18 5154601 /usr/bin/ls
555555577000-555555579000 rw-p 00022000 00:18 5154601 /usr/bin/ls
555555579000-55555557a000 rw-p 00000000 00:00 0 [heap]
7ffff7fcc000-7ffff7fd0000 r--p 00000000 00:00 0 [vvar]
...
Run Code Online (Sandbox Code Playgroud)
注意:我使用!cat /proc/PID/maps
而不是info proc mappings
这里,因为不幸的是后者没有显示权限。
调用mprotect()
libc函数来改变你想要的页面的权限。例如这里我将单个页面更改为RWX:
(gdb) call (long)mprotect(0x555555577000, 0x1000, 0x7)
$1 = 0 <-- return value, 0 == success
Run Code Online (Sandbox Code Playgroud)
现在detach
让进程以修改后的权限运行。
您还可以编写GDB 脚本来自动执行此操作。例如,如果您知道在某个时刻 RDI 将包含您想要访问的页面中的地址,您可以执行以下操作:
file path/to/your/elf
# or alternatively `attach PID`
# Set a breakpoint to some known address (assuming your ELF is not position independent).
# You could also do `break some_symbol+offset` if there are symbols.
break *0x123450
command 1
set $page = $rdi & ~0xfff
call (long)mprotect($page, 0x1000, 0x7)
detach
end
run
Run Code Online (Sandbox Code Playgroud)
然后在你的终端中:
$ gdb -x yourscript.txt
Run Code Online (Sandbox Code Playgroud)
ptrace
或者,您可以利用 GDB 在幕后使用的相同低级工具来编写一个自动为您执行此操作的程序:系统ptrace
调用。您可以编写一个程序来执行以下操作:
fork
通过+生成目标进程execve
(或者只是在另一个终端中运行它)。PTRACE_ATTACH
到它。PTRACE_GETREGS
(保存初始寄存器状态供以后使用)、PTRACE_PEEKDATA
(检查内存)等。mprotect
您调用的简单存根 ( PTRACE_POKEDATA
)。这当然比基于调试器的方法困难得多,但尝试起来很有趣。您基本上是在编写自己的非常专业的调试器。
请参阅我关于“编写最简单的程序集调试器”的答案,以获取更多信息和它的外观的代码示例。
GitHub 上还有一个更复杂的示例:在这种情况下,程序员希望通过ptrace
.