首页
社区
课程
招聘
[分享][原创]修改android app_process elf (实现rrrfff大神 <android全局注入>第一步)
发表于: 2018-1-25 23:11 12857

[分享][原创]修改android app_process elf (实现rrrfff大神 <android全局注入>第一步)

2018-1-25 23:11
12857

好久没注意我自己留的坑,所以,看到有人回复想要镜像,于是根据这段时间看android/linker源码的内容,写了一个简单的自动化修改app_process工具,运行过之后返回的so的名字,就是最终你注入的so的名字。






tag 为debug的被修改为了我们自己注入的so的名字

更新

好久没注意我自己留的坑,所以,看到有人回复想要镜像,于是根据这段时间看android/linker源码的内容,写了一个简单的自动化修改app_process工具,运行过之后返回的so的名字,就是最终你注入的so的名字。






tag 为debug的被修改为了我们自己注入的so的名字


我是一名做android安全的新手,最近在论坛里看到@rrrfff大神发的博文一种简单的Android全局注入方案 很受启发,准备结合着xposed学习一下。没想到第一步就遇到了阻碍^_^。不知道论坛里的各位大佬是怎么修改elf的,我的方案是手动寻找到dyn表的位置,然后打印出来tag和value值,再把映射的值放到程序里去写入到app_process中。以下是我个人的思路:
第一步找到dyn在app_process文件中的偏移位置:
readelf -d app_process
看显示内容:
yougar@ubuntu:~/Programs/so_injection/os$ readelf -d app_process 

Dynamic section at offset 0x3dc0 contains 32 entries: ## offset
  Tag        Type                         Name/Value
 0x00000003 (PLTGOT)                     0x4f0c
 0x00000002 (PLTRELSZ)                   440 (bytes)
 0x00000017 (JMPREL)                     0xe74
 0x00000014 (PLTREL)                     REL
 0x00000011 (REL)                        0xdb4
 0x00000012 (RELSZ)                      192 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffa (RELCOUNT)                   21
 0x00000015 (DUBUG)                      0x0
 0x00000006 (SYMTAB)                     0x148
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000005 (STRTAB)                     0x598
 0x0000000a (STRSZ)                      1521 (bytes)
 0x00000004 (HASH)                       0xb8c
 0x00000001 (NEEDED)                     Shared library: [libandroid_runtime.so]
 0x00000001 (NEEDED)                     Shared library: [libbinder.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x00000001 (NEEDED)                     Shared library: [libcutils.so]
 0x00000001 (NEEDED)                     Shared library: [libdl.so]
 0x00000001 (NEEDED)                     Shared library: [liblog.so]
 0x00000001 (NEEDED)                     Shared library: [libm.so]
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so]
 0x00000001 (NEEDED)                     Shared library: [libutils.so]
 0x00000020 (PREINIT_ARRAY)              0x4d40
 0x00000021 (PREINIT_ARRAYSZ)            0x8
 0x00000019 (INIT_ARRAY)                 0x4d48
 0x0000001b (INIT_ARRAYSZ)               12 (bytes)
 0x0000001a (FINI_ARRAY)                 0x4d54
 0x0000001c (FINI_ARRAYSZ)               8 (bytes)
 0x0000001e (FLAGS)                      BIND_NOW
 0x6ffffffb (FLAGS_1)                    Flags: NOW
 0x00000000 (NULL)                       0x0
发现偏移位置为0x3dc0,转换为10进制是15808
第二步结合<elf.h>打印出d_tag为0x00000001,第一个tag类型为needed的d_val,源码如下:
#include <stdio.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>

long parse_long(const char * v) {
  long off;
  off = atol(v);
  if(off == 0) {
    if(errno != 0) {
      error(201, errno, "parse offset <%s> to unsigned long", v);
      return -1;
    }
  }
  return off;
}

int main(int argc, const char **argv) {
  if(argc != 3) {
    printf("usage:%s <file> <offset>\n", argv[0]);
    return -1;
  }

  off_t offset, current, value;
  offset = parse_long(argv[2]);
  if(offset == -1) {
    return -1;
  }

  int f_id;
  f_id = open(argv[1], O_RDONLY);
  if (f_id == -1) {
    error(201, errno, "open %s;", argv[1]);
    return -1;
  }
  
  size_t len = sizeof(Elf32_Dyn); // 单个dyn在文件中所占大小

  offset +=  14 * len;  // 由于第一个出现needed类型的tag在tag数组里的偏移是14,所以这里设置偏移长度+14 * len

  current = lseek(f_id, offset, SEEK_SET);
  if(current == -1) {
    error(201, errno, "lseek file with offset %ld", offset);
    return -1;
  }

  if(current != offset) {
    printf("file %s current pos <%ld> not equal to offset <%ld>\n", argv[1], current, offset);
    return -1;
  }
    
  Elf32_Dyn *elf32_dyn = (Elf32_Dyn*)malloc(len);  

  read(f_id, elf32_dyn, len);
  printf("Tag: %u, Val: %u\n", elf32_dyn -> d_tag, elf32_dyn -> d_un.d_val);
      
}
运行之,打印结果:
Tag: 1, Val: 1413
这里的这个val对应的是字符表的字符偏移,去掉lib占的内存,那么我的程序应该设置的val大小为1416
第三步修改tag和val,代码如下:
#include <stdio.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>

long parse_long(const char * v) {
  long off;
  off = atol(v);
  if(off == 0) {
    if(errno != 0) {
      error(201, errno, "parse offset <%s> to unsigned long", v);
      return -1;
    }
  }
  return off;
}

int main(int argc, const char **argv) {
  if(argc != 4) {
    printf("usage:%s <file> <offset> <value>\n", argv[0]);
    return -1;
  }

  off_t offset, current, value;
  offset = parse_long(argv[2]);
  if(offset == -1) {
    return -1;
  }

  value = parse_long(argv[3]);
  if(value == -1) {
    return -1;
  }

  int f_id;
  f_id = open(argv[1], O_RDWR);
  if (f_id == -1) {
    error(201, errno, "open %s;", argv[1]);
    return -1;
  }
  
  size_t len = sizeof(Elf32_Dyn);

  offset +=  8 * len; // 要修改的dyn在数组中的偏移位置是8 

  current = lseek(f_id, offset, SEEK_SET);
  if(current == -1) {
    error(201, errno, "lseek file with offset %ld", offset);
    return -1;
  }

  if(current != offset) {
    printf("file %s current pos <%ld> not equal to offset <%ld>\n", argv[1], current, offset);
    return -1;
  }
    
  Elf32_Dyn *elf32_dyn = (Elf32_Dyn*)malloc(len);  

  elf32_dyn -> d_tag = DT_NEEDED;
  elf32_dyn -> d_un.d_val = value;
  
  write(f_id, elf32_dyn, len);
      
}

到这里修改操作全部完成。查看结果:
有一点我的方案跟rrrfff大神的不太一样,就是我是直接把修改过的app_process push到模拟器里面的,没有改虚拟机文件。在这一步,我还遇到了一点小问题,不过,google之后,还是顺利解决了。这里我还是分享一下吧,作为备忘录。
问题如下:
adb push C:\***\app_process /system/bin之后,报read-only file system错误。这个我早想到过,于是按照有人提出的解决方法mount -o remount,rw /system,发现运行过这个命令之后,竟然报相同的错误。这一解决方案被很多人采纳了,可为啥我的就不行。后来又看到一个相似的提问的回答,然后成功解决了我的问题。回答是:启动模拟器的命令参数要有-writable-system才可以写/system文件夹。

readelf -d app_process
看显示内容:
yougar@ubuntu:~/Programs/so_injection/os$ readelf -d app_process 

Dynamic section at offset 0x3dc0 contains 32 entries: ## offset
  Tag        Type                         Name/Value
 0x00000003 (PLTGOT)                     0x4f0c
 0x00000002 (PLTRELSZ)                   440 (bytes)
 0x00000017 (JMPREL)                     0xe74
 0x00000014 (PLTREL)                     REL
 0x00000011 (REL)                        0xdb4
 0x00000012 (RELSZ)                      192 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffa (RELCOUNT)                   21
 0x00000015 (DUBUG)                      0x0
 0x00000006 (SYMTAB)                     0x148
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000005 (STRTAB)                     0x598
 0x0000000a (STRSZ)                      1521 (bytes)
 0x00000004 (HASH)                       0xb8c
 0x00000001 (NEEDED)                     Shared library: [libandroid_runtime.so]
 0x00000001 (NEEDED)                     Shared library: [libbinder.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x00000001 (NEEDED)                     Shared library: [libcutils.so]
 0x00000001 (NEEDED)                     Shared library: [libdl.so]
 0x00000001 (NEEDED)                     Shared library: [liblog.so]
 0x00000001 (NEEDED)                     Shared library: [libm.so]
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so]
 0x00000001 (NEEDED)                     Shared library: [libutils.so]
 0x00000020 (PREINIT_ARRAY)              0x4d40
 0x00000021 (PREINIT_ARRAYSZ)            0x8
 0x00000019 (INIT_ARRAY)                 0x4d48
 0x0000001b (INIT_ARRAYSZ)               12 (bytes)
 0x0000001a (FINI_ARRAY)                 0x4d54
 0x0000001c (FINI_ARRAYSZ)               8 (bytes)
 0x0000001e (FLAGS)                      BIND_NOW
 0x6ffffffb (FLAGS_1)                    Flags: NOW
 0x00000000 (NULL)                       0x0
发现偏移位置为0x3dc0,转换为10进制是15808
第二步结合<elf.h>打印出d_tag为0x00000001,第一个tag类型为needed的d_val,源码如下:
#include <stdio.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>

long parse_long(const char * v) {
  long off;
  off = atol(v);
  if(off == 0) {
    if(errno != 0) {
      error(201, errno, "parse offset <%s> to unsigned long", v);
      return -1;
    }
  }
  return off;
}

int main(int argc, const char **argv) {
  if(argc != 3) {
    printf("usage:%s <file> <offset>\n", argv[0]);
    return -1;
  }

  off_t offset, current, value;
  offset = parse_long(argv[2]);
  if(offset == -1) {
    return -1;
  }

  int f_id;
  f_id = open(argv[1], O_RDONLY);
  if (f_id == -1) {
    error(201, errno, "open %s;", argv[1]);
    return -1;
  }
  
  size_t len = sizeof(Elf32_Dyn); // 单个dyn在文件中所占大小

  offset +=  14 * len;  // 由于第一个出现needed类型的tag在tag数组里的偏移是14,所以这里设置偏移长度+14 * len

  current = lseek(f_id, offset, SEEK_SET);
  if(current == -1) {
    error(201, errno, "lseek file with offset %ld", offset);
    return -1;
  }

  if(current != offset) {
    printf("file %s current pos <%ld> not equal to offset <%ld>\n", argv[1], current, offset);
    return -1;
  }
    
  Elf32_Dyn *elf32_dyn = (Elf32_Dyn*)malloc(len);  

  read(f_id, elf32_dyn, len);
  printf("Tag: %u, Val: %u\n", elf32_dyn -> d_tag, elf32_dyn -> d_un.d_val);
      
}
运行之,打印结果:
Tag: 1, Val: 1413
这里的这个val对应的是字符表的字符偏移,去掉lib占的内存,那么我的程序应该设置的val大小为1416
第三步修改tag和val,代码如下:
#include <stdio.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>

long parse_long(const char * v) {
  long off;
  off = atol(v);
  if(off == 0) {
    if(errno != 0) {
      error(201, errno, "parse offset <%s> to unsigned long", v);
      return -1;
    }
  }
  return off;
}

int main(int argc, const char **argv) {
  if(argc != 4) {
    printf("usage:%s <file> <offset> <value>\n", argv[0]);
    return -1;
  }

  off_t offset, current, value;
  offset = parse_long(argv[2]);
  if(offset == -1) {
    return -1;
  }

  value = parse_long(argv[3]);
  if(value == -1) {
    return -1;
  }

  int f_id;
  f_id = open(argv[1], O_RDWR);
  if (f_id == -1) {
    error(201, errno, "open %s;", argv[1]);
    return -1;
  }
  
  size_t len = sizeof(Elf32_Dyn);

  offset +=  8 * len; // 要修改的dyn在数组中的偏移位置是8 

  current = lseek(f_id, offset, SEEK_SET);
  if(current == -1) {
    error(201, errno, "lseek file with offset %ld", offset);
    return -1;
  }

  if(current != offset) {
    printf("file %s current pos <%ld> not equal to offset <%ld>\n", argv[1], current, offset);
    return -1;
  }
    
  Elf32_Dyn *elf32_dyn = (Elf32_Dyn*)malloc(len);  

  elf32_dyn -> d_tag = DT_NEEDED;
  elf32_dyn -> d_un.d_val = value;
  
  write(f_id, elf32_dyn, len);
      
}

到这里修改操作全部完成。查看结果:
有一点我的方案跟rrrfff大神的不太一样,就是我是直接把修改过的app_process push到模拟器里面的,没有改虚拟机文件。在这一步,我还遇到了一点小问题,不过,google之后,还是顺利解决了。这里我还是分享一下吧,作为备忘录。
问题如下:
adb push C:\***\app_process /system/bin之后,报read-only file system错误。这个我早想到过,于是按照有人提出的解决方法mount -o remount,rw /system,发现运行过这个命令之后,竟然报相同的错误。这一解决方案被很多人采纳了,可为啥我的就不行。后来又看到一个相似的提问的回答,然后成功解决了我的问题。回答是:启动模拟器的命令参数要有-writable-system才可以写/system文件夹。

yougar@ubuntu:~/Programs/so_injection/os$ readelf -d app_process 

Dynamic section at offset 0x3dc0 contains 32 entries: ## offset
  Tag        Type                         Name/Value
 0x00000003 (PLTGOT)                     0x4f0c
 0x00000002 (PLTRELSZ)                   440 (bytes)
 0x00000017 (JMPREL)                     0xe74
 0x00000014 (PLTREL)                     REL
 0x00000011 (REL)                        0xdb4
 0x00000012 (RELSZ)                      192 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffa (RELCOUNT)                   21
 0x00000015 (DUBUG)                      0x0
 0x00000006 (SYMTAB)                     0x148
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000005 (STRTAB)                     0x598
 0x0000000a (STRSZ)                      1521 (bytes)
 0x00000004 (HASH)                       0xb8c
 0x00000001 (NEEDED)                     Shared library: [libandroid_runtime.so]
 0x00000001 (NEEDED)                     Shared library: [libbinder.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x00000001 (NEEDED)                     Shared library: [libcutils.so]
 0x00000001 (NEEDED)                     Shared library: [libdl.so]
 0x00000001 (NEEDED)                     Shared library: [liblog.so]
 0x00000001 (NEEDED)                     Shared library: [libm.so]
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so]
 0x00000001 (NEEDED)                     Shared library: [libutils.so]
 0x00000020 (PREINIT_ARRAY)              0x4d40
 0x00000021 (PREINIT_ARRAYSZ)            0x8
 0x00000019 (INIT_ARRAY)                 0x4d48
 0x0000001b (INIT_ARRAYSZ)               12 (bytes)
 0x0000001a (FINI_ARRAY)                 0x4d54
 0x0000001c (FINI_ARRAYSZ)               8 (bytes)
 0x0000001e (FLAGS)                      BIND_NOW
 0x6ffffffb (FLAGS_1)                    Flags: NOW
 0x00000000 (NULL)                       0x0
发现偏移位置为0x3dc0,转换为10进制是15808
第二步结合<elf.h>打印出d_tag为0x00000001,第一个tag类型为needed的d_val,源码如下:
#include <stdio.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>

long parse_long(const char * v) {
  long off;
  off = atol(v);
  if(off == 0) {
    if(errno != 0) {
      error(201, errno, "parse offset <%s> to unsigned long", v);
      return -1;
    }
  }
  return off;
}

int main(int argc, const char **argv) {
  if(argc != 3) {
    printf("usage:%s <file> <offset>\n", argv[0]);
    return -1;
  }

  off_t offset, current, value;
  offset = parse_long(argv[2]);
  if(offset == -1) {
    return -1;
  }

  int f_id;
  f_id = open(argv[1], O_RDONLY);
  if (f_id == -1) {
    error(201, errno, "open %s;", argv[1]);
    return -1;
  }
  
  size_t len = sizeof(Elf32_Dyn); // 单个dyn在文件中所占大小

  offset +=  14 * len;  // 由于第一个出现needed类型的tag在tag数组里的偏移是14,所以这里设置偏移长度+14 * len

  current = lseek(f_id, offset, SEEK_SET);
  if(current == -1) {
    error(201, errno, "lseek file with offset %ld", offset);
    return -1;
  }

  if(current != offset) {
    printf("file %s current pos <%ld> not equal to offset <%ld>\n", argv[1], current, offset);
    return -1;
  }
    
  Elf32_Dyn *elf32_dyn = (Elf32_Dyn*)malloc(len);  

  read(f_id, elf32_dyn, len);
  printf("Tag: %u, Val: %u\n", elf32_dyn -> d_tag, elf32_dyn -> d_un.d_val);
      
}
运行之,打印结果:
Tag: 1, Val: 1413
这里的这个val对应的是字符表的字符偏移,去掉lib占的内存,那么我的程序应该设置的val大小为1416
第三步修改tag和val,代码如下:
#include <stdio.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>

long parse_long(const char * v) {
  long off;
  off = atol(v);
  if(off == 0) {
    if(errno != 0) {
      error(201, errno, "parse offset <%s> to unsigned long", v);
      return -1;
    }
  }
  return off;
}

int main(int argc, const char **argv) {
  if(argc != 4) {
    printf("usage:%s <file> <offset> <value>\n", argv[0]);
    return -1;
  }

  off_t offset, current, value;
  offset = parse_long(argv[2]);
  if(offset == -1) {
    return -1;
  }

  value = parse_long(argv[3]);
  if(value == -1) {
    return -1;
  }

  int f_id;
  f_id = open(argv[1], O_RDWR);
  if (f_id == -1) {
    error(201, errno, "open %s;", argv[1]);
    return -1;
  }
  
  size_t len = sizeof(Elf32_Dyn);

  offset +=  8 * len; // 要修改的dyn在数组中的偏移位置是8 

  current = lseek(f_id, offset, SEEK_SET);
  if(current == -1) {
    error(201, errno, "lseek file with offset %ld", offset);
    return -1;
  }

  if(current != offset) {
    printf("file %s current pos <%ld> not equal to offset <%ld>\n", argv[1], current, offset);
    return -1;
  }
    
  Elf32_Dyn *elf32_dyn = (Elf32_Dyn*)malloc(len);  

  elf32_dyn -> d_tag = DT_NEEDED;
  elf32_dyn -> d_un.d_val = value;
  
  write(f_id, elf32_dyn, len);
      
}

到这里修改操作全部完成。查看结果:
有一点我的方案跟rrrfff大神的不太一样,就是我是直接把修改过的app_process push到模拟器里面的,没有改虚拟机文件。在这一步,我还遇到了一点小问题,不过,google之后,还是顺利解决了。这里我还是分享一下吧,作为备忘录。
问题如下:
adb push C:\***\app_process /system/bin之后,报read-only file system错误。这个我早想到过,于是按照有人提出的解决方法mount -o remount,rw /system,发现运行过这个命令之后,竟然报相同的错误。这一解决方案被很多人采纳了,可为啥我的就不行。后来又看到一个相似的提问的回答,然后成功解决了我的问题。回答是:启动模拟器的命令参数要有-writable-system才可以写/system文件夹。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2018-4-10 16:13 被Yougar编辑 ,原因: 提供一个自动化工具
上传的附件:
收藏
免费 1
支持
分享
最新回复 (12)
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
2018-1-25 23:28
0
雪    币: 7001
活跃值: (4212)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2018-1-26 08:54
0
雪    币: 878
活跃值: (496)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
其实可以再自动化一点,  省去readelf的步骤,  最后弄成类似xposed_installer那样的东西
2018-1-27 21:35
0
雪    币: 1449
活跃值: (128)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5

rrrfff

其实可以再自动化一点,  省去readelf的步骤,  最后弄成类似xposed_installer那样的东西

多谢指导 自动化工具接下来我会去做一个的

2018-1-28 01:28
0
雪    币: 6818
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
2018-1-28 23:11
0
雪    币: 3429
活跃值: (1566)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
求分享修改后的镜像
2018-4-9 23:19
0
雪    币: 1449
活跃值: (128)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
Elice 求分享修改后的镜像
上次搞完之后就没再深入了,不过可以自己写一个修改SO文件的命令行工具来改一下SO,工具我有时间了私信发你吧,或者你自己动手写一个也行,不算复杂,而且你还能学习一下ELF文件格式,何乐而不为呢?
2018-4-10 11:32
0
雪    币: 3429
活跃值: (1566)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
Yougar 上次搞完之后就没再深入了,不过可以自己写一个修改SO文件的命令行工具来改一下SO,工具我有时间了私信发你吧,或者你自己动手写一个也行,不算复杂,而且你还能学习一下ELF文件格式,何乐而不为呢?
感谢了
2018-4-12 10:26
0
雪    币: 55
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
可以用LIEF
2018-8-8 20:00
1
雪    币: 1
活跃值: (883)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
HI,elf.zip是怎么个运行环境?是在linux上运行的吗?windows上编译不过
2018-9-2 16:25
0
雪    币: 148
活跃值: (208)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
请问大佬,这个方法在Android7.0以上也成立?
2019-4-16 11:56
0
雪    币: 582
活跃值: (317)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
可以修改Framework.jar来达到全局注入的目的,那个相对来说简单一点.只需要把Framework.jar反编译加入自己的代码再打包就行了.
2019-4-18 22:48
0
游客
登录 | 注册 方可回帖
返回
//