我想要做的事情我觉得非常简单,我只是不确定该怎么做。
具体来说,我只想获得在另一个进程中加载的模块列表(共享/动态库)。以及获取该模块在给定过程中的起始地址。
通过GDB获取此信息非常简单。您只需连接到该流程,然后键入“info shared”。这是我想要的确切信息类型。如:
Num Basename
输入地址原因| |资源 | |
| | | | | |
1 Adium
- 0x1000 exec Y Y /Applications/Adium.app/Contents/MacOS/Adium (偏移0x0)2 dyld
- 0x8fe00000 dyld Y Y / usr / lib / dyld,0x8fe00000(偏移量 0x0)带有前缀“__dyld_”3 WebCore F 0x95b6a000 dyld Y Y. /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebCore.framework/Versions/A/WebCore 在0x95b6a000(偏移0x95b6a000)
有没有人知道如何以编程方式执行此操作?显然模块负载是动态的,所以我需要确定它的位置。
答案 0 :(得分:10)
首先使用task_for_pid()获取任务端口。
然后找到" dyld所有图片信息地址"使用task_info:
struct task_dyld_info dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count) == KERN_SUCCESS)
{
// retrieve dyld_info.all_image_info_addr;
}
此地址将指向内存中的struct dyld_all_image_infos:
struct dyld_all_image_infos {
uint32_t version;
uint32_t infoArrayCount;
const struct dyld_image_info* infoArray;
// ...
}
infoArrayCount和infoArray条目在这里很重要。您必须检索这些值(使用mach_vm_read)并遍历infoArray。每个条目都是struct dyld_image_info:
struct dyld_image_info {
const struct mach_header* imageLoadAddress;
const char* imageFilePath;
uintptr_t imageFileModDate;
};
在这个结构中,您有兴趣检索imageLoadAddress(内存中库的地址)和imageFilePath(内存中以NULL终止的文件路径的地址)的值。
重要提示:上面结构中标记为指针或uintptr_t的字段具有不同的字节大小,具体取决于正在运行的进程是32位还是64位。您可以通过查看dyld_info.all_image_info_format是否为TASK_DYLD_ALL_IMAGE_INFO_32或TASK_DYLD_ALL_IMAGE_INFO_64来确定指针大小(应该可以使用,但我自己没有对此进行过测试)。
最后,这仍然不包括动态链接器本身的条目。要检索它,我发现的一种方法是遍历vm区域(即mach_vm_region),找到第一个看起来像它的区域(检查MH_DYLINKER作为文件类型;请参阅mach-o文件格式以获取更多信息)。最后我记得检查,gdb和/或lldb也有这样做的功能。解析mach头也是判断进程是32位还是64位的一种可能方法。
检索完所有dyld图像信息条目后,您可能还希望按地址对它们进行排序。
我建议不要查看newosxbook的vmmap实现代码。它已经过时了(因为它仍然使用DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET),它会做一些不必要的暴力破解。
答案 1 :(得分:2)
我建议您下载gdb as used by the Development Tools的来源。
但是,好吧,我已读取该来源,我不确定告诉任何人去阅读它是一个富有成效的建议。
在任何情况下,您都希望使用各种mach
API来执行此操作。特别是,API可以在/usr/include/mach/*.h
中找到。具体来说,您需要从task_for_pid()
开始,然后逐步了解所需的信息。
请注意task_for_pid()
(以及用于grub通过其他任务的任何其他机制)需要管理员访问权限或计算机上development
组的成员资格。
答案 2 :(得分:2)
您可以从Breakpad项目中获取一些现有的BSD许可代码,这些代码就是这样:
dyld为GDB提供了一些钩子,特别是一个众所周知的函数符号,gdb可以使用它来访问包含此信息的结构。 见http://www.opensource.apple.com/source/dyld/dyld-132.13/include/mach-o/dyld_images.h 您可以在这里看到GDB如何做到这一点: http://www.opensource.apple.com/source/gdb/gdb-1344/src/gdb/macosx/macosx-nat-dyld.c(查找“macosx_init_addresses”)。 lookup_minimal_symbol的内部结构太难以讨论,但Breakpad的实现相当简单。
答案 3 :(得分:1)
感谢@Zorg提供了很好的解释。基于@Zorg的澄清,我编写了一个简单的代码片段,它实现了内核内存复制部分所需的功能。请看一看。
#include <stdio.h>
#include <stdlib.h>
#include <mach-o/dyld_images.h>
#include <mach/vm_map.h>
#define PATH_MAX 2048
// to build.
// cc -o test_mach test_mach.c
// Helper function to read process memory (a la Win32 API of same name) To make
// it easier for inclusion elsewhere, it takes a pid, and does the task_for_pid
// by itself. Given that iOS invalidates task ports after use, it's actually a
// good idea, since we'd need to reget anyway
unsigned char *
readProcessMemory (int pid,
mach_vm_address_t addr,
mach_msg_type_number_t* size) {
task_t t;
task_for_pid(mach_task_self(), pid, &t);
mach_msg_type_number_t dataCnt = (mach_msg_type_number_t) *size;
vm_offset_t readMem;
// Use vm_read, rather than mach_vm_read, since the latter is different in
// iOS.
kern_return_t kr = vm_read(t, // vm_map_t target_task,
addr, // mach_vm_address_t address,
*size, // mach_vm_size_t size
&readMem, //vm_offset_t *data,
&dataCnt); // mach_msg_type_number_t *dataCnt
if (kr) {
fprintf (stderr, "Unable to read target task's memory @%p - kr 0x%x\n" ,
(void *) addr, kr);
return NULL;
}
return ( (unsigned char *) readMem);
}
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "Invalid usage %s\n", argv[0]);
exit(0);
}
int pid = atoi(argv[1]);
task_t task;
task_for_pid(mach_task_self(),pid, &task);
struct task_dyld_info dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(task, TASK_DYLD_INFO, (task_info_t) &dyld_info, &count)
== KERN_SUCCESS) {
mach_msg_type_number_t size = sizeof(struct dyld_all_image_infos);
uint8_t* data =
readProcessMemory(pid, dyld_info.all_image_info_addr, &size);
struct dyld_all_image_infos* infos = (struct dyld_all_image_infos *) data;
mach_msg_type_number_t size2 =
sizeof(struct dyld_image_info) * infos->infoArrayCount;
uint8_t* info_addr =
readProcessMemory(pid, (mach_vm_address_t) infos->infoArray, &size2);
struct dyld_image_info* info = (struct dyld_image_info*) info_addr;
for (int i=0; i < infos->infoArrayCount; i++) {
mach_msg_type_number_t size3 = PATH_MAX;
uint8_t* fpath_addr = readProcessMemory(pid,
(mach_vm_address_t) info[i].imageFilePath, &size3);
if (fpath_addr)
printf("path: %s %d\n",fpath_addr , size3);
}
}
return 0;
}