ios遍历模块的方式

方式一:
通过mach_vm_region系统API
参考代码:https://github.com/davidrhodus/misc/blob/master/iOS-internals/vmmap.c

#include <mach/vm_map.h>
#include <stdio.h>

#include <mach-o/dyld_images.h>

/**
 * vmmap(1) clone for OS X and iOS
 * -------------------------------
 *
 * This is a simple example of using the mach_vm_region_info APIs in order to 
 * obtain a process' (technically, a task's) virtual memory address space, in a
 * manner akin to /proc/[pid]/maps on Linux.
 *
 * The process is simple - get the task port, then call mach_vm_region_info until
 * you've exhausted the address space (in iOS this happens around 0x40000000, 
 * where the commpage is). On iOS 6, for some peculiar reason the task port is
 * invalidated after each call, so the quick workaround here solves the problem
 * by regetting the port. The actual mach error code to check for is in the header
 * files, though the code simply tries regetting.
 *
 * N.B - For this code to work, you MUST provide the entitlements to allow 
 * task-for-pid to work, else you'll fail with error 5. The entitlements are in 
 * the output in Chapter 3, but for those of you who haven't bought the book, it would be:
 *
--- Cut here 

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>com.apple.springboard.debugapplications</key>
        <true/>
        <key>get-task-allow</key>
        <true/>
        <key>proc_info-allow</key>
        <true/>
        <key>task_for_pid-allow</key>
        <true/>
        <key>run-unsigned-code</key>
        <true/>
</dict>
</plist>

--- Ok, enough :-)
 *
 *  so - copy the above XML to a file, say, "ent.xml", and be sure to run "ldid -Sent.xml vmmap"
 *  before trying to run this. You can download the binary (already thus signed) if you're lazy
 *  (and trust me, because you *will* need root on your i-Device for this)
 *
 *  As the book clearly states, once you have the task port, the world is your oyster. You can
 *  control the entire virtual memory space, reading and writing it as you please. Stay tuned
 *  for the corrupt tool (which will be provided soon in binary form)
 *
 */

int g_pid = 0; // required in iOS 6 (read below)

 /* 03/08/13 - Added List of Mach-O images: */

struct dyld_image_info *g_dii = NULL;
int     g_imageCount;
//读取进程内存数据
unsigned char *
readProcessMemory (int pid, mach_vm_address_t addr, mach_msg_type_number_t *size)
{
    // 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

    task_t  t;
    //获取进程中的任务
    task_for_pid(mach_task_self(),pid, &t);
        mach_msg_type_number_t  dataCnt = 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,
                     size);     // mach_msg_type_number_t *dataCnt

        if (kr) {
                // DANG..
                fprintf (stderr, "Unable to read target task's memory @%p - kr 0x%x\n" , addr, kr);
                 return NULL;
                }

    return ( (unsigned char *) readMem);

}

kern_return_t mach_vm_read (vm_map_t, mach_vm_address_t, mach_vm_size_t, vm_offset_t *, mach_msg_type_number_t *);
//暴利搜索内存
void 
findListOfBinaries(task_t  t, mach_vm_address_t    addr, int size)
{

        kern_return_t kr;
        mach_msg_type_number_t  dataCnt = size;
        // 读取指定内存地址上指定大小的内容
        unsigned char *readData = readProcessMemory (g_pid, addr, &dataCnt);
        int machsig = 0xfeedface;

    // Checking only 0xfeedfa is a simple way to catch both 64-bit (facf) and 32-bit (face) headers
        // Machine endianness is automatically taken care of, too..
    // 判断是否是macho头
    if (readData && memcmp (readData + 1, ((unsigned char *) &machsig) + 1 , 3) == 0)
    {
        // This is a Mach header
        int i = 0;
        // A MUCH better way would be to iterate through the LC and find the name of dyld
        // but this would require my machlib.c (closed source) and really get the same result.
        // This works because on both iOS and OS X dyld is at /usr/lib.

        for (i = 0; i <dataCnt; i++)
        {   
            // 循环比较内存内容是否是"lib/dyld"
            if (memcmp(readData+i, "lib/dyld", 8) == 0)
            {
                unsigned int dyld_all_image_infos_offset ;
                int imageCount = 0;
                // 拷贝导入模块信息
                memcpy (&dyld_all_image_infos_offset, readData+DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET, sizeof (unsigned int));
                 struct dyld_all_image_infos *dyldaii ;
                 // Safeguard: should check that dyld_all_image_infos_offset is < size..
                if (dyld_all_image_infos_offset > size)
                {
                    // This is to be expected, since the dyld_all_image_infos is in a data region
                    //printf ("Offset %x is greater than region size : %x\n", dyld_all_image_infos_offset, size);
                    dataCnt = sizeof(dyld_all_image_infos);
                    readData = readProcessMemory (g_pid, addr + dyld_all_image_infos_offset , &dataCnt);

                    if (!readData) { return;}
                    dyldaii = (struct dyld_all_image_infos *) readData;
                }
                else
                {
                    dyldaii = (struct dyld_all_image_infos *) (readData +dyld_all_image_infos_offset);
                }
                printf ("Version: %d, %d images at offset %p\n",
                        dyldaii->version, dyldaii->infoArrayCount, dyldaii->infoArray);

                // Go to dyldaii->infoArray address

                imageCount = dyldaii->infoArrayCount;
                // 保存导入模块信息
                dataCnt = imageCount * sizeof(struct dyld_image_info);
                g_dii = (struct dyld_image_info *) malloc (dataCnt);
                g_imageCount = imageCount;
                readData = readProcessMemory(g_pid, dyldaii->infoArray, &dataCnt);
                if (!readData) { return;}

                struct dyld_image_info *dii = (struct dyld_image_info *) readData;

                // We don't need i anymore, anyway
                for (i = 0; i < imageCount; i++)
                    {
                        dataCnt = 1024;
                        char *imageName = readProcessMemory (g_pid, dii[i].imageFilePath, &dataCnt);
                        if (imageName) g_dii[i].imageFilePath = strdup(imageName);
                        else g_dii[i].imageFilePath = NULL;
                        g_dii[i].imageLoadAddress = dii[i].imageLoadAddress;
                    }

                break;
            }

        }
    }

}

 /* End 03/08/13 */
char *
behavior_to_text (vm_behavior_t b)
{

  switch (b)
    {
        case VM_BEHAVIOR_DEFAULT: return("default");
        case VM_BEHAVIOR_RANDOM:  return("random");
        case VM_BEHAVIOR_SEQUENTIAL: return("fwd-seq");
        case VM_BEHAVIOR_RSEQNTL: return("rev-seq");
        case VM_BEHAVIOR_WILLNEED: return("will-need");
        case VM_BEHAVIOR_DONTNEED: return("will-need");
        case VM_BEHAVIOR_FREE: return("free-nowb");
        case VM_BEHAVIOR_ZERO_WIRED_PAGES: return("zero-wire");
        case VM_BEHAVIOR_REUSABLE: return("reusable");
        case VM_BEHAVIOR_REUSE: return("reuse");
        case VM_BEHAVIOR_CAN_REUSE: return("canreuse");
        default: return ("?");
    }

}
//内存属性
char *
protection_bits_to_rwx (vm_prot_t p)
{

  // previous version of this somehow lost the "p&", always returning rwx..
  static char returned[4];

  returned[0] = (p &VM_PROT_READ    ? 'r' : '-');
  returned[1] = (p &VM_PROT_WRITE   ? 'w' : '-');
  returned[2] = (p & VM_PROT_EXECUTE ? 'x' : '-');
  returned[3] = '\0';

 // memory leak here. No biggy
  return (strdup(returned));

}
//当前内存状态
const char *
unparse_inheritance (vm_inherit_t i)
{
  switch (i)
    {
    case VM_INHERIT_SHARE:
      return "share";
    case VM_INHERIT_COPY:
      return "copy";
    case VM_INHERIT_NONE:
      return "none";
    default:
      return "???";
    }
}

macosx_debug_regions (task_t task, mach_vm_address_t address, int max)
{
  kern_return_t kret;

  mach_vm_address_t prev_address;
  /* @TODO: warning - potential overflow here - gotta fix this.. */
  vm_region_basic_info_data_t prev_info,info;
  mach_vm_size_t size, prev_size;

  mach_port_t object_name;
  mach_msg_type_number_t count;
  //模块总共读的块数
  int nsubregions = 0;
  // 已遍历的模块数
  int num_printed = 0;

  count = VM_REGION_BASIC_INFO_COUNT_64;
  kret = mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO,
             (vm_region_info_t) &info, &count, &object_name);

  if (kret != KERN_SUCCESS)
    {
      printf ("mach_vm_region: Error %d - %s", kret, mach_error_string(kret));
      return;
    }
  //保存上一次遍历的模块信息
  memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_t));
  prev_address = address;
  prev_size = size;
  // 已获取1块
  nsubregions = 1;

  for (;;)
    {
      int print = 0;
      int done = 0;

      address = prev_address + prev_size;

      /* Check to see if address space has wrapped around. */
      // 遍历模块结束
      if (address == 0)
    { 
        print = done = 1;
    }

      if (!done)
        {
          // Even on iOS, we use VM_REGION_BASIC_INFO_COUNT_64. This works.

          count = VM_REGION_BASIC_INFO_COUNT_64;

          // 读取从address开始的第一个正确的模块信息,注意这里可能不是一个模块头
          kret =
            mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO,
                          (vm_region_info_t) &info, &count, &object_name);

          if (kret != KERN_SUCCESS)
            {
        /* iOS 6 workaround - attempt to reget the task port to avoiD */
        /* "(ipc/send) invalid destination port" (1000003 or something) */
        task_for_pid(mach_task_self(),g_pid, &task);
        // 重新获取一遍
        kret =
            mach_vm_region (task, &address, &size, VM_REGION_BASIC_INFO,
                              (vm_region_info_t) &info, &count, &object_name);

        }
       if (kret != KERN_SUCCESS)
    {
        fprintf (stderr,"mach_vm_region failed for address %p - Error: %x\n", address,(kret));
              size = 0;
    if (address >= 0x4000000) return;
              print = done = 1;
            }
        }
      // 如果上一个内存起始地址+内存大小!=当前的地址,说明是新的模块
      if (address != prev_address + prev_size)
        print = 1;
      // 如果内存属性不同,说明是新的模块
      if ((info.protection != prev_info.protection)
          || (info.max_protection != prev_info.max_protection)
          || (info.inheritance != prev_info.inheritance)
          || (info.shared != prev_info.reserved)
          || (info.reserved != prev_info.reserved))
        print = 1;
      //如果是新的模块,获取它的其它信息
      if (print)
        {
      int   print_size;
      char *print_size_unit;
          if (num_printed == 0)

            printf ("Region ");
          else
            printf ("   ... ");

       findListOfBinaries(task, prev_address, prev_size);
      /* Quick hack to show size of segment, which GDB does not */
      print_size = prev_size;
      if (print_size > 1024) { print_size /= 1024; print_size_unit = "K"; }
      if (print_size > 1024) { print_size /= 1024; print_size_unit = "M"; }
      if (print_size > 1024) { print_size /= 1024; print_size_unit = "G"; }
      /* End Quick hack */
          printf (" %p-%p [%d%s](%s/%s; %s, %s, %s) %s",
                           (prev_address),
                           (prev_address + prev_size),
               print_size,
               print_size_unit,
                           protection_bits_to_rwx (prev_info.protection),
                           protection_bits_to_rwx (prev_info.max_protection),
                           unparse_inheritance (prev_info.inheritance),
                           prev_info.shared ? "shared" : "private",
                           prev_info.reserved ? "reserved" : "not-reserved",
               behavior_to_text (prev_info.behavior));

          if (nsubregions > 1)
            printf (" (%d sub-regions)", nsubregions);

          printf ("\n");
          // 把此次内存信息保存起来
          prev_address = address;
          prev_size = size;
          memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_t));
          nsubregions = 1;

          num_printed++;
        }
      else
        {
          //如果不是新的模块,只增加模块大小
          prev_size += size;
          nsubregions++;
        }

      if ((max > 0) && (num_printed >= max))
    {
     printf ("Max %d num_printed %d\n", max, num_printed);
        done = 1;
    }

      if (done)
        break;
    }
}

void 
main(int argc, char **argv)
{

    struct vm_region_basic_info vmr;
    kern_return_t   rc;
    mach_port_t task;

    mach_vm_size_t  size = 8;
    vm_region_info_t    info = (vm_region_info_t) malloc(10000);
    mach_msg_type_number_t  info_count;
    mach_port_t     object_name;
    //初始值设为1
    mach_vm_address_t   addr =1;
    int pid;
    //需要提供参数1为目标进程的PID
        if (!argv[1]) { printf ("Usage: %s <PID>\n"); exit (1);}
        //把参数1转换成pid
    pid = atoi(argv[1]);
    g_pid = pid; // req for iOS 6
    // 获取目标进程的task
    rc = task_for_pid(mach_task_self(),pid, &task);

    if (rc) { fprintf (stderr, "task_for_pid() failed with error %d - %s\n", rc, mach_error_string(rc)); exit(1); }
    printf ("RC %d - Task: %d\n",rc, task);

    macosx_debug_regions (task, addr, 1000);

    int i ;

    for ( i = 0; i < g_imageCount; i++)
    {
        printf("Image: %s loaded @%p\n",
            g_dii[i].imageFilePath, g_dii[i].imageLoadAddress);
    }
    printf("Done\n");

}

方式二:
通过_dyld_getimage*系列API

头文件:dyld.h
函数原型:
//获取当前进程加载的模块数。
uint32_t                    _dyld_image_count(void);
//获取内存中某个模块的头部指针。
const struct mach_header*   _dyld_get_image_header(uint32_t image_index);
//获取内存中某个模块的slide值。
intptr_t                    _dyld_get_image_vmaddr_slide(uint32_t image_index);
// 获取内存中某个模块的名称。
const char*                 _dyld_get_image_name(uint32_t image_index);
实现:
#import
int32_t nModNums= _dyld_image_count();
const char *pszModName = NULL;
intptr_t pModSlide = 0;
const struct mach_header* pModHeader = NULL;

for (uint32_t i = 0; i < nModNums; i++)
{
pModSlide  = _dyld_get_image_vmaddr_slide(i);
pszModName = _dyld_get_image_name(i);
pModHeader = _dyld_get_image_header(i);
}

转载于:https://blog.51cto.com/haidragon/2164203

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS框架模块开发指的是将iOS应用程序按照功能进行拆分,将不同功能的代码和资源整合到不同的框架中进行开发。这样做的好处是可以提高代码的可重用性和项目的可维护性。 在iOS开发中,一个框架是一个集合了相关功能代码、资源文件和配置文件的独立模块。通过将应用程序的功能拆分成不同的框架,可以让代码结构更加清晰,易于组织和维护。同时,这也便于多人协作开发,不同的团队可以负责不同的框架,提高开发效率。 另外,框架模块化开发的另一个好处是代码的可重用性。一个好的框架应该是独立、可移植和可扩展的,可以被多个项目共用,减少重复开发的工作量。例如,可以将网络请求、数据库操作、UI组件等功能封装到不同的框架中,其他项目只需要引入相应的框架即可使用这些功能,提高开发效率和代码质量。 在开发iOS框架模块时,我们需要注意将主要的业务逻辑与框架相关的代码进行分离,提高框架的可重用性。同时,框架的接口设计也需要易于理解和使用,方便其他开发者进行集成和扩展。 总而言之,iOS框架模块开发可以帮助我们将应用程序按照功能进行拆分,提高代码的可重用性和项目的可维护性。通过合理的框架设计和模块化开发,可以提高开发效率,减少重复劳动,同时也提高了代码的可读性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值