- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
最近我对 Linux 产生了兴趣,并且正在尝试创建一个能够注入(inject)共享对象(即 .so 文件、“动态可加载库”、Windows 下的“DLL”)的程序。我知道这可以是通过设置环境变量来完成,但我想在已经运行的进程上进行。
我已经知道如何在 Windows 下执行此操作。有几种方法,但一般来说,您可以通过使用 CreateRemoteThread() 创建远程线程来调用 LoadLibrary()。当然,您需要远程进程中 LoadLibrary 的地址,但(以我的经验)它对于每个进程始终处于相同的偏移量。
我已经研究了如何在 Linux 下完成此操作。例如一个有趣的 article在 Phrack 59 中展示了如何做到这一点。该文章还附有源代码,但由于对目标进程做了一些假设并且它是 32 位的,所以我无法让它工作。我遇到的其他事情:a codeproject article ,但这一篇只解释了如何在 gdb 中进行操作。 (我会发布更多链接,但该网站将我限制为 2 :-/。)
首先,我想获取远程进程中 dlopen() 函数的地址。为此,我发现我必须获取进程的 ELF header 并遍历符号表。实际上,我设法做到了这一点,方法是:
1) 获取 ELF-header(根据我的经验,64 位以下存储在 0x400000。)
2) 在标记为 DYNAMIC 的程序头中找到全局偏移表。
3) 通过访问全局偏移表中的第二个条目来检索第一个 link_map。
4)遍历link_map链的动态部分,从而得到String Table、Symbol Table和Hash Table的地址(*Hash_Table + 0x4保存了符号表的表项数量。)
5) 遍历符号表
我程序的一些示例输出:
** looking at lib "" **
Trying to find symbol main in symbol table... numentries: 49
index 1 name: val: 0
...
index 49 name: memcpy val: 0
symbol not found.
** looking at lib "" **
Trying to find symbol main in symbol table... numentries: 11
index 1 name: val: 0
...
index 11 name: __vdso_time val: 0xffffffffff700a80
symbol not found.
** looking at lib "/lib/x86_64-linux-gnu/libc.so.6" **
Trying to find symbol main in symbol table... numentries: 2190
index 1 name: val: 0
...
index 2190 name: wcpcpy val: 0xa3570
symbol not found.
但是,我无法找到 dlopen 的有效地址! (甚至 main 的地址,就此而言!)出于测试目的,我让程序进行 self 分析,因此我确定 main 存在。我还尝试了 readelf -s 查看符号表,它显示:
Symbol table '.symtab' contains 151 entries:
Num: Value Size Type Bind Vis Ndx Name
...
149: 0000000000401880 216 FUNC GLOBAL DEFAULT 13 main
因此,readelf 以某种方式设法找到了 main,而我却找不到。我还查看了 libelf 库,但它依赖于从应用程序文件中读取,而不是访问进程的内存(即它不能在进程运行时使用。)有没有人知道我如何定位dlopen() 在远程进程中,甚至在主进程中?
我正在运行 Ubuntu 12.04 64 位。
最佳答案
首先,关于main的地址:似乎必须使用 Section Headers 才能找到 main 的地址。只使用动态部分来做这件事似乎是不可能的。运行 readelf -D -s
和 readelf -D --dyn-sym
也不会给出 main 的地址。
现在,关于查找dlopen
的地址。事实证明我从哈希表中读取了错误数量的符号表条目。哈希表有两种类型(我目前遇到过):DT_HASH
表和DT_GNU_HASH
表。前者的条目数量位于 hash_table_addr + 4
( source ),后者没有明确指定哈希表的数量。需要通过遍历哈希表的桶表来获得这个数量。除此之外,我的方法还不错,现在可以找到dlopen
、malloc
等的地址
要从哈希表中获取符号表的条目数(即大小),可以使用 (C):
ssize_t ReadData(int pid, void* buffer, const void* source, ssize_t size)
{
// Under Ubuntu and other distros with a 'hardened kernel', processes using this function
// should be run as root.
// See https://wiki.ubuntu.com/SecurityTeam/Roadmap/KernelHardening#ptrace_Protection
iovec local_vec;
local_vec.iov_base = Buffer;
local_vec.iov_len = Size;
iovec remote_vec;
remote_vec.iov_base = Address;
remote_vec.iov_len = Size;
return process_vm_readv(pid, &local_vec, 1, &remote_vec, 1, 0);
}
unsigned long FindNumEntriesHashTable(int pid, void* TablePtr, const void* TableLibAddr)
{
// Check if TablePtr is smaller than 0.
unsigned long pointer = ((long)TablePtr < 0) ? (unsigned long)TablePtr + (unsigned long)TableLibAddr : (unsigned long)TablePtr;
unsigned long ret = 0;
ReadData(pid, &ret, (void*)(pointer + sizeof(Elf_Word)), sizeof(Elf_Word));
return ret;
}
unsigned long FindNumEntriesGnuHashTable(int pid, void *TablePtr, const remote_voidptr TableLibAddr)
{
unsigned long pointer = ((long)TablePtr < 0) ? (unsigned long)TablePtr + (unsigned long)TableLibAddr : (unsigned long)TablePtr;
// Read in required info on the gnu_hash table
unsigned long nbuckets = 0;
unsigned long symndx = 0;
unsigned long maskwords = 0;
ReadData(pid, &nbuckets, (const remote_voidptr)pointer, sizeof(Elf_Word));
ReadData(pid, &symndx, (const remote_voidptr)(pointer + sizeof(Elf_Word)), sizeof(Elf_Word));
ReadData(pid, &maskwords, (const remote_voidptr)(pointer + 2 * sizeof(Elf_Word)), sizeof(Elf_Word));
// Calculate the offset to the bucket table. The size of the maskwords entries is 4 under 32 bit, 8 under 64 bit.
unsigned long masktab_size = (ENV_NUMBITS == 32) ? 4 * maskwords : 8 * maskwords;
unsigned long buckettab_offs = 4 * sizeof(Elf_Word) + masktab_size;
// Read in the bucket table
Elf_Word buckettab[nbuckets];
ReadData(pid, &buckettab, (const remote_voidptr)(pointer + buckettab_offs), nbuckets * sizeof(Elf_Word));
// Loop through the bucket table. If the given index is larger than the already known index, update.
unsigned long num_entries = 0;
for (size_t i = 0; i < nbuckets; i++)
{
if (num_entries == 0 || buckettab[i] > num_entries)
{
num_entries = buckettab[i];
}
}
if (num_entries == 0)
{
return 0;
}
// Add one, since the first entry is always NULL.
return num_entries++;
}
关于linux - .so在linux下注入(inject): how to locate address of dlopen()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21651761/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
Linux 管道可以缓冲多少数据?这是可配置的吗? 如果管道的两端在同一个进程中,但线程不同,这会有什么不同吗? 请注意:这个“同一个进程,两个线程”的问题是理论上的边栏,真正的问题是关于缓冲的。 最
我找到了here [最后一页] 一种有趣的通过 Linux 启动 Linux 的方法。不幸的是,它只是被提及,我在网上找不到任何有用的链接。那么有人听说过一种避免引导加载程序而使用 Linux 的方法
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我试图了解 ld-linux.so 如何在 Linux 上解析对版本化符号的引用。我有以下文件: 测试.c: void f(); int main() { f(); } a.c 和 b.c:
与 RetroPie 的工作原理类似,我可以使用 Linux 应用程序作为我的桌面环境吗?我实际上并不需要像实际桌面和安装应用程序这样的东西。我只需要一种干净简单的方法来在 RaspberryPi 上
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
有什么方法可以覆盖现有的源代码,我应该用 PyQt、PyGTK、Java 等从头开始构建吗? 最佳答案 如果您指的是软件本身而不是它所连接的存储库,那么自定义应用程序的方法就是 fork 项目。据我所
我的情况是:我在一个磁盘上安装了两个 linux。我将第一个安装在/dev/sda1 中,然后在/dev/sda2 中安装第二个然后我运行第一个系统,我写了一个脚本来在第一个系统运行时更新它。
我在 i2c-0 总线上使用地址为 0x3f 的系统监视器设备。该设备在设备树中配置有 pmbus 驱动程序。 问题是,加载 linux 内核时,这个“Sysmon”设备没有供电。因此,当我在总线 0
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我正试图在 linux 模块中分配一大块内存,而 kalloc 做不到。 我知道唯一的方法是使用 alloc_bootmem(unsigned long size) 但我只能从 linux 内核而不是
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我有 .sh 文件来运行应用程序。在该文件中,我想动态设置服务器名称,而不是每次都配置。 我尝试了以下方法,它在 CentOS 中运行良好。 nohup /voip/java/jdk1.8.0_71/
我是在 Linux 上开发嵌入式 C++ 程序的新手。我有我的 Debian 操作系统,我在其中开发和编译了我的 C++ 项目(一个简单的控制台进程)。 我想将我的应用程序放到另一个 Debian 操
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我使用4.19.78版本的稳定内核,我想找到带有企鹅二进制数据的C数组。系统启动时显示。我需要在哪里搜索该内容? 我在 include/linux/linux_logo.h 文件中只找到了一些 Log
我知道可以使用 gdb 的服务器模式远程调试代码,我知道可以调试针对另一种架构交叉编译的代码,但是是否可以更进一步,从远程调试 Linux 应用程序OS X 使用 gdbserver? 最佳答案 当然
是否有任何可能的方法来运行在另一个 Linux 上编译的二进制文件?我知道当然最简单的是在另一台机器上重建它,但假设我们唯一能得到的是一个二进制文件,那么这可能与否? (我知道这可能并不容易,但我只是
我是一名优秀的程序员,十分优秀!