gpt4 book ai didi

linux - .so在linux下注入(inject): how to locate address of dlopen()?

转载 作者:太空狗 更新时间:2023-10-29 12:16:51 26 4
gpt4 key购买 nike

最近我对 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 -sreadelf -D --dyn-sym 也不会给出 main 的地址。

现在,关于查找dlopen 的地址。事实证明我从哈希表中读取了错误数量的符号表条目。哈希表有两种类型(我目前遇到过):DT_HASH 表和DT_GNU_HASH 表。前者的条目数量位于 hash_table_addr + 4 ( source ),后者没有明确指定哈希表的数量。需要通过遍历哈希表的桶表来获得这个数量。除此之外,我的方法还不错,现在可以找到dlopenmalloc等的地址

要从哈希表中获取符号表的条目数(即大小),可以使用 (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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com