https://blog.csdn.net/qq1084283172/article/details/53561622
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/QQ1084283172/article/details/53561622

本文博客地址:http://blog.csdn.net/qq1084283172/article/details/53561622

在前面的博客中已经介绍了Android的脱壳工具DexExtractor的原理和使用说明,接下来就来分析一下另一个Android的脱壳工具drizzleDumper的原理和使用说明。drizzleDumper脱壳工具的作者是Drizzle.Risk,他是在strazzere大神的android-unpacker脱壳工具的基础上修改过来的drizzleDumper,他在完成drizzleDumper脱壳工具的时候,对某数字加固、ijiami、bangbang加固进行了脱壳测试,效果比较理想。drizzleDumper脱壳工具是一款基于内存特征搜索的dex文件dump脱壳工具。

一、drizzleDumper脱壳工具的相关链接和讨论

github地址:https://github.com/DrizzleRisk/drizzleDumper#drizzledumper

freebuf地址:http://www.freebuf.com/sectool/105147.html

看雪地址:http://bbs.pediy.com/showthread.php?goto=nextoldest&nojs=1&t=213174

android-unpacker地址:https://github.com/strazzere/android-unpacker/tree/master/native-unpacker

二、drizzleDumper脱壳工具的原理分析(见代码的注释):

drizzleDumper工作的原理是root环境下,通过ptrace附加需要脱壳的apk进程,然后在脱壳的apk进程的内存中进行dex文件的特征搜索,当搜索到dex文件时,进行dex文件的内存dump。

drizzleDumper.h头文件

  1.  
    /*
  2.  
    * drizzleDumper Code By Drizzle.Risk
  3.  
    * file: drizzleDumper.h
  4.  
    */
  5.  
     
  6.  
    #include <stdlib.h>
  7.  
    #include <stdio.h>
  8.  
    #include <dirent.h>
  9.  
    #include <fcntl.h>
  10.  
    #include <unistd.h>
  11.  
    #include <stdarg.h>
  12.  
    #include <string.h>
  13.  
    #include <errno.h>
  14.  
    #include <sys/ptrace.h>
  15.  
    #include <sys/types.h>
  16.  
    #include <sys/wait.h>
  17.  
    #include <unistd.h>
  18.  
    #include <linux/user.h>
  19.  
     
  20.  
    #ifdef HAVE_STDINT_H
  21.  
    #include <stdint.h> /* C99 */
  22.  
    typedef uint8_t u1;
  23.  
    typedef uint16_t u2;
  24.  
    typedef uint32_t u4;
  25.  
    typedef uint64_t u8;
  26.  
    typedef int8_t s1;
  27.  
    typedef int16_t s2;
  28.  
    typedef int32_t s4;
  29.  
    typedef int64_t s8;
  30.  
    #else
  31.  
    typedef unsigned char u1;
  32.  
    typedef unsigned short u2;
  33.  
    typedef unsigned int u4;
  34.  
    typedef unsigned long long u8;
  35.  
    typedef signed char s1;
  36.  
    typedef signed short s2;
  37.  
    typedef signed int s4;
  38.  
    typedef signed long long s8;
  39.  
    #endif
  40.  
     
  41.  
    /*
  42.  
    * define kSHA1DigestLen
  43.  
    */
  44.  
    enum { kSHA1DigestLen = 20,
  45.  
    kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 };
  46.  
     
  47.  
    /*
  48.  
    * define DexHeader
  49.  
    */
  50.  
    typedef struct DexHeader {
  51.  
    u1 magic[8]; /* includes version number */
  52.  
    u4 checksum; /* adler32 checksum */
  53.  
    u1 signature[kSHA1DigestLen]; /* SHA-1 hash */
  54.  
    u4 fileSize; /* length of entire file */
  55.  
    u4 headerSize; /* offset to start of next section */
  56.  
    u4 endianTag;
  57.  
    u4 linkSize;
  58.  
    u4 linkOff;
  59.  
    u4 mapOff;
  60.  
    u4 stringIdsSize;
  61.  
    u4 stringIdsOff;
  62.  
    u4 typeIdsSize;
  63.  
    u4 typeIdsOff;
  64.  
    u4 protoIdsSize;
  65.  
    u4 protoIdsOff;
  66.  
    u4 fieldIdsSize;
  67.  
    u4 fieldIdsOff;
  68.  
    u4 methodIdsSize;
  69.  
    u4 methodIdsOff;
  70.  
    u4 classDefsSize;
  71.  
    u4 classDefsOff;
  72.  
    u4 dataSize;
  73.  
    u4 dataOff;
  74.  
    } DexHeader;
  75.  
     
  76.  
    //#define ORIG_EAX 11
  77.  
    static const char* static_safe_location = "/data/local/tmp/";
  78.  
    static const char* suffix = "_dumped_";
  79.  
     
  80.  
    typedef struct {
  81.  
    uint32_t start;
  82.  
    uint32_t end;
  83.  
    } memory_region;
  84.  
     
  85.  
    uint32_t get_clone_pid(uint32_t service_pid);
  86.  
     
  87.  
    uint32_t get_process_pid(const char* target_package_name);
  88.  
     
  89.  
    char *determine_filter(uint32_t clone_pid, int memory_fd);
  90.  
     
  91.  
    int find_magic_memory(uint32_t clone_pid, int memory_fd, memory_region *memory ,const char* file_name);
  92.  
     
  93.  
    int peek_memory(int memory_file, uint32_t address);
  94.  
     
  95.  
    int dump_memory(const char *buffer , int len , char each_filename[]);
  96.  
     
  97.  
    int attach_get_memory(uint32_t pid);

drizzleDumper.c实现文件

  1.  
    /*
  2.  
    * drizzleDumper Code By Drizzle.Risk
  3.  
    * file: drizzleDumper.c
  4.  
    */
  5.  
     
  6.  
    #include "drizzleDumper.h"
  7.  
     
  8.  
     
  9.  
    // 主函数main
  10.  
    int main(int argc, char *argv[]) {
  11.  
     
  12.  
    printf("[>>>] This is drizzleDumper [<<<]\n");
  13.  
    printf("[>>>] code by Drizzle [<<<]\n");
  14.  
    printf("[>>>] 2016.05 [<<<]\n");
  15.  
     
  16.  
    // 脱壳工具drizzleDumper在工作的实收需要3个参数(需要脱壳的apk的package_name、脱壳等待的时间wait_times(s))
  17.  
    if(argc <= 1)
  18.  
    {
  19.  
    printf("[*] Useage : ./drizzleDumper package_name wait_times(s)\n[*] The wait_times(s) means how long between the two Scans, default 0s \n[*] if successed, you can find the dex file in /data/local/tmp\n[*] Good Luck!\n");
  20.  
    return 0;
  21.  
    }
  22.  
     
  23.  
    // 由于脱壳的原理是基于进程的ptrace,需要有root权限
  24.  
    if(getuid() != 0)
  25.  
    {
  26.  
    printf("[*] Device Not root!\n");
  27.  
    return -1;
  28.  
    }
  29.  
     
  30.  
    double wait_times = 0.01;
  31.  
    // 脱壳工具drizzleDumper在工作的实收需要3个参数(需要脱壳的apk的package_name、脱壳等待的时间wait_times(s))
  32.  
    if(argc >= 3)
  33.  
    {
  34.  
    // 获取加固脱壳的等待时间
  35.  
    wait_times = strtod(argv[2], NULL);
  36.  
    printf("[*] The wait_times is %ss\n", argv[2]);
  37.  
    }
  38.  
     
  39.  
    // 获取需要被脱壳的加固apk的包名
  40.  
    char *package_name = argv[1];
  41.  
    printf("[*] Try to Find %s\n", package_name);
  42.  
     
  43.  
    uint32_t pid = -1;
  44.  
     
  45.  
    int i = 0;
  46.  
    int mem_file;
  47.  
    uint32_t clone_pid;
  48.  
    char *extra_filter;
  49.  
    char *dumped_file_name;
  50.  
     
  51.  
    // 进入循环
  52.  
    while(1)
  53.  
    {
  54.  
    // 休眠等待一段时间
  55.  
    sleep(wait_times);
  56.  
     
  57.  
    pid = -1;
  58.  
    // 获取加固需要被脱壳的apk的进程pid
  59.  
    pid = get_process_pid(package_name);
  60.  
    // 判断获取的进程pid是否有效
  61.  
    if(pid < 1 || pid == -1)
  62.  
    {
  63.  
    continue;
  64.  
    }
  65.  
    printf("[*] pid is %d\n", pid);
  66.  
     
  67.  
    // 获取进程pid的一个线程tid,方便后面进行ptrace附加
  68.  
    clone_pid = get_clone_pid(pid);
  69.  
    if(clone_pid <= 0)
  70.  
    {
  71.  
    continue;
  72.  
    }
  73.  
    printf("[*] clone pid is %d\n", clone_pid);
  74.  
     
  75.  
    memory_region memory;
  76.  
    printf("[*] ptrace [clone_pid] %d\n", clone_pid);
  77.  
     
  78.  
    // 对指定pid进程的克隆即tid进程ptrace附加,获取指定pid进程的内存模块基址
  79.  
    mem_file = attach_get_memory(clone_pid);
  80.  
    // 对获取到的内存有效数据的进行校验3次即最多进行3次脱壳尝试
  81.  
    if(mem_file == -10201)
  82.  
    {
  83.  
    continue;
  84.  
    }
  85.  
    else if(mem_file == -20402)
  86.  
    {
  87.  
    //continue;
  88.  
    }
  89.  
    else if(mem_file == -30903)
  90.  
    {
  91.  
    //continue
  92.  
    }
  93.  
     
  94.  
    /****
  95.  
    *static const char* static_safe_location = "/data/local/tmp/";
  96.  
    *static const char* suffix = "_dumped_";
  97.  
    ****/
  98.  
     
  99.  
    // 申请内存空间保存内存dump出来的dex文件的名称
  100.  
    dumped_file_name = malloc(strlen(static_safe_location) + strlen(package_name) + strlen(suffix));
  101.  
    // 格式化生成存dump出来的dex文件的名称
  102.  
    sprintf(dumped_file_name, "%s%s%s", static_safe_location, package_name, suffix);
  103.  
     
  104.  
    printf("[*] Scanning dex ...\n");
  105.  
     
  106.  
    // 通过ptrace附件目标pid进程,在目标进程的pid中进行dex文件的搜索然后进行内存dump
  107.  
    if(find_magic_memory(clone_pid, mem_file, &memory, dumped_file_name) <= 0)
  108.  
    {
  109.  
    printf("[*] The magic was Not Found!\n");
  110.  
    ptrace(PTRACE_DETACH, clone_pid, NULL, 0);
  111.  
    close(mem_file);
  112.  
    continue;
  113.  
    }
  114.  
    else
  115.  
    {
  116.  
    // dex的内存dump成功,跳出循环
  117.  
    close(mem_file);
  118.  
    ptrace(PTRACE_DETACH, clone_pid, NULL, 0);
  119.  
    break;
  120.  
    }
  121.  
    }
  122.  
     
  123.  
    printf("[*] Done.\n\n");
  124.  
    return 1;
  125.  
    }
  126.  
     
  127.  
    // 获取指定进程的一个线程tid
  128.  
    uint32_t get_clone_pid(uint32_t service_pid)
  129.  
    {
  130.  
    DIR *service_pid_dir;
  131.  
    char service_pid_directory[1024];
  132.  
     
  133.  
    // 格式化字符串
  134.  
    sprintf(service_pid_directory, "/proc/%d/task/", service_pid);
  135.  
    // 查询指定进程的pid的线程TID的信息
  136.  
    if((service_pid_dir = opendir(service_pid_directory)) == NULL)
  137.  
    {
  138.  
    return -1;
  139.  
    }
  140.  
     
  141.  
    struct dirent* directory_entry = NULL;
  142.  
    struct dirent* last_entry = NULL;
  143.  
     
  144.  
    // 获取指定pid进程的线程TID
  145.  
    while((directory_entry = readdir(service_pid_dir)) != NULL)
  146.  
    {
  147.  
    last_entry = directory_entry;
  148.  
    }
  149.  
    if(last_entry == NULL)
  150.  
    return -1;
  151.  
     
  152.  
    closedir(service_pid_dir);
  153.  
     
  154.  
    // 返回获取到的指定pid的线程tid
  155.  
    return atoi(last_entry->d_name);
  156.  
    }
  157.  
     
  158.  
     
  159.  
    // 通过运行的apk的名称的获取进程的pid
  160.  
    uint32_t get_process_pid(const char *target_package_name)
  161.  
    {
  162.  
    char self_pid[10];
  163.  
    sprintf(self_pid, "%u", getpid());
  164.  
     
  165.  
    DIR *proc = NULL;
  166.  
     
  167.  
    if((proc = opendir("/proc")) == NULL)
  168.  
    return -1;
  169.  
     
  170.  
    struct dirent *directory_entry = NULL;
  171.  
    while((directory_entry = readdir(proc)) != NULL)
  172.  
    {
  173.  
     
  174.  
    if (directory_entry == NULL)
  175.  
    return -1;
  176.  
     
  177.  
    if (strcmp(directory_entry->d_name, "self") == 0 || strcmp(directory_entry->d_name, self_pid) == 0)
  178.  
    continue;
  179.  
     
  180.  
    char cmdline[1024];
  181.  
    snprintf(cmdline, sizeof(cmdline), "/proc/%s/cmdline", directory_entry->d_name);
  182.  
    FILE *cmdline_file = NULL;
  183.  
    if((cmdline_file = fopen(cmdline, "r")) == NULL)
  184.  
    continue;
  185.  
     
  186.  
    char process_name[1024];
  187.  
    fscanf(cmdline_file, "%s", process_name);
  188.  
    fclose(cmdline_file);
  189.  
     
  190.  
    if(strcmp(process_name, target_package_name) == 0)
  191.  
    {
  192.  
    closedir(proc);
  193.  
    return atoi(directory_entry->d_name);
  194.  
    }
  195.  
    }
  196.  
     
  197.  
    closedir(proc);
  198.  
    return -1;
  199.  
    }
  200.  
     
  201.  
    // 在目标进程的内存空间中进行dex文件的搜索
  202.  
    int find_magic_memory(uint32_t clone_pid, int memory_fd, memory_region *memory , const char *file_name) {
  203.  
     
  204.  
    int ret = 0;
  205.  
    char maps[2048];
  206.  
     
  207.  
    // 格式化字符串得到/proc/pid/maps
  208.  
    snprintf(maps, sizeof(maps), "/proc/%d/maps", clone_pid);
  209.  
     
  210.  
    FILE *maps_file = NULL;
  211.  
    // 打开文件/proc/pid/maps,获取指定pid进程的内存分布信息
  212.  
    if((maps_file = fopen(maps, "r")) == NULL)
  213.  
    {
  214.  
    printf(" [+] fopen %s Error \n" , maps);
  215.  
    return -1;
  216.  
    }
  217.  
     
  218.  
    char mem_line[1024];
  219.  
    // 循环读取文件/proc/pid/maps中的pid进程的每一条内存分布信息
  220.  
    while(fscanf(maps_file, "%[^\n]\n", mem_line) >= 0)
  221.  
    {
  222.  
    char mem_address_start[10]={0};
  223.  
    char mem_address_end[10]={0};
  224.  
    char mem_info[1024]={0};
  225.  
     
  226.  
    // 解析pid进程的的内存分布信息--内存分布起始地址、内存分布结束地址等
  227.  
    sscanf(mem_line, "%8[^-]-%8[^ ]%*s%*s%*s%*s%s", mem_address_start, mem_address_end, mem_info);
  228.  
    memset(mem_line , 0 ,1024);
  229.  
     
  230.  
    // 获取内存分布起始地址的大小
  231.  
    uint32_t mem_start = strtoul(mem_address_start, NULL, 16);
  232.  
    memory->start = mem_start;
  233.  
    // 获取内存分布结束地址的大小
  234.  
    memory->end = strtoul(mem_address_end, NULL, 16);
  235.  
    // 获取实际的内存区间大小
  236.  
    int len = memory->end - memory->start;
  237.  
    // 过滤掉不符合条件的内存分布区间
  238.  
    if(len <= 10000)
  239.  
    {//too small
  240.  
    continue;
  241.  
    }
  242.  
    else if(len >= 150000000)
  243.  
    {//too big
  244.  
    continue;
  245.  
    }
  246.  
     
  247.  
    char each_filename[254] = {0};
  248.  
    char randstr[10] = {0};
  249.  
    sprintf(randstr ,"%d", rand()%9999);
  250.  
     
  251.  
    // 拼接字符串得到dump的dex文件的生成名称
  252.  
    strncpy(each_filename , file_name , 200);//防溢出
  253.  
    strncat(each_filename , randstr , 10);
  254.  
    strncat(each_filename , ".dex" , 4);
  255.  
     
  256.  
    // 先将pid进程内存文件句柄的指针置文件开头
  257.  
    lseek64(memory_fd , 0 , SEEK_SET);
  258.  
    // 设置pid进程内存文件句柄的指针为内存分布起始地址
  259.  
    off_t r1 = lseek64(memory_fd , memory->start , SEEK_SET);
  260.  
    if(r1 == -1)
  261.  
    {
  262.  
    //do nothing
  263.  
    }
  264.  
    else
  265.  
    {
  266.  
    // 根据内存分布区间的大小申请内存空间
  267.  
    char *buffer = malloc(len);
  268.  
    // 读取pid进程的指定区域的内存数据
  269.  
    ssize_t readlen = read(memory_fd, buffer, len);
  270.  
    printf("meminfo: %s ,len: %d ,readlen: %d, start: %x\n", mem_info, len, readlen, memory->start);
  271.  
     
  272.  
    // 对读取的内存分布区域的数据进行dex文件的扫描和查找
  273.  
    if(buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F')
  274.  
    {
  275.  
    free(buffer);
  276.  
     
  277.  
    continue;
  278.  
    }
  279.  
     
  280.  
    // 查找到dex文件所在的内存区域
  281.  
    if(buffer[0] == 'd' && buffer[1] == 'e' && buffer[2] == 'x' && buffer[3] == '\n' && buffer[4] == '0' && buffer[5] == '3')
  282.  
    {
  283.  
    printf(" [+] find dex, len : %d , info : %s\n" , readlen , mem_info);
  284.  
     
  285.  
    DexHeader header;
  286.  
    char real_lenstr[10]={0};
  287.  
     
  288.  
    // 获取内存区域中dex文件的文件头信息
  289.  
    memcpy(&header , buffer ,sizeof(DexHeader));
  290.  
    sprintf(real_lenstr , "%x" , header.fileSize);
  291.  
     
  292.  
    // 通过dex文件头信息,获取到整个dex文件的大小
  293.  
    long real_lennum = strtol(real_lenstr , NULL, 16);
  294.  
    printf(" [+] This dex's fileSize: %d\n", real_lennum);
  295.  
     
  296.  
    // 对dex文件所在的内存区域进行内存dump
  297.  
    if(dump_memory(buffer , len , each_filename) == 1)
  298.  
    {
  299.  
    // 打印dump的dex文件的名称
  300.  
    printf(" [+] dex dump into %s\n", each_filename);
  301.  
    free(buffer);
  302.  
    continue;
  303.  
    }
  304.  
    else
  305.  
    {
  306.  
    printf(" [+] dex dump error \n");
  307.  
    }
  308.  
     
  309.  
    }
  310.  
     
  311.  
    free(buffer);
  312.  
    }
  313.  
     
  314.  
    // 前面的内存方法搜索没有查找dex文件的内存,尝试下面的内存+8位置进行搜索
  315.  
    // 具体什么原因没太明白??
  316.  
    lseek64(memory_fd , 0 , SEEK_SET);//保险,先归零
  317.  
    r1 = lseek64(memory_fd , memory->start + 8 , SEEK_SET); //不用 pread,因为pread用的是lseek
  318.  
    if(r1 == -1)
  319.  
    {
  320.  
    continue;
  321.  
    }
  322.  
    else
  323.  
    {
  324.  
    char *buffer = malloc(len);
  325.  
    ssize_t readlen = read(memory_fd, buffer, len);
  326.  
     
  327.  
    if(buffer[0] == 'd' && buffer[1] == 'e' && buffer[2] == 'x' && buffer[3] == '\n' && buffer[4] == '0' && buffer[5] == '3')
  328.  
    {
  329.  
    printf(" [+] Find dex! memory len : %d \n" , readlen);
  330.  
     
  331.  
    DexHeader header;
  332.  
    char real_lenstr[10]={0};
  333.  
     
  334.  
    // 获取内存dex文件的文件头信息
  335.  
    memcpy(&header , buffer ,sizeof(DexHeader));
  336.  
    sprintf(real_lenstr , "%x" , header.fileSize);
  337.  
     
  338.  
    // 通过dex文件头信息,获取到整个dex文件的大小
  339.  
    long real_lennum = strtol(real_lenstr , NULL, 16);
  340.  
    printf(" [+] This dex's fileSize: %d\n", real_lennum);
  341.  
     
  342.  
    // 对dex文件所在的内存区域进行内存dump
  343.  
    if(dump_memory(buffer , len , each_filename) == 1)
  344.  
    {
  345.  
    printf(" [+] dex dump into %s\n", each_filename);
  346.  
    free(buffer);
  347.  
    continue;//如果本次成功了,就不尝试其他方法了
  348.  
    }
  349.  
    else
  350.  
    {
  351.  
    printf(" [+] dex dump error \n");
  352.  
    }
  353.  
    }
  354.  
     
  355.  
    free(buffer);
  356.  
    }
  357.  
    }
  358.  
    fclose(maps_file);
  359.  
     
  360.  
    return ret;
  361.  
    }
  362.  
     
  363.  
     
  364.  
    // 从内存中dump数据到文件中
  365.  
    int dump_memory(const char *buffer , int len , char each_filename[])
  366.  
    {
  367.  
    int ret = -1;
  368.  
     
  369.  
    // 创建文件
  370.  
    FILE *dump = fopen(each_filename, "wb");
  371.  
    // 将需要dump的内存数据写入到/data/local/tmp文件路径下
  372.  
    if(fwrite(buffer, len, 1, dump) != 1)
  373.  
    {
  374.  
    ret = -1;
  375.  
    }
  376.  
    else
  377.  
    {
  378.  
    ret = 1;
  379.  
    }
  380.  
     
  381.  
    fclose(dump);
  382.  
    return ret;
  383.  
    }
  384.  
     
  385.  
    // 获取指定附加pid进程的内存模块基址
  386.  
    int attach_get_memory(uint32_t pid) {
  387.  
     
  388.  
    char mem[1024];
  389.  
    bzero(mem,1024);
  390.  
     
  391.  
    // 格式化字符串得到字符串/proc/pid/mem
  392.  
    snprintf(mem, sizeof(mem), "/proc/%d/mem", pid);
  393.  
     
  394.  
    int ret = -1;
  395.  
    int mem_file;
  396.  
     
  397.  
    // 尝试ptrace附加目标pid进程
  398.  
    ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
  399.  
    // 对ptrace附加目标pid进程的操作结果进行判断
  400.  
    if (0 != ret)
  401.  
    {
  402.  
    int err = errno;//这时获取errno
  403.  
    if(err == 1) //EPERM
  404.  
    {
  405.  
    return -30903;//代表已经被跟踪或无法跟踪
  406.  
    }
  407.  
    else
  408.  
    {
  409.  
    return -10201;//其他错误(进程不存在或非法操作)
  410.  
    }
  411.  
    }
  412.  
    else
  413.  
    {
  414.  
    // ptrace附加目标进程pid成功,获取指定pid进程的内存模块基址
  415.  
    // 获取其它进程的内存模块基址,需要root权限
  416.  
    if(!(mem_file = open(mem, O_RDONLY)))
  417.  
    {
  418.  
    return -20402; //打开错误
  419.  
    }
  420.  
    }
  421.  
     
  422.  
    return mem_file;
  423.  
    }

drizzleDumper的编译配置文件Android.mk

  1.  
    LOCAL_PATH := $(call my-dir)
  2.  
     
  3.  
    TARGET_PIE := true
  4.  
    NDK_APP_PIE := true
  5.  
     
  6.  
    include $(CLEAR_VARS)
  7.  
     
  8.  
    # 需要编译的源码文件
  9.  
    LOCAL_SRC_FILES := \
  10.  
    drizzleDumper.c
  11.  
    LOCAL_C_INCLUDE := \
  12.  
    drizzleDumper.h \
  13.  
    definitions.h
  14.  
     
  15.  
    LOCAL_MODULE := drizzleDumper
  16.  
    LOCAL_MODULE_TAGS := optional
  17.  
     
  18.  
    # Allow execution on android-16+
  19.  
    # 支持PIE
  20.  
    LOCAL_CFLAGS += -fPIE
  21.  
    LOCAL_LDFLAGS += -fPIE -pie
  22.  
     
  23.  
    # 编译生成可执行ELF文件
  24.  
    include $(BUILD_EXECUTABLE)
  25.  
     
  26.  
    include $(call all-makefiles-under,$(LOCAL_PATH))

三、drizzleDumper的使用说明

关于drizzleDumper的使用,作者已经在freebuf的文章中已经讲的很详细了,具体的修改的地方也指出来了。

drizzleDumper的原理分析和使用说明-LMLPHP

四、下面就使用nexcus
5的已经root的真机
进行drizzleDumper的脱壳实战(以com.qihoo.freewifi为例)

在cmd控制台的条件下,执行cd命令进入到存放drizzleDumper的文件夹,然后将drizzleDumper文件推送到android手机的/data/local/tmp文件夹下并赋予可执行权限,然后根据每种android加固的特点,选择需要脱壳的apk和drizzleDumper运行的先后顺序,调整能够脱壳成功的过程。这里使用的com.qihoo.freewifi为例,先运行com.qihoo.freewifi程序,然后adb
shell条件下su提权,
执行drizzleDumper的脱壳操作,等待2秒。

  1.  
    cd xxxxx/drizzleDumper
  2.  
     
  3.  
    adb push drizzleDumper /data/local/tmp
  4.  
    adb shell chmod 0777 /data/local/tmp/drizzleDumper
  5.  
     
  6.  
    adb shell#进入androd系统的shell
  7.  
    su#获取root权限
  8.  
    ./data/local/tmp/drizzleDumper com.qihoo.freewifi 2#执行脱壳操作

drizzleDumper的原理分析和使用说明-LMLPHP

说明:对脱壳是否成功,这个估计有一定的概率性,主要的目的是学习工具作者的脱壳思想和方法,自己去实践,不管怎样谢谢工具的作者Drizzle.Risk,代码中有理解错误的地方希望大牛不吝赐。

编译好的drizzleDumper文件和代码的打包下载地址:http://download.csdn.net/detail/qq1084283172/9707768

 

参考网址

http://www.freebuf.com/sectool/105147.html

https://github.com/DrizzleRisk/drizzleDumper

jpg改rar drizzleDumper的原理分析和使用说明-LMLPHP

05-11 10:57