借鉴于大佬的教程
https://www.52pojie.cn/thread-685918-1-1.html
https://blog.csdn.net/qing666888/article/details/71307295

安卓逆向笔记-得到360加固dex文件

这个方法很老了,所以部分apk可能没有用
工具
drizzleDumper ,雷电模拟器,androidkiller
附上drizzleDumper源码及工具
自己相尝试编译drizzleDumper的时候要在liunx下编译
链接:https://github.com/iaa-mr/android_unprotect (脱壳.zip就是)

drizzleDumper源码

drizzleDumper编译环境

LOCAL_PATH := $(call my-dir)  TARGET_PIE := true
NDK_APP_PIE := true  include $(CLEAR_VARS)  # 需要编译的源码文件
LOCAL_SRC_FILES := \  drizzleDumper.c
LOCAL_C_INCLUDE := \  drizzleDumper.h \  definitions.h  LOCAL_MODULE := drizzleDumper
LOCAL_MODULE_TAGS := optional  # Allow execution on android-16+
# 支持PIE
LOCAL_CFLAGS += -fPIE
LOCAL_LDFLAGS += -fPIE -pie  # 编译生成可执行ELF文件
include $(BUILD_EXECUTABLE)  include $(call all-makefiles-under,$(LOCAL_PATH))

drizzleDumper头文件

/* * 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代码

/* * 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()%9999);  // 拼接字符串得到dump的dex文件的生成名称  strncpy(each_filename , file_name , 200); //防溢出  strncat(each_filename , randstr , 10);  strncat(each_filename , ".dex" , 4);  // 先将pid进程内存文件句柄的指针置文件开头  lseek64(memory_fd , 0 , SEEK_SET);     // 设置pid进程内存文件句柄的指针为内存分布起始地址  off_t r1 = lseek64(memory_fd , memory->start , SEEK_SET);  if(r1 == -1)  {  //do nothing  }  else  {  // 根据内存分布区间的大小申请内存空间  char *buffer = malloc(len);  // 读取pid进程的指定区域的内存数据  ssize_t readlen = read(memory_fd, buffer, len);  printf("meminfo: %s ,len: %d ,readlen: %d, start: %x\n", mem_info, len, readlen, memory->start);  // 对读取的内存分布区域的数据进行dex文件的扫描和查找  if(buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F')  {  free(buffer);  continue;  }  // 查找到dex文件所在的内存区域  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};  // 获取内存区域中dex文件的文件头信息  memcpy(&header , buffer ,sizeof(DexHeader));  sprintf(real_lenstr , "%x" , header.fileSize);  // 通过dex文件头信息,获取到整个dex文件的大小  long real_lennum = strtol(real_lenstr , NULL, 16);  printf(" [+] This dex's fileSize: %d\n", real_lennum);  // 对dex文件所在的内存区域进行内存dump  if(dump_memory(buffer , len , each_filename)  == 1)  {  // 打印dump的dex文件的名称  printf(" [+] dex dump into %s\n", each_filename);  free(buffer);  continue;  }  else  {  printf(" [+] dex dump error \n");  }  }  free(buffer);  }  // 前面的内存方法搜索没有查找dex文件的内存,尝试下面的内存+8位置进行搜索  // 具体什么原因没太明白??  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};  // 获取内存dex文件的文件头信息  memcpy(&header , buffer ,sizeof(DexHeader));  sprintf(real_lenstr , "%x" , header.fileSize);  // 通过dex文件头信息,获取到整个dex文件的大小  long real_lennum = strtol(real_lenstr , NULL, 16);  printf(" [+] This dex's fileSize: %d\n", real_lennum);  // 对dex文件所在的内存区域进行内存dump  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;
}  // 从内存中dump数据到文件中
int dump_memory(const char *buffer , int len , char each_filename[])
{  int ret = -1;  // 创建文件  FILE *dump = fopen(each_filename, "wb");  // 将需要dump的内存数据写入到/data/local/tmp文件路径下  if(fwrite(buffer, len, 1, dump) != 1)  {  ret = -1;  }  else  {  ret = 1;  }  fclose(dump);  return ret;
}  // 获取指定附加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);  int ret = -1;  int mem_file;  // 尝试ptrace附加目标pid进程  ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);  // 对ptrace附加目标pid进程的操作结果进行判断  if (0 != ret)  {  int err = errno;  //这时获取errno  if(err == 1) //EPERM  {  return -30903;    //代表已经被跟踪或无法跟踪  }  else  {  return -10201;    //其他错误(进程不存在或非法操作)  }  }  else  {  // ptrace附加目标进程pid成功,获取指定pid进程的内存模块基址  // 获取其它进程的内存模块基址,需要root权限  if(!(mem_file = open(mem, O_RDONLY)))  {  return -20402;      //打开错误  }  }  return mem_file;
}

drizzleDumper使用教程

首先将脱壳.zip解压会得到两个drizzleDumper,雷电模拟器用x86就行
然后打开雷电模拟器和androidkiller
Androidkiller 上方可以找到模拟器或者已连接的手机


然后把drizzleDumper移到这个/data/local/tmp文件夹
打开雷电模拟器,安装需要解加固的软件
然后打开系统工具中的终端模拟器
输入 su
cd /data/local/tmp
./drizzleDumper 你需要dumper的包名
输入后回到主界面运行需要dumper的软件

然后就把dex文件解出来了

drizzleDumper后apk修复

此时需要注意oncreat有没有被抽空,如果被抽空就需要手动修复了。
如果没有的话那就是最好的,现在只需要将dex文件反编译成smali替换反编译后的apk里面
然后修改androidmanifest.xml里面
<application … android name=" 源程序的包名"…>
只适用于简单加固的程序,现在的壳基本没用了。。。。。。。。。。

安卓逆向笔记-得到360加固的dex文件相关推荐

  1. 安卓逆向笔记--apk加固

    安卓逆向笔记–apk加固 资料来源: 浅谈安卓apk加固原理和实现 Android中的Apk的加固(加壳)原理解析和实现 前两个太老了所以具体代码借鉴下面的 Android Apk加壳技术实战详解 一 ...

  2. 安卓逆向笔记(课外资料)

    安卓逆向笔记(课外资料) 只有知识点 分析apk主要组成 1.AndroidMainfest.xml-----配置清单 该文件是每个应用都必须定义和包含的,它描述了用的名字.版本.权限.引用的库文件等 ...

  3. android 360加固 反编译,[原创]逆向360加固等dex被隐藏的APK

    如果遇到apk中的lib文件夹中是这样的 基本没有dex文件可以反编译,这中的dex文件一般都是加密混淆压缩后放在so中啦. 但是软件要想运行就需要解出dex字节码然后加载到手机内存中,这样就可以在软 ...

  4. 《0基础学安卓逆向》第2集:初始apk文件和smali语法

    1.APK文件 apk=android Application PacKage=APKapk文件是什么:是安卓app的安装文件本质:(apk文件其实就是个)zip压缩包 意味着可以用解压缩工具把apk ...

  5. Android中Apk加固之Dex文件的加密与解密

    参考文档:https://developer.android.google.cn/studio/build/multidex.html#keep 1.由文档中可以知道 了解到 在Android5.0之 ...

  6. Android逆向与安全——360 dex加固与脱壳

    前言 现在市面上对APP的安全合规管控越来越严格了,也就要求了APP在上架之前一定要做合规检测和加固处理.对APP就是加固的好处,可以提高APP的安全性,提高APP被逆向分析破解的门槛,同时通过加固保 ...

  7. 360加固保的dex脱壳方法

    博客地址:http://blog.csdn.net/qq1084283172/article/details/53149214 360整体加固classes.dex后的apk程序的特点,以超信1.1. ...

  8. 安卓逆向007之安卓系统架构

    文章目录 Java闲谈 Android系统架构 安卓开发的第一个程序 安卓的四大组件 dalvik字节码 本篇文章主要记录一些概念性的东西 Java闲谈 继续深入学习安卓逆向,建议先去学一下java的 ...

  9. IO操作Dex文件加密,APK加固项目实战

    APK加固原理分析 1.1 APK文件结构 首先让我们先了解一下一个完整的Android应用程序都由哪些文件组成.解压一个apk包,我们可以看到一下的这些文件及文件夹: 每个文件及文件夹的作用如下表所 ...

最新文章

  1. 适用于AMD ROC GPU的Numba概述
  2. tomcat 7.0 linux下载,Tomcat 7.0.67 发布下载
  3. R语言构建随机森林模型错误解决:Error in y - ymean : non-numeric argument to binary operator
  4. c++ vector嵌套传参
  5. 手脱UPX(堆栈平衡原理)
  6. STM32 基础系列教程 49 – Jansson
  7. Linux视频切片m3u8,使用ffmpeg+nginx使用视频切片播放
  8. pip install安装php,详述Python、pip、easy_install的安装教程
  9. linux结束所有任务命令行,Linux基础命令(15)定时任务
  10. python语言程序设计实践教程实验八答案_清华大学出版社-图书详情-《Java程序设计教程及实验指导》...
  11. SpringBoot 集成 layering-cache 实现两级缓存调研与实践
  12. 国内首部《数字货币词典》在新莫干山会议上启动,巴比特智库担任主编单位...
  13. php微信转发无法显示标题图片,解决微信公众号分享朋友圈不显示标题图片描述的方法...
  14. 【5G模组】讨论RSSI,RSRP,RSRQ and SINR
  15. Linux磁盘管理和文件系统
  16. 手把手教你拥有自己的代码生成器-------->坑居多
  17. 虚拟机的虚拟化如何开启?
  18. 条件极值(拉格朗日乘数法)_Simplelife_新浪博客
  19. python办公自动化ppt_最全总结 | 聊聊 Python 办公自动化之 PPT(下)
  20. 股票指标SMA EMA WMA...

热门文章

  1. 车载毫米波雷达系列专题规划和文章目录
  2. c++ 图片HWC格式转CHW格式
  3. e470换高分屏_ThinkPadE470笔电(8G内存 256G固态 高分屏 14英寸) 京东5499元
  4. 思念是美好的,思念是痛心的...
  5. 通过DeviceIoControl获取U盘或移动硬盘的出品商、制造商和版本号等信息
  6. Linux 防火墙(一)——基础介绍以及基本扩展模块
  7. 文献丨GWAS分析菜用大豆可溶性糖含量调控基因
  8. 计时器(视频的计时:时间码)
  9. 如何解决Eclipse启动慢?多图、Eclipse详细配置说明
  10. 分享138个HTML公司企业模板,总有一款适合您