内容纲要
drizzleDumper
源码分析
main函数
首先检查设备是否root
if(getuid() != 0)
{
printf("[*] Device Not root!\n");
return -1;
}
获取指定进程的pid
pid = get_process_pid(package_name);
//find process
if(pid < 1 || pid == -1)
{
continue;
}
printf("[*] pid is %d\n", pid);
get_process_pid
通过遍历proc目录下的目录(目录名为进程的pid),得到每个目录下的cmdline(运行时的命令),来确认当前目录为指定包名的进程,从而得到pid
uint32_t get_process_pid(const char *target_package_name)
{
//获取自己的pid
char self_pid[10];
sprintf(self_pid, "%u", getpid());
DIR *proc = NULL;
//得到proc目录
if((proc = opendir("/proc")) == NULL)
return -1;
struct dirent *directory_entry = NULL;
while((directory_entry = readdir(proc)) != NULL)
{
if (directory_entry == NULL)
return -1;
//如果当前目录名(pid)为self或自己的pid则继续遍历
if (strcmp(directory_entry->d_name, "self") == 0 || strcmp(directory_entry->d_name, self_pid) == 0)
continue;
char cmdline[1024];
// /proc/[pid]/cmdline: 获得该进程启动时的命令
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);
//如果为指定包名,则确认该pid为该包名的pid
if(strcmp(process_name, target_package_name) == 0)
{
closedir(proc);
return atoi(directory_entry->d_name);
}
}
closedir(proc);
return -1;
}
得到一个cloned的进程id
//find cloned process
clone_pid = get_clone_pid(pid);
if(clone_pid <= 0)
{
continue;
}
printf("[*] clone pid is %d\n", clone_pid);
get_clone_pid
遍历/proc/[pid]/task(目录内为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);
if((service_pid_dir = opendir(service_pid_directory)) == NULL)
{
return -1;
}
struct dirent* directory_entry = NULL;
struct dirent* last_entry = NULL;
//得到/proc/[pid]/task目录下的最后一个文件(名字即为tid)
while((directory_entry = readdir(service_pid_dir)) != NULL)
{
last_entry = directory_entry;
}
if(last_entry == NULL)
return -1;
closedir(service_pid_dir);
return atoi(last_entry->d_name);
}
ptraceAttach cloned pid
memory_region memory;
//ptrace cloned process
printf("[*] ptrace [clone_pid] %d\n", clone_pid);
mem_file = attach_get_memory(clone_pid);
int attach_get_memory(uint32_t pid) {
char mem[1024];
bzero(mem,1024);
// /proc/[pid]/mem: 当前进程的内存内容
snprintf(mem, sizeof(mem), "/proc/%d/mem", pid);
// Attach to process so we can peek/dump
int ret = -1;
/*****!!!!!!!!!!!*****/
ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
int mem_file;
if (0 != ret)
{
int err = errno; //这时获取errno
if(err == 1) //EPERM
{
return -30903; //代表已经被跟踪或无法跟踪
}
else
{
return -10201; //其他错误(进程不存在或非法操作)
}
}
else
{
if(!(mem_file = open(mem, O_RDONLY)))
{
return -20402; //打开错误
}
}
return mem_file;
}
扫描进程
// static_safe_location = "/data/local/tmp/"
// suffix = "_dumped_"
dumped_file_name = malloc(strlen(static_safe_location) + strlen(package_name) + strlen(suffix));
sprintf(dumped_file_name, "%s%s%s", static_safe_location, package_name, suffix);
printf("[*] Scanning dex ...\n");
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
{
/*
* Successed & exit
*/
close(mem_file);
ptrace(PTRACE_DETACH, clone_pid, NULL, 0);
break;
}
find_magic_memory
获取/proc/[pid]/maps内容(进程内存映射信息),对每一块(文件中的每行)地址进行分析,如果文件的magic number是dex03(dex的magic number),则进行内存提取
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;
if((maps_file = fopen(maps, "r")) == NULL)
{
printf(" [+] fopen %s Error \n" , maps);
return -1;
}
char mem_line[1024];
// 对maps信息一行一行读取
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};
// 得到内存起始地址、结束地址和内存权限信息
sscanf(mem_line, "%8[^-]-%8[^ ]%*s%*s%*s%*s%s", mem_address_start, mem_address_end,mem_info);
// 清空初始
memset(mem_line , 0 ,1024);
// 获得数字部分,以16进制形式
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()%9999 );
strncpy(each_filename , file_name , 200); //防溢出
strncat(each_filename , randstr , 10);
strncat(each_filename , ".dex" , 4);
lseek64(memory_fd , 0 , SEEK_SET); //保险,先归零
off_t r1 = lseek64(memory_fd , memory->start , SEEK_SET);
if(r1 == -1)
{
//do nothing
}
else{
char *buffer = malloc(len);
ssize_t readlen = read(memory_fd, buffer, len);
printf("meminfo: %s ,len: %d ,readlen: %d, start: %x\n",mem_info, len, readlen, memory->start);
//判断magic number
if(buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F')
{
free(buffer);
continue;
}
if(buffer[0] == 'd' && buffer[1] == 'e' && buffer[2] == 'x' && buffer[3] == '\n' && buffer[4] == '0' && buffer[5] == '3')
{
printf(" [+] find dex, len : %d , info : %s\n" , readlen , mem_info);
DexHeader header;
char real_lenstr[10]={0};
memcpy(&header , buffer ,sizeof(DexHeader));
sprintf(real_lenstr , "%x" , header.fileSize);
long real_lennum = strtol(real_lenstr , NULL, 16);
printf(" [+] This dex's fileSize: %d\n", real_lennum);
if(dump_memory(buffer , len , each_filename) == 1)
{
printf(" [+] dex dump into %s\n", each_filename);
free(buffer);
continue;
}
else
{
printf(" [+] dex dump error \n");
}
}
free(buffer);
}
lseek64(memory_fd , 0 , SEEK_SET); //保险,先归零
r1 = lseek64(memory_fd , memory->start + 8 , SEEK_SET);//不用 pread,因为pread用的是lseek
if(r1 == -1)
{
continue;
}
else
{
char *buffer = malloc(len);
ssize_t readlen = read(memory_fd, buffer, len);
if(buffer[0] == 'd' && buffer[1] == 'e' && buffer[2] == 'x' && buffer[3] == '\n' && buffer[4] == '0' && buffer[5] == '3')
{
printf(" [+] Find dex! memory len : %d \n" , readlen);
DexHeader header;
char real_lenstr[10]={0};
memcpy(&header , buffer ,sizeof(DexHeader));
sprintf(real_lenstr , "%x" , header.fileSize);
long real_lennum = strtol(real_lenstr , NULL, 16);
printf(" [+] This dex's fileSize: %d\n", real_lennum);
if(dump_memory(buffer , len , each_filename) == 1)
{
printf(" [+] dex dump into %s\n", each_filename);
free(buffer);
continue; //如果本次成功了,就不尝试其他方法了
}
else
{
printf(" [+] dex dump error \n");
}
}
free(buffer);
}
}
fclose(maps_file);
return ret;
}
待解决问题
cloned pid是啥情况