2010-11-29 9 views
7

Lo que estoy tratando de hacer creo que es bastante sencillo, simplemente no estoy seguro de cómo hacerlo exactamente.Determinar mediante programación qué módulos se cargan en otro proceso? (OS X)

Específicamente, solo quiero obtener una lista de módulos (bibliotecas compartidas/dinámicas) que se cargan en otro proceso. Además de obtener la dirección de inicio de dónde está ese módulo en el proceso determinado.

Es muy sencillo obtener esta información con GDB. Simplemente, conéctese al proceso y escriba "información compartida". Ese es el tipo exacto de información que me gustaría obtener. Tales como:

Num Nombre base
Tipo de dirección Razón | | Fuente | |
| | | | | |
1 Adium
- 0x1000 /Applications/Adium.app/Contents/MacOS/Adium exec YY (offset 0x0) 2 dyld
- 0x8fe00000 dyld YY/usr/lib/dyld en 0x8fe00000 (offset 0x0) con el prefijo "__dyld_" 3 WebCore F 0x95b6a000 dyld YY /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebCore.framework/Versions/A/WebCore en 0x95b6a000 (offset 0x95b6a000)

¿Alguien sabe cómo hacer esto programáticamente? Obviamente, donde la carga de los módulos es dinámica, necesito determinar dónde está ubicada.

+0

¿Está interesado únicamente en hacer esto para OS X? – Karmastan

Respuesta

2

Yo sugeriría que pudiera descargar la fuente gdb as used by the Development Tools.

Pero, bueno, tengo leo esa fuente y no estoy seguro de que decirle a alguien que vaya a leerla sea una sugerencia productiva.

En cualquier caso, querrá usar las diversas API mach para hacer esto. En particular, las API se encuentran en /usr/include/mach/*.h. Específicamente, querrás comenzar con task_for_pid() y seguir la información que necesites.

Tenga en cuenta que task_for_pid() (y cualquier otro mecanismo utilizado para atravesar otras tareas internas) requiere acceso de administrador o membresía en el grupo development en la máquina.

+0

Gracias por las sugerencias, en realidad comencé por esa ruta pero no pude ver qué funciones realmente proporcionan la información en los módulos compartidos:/ Pero sí enciendo la aplicación con acceso de root y uso task_for_pid y vm_read_overwrite para memoria acceso, etc ... ¿Alguna idea en GDB donde debería buscar más específicamente? Literalmente pasé 2 horas en él cuando lo intenté por primera vez y no pude encontrar dónde estaba:/ – Geesu

+1

No, no he extraído el código gdb en mucho, mucho tiempo. Es un lugar hiriente. – bbum

+0

No creo que deba leer la memoria de la aplicación de destino, pero lea el mach-o pase la información de la zona vm. Si se puede encontrar la fuente de vmmap, dará un ejemplo mucho más conciso. – bbum

2

Hay un cierto código de licencia BSD existente se puede tomar desde el proyecto Breakpad que hace exactamente esto:

dyld ofrece algunos ganchos para GDB, en particular un pozo - Símbolo de función conocida que gdb puede usar para obtener acceso a una estructura que contiene esta información. Ver http://www.opensource.apple.com/source/dyld/dyld-132.13/include/mach-o/dyld_images.h Puede ver cómo lo hace GDB aquí: http://www.opensource.apple.com/source/gdb/gdb-1344/src/gdb/macosx/macosx-nat-dyld.c (busque "macosx_init_addresses"). Las partes internas de lookup_minimal_symbol son demasiado horribles para hablar, pero la implementación de Breakpad es bastante sencilla.

9

Primero use task_for_pid() para obtener un puerto de tarea.

luego encontrar el "dyld todas las direcciones de imágenes información" utilizando 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; 
} 

Esta dirección redireccionen a un dyld_all_image_infos struct en la memoria:

struct dyld_all_image_infos { 
    uint32_t version; 
    uint32_t infoArrayCount; 
    const struct dyld_image_info* infoArray; 
    // ... 
} 

Las entradas infoArrayCount y infoArray son importantes aquí . Debe recuperar estos valores (use mach_vm_read) e iterar a través de infoArray. Cada entrada es un dyld_image_info estructura:

struct dyld_image_info { 
    const struct mach_header* imageLoadAddress; 
    const char* imageFilePath; 
    uintptr_t imageFileModDate; 
}; 

En esta estructura, que está interesado en la recuperación de los valores a imageLoadAddress (una dirección a la biblioteca en la memoria) y imageFilePath (una dirección a la terminación nula ruta de archivo en la memoria) .

Nota importante: los campos que están marcados como un puntero o como uintptr_t en las estructuras anteriores tienen un tamaño de bytes diferente según si el proceso en ejecución es de 32 o 64 bits. Puede determinar el tamaño del puntero al ver si dyld_info.all_image_info_format es TASK_DYLD_ALL_IMAGE_INFO_32 o TASK_DYLD_ALL_IMAGE_INFO_64 (debería funcionar, pero yo no lo he probado).

Por último, esto todavía no incluirá una entrada en el vinculador dinámico en sí. Para recuperar eso, una manera que he encontrado es recorrer las regiones vm (es decir, mach_vm_region), y encontrar la primera región que parece que es un dylinker mach (verifique MH_DYLINKER como el tipo de archivo; consulte el formato de archivo mach-o para más información). La última vez que recuerdo, check, gdb y/o lldb tienen una función para hacer esto también. Analizar el encabezado mach también es una forma posible de saber si el proceso es de 32 o 64 bits.

Después de recuperar todas las entradas de información de imagen Dyld, es posible que también desee ordenarlas por dirección.

Recomiendo no mirar el código de newosxbook para su implementación de vmmap. Está desactualizado (ya que todavía usa DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET), y hace un forzado bruto innecesario.

+0

No puedo expresar lo agradecido que estoy por esto. Me ahorrará mucho tiempo. – alcuadrado

+0

Tengo problemas para obtener la estructura dyld_image_info. Cada vez que lo saco de la memoria me estoy poniendo NULO. Estoy calculando el tamaño del byte como infoSize = sizeof (* imageInfo) * imageInfos-> infoArrayCount; ¿Podría ser esto para hacer con 64/32bit count? – mattvv

+0

@mattvv que el cálculo no parece funcionar si el tamaño del puntero del proceso difiere del tamaño del puntero del objetivo; por lo tanto, tampoco debería usar struct dyld_image_info. Edité mi publicación anterior que muestra otra forma posible de determinar el tamaño del puntero del objetivo. – Zorg

1

Gracias @Zorg por una gran explicación. Basado en la aclaración de @Zorg, escribí un fragmento simple que implementa las funcionalidades requeridas junto con la parte de copia de la memoria del kernel. Por favor échale un vistazo.

#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; 
} 
+0

¿Cuál es el propósito de * vm_offset_t readMem; *? No encuentro ninguna documentación sobre el tipo * vm_offset_t * y parece que * readMem * es solo un tipo de variable ficticia. –

Cuestiones relacionadas