drizzleDumper的原理分析和使用说明

xiaoxiao2021-02-28  106

在前面的博客中已经介绍了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头文件

[cpp]  view plain  copy   /*   * drizzleDumper Code By Drizzle.Risk   * file: drizzleDumper.h   */      #include <stdlib.h>   #include <stdio.h>   #include <dirent.h>   #include <fcntl.h>   #include <unistd.h>   #include <stdarg.h>   #include <string.h>   #include <errno.h>   #include <sys/ptrace.h>   #include <sys/types.h>   #include <sys/wait.h>   #include <unistd.h>   #include <linux/user.h>      #ifdef HAVE_STDINT_H   #include <stdint.h>    /* C99 */   typedef uint8_t             u1;   typedef uint16_t            u2;   typedef uint32_t            u4;   typedef uint64_t            u8;   typedef int8_t              s1;   typedef int16_t             s2;   typedef int32_t             s4;   typedef int64_t             s8;   #else   typedef unsigned char       u1;   typedef unsigned short      u2;   typedef unsigned int        u4;   typedef unsigned long long  u8;   typedef signed char         s1;   typedef signed short        s2;   typedef signed int          s4;   typedef signed long long    s8;   #endif      /*   * define kSHA1DigestLen   */   enum { kSHA1DigestLen = 20,          kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 };      /*   * define DexHeader   */   typedef struct DexHeader {       u1  magic[8];           /* includes version number */       u4  checksum;           /* adler32 checksum */       u1  signature[kSHA1DigestLen]; /* SHA-1 hash */       u4  fileSize;           /* length of entire file */       u4  headerSize;         /* offset to start of next section */       u4  endianTag;       u4  linkSize;       u4  linkOff;       u4  mapOff;       u4  stringIdsSize;       u4  stringIdsOff;       u4  typeIdsSize;       u4  typeIdsOff;       u4  protoIdsSize;       u4  protoIdsOff;       u4  fieldIdsSize;       u4  fieldIdsOff;       u4  methodIdsSize;       u4  methodIdsOff;       u4  classDefsSize;       u4  classDefsOff;       u4  dataSize;       u4  dataOff;   } DexHeader;      //#define ORIG_EAX 11   static const char* static_safe_location = "/data/local/tmp/";   static const char* suffix = "_dumped_";      typedef struct {     uint32_t start;     uint32_t end;   } memory_region;      uint32_t get_clone_pid(uint32_t service_pid);      uint32_t get_process_pid(const char* target_package_name);      char *determine_filter(uint32_t clone_pid, int memory_fd);      int find_magic_memory(uint32_t clone_pid, int memory_fd, memory_region *memory ,const char* file_name);      int peek_memory(int memory_file, uint32_t address);      int dump_memory(const char *buffer , int len , char each_filename[]);      int attach_get_memory(uint32_t pid);   drizzleDumper.c实现文件

[cpp]  view plain  copy   /*   * drizzleDumper Code By Drizzle.Risk   * file: drizzleDumper.c   */      #include "drizzleDumper.h"         // 主函数main   int main(int argc, char *argv[]) {        printf("[>>>]  This is drizzleDumper [<<<]\n");     printf("[>>>]    code by Drizzle     [<<<]\n");     printf("[>>>]        2016.05         [<<<]\n");          // 脱壳工具drizzleDumper在工作的实收需要3个参数(需要脱壳的apk的package_name、脱壳等待的时间wait_times(s))     if(argc <= 1)      {       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");       return 0;     }        // 由于脱壳的原理是基于进程的ptrace,需要有root权限     if(getuid() != 0)      {       printf("[*]  Device Not root!\n");       return -1;     }        double wait_times = 0.01;     // 脱壳工具drizzleDumper在工作的实收需要3个参数(需要脱壳的apk的package_name、脱壳等待的时间wait_times(s))     if(argc >= 3)     {       // 获取加固脱壳的等待时间       wait_times = strtod(argv[2], NULL);       printf("[*]  The wait_times is %ss\n", argv[2]);     }          // 获取需要被脱壳的加固apk的包名     char *package_name = argv[1];     printf("[*]  Try to Find %s\n", package_name);        uint32_t pid = -1;        int i = 0;     int mem_file;     uint32_t clone_pid;     char *extra_filter;     char *dumped_file_name;        // 进入循环     while(1)     {         // 休眠等待一段时间         sleep(wait_times);                  pid = -1;         // 获取加固需要被脱壳的apk的进程pid         pid = get_process_pid(package_name);         // 判断获取的进程pid是否有效         if(pid < 1 || pid == -1)         {             continue;         }         printf("[*]  pid is %d\n", pid);            // 获取进程pid的一个线程tid,方便后面进行ptrace附加         clone_pid = get_clone_pid(pid);         if(clone_pid <= 0)          {           continue;         }         printf("[*]  clone pid is %d\n", clone_pid);            memory_region memory;         printf("[*]  ptrace [clone_pid] %d\n", clone_pid);                  // 对指定pid进程的克隆即tid进程ptrace附加,获取指定pid进程的内存模块基址         mem_file = attach_get_memory(clone_pid);         // 对获取到的内存有效数据的进行校验3次即最多进行3次脱壳尝试         if(mem_file == -10201)          {           continue;         }         else if(mem_file == -20402)         {            //continue;         }         else if(mem_file == -30903)         {            //continue         }                  /****         *static const char* static_safe_location = "/data/local/tmp/";         *static const char* suffix = "_dumped_";         ****/                // 申请内存空间保存内存dump出来的dex文件的名称         dumped_file_name = malloc(strlen(static_safe_location) + strlen(package_name) + strlen(suffix));         // 格式化生成存dump出来的dex文件的名称         sprintf(dumped_file_name, "%s%s%s", static_safe_location, package_name, suffix);                  printf("[*]  Scanning dex ...\n");                  // 通过ptrace附件目标pid进程,在目标进程的pid中进行dex文件的搜索然后进行内存dump         if(find_magic_memory(clone_pid, mem_file, &memory, dumped_file_name) <= 0)         {           printf("[*]  The magic was Not Found!\n");           ptrace(PTRACE_DETACH, clone_pid, NULL, 0);           close(mem_file);           continue;         }         else         {            // dex的内存dump成功,跳出循环            close(mem_file);            ptrace(PTRACE_DETACH, clone_pid, NULL, 0);            break;         }      }        printf("[*]  Done.\n\n");     return 1;   }      // 获取指定进程的一个线程tid   uint32_t get_clone_pid(uint32_t service_pid)   {     DIR *service_pid_dir;     char service_pid_directory[1024];          // 格式化字符串     sprintf(service_pid_directory, "/proc/%d/task/", service_pid);     // 查询指定进程的pid的线程TID的信息     if((service_pid_dir = opendir(service_pid_directory)) == NULL)     {       return -1;     }        struct dirent* directory_entry = NULL;     struct dirent* last_entry = NULL;        // 获取指定pid进程的线程TID     while((directory_entry = readdir(service_pid_dir)) != NULL)     {       last_entry = directory_entry;     }     if(last_entry == NULL)       return -1;        closedir(service_pid_dir);        // 返回获取到的指定pid的线程tid     return atoi(last_entry->d_name);   }         // 通过运行的apk的名称的获取进程的pid   uint32_t get_process_pid(const char *target_package_name)   {     char self_pid[10];     sprintf(self_pid, "%u", getpid());        DIR *proc = NULL;        if((proc = opendir("/proc")) == NULL)       return -1;        struct dirent *directory_entry = NULL;     while((directory_entry = readdir(proc)) != NULL)     {          if (directory_entry == NULL)         return -1;          if (strcmp(directory_entry->d_name, "self") == 0 || strcmp(directory_entry->d_name, self_pid) == 0)           continue;            char cmdline[1024];         snprintf(cmdline, sizeof(cmdline), "/proc/%s/cmdline", directory_entry->d_name);         FILE *cmdline_file = NULL;         if((cmdline_file = fopen(cmdline, "r")) == NULL)             continue;            char process_name[1024];         fscanf(cmdline_file, "%s", process_name);         fclose(cmdline_file);            if(strcmp(process_name, target_package_name) == 0)         {            closedir(proc);            return atoi(directory_entry->d_name);         }       }          closedir(proc);       return -1;   }      //  在目标进程的内存空间中进行dex文件的搜索   int find_magic_memory(uint32_t clone_pid, int memory_fd, memory_region *memory , const char *file_name) {            int ret = 0;     char maps[2048];          // 格式化字符串得到/proc/pid/maps     snprintf(maps, sizeof(maps), "/proc/%d/maps", clone_pid);        FILE *maps_file = NULL;     // 打开文件/proc/pid/maps,获取指定pid进程的内存分布信息     if((maps_file = fopen(maps, "r")) == NULL)     {       printf(" [+] fopen %s Error  \n" , maps);       return -1;     }         char mem_line[1024];      // 循环读取文件/proc/pid/maps中的pid进程的每一条内存分布信息      while(fscanf(maps_file, "%[^\n]\n", mem_line) >= 0)      {        char mem_address_start[10]={0};        char mem_address_end[10]={0};        char mem_info[1024]={0};           // 解析pid进程的的内存分布信息--内存分布起始地址、内存分布结束地址等        sscanf(mem_line, "%8[^-]-%8[^ ]%*s%*s%*s%*s%s", mem_address_start, mem_address_end, mem_info);        memset(mem_line , 0 ,1024);                // 获取内存分布起始地址的大小        uint32_t mem_start = strtoul(mem_address_start, NULL, 16);        memory->start = mem_start;        // 获取内存分布结束地址的大小        memory->end = strtoul(mem_address_end, NULL, 16);        // 获取实际的内存区间大小        int len =  memory->end - memory->start;        // 过滤掉不符合条件的内存分布区间        if(len <= 10000)        {//too small           continue;        }        else if(len >= 150000000)        {//too big            continue;        }            char each_filename[254] = {0};         char randstr[10] = {0};         sprintf(randstr ,"%d", rand()
转载请注明原文地址: https://www.6miu.com/read-65634.html

最新回复(0)