当前位置:   article > 正文

【app逆向】app逆向常用知识点汇总_app逆向百集

app逆向百集

Android逆向

常用工具:

JDK/SDK/NDK

eclpise集成开发环境/Android Studio

AndroidKiller/jeb/jadx / GDA/Androidk逆向助手

IDA/GDB 

apkhelper/getsign/APK上上签

模拟器(雷电3.59)

MT管理器/RE文件管理器

工具安装注意事项:

1.jdk安装路径中不能有中文

2.ndk的配置路径中不能有中文和空格,可以把它放在根目录

3.安装包文件不全,运行会出错

4.没有配置环境变量可以按住shift+右键=>”在此处打开命令窗口”选项

5.ndk安装正确的提示

D:\android-ndk-r10e>ndk-build

Android NDK: Could not find application project directory !

Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.

D:\android-ndk-r10e\build/core/build-local.mk:143: *** Android NDK: Aborting.  Stop.

APK文件:

APK是Android Package的缩写,即Android安装包。APK是类似Symbian Sis或Sisx的文件格式。通过将APK文件直接传到Android模拟器或Android手机中执行即可安装。

APK文件目录:

assets   不经过 aapt 编译的资源文件

lib   .so文件

META-INF 文件摘要,摘要加密和签名证书文件目录

CERT.RSA 公钥和加密算法描述

CERT.SF 加密文件,它是使用私钥对摘要明文加密后得到的 密文信息,只有使用私钥配对的公钥才能解密该文 件

MANIFEST.MF 程序清单文件,它包含包中所有文件的摘要明文

res 资源文件目录,二进制格式

drawable         图片

layout 布局

menu 菜单

resources.arsc 经过 aapt 编译过的资源文件

classes.dex 可执行文件

AndroidManifest.xml   配置文件

APK打包流程: 

打包资源(res/assets/AndroidManifest.xml/Android基础类库)文件,生成 R.java和resources.ap_文件

处理AIDL文件,生成对应的.java文件

编译Java文件,生成对应的.class文件

把.class文件转化成Davik VM支持的.dex文件(.java=>.class=>.dex)

打包生成未签名的.apk文件

对未签名.apk文件进行签名

对签名后的.apk文件进行对齐处理

APK安装流程:

1.安装方式

系统程序安装

通过Android市场安装

ADB安装(adb devices:显示当前连接的设备;adb install 安装包路径)

手机自带安装

2.安装过程

复制APK安装包到/data/app目录下,解压并扫描安装包,把dex文 件(Dalvik字节码)保存到/data/dalvik-cache目录,并/data/data目录 下创建对应的应用数据目录。

3.安装后文件所在目录

/system/app

系统自带的应用程序,获得adb root权限才能删除

/data/app

用户程序安装的目录,安装时把apk文件复制到此目录

/data/data

存放应用程序的数据

/data/dalvik-cache

将apk中的dex文件安装到dalvik-cache目录下

4.卸载过程

删除安装过程中在上述三个目录下创建的文件及目录。   

虚拟机:

1.java虚拟机

java字节码

基于栈架构

2.dalvik虚拟机(jit机制)

Android 5.0以下

dalvik字节码

dalvik可执行文件体积更小

基于寄存器架构

3.art虚拟机(aot机制)

Android 5.0版本及以上

注意:

.dex =>dexopt=>.odex  dalvik加载执行的odex文件

.dex=>dex2oat=>.oat    art加载执行的是oat文件

Dalvik字节码:

1.了解dalvik寄存器

dalvik中的寄存器都是32位

2.寄存器之v命名法与p命名法

参数寄存器 P0-Pn

局部变量寄存器 V0-Vn

3.dex文件反汇编工具

smali.jar\ddx.jar

4.类型

smali==>Java

V void

Z boolean

B byte

C        char

S short

I int

J long

F float

D double

L java类

[ 数组

5.字段

Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;

6.方法

Lpackage/name/ObjectName;->MethodName (III) Z

Dalvik指令:

基础字节码-名称后缀/字节码后缀 目的寄存器  源寄存器

名称后缀是wide,表示数据宽度为64位

字节码后缀是from16,表示源寄存器为16位

空操作指令

nop

数据操作指令

move(-wide/-object/-result/-result-object/-result-wide/- exception)

move(-wide/-object)/from16

move(-object)/16

返回指令(重点)

return-void(表示方法的放回值为空)

return(表示方法的反回值为32位非对象类型的值)

return-wide(表示方法的反回值为64位非对象类型的值)

return-object(表示方法的反回值为对象类型的值)

数据定义指令(重点)

const(-wide/-string/-class)

const/4

const(-wide)/16

const(-wide)/32

const(-wide)/high16

实例操作指令

check-cast(类型转换)

instance-of(检查)  

new-instance(新建) 

数组操作指令

array-length(获取数组长度)

new-array(新建数组)

filled-new-array(定义数组并初始化)

filled-new-array/range(定义数组并初始化/指定取值范围)

filled-array-data(数组元素取值与赋值)

异常指令(throw)

跳转指令(重点)

goto 紧跟一个标签直接跳转到标签所在位置

packed-switch(有规律)、sparse-switch(无规律)

if-eq(等于)/if-ne(不等于)

if-lt(小于)/if-le(小于等于)

if-gt(大于)/if-ge(大于等于)

比较指令(cmp)

大于(1)/等于(0)/小于(-1)=>cmpg、cmp

大于(-1)/等于(0)/小于(1)=>cmpl

字段操作指令

普通字段=>iget(读)/iput(写)

静态字段=>sget(读)/sput(写)

方法调用指令(重点)

invoke-virtual(调用实例的虚方法) Java当中的普通方法

invoke-super(调用实例的父类/基类方法) 

invoke-direct(调用实例的直接方法) 调用java当中的构造方法

invoke-static(调用实例的静态方法)

invoke-interface(调用实例的接口方法)

数据转换指令

neg-数据类型=>求补

not-数据类型=>求反

数据类型1-to-数据类型2=>将数据类型1转换为数据类型2

数据运算指令

add/sub/mul/div/rem  加/减/乘/除/模

and/or/xor  与/或/非

sh1/shr/ushr 有符号左移/有符号右移/无符号右移

APK反编译与回编译:

先查壳,再反编译看验证

.apk文件==>反编译apk(dex/配置文件/资源文件(apk反编译败)) ==>修改关键文件实现自己的目的==>重新打包签名(无法重新打包) ==>apk安装后无法 运行。

apktool  .dex=>.smali  

          dex2jar  .dex=>.jar

Apktool工具实际上只反编译以下三种类型文件:

.xml文件、.dex文件、.arsc文件

去除广告和弹窗,撇开不存在于smali的这种情况,容易的就是 可以在XML中寻到Activity,难的就是寻不到,发生这种情况时,        就要分析代码,程序逻辑,抓住关键信息,界面和函数。

注意:

当字符串等关键信息搜不到时,可以从三个方向考虑:1.字符串 在so层;2.字符串被加密了3.结合了服务器,服务器返回,本地 显示。

smali文件:

  无论是普通类、抽象类、接口类或者内部类,在反编译出的代码中,它 们都以单独的smali 文件来存放。每个 smali 文件都由若干条语句组成, 所有的语句都遵循着一套语法规范。

1.描述类的信息

.class < 访问权限> [ 修饰关键字] < 类名>

.super < 父类名>

.source <源文件名>

 2. 静态字段

# static fields

.field < 访问权限> static [ 修饰关键字] < 字段名>:< 字段类型>

 3.实例字段

# instance fields

.field < 访问权限> [ 修饰关键字] < 字段名>:< 字段类型>

 4.直接方法

# direct methods

.method <访问权限> [ 修饰关键字] < 方法原型>

<.locals> “.locals ”指定了使用的局部变量的个数
[.param] “.param”指定了方法的参数

[.prologue] “.prologue ”指定了代码的开始处

[.line]          “.line ”指定了该处指令在源代码中的行号

<代码体>

 .end method

 5. 虚方法的声明与直接方法相同,只是起始处的注释为“virtual  methods”。

 6.接口

 # interfaces

   .implements < 接口名>“.implements ”是接口关键字,后面的接口

   名是 DexClassDef 结构中 interfacesOff 字段指定的内容。

 7.注解

  # annotations

    .annotation [ 注解属性] < 注解类名>

[ 注解字段 = 值]

  .end annotation

   注解的作用范围可以是类、方法或字段。如果注解的作用范围是类,   “.annotation ”指令会直接定义在 smali 文件中,如果是方法或字段,“.annotation ”指令则会包含在方法或字段定义中。

快速定位关键代码:

1.分析流程

搜索特征字符串

搜索关键api

通过方法名来判断方法的功能

2.快速定位关键代码

反编译APK程序

AndroidManifest.xml=>包名/系统版本/组件

程序的主activity(程序入口界面)

每个Android程序有且只有一个主Activity

分析程序的执行流程

需重点关注的application

application执行时间

授权验证

3.定位关键代码的技巧

信息反馈法(资源id/字符串)

特征函数法(api函数)

顺序查看法(分析程序执行流程/病毒分析)

代码注入法(动态调式/插入log/查看logcat/分析加解密)

栈跟踪法(动态调式/函数调用流程)

Method Profiling(方法剖析=>动态调式/热点分析//函数调用流程)

动态调式:

jdwp(调式有线协议)=>jdb

ddms(dalvik调式监视器服务)

通过该命令(adb shell getprop ro.debuggable)获取当前设备 ro.debuggable的值,当值为1时开启系统调试开关。

android.debuggable="true"

logcat(查看调式信息)/method profiling(跟踪程序的执行流程)

游戏内购:

去除可能会产生费用的危险权限

android.permission.SEND_SMS

android.permission.CALL_PHONE

支付接口

电信支付接口

logcat字符串定位(Egame支付成功/Egame支付Cancel/order id)=>搜索字符串,向上分析,回溯分析/函数名替换

联通支付接口

logcat字符串定位(Unicom支付cancel/Unicom支付成功)=> 在下面类修改处理,可以用goto或switch方法

移动支付接口

logcat字符串定位(购买道具:[] 成功/购买道具:[] 失败)=>在 下面类修改

特征码                     

中国移动 46000、46002、46007、46020

中国联通 46001、46006、46010        

中国电信 46003、46005、46011

内购关键词

和游戏搜索方法名

onResult,onchinabilling,resulton,Paycenter,        Callback

联通游戏搜索方法名

OnPayResult,PyaResulton,Activity,result,callback

电信爱游戏搜索方法名

paySuccess成功,payCancel取消,payFailed失败

移动mm搜索方法名

onBillingFinish,Billing,CallBack,onresult无用

       对关键onsuccess()函数的筛选与定位

支付宝和银行卡方法名

handle,message

支付宝搜索字符

搜索字符串“9000”

360支付

onfinishedon,Activityresult

4399

notifyDeliverGoods  

内购技巧

从静态代码分析程序逻辑,找到修改点

程序逻辑分析=>最重要的又是流程分析/流程图=>核心(层次)

关键性信息查找=>静态(整体分析与局部分析)/动态

Android NDK:

1. 如何编译原生程序

Application.mk(ARM硬件指令集/工程编译脚本/stl支持等)

Android.mk(编译选项/头文件/源文件及依赖库等)

local_path(call my-dir)

include $(clear_vars)

local_arm_mode:= arm指令模式

local_module:=模块名称

local_src_files:=源文件

build_executable(可执行文件)

build_shared_library(动态链接库)

build_static_library(静态链接库))

2. 原生程序的启动流程

原生程序的入口函数

动态库的加载/程序参数argc和argv的初始化

静态链接/动态链接(动态链接程序/动态链接库)

静态链接(crtbedin_static.o/crend_android.o)

动态链接(crtbegin_dynamic.o/crtend_android.o/加载 器 (system/bin/linker))

静态链接程序在启动时不需要额外的加载其他的动态库 (init/adbd/linker)

静态链接与动态链接程序的入口函数相同,动态链接程序 在执行入口函数前需要通过linker进行额外的初始化

main函数究竟何时被执行

静态链接(libc_init_static)/动态链接程序 (libc_init_dynamic)

3. 原生C++程序逆向分析

C++类的逆向

C++中的类可以理解为C语言中的结构体,每一个成员变 量就是一个结构字段,每一个成员函数的代码都被优化到 了类的外部,它们不占据存储空间

Android NDK对C++特性的支持(app_stl)

system

gabi++(rtti)=>gabi++_static/gabi_shared

stlport(rtti/stl)=>stlport_static/stlport_shared

gnustl(c++异常/rtti/stl)=>gnustl_static/gnustl_shared

4. Android NDK JNI API逆向分析

Android NDK提供了那些函数

Linux C/C++

Android NDK<=>JNI接口<=>java

JNINativeInterfasce(jni本地接口)

JNIInvokeInterface(jni调用接口)

移植/保护核心代码

如何静态分析Android NDK程序

     file=>load file=>parse c header file=>jni.h=>structures

Android与ARM处理器:

ARM处理器架构概述

ARM处理器家族

Android支持的处理器架构

ARM/x86/MIPS

原生程序与ARM汇编语言: 

原生程序逆向初步

代码混淆技术

ARM指令集

堆栈指针寄存器sp/堆栈寻址指令(stmfd压栈/ldmfd出栈)

存储器访问指令(str写入数据到存储器中/ldr从存储器中读取数 据到寄存器)

数据处理指令(mov)/带链接跳转指令(bl)

原生程序的生成过程(交叉编译/跨平台编译)

预处理(预处理指令) 编译 汇编 链接

必须了解的ARM知识

汇编:芯片,高级语言的逆向,中间语言

分析和修改汇编指令:赋值、跳转、算术运算、移位运算、堆栈操 作、内存读写指令、函数调用约定

Thumb(16位)、Thumb2(32位)、ARM(32位)

用户模式(usr):

不分组寄存器(R0-R7)

分组寄存器(R8-R14)

传递参数与返回值(R0-R3)

保存栈顶地址(R13/SP)

保存函数的返回地址(R14/LR)

程序计数器R15(PC)

状态寄存器CPSR

ARM处理器:

ARM状态(执行32位对齐指令的ARM指令)

Thumb状态(执行16位对齐的Thumb指令)


ARM汇编语言程序结构:

完整的ARM汇编程序

处理器架构定义

段定义

注释与标号

@=>单行注释

/**/=>多行注释

汇编器指令

子程序与参数传递

R0-R3这4个寄存器用来传递函数调用的第1到第4个参数,超 出的参数通过堆栈来传递

R0寄存器同时用来存放函数调用的返回值

被调用的函数在返回前无需恢复这些寄存器的内容

ARM指令集:

立即寻址(mov r0,#0x123) 

寄存器寻址(mov r0,r1)

寄存器移位寻址(mov r0,r1,lsl #0x2)

LSL(逻辑左移)

LSR(逻辑右移)

ASR(算术右移)

ROR(循环右移)

RRX(带扩展的循环右移)

寄存器间接寻址(ldr r0,[r1])

基址寻址(ldr r0,[r1,#-4])

多寄存器寻址(ldmia r0,{r1,r2,r3,r4})

堆栈寻址(stmfd sp!,{r1-r7,lr}(入栈保护)/ldmfd sp,{r1-r7,lr}(出栈恢复))

ldmfa/stmfa

ldmea/stmea

ldmfd/stmfd

ldmed/stmed

块拷贝寻址

ldmia/stmia

ldmda/stmda

ldmib/stmib

ldmdb/stmdb

相对寻址

相对寻址以程序计算器pc的当前值作为基地址,指令中的地址 标号作为偏移量,将两者相加之后得到操作数有效地址ARM与 Thum指令集

指令格式

<opcode>:指令助记符

 {<cond>}:执行条件

{s}:是否影响cpsr寄存器的值

{.w}:指令宽度说明符.w表示是32位

{.n}:指令宽度说明符.n表示16位

<rd>:目的寄存器

,<rn>:第一个操作数寄存器

{,<perand2>}:第二个操作数:立即数、寄存器、寄存器移位

eq:相等/z=1

ne:不相等/标志z=0

hi:无符号数大于/c=1,z=0   

cs/hs:无符号数大于或等于/c=1

cc/lo:无符号数小于/c=0  

ls:无符号数小于或等于/c=0,z=1

gt:有符号数大于/z=0,n=v   

ge:有符号数大于或等于/n=v

lt:有符号数小于/n!=v   

le:有符号数小于或等于/z=1,n!=v

mi:负数/n=1              

pl:整数或0/n=0

vs:溢出/v=1           

vc:没有溢出

跳转指令

B 无条件跳转

BL 带链接的无条件跳转

BX 带状态切换的无条件跳转

BLX 带链接和状态切换的无条件跳转

寄存器访问指令

ldr(<-)/ldrd

str(->)/strd

ldm(->)

stm(<-)

push(入栈)/pop(出栈)

swp

数据处理指令

数据传送指令(mov)/数据非传送指令(mvn)

算术运算指令

add/adc

sub/rsb/sbc/rsc

mul/mls/mla   umull/umlal smull/smlal smlad/smlsd

sdiv/udiv

asr(算术右移指令)

逻辑运算指令

and/orr/eor   逻辑与/逻辑或/逻辑异或

bic(位清楚指令)

lsl/lsr   逻辑左移/逻辑右移

ror/rrx   循环右移/带扩展的循环右移

比较指令

cmp/cmn/tst/teq

其他指令

nop(空操作指令)

swi(软中断指令)

mrs(读状态寄存器指令)

msr(写状态寄存器指令)

ARM指令机器码:

B/BL指令

00001BD0   BEQ loc_1c04

31-28:cond=>0000   

27-25:101

25-24:L=>B:0 /BL:1

23-0:offset:目标地址与该指令的相对偏移

offset:(1c04-(1bd0+8))/4=1011

0000 101 0 000000000000000000001011

0A 00 00 0B

00001BD0 0B 00 00 0A

LDR/STR指令

00001BC0 LDR R2,[R12]

00001BC0 00 20 9C E5

E5 9C 20 00

1110 01 011001 1100 0010 000000000000

cond    1110

指令标识   01

IPUBWL   011001

Rn:R12    1100

Rd:R2      0010

offset:0    000000000000

MOV指令

MOV R1, #0x56000000

56 14 A0 E3

E3 A0 14 56

1110 00 1 1101 0 0000 0001 0100 01010110

Thumb指令

CPSR寄存器

T位:1-thumb,0-arm

IDA Pro工具介绍:

交互式反汇编器,是典型的递归下降反汇编器。

导航条

蓝色 :表示常规的指令函数

黑色 :节与节之间的间隙

银白色 :数据内容

粉色 :表示外部导入符号

暗黄色: 表示ida未识别的内容

IDA主界面

IDA View三种反汇编视图:文本视图、图表视图、路径视图

Hex View 十六进制窗口

Struceures 结构体窗口

Enums 枚举窗口

Imports 导入函数窗口

Exports 导出函数窗口

Strings 字符串窗口

IDA常用功能及快捷键:

空格键:切换文本视图与图表视图

ESC:返回上一个操作地址

G:搜索地址和符号

N:对符号进行重命名

冒号键:常规注释

分号键:可重复注释

Alt+M:添加标签

Ctrl+M:查看标签

Ctrl+S:查看段的信息

代码数据切换

C=>代码  D=>数据  A=>ascii字符串 U=>解析成未定义的内容

X:查看交叉应用

F5:查看伪代码

Alt+T:搜索文本

    Alt+B:搜索十六进制

IDA静态分析:

导入jni.h分析jni库函数

拷贝伪C代码到反汇编窗口

右键=>copy to -assembly-把伪c代码复制到反汇编窗口的汇 编代码。

IDA可以修改so的hex来修改so,edit=>edit-patchrogram

       在这里建议使用winhex来实现。

IDA动态调试:

       IDA调式界面

1.反汇编窗口

C 将当前地址处的数据解析成代码

P

2.十六进制窗口

编辑内存数据和代码

3.寄存器窗口

修改寄存器的值

4.模块窗口

模块路径和地址

5.线程窗口

6.栈窗口

7.输出信息窗口

IDA调式常用功能

1.断点和运行

设置断点 F2

设置断点不可用 Disable breakpoint

编辑断点 Edit breakpoint

删除断点 Delete breakpoint

继续运行 F9

查看当前所有断点 Ctrl+Alt+B

2.单步调式

单步步入 F7

单步步过 F8

运行到函数的返回地址 Ctrl+F7

运行到光标处 F4

3.IDC脚本

static main(void)

{

auto fp, dexAddress, end, size;

dexAddress = 0x77607640;

size = 0x19E118;

end = dexAddress + size;

fp = fopen("D:\\classes.dex", "wb");

for ( ; dexAddress < end; dexAddress++ )

fputc(Byte(dexAddress), fp);

}

4.修改内存数据

5.修改寄存器

修改PC寄存器时,最好在跳转指令改,当然如果你对程序流程    把握很好,可以随便PC,只要程序不出错

7.NOP函数或代码

NOP函数MOV R0,R0(00 00 A0 E1/00 1C)

清空指令(00 00 00 00/00 00)

函数头直接返回mov pc,lr(0E F0 A0 E1/F7 46)

8.改变执行流程

修改寄存器的值

修改跳转指令

注意:修改内存和修改代码的时机选择不同,因为修改内存和寄存       器,必须调式到某一处,才能让寄存器和内存是想要的值,此       时修改,而且数据的值一般对程序影响不大,而修改代码就不同了       如果已经走到了那一句代码,才去修改代码,是要报错的,提前在         它 运行到前面1-2条指令时修改代码。原因是PC指令预读三级流       水线:

1.读取指令

2.解析指令

3.执行指令

ADD R6,PC,R6 =>R6=PC+R6=847C+1840=9CBC+8? 9CC4

JNI_OnLoad下断方法技巧

so内寻找

基址+偏移

dvmloadnativecode函数

dlsym(handle,"jni_onload")

.init和.init_array下断技巧

linker大法,先勾选三项F9运行,再执行jdb,当目标so被加载       时通过基址+偏移下段

APK保护策略:

Java层混淆、资源混淆、SO层混淆(ollvm)

签名验证、文件验证、整包验证

本地验证、服务器验证、综合验证

本地验证

java层验证

so层验证

网络验证

java层验证

so层验证

通信/实时控制

服务器

判断验证

去签名验证

PackageManager

getAppSignature

签名hash值

signatures

反调试:

java层Debug类的isDebugged方法

native层的isDebugged方法

检测status文件的TracePid

检测开放端口

inotify 文件监控/proc/pid/maps等文件打开事件与检测其中内存运行的文件gettimeofday时间循环检测

fork父子循环检测

异常触发、非法指令、引入与异常信号陷阱

检测代码暂停时间

反-反调试:

修改java层isDebugged方法返回

利用py脚本HOOK native层Debug方法

HOOK open、fopen函数动态下断修改TracePid的值或修改为过反调试的内核

利用其他端口调式

修改内核改变文件打开事件响应与修改打开/proc/pid/maps后内存运行文件结果

HOOK gettimeofday函数让其不能循环

修改内核fork方法与多IDA挂起kill19等方法调式

修改异常指令信号与识别非法指令使用异常HOOK

HOOK 常用获取时间的系统函数

修改检测时间,让其只检测一次

常见加密算法:

古典密码学(以字符为基本加密单元)

移位密码/错位密码

替代密码/置换密码

现代密码学(以信息块为基本加密单元)

哈希算法

非对称加密与解密

椭圆曲线

数字签名

数据分组与校验

散列函数

用于数据完整性校验

MD  消息摘要算法

SHA 安全散列算法

MAC 消息认证算法

CRC 循环冗余校验算法

对称加密算法

加密密钥==解密密钥

流密码:指加密时每次加密一位或一个字节的明文。

同步流密码

同步性 无错误传递性 主动攻击性

音频/视频数据提供版权保护

自同步流密码

自同步性 错误传递有限性

主动攻击性 明文统计扩散性

RC4/SEAL

分组密码(http://www.seacha.com/tools/):指加密时将明文分 成固定长度的组,用同一密钥和算法对每一块加密,输出也是固 定长度的密文。

常用于网络加密

安全性=>扩散/混乱原则

实现性=>软件/硬件

ECB 电子密码本模式

CBC 密文链接模式

CFB 密文反馈模式

OFB 输出反馈模式

CTR 计数器模式

DES

DESede/3DES/Triple DES

AES

TEA

DEA

PBE

非对称加密算法

加密密钥!=解密密钥

公钥==>对外公开

私钥==>对外保密

私钥加密==>公钥解密

公钥加密==>私钥解密

DH 密钥交换算法

基于因子分解

RSA 数据加密/解密 数字签名

基于离散对数

ElGameal 数据加密/解密 数字签名

DSS数据签名标准=>DSA 数字签名

ECC 椭圆曲线加密算法

使用对称加密算法对数据进行加密与解密,使用非对称加密算法 对对称加密算法所使用的密钥进行加密与解密。

数字签名

私钥==>签名

公钥==>验证

单向认证

双向认证

RSA

DSA

ECC+DSA==>ECDSA 椭圆曲线数字签名算法

认证/鉴别服务

数据完整性服务

抗否认性服务

数字证书

消息摘要算法

对称加密算法

非对称加密算法

数字签名

鉴别/认证

数据保密性

数据完整性

抗否认性

证书管理

KeyTool

构建自签名证书

构建CA签发证书

OpenSSL

根证书

服务器证书

客户端证书

密钥库==>管理私钥

数字证书==>管理公钥

加密/解密

签名/验证

X.509

服务器数字证书

协议加解密分析:

协议与安全协议(服务器协议关键,就是先抓包,再解密)

概念:协议就是服务器与客户端交互信息的一种规则

客户端和服务器连接:实质都是连接服务器的IP地址和开放端口

POST:客户端提交数据给服务器

GET:客户端获取服务器数据

http,ftp,smtp:应用层

tcp,udp:传输层

IP:网络层

帧相关协议:数据链路层

HTTP/HTTP2

HTTPS协议=>https是基于sll/tls的http协议

ssl协议=>安全套接字层

tls协议=>传输层安全

socket=>tcp/udp=>http/ftp

抓包工具:

http/https

fiddler/charels

socket/tcp

抓网卡

wireshark/sniffer

防止代理

小米wifi+wpe

抓不到包原因:

1.如网游副本,有的就是没有包;

2.fiddler只能抓HTTP/HTTPS,如果是socket抓不到的;

3.在动态调试时,没有走到发包的地方。

tcpdump+Wireshark:

adb shell tcpdump -p -vv -s 0 -w /sdcard/capture.pcap 开始抓包

ctrl+c 结束抓包

adb pull /sdcard/capture.pcap 导出文件

Dex文件结构:

1.dex文件中的数据结构

u1/uint8_t=>表示1字节的无符号数

u2/uint16_t=>表示2字节的无符号数

u4/uint32_t=>表示4字节的无符号数

u8/unit64_t=>表示8字节的无符号数

sleb128=>有符号leb128,可变长度为1-5字节

uleb128=>无符号符号leb128,可变长度为1-5字节

uleb128p1=>无符号leb128值加1,可变长度为1-5字节

2.dex文件整体结构

struct DexFile {

DexHeader

DexStringId

DexTypeId

DexProtoId//对DexType进一步说明

DexFieldId

DexMethodId

DexClassDef

DexData

DexLink

}

以索引为线索

3.DEX的内存映射

与静态类似,只是变为xxxItem结构

ClassObject结构由六个部分组成:    

PDvmDex:// DEX文件字段     

super://超类    

sfields://对应DexClassData结构中的staticFields静态字段      

iFields://对应DexClassData结构中的instanceFields实例字段       

directMethods://对应DexClassData结构中的directMethods直接方法字段   

virtualMethods:///对应DexClassData结构中的virtualMethods虚方法字段

DexClassDef :  class_def_item   

DexClassData:  class_data_item     

DexFiled(staticFields): sfileds      

DexFiled(instanceFields): ifileds         

DexMethod(directMethods):directMethods     

DexMethod(virtualMethods):virtualMethods        

DexCode: code_item  

ELF文件结构:

linux elf文件、windows pe文件

Android操作系统内核采用Linux内核框架实现  Android ELF文件

ELF文件整体结构:

ELF Header-->ELF文件头的位置是固定的

Segment Header Table-->ELF程序头描述的是段的相关信息

.init

.text

.rodata

.data

.symtab  符号表

.line         

.strtab  字符串表

Section Header Table-->ELF节头表描述的是节区的信息

动态用段,静态用节

readelf的使用:

 -a

 -h

 -l

 -S

 -e

 -s

arsc文件:

arsc文件解析

xml文件:

xml文件解析及工具

xml加密

xml和arsc简单十六进制加密:

以arsc为例:在0x00000028h的文件偏移地址之前进行修改,如改头 部第一个HEX操作数为00。搜索字符,'1c' 搜索3下。把1c前面的 01改00,就可以了。看020行,头部字节流,把尾部的00改为和头 部一样。

思考:ARSC、xml文件很难去做单纯的动态加载,如DEX,这也是文件根本性质决定的,还有一个原因,就是安装后这个APK必须要打开。我们最多能做到的,在动态上(自然这就比外部混淆、十六进制加密要强些),就是用壳的apk,然后结合APK动态加载,让真实APK的资源文件是正确的,可以考虑动态代码生成(如动态生成真实APK的配置清单xml,而在asset文件夹下的APK压缩包中并没有配置清单xml),或者解密替换(这就分两种,你是保护xml\arsc文件,还是那些png等外部资源,当然原理一样,文件的加密解密)等。事实是,DEX和APK的动态加载往往必须要考虑资源怎么办的问题,解决方法往往是资源保护的一个反面,将动态加载需要的资源文件中数据先写在壳的资源文件中。毕竟,在代码与资源保护直接抉择,肯定是保护代码优先。

DEX类加载过程解析:

http://androidxref.com/

1.DEX文件优化与验证:

run_dexopt:

static const char* Dex_OPT_BIN = "/system/bin/dexopt"

\dexopt\Optmain.cpp:extractAndProcessZip() //读取和抽出dex,加上odex文件头,设置优化选项,可以看作DEX文件优化的主控函数

\vm\analysis\DexPrepare.cpp:dvmContinueOptimization()//写入odex文件,可以说优化与验证工作的完成就是写入odex文件

2.DEX文件解析:

\vm\RawDexFile.cpp:dvmRawDexFileOpen()//DEX文件解析的主控函数

\libdex\OptInvocation.cpp:dexOptGenerateCacheFileName()//生成该dex对应odex文件

\vm\DvmDex.cpp:dvmDexFileOpenFromFd()//完成对DEX文件映射,设置为只读文件,并进一步优化

\libdex\DexFile.cpp:dexFileParse()//解析DEX

在实践中,我们发现并不是所有的dexfileopenpartial都能断下来,但

_Z27dexOptGenerateCacheFileNamePKcS0

dvmdexfileopenfromfd

dexfileparse

这些函数一定能断下来,而dexfileopenpartial常常在有壳时,也就是真正dex出现时才可以断下来,由此可知,

其实dalvik很喜欢走的路就是用odex,而不是dex。dex文件只有在odex文件不好用时才去用,这与oat文件一致。

3.DEX类加载

\vm\native\dalvik_system_DexFile.cpp:

Dalvik_dalvik_system_DexFile_defineClassNative //类加载的主控函数

\vm\oo\Class.cpp:dvmDefineClass()//确认类加载描述符进行类加载

\vm\oo\Class.cpp:findClaaNoInit()//完成实际类加载工作

\vm\oo\Class.cpp:loadClassFromDex()//返回值是一个ClassObject结构体

往后便是FindClass、GetStaticMthodID、CallStaticMthod、dvmInterpretStd

so的加载、链接、执行过程解析:

begin.S:__linker_init

1.dlopen函数

dlfcn.cpp

2.整体流程

linker.cpp

do_dlopen函数:

find_library函数:完成对so的解析装载、分配、链接

CallConstructors函数:完成对so中.init和.initarray的执行

3.先看CallConstructors函数,从后面的执行来看

  CallFunction("DT_INIT", init_func);

  CallArray("DT_INIT_ARRAY", init_array, init_array_count, false);

4.回到find_library函数,看so的具体加载

find_library_interna

load_library是整个so加载的主控函数

5.so加载的详细步骤

解析装载:

elf_reader.Load函数包括了下列函数:

         ReadElfHeader() &&

         VerifyElfHeader() &&

         ReadProgramHeader() &&

         ReserveAddressSpace() &&

         LoadSegments() &&

         FindPhdr();

所以,so的装载是一种解析式装载,这与dex有一定区别,dex是先加载进行优化验证生成odex,再去解析odex文件,而so更像边解析边装载,在装载过程中主要解析是load段。

分配soinfo:

soinfo_alloc函数,生成了一个soinfo结构

链接:

soinfo_link_image函数,也就是soinfo结构链接镜像,从而得到一个以后用的镜像文件

so中用于动态链接的结构就是.dynamic节,即动态节区

a.定位动态节

b.解析动态节

c.加载依赖so

d.重定位:

主要函数为soinfo_relocate,此函数会被soinfo_link_image函数调用

解析重定位项:.rel(.plt安卓并不用),重定位表

导入符号信息:.dynsym, 符号表

修正需要重定位的地址

DEX类加载过程在加固脱壳应用:

1.dump dex,脱壳。

2.内存动态替换dex,dex自修改,自调用底层函数解析dex。

3.dex自解析重构,完成dex重组脱壳。

Linker在加固脱壳应用:

1.在.init和.intarray下断,若.initarray节存在dex解密,dump dex,也就是dex脱壳。

2.dump so再修复,也就是so脱壳,一般选择在jni_onload。

3.因为在.init和.intarray运行之后,如果有jni_onload,就调用,变相断jni_onload。

4.自定义linker。

5.HOOK dlopen等函数,判断是否加载了so,如果加载就解密,同理在整个so的装载、链接过程中可以对so进行变形后的修复,so解密脱壳最迟要在jni_onload,当然混淆等基于内部保护的不在考虑之列。

DEX文件加固:

DEX文件结构变形

DEX文件结构拼接隐藏

DEX文件整体加密

ELF文件加固:

ELF文件结构变形

so文件结构拼接隐藏

so文件反汇编注入

so文件整体加密、函数加密、区段加密、加壳

Apk保护:

1.app存在的危险

代码修改(广告植入、替换广告id)

资源修改(界面替换广告、链接替换)

破解(应用收费、内购)

篡改数据(无限金币、钻石)

加入恶意代码(木马、隐私、交易)

动态注入(数据拦截、窃取、修改)

本地数据修改、数据库文件修改

协议修改(服务器欺骗、向服务器发送假数据)

2.加固目的

需要防止逆向分析(防逆向)--防止核心代码被反编译

防止二次打包(防篡改)--校验完整性、签名、防止盗版

防止调式和注入(防调试)--防止动态调式,注入获取关键数据

防止应用数据窃取(防窃取)--加密敏感数据

防止协议直接被盗刷--加密协议通信

3.常见加固厂商

360/娜迦/梆梆

爱加密/阿里

百度//腾讯/网秦/通付盾

4.常用加固方式

类加载技术

针对apk中的classes.dex文件进行处理,放入特定的文件中,通 过native代码来对其运行时解密

使用厂商(娜迦/爱加密/梆梆)

对原dex文件整体压缩加密,保存在壳代理的dex文件尾部,加 载到内存中解密运行

使用厂商(360)

方法替换技术

将classes.dex文件中的方法代码进行提取,抽取方法,在运行 时对其进行动态解密还原

使用厂商(娜迦/梆梆)

5.加固厂商特征

娜迦:libchaosvmp.so, libddog.so libfdog.so

梆梆:libsecexe.so, libsecmain.so, libSecShell.so

梆梆企业版:libDexHelper.so, libDexHelper-x86.so

爱加密:libexec.so, libexecmain.so, ijiami.dat

360:libprotectClass.so, libjiagu.so; libjiagu.so, libjiagu_art.so; libjiagu.so, libjiagu_x86.so

百度:libbaiduprotect.so

阿里聚安全:aliprotect.dat, libsgmain.so, libsgsecuritybody.so

腾讯:libtup.so, libexec.so, libshell.so; mix.dex; lib/armeabi/mix.dex, lib/armeabi/mixz.dex

腾讯御安全:libtosprotection.armeabi.so, libtosprotection.armeabi-v7a.so, libtosprotection.x86.so

通付盾:libegis.so, libNSaferOnly.so

网秦:libnqshield.so

网易易盾:libnesec.so

APKProtect:libAPKProtect.so

几维安全:libkwscmm.so, libkwscr.so, libkwslinker.so

顶像科技:libx3g.so

6.脱壳手法

修改系统源码自动脱壳

通过hook方式对关键函数进行脱壳

开源工具如zjdroid,dexhunter进行脱壳

利用IDA或者GDB动态调式进行脱壳

分析virualapp

去框架HOOK

制作vm策略

实现vm置换

置换后销毁

其他

dex vmp(制作native oncreate)

典型非主流加固

脱壳机

虚拟机技术

加固技术:

第一代加固 DEX加密

proguard等混淆、其他弱加密

DEX字符串加密

静态DEX文件整体加密解密

资源加密(xml与arsc文件加密及十六进制加密)

对抗反编译(添加垃圾类)

反调试

自定义DexClassLoader

第二代加固 DEX抽取与SO加固

DEX动态加载(分为利用jni和自定义jni即自定义底层函数)

DEX代码抽取到外部(类抽取加密按需解密和动态方法修改替换)

SO加密

第三代加固 DEX动态解密与SO混淆

Dex代码动态解密

SO代码膨胀混淆

第四代加固 arm vmp

jni反射抽取方法成本地原生代码即半vmp(分为jni反射解密DEX方 法和完全翻译为C代码)

初级vm即dex opcode vm指令虚拟使用jni指令还原(分为自定义后 端编译器和jni反射置换表)

高级vm即解释框架dex opcode不存在还原使用解释引擎的vm文件

脱第一代壳:

内存Dump法

内存中寻找dex.035或者dey.036

/proc/xxx/maps中查找后,手动Dump

文件监视法

Dex优化生成odex

监视文件变化(inotifywait-for-Android)

监视DexOpt输出(notifywait-for-Android)

Hook法

Hook dvmDexFileOpenPartial

定制系统

修改安卓源码并刷机

脱第二代壳:

内存重组法

Dex ZjDroid

对付一切内存中完整的dex,包括壳与动态加载的jar

SO elfrebuild

构造soinfo,然后对其进行重建

Hook法

针对无代码抽取且Hook dvmDexFileOpenPartial失败

Hook dexFileParse

针对无代码抽取且Hook dexFileParse失败

Hook memcmp

定制系统

修改安卓源码并刷机-针对无抽取代码

DexHunter

绕过三进程反调试-修改系统源码

断点mmap调试,针对Hook dexFileParse无效

dexopt优化时,dvmContinueOptimization()->mmap()

静态脱壳机

分析SO壳逻辑并还原加密算法

自定义linker脱SO壳

脱第三代壳:

dex2oat

ART模式下,dex2oat生成oat时,内存中的DEX是完整的

定制系统

Hook Dalvik_dalvik_system_DexFile_defineClassNative

枚举所有DexClassDef,对所有的class,调用dvmDefineClass进行 强制加载

脱第四代壳

so + vmp

阶段发展(换个角度,要从解密后dex文件的状态来看)

静态:dex文件解密后以静态文件存储(如某一个文件夹下的odex文件)

动态:dex文件解密后也在内存中

整体加密:真实、完整的dex出现在内存中

抽取加密:真实、完整的dex从不出现在内存中

对于整体加密和抽取加密,从实现来看,整体加密就是把dex整体隐藏在so中,而抽取加密就是先从so里解密出一个待修复的dex文件,真正的dex从这个文件里抽取部分。

为什么dex从内存中抠出是不完整的?

1.dex内存中不连续(如修改DexHeader结构)

2.dex在内存中执行是以结构体存在的,如果修复时只修复结构体,根本没有修复dex/odex文件本身(如只修复DexMethod结构体)

3.dex文件的一些方法不是事先解密,而是用到再解密,用完就删掉(如百度加固的onCreate方法)

4.dex文件在加载或运行时,被HOOK,解密后,使之一些结构体或一些结构体的一些字段人为改为错误,或删除(如阿里加固对于annotionoff注解字段的处理)

5.dex文件本身就是错的,结构体的字段值错误,或方法是干扰无效的,在加载或运行时,被HOOK,解密修复成正确的,解密后再删掉或继续用错误部分填充。

三代脱壳机实现与关键函数:

规律:无论加固还是脱壳,都往底层发展。

1.dex优化与验证过程(实例:在dexFileParse函数HOOK)

2.虚拟机动态加载打开dex过程

3.dex类加载的过程

脱壳时机总结(DEX文件从打开到方法指令执行前):

1.打开dex文件时

存在dex优化验证时的打开和虚拟机本地native打开两种,分别对应着一代和二代脱壳。

2.加载类时:defineclassnative函数

虽然类加载过程的函数很多,但我们一般脱壳只在defineclassnative函数。

这里列举出类的整个加载过程的函数

defineclassnative函数分析与类加载概念

defineclass函数分析

findnoinit函数分析(包括了dvmLookupClass)

loadClassFromDEX函数分析

loadClassFromDEX0函数分析与解析概念

dvmLinkClass函数分析

loadMethodFromDEX函数分析

3.类的初始化时:dvmIsClassInitialized和dvmInitClass这两个函数

4.查找类FindClass

5.获得方法ID并调用方法 GetStaticMethodID,CallStaticVoidMethod

(其实在GetStaticMethodID执行了类的初始化,可以尝试从这里)

  1. 方法指令执行(一般不考虑)

DEX自解析重构技术:

DexHunter介绍

DexHunter使用方法与注意

DexHunter源码详细分析

/dalvik/vm/native/dalvik_system_DexFile.cpp

https://github.com/zyq8709/DexHunter

https://github.com/kesuki/DexHunter

如果你想脱壳一个APP,在运行APP之前,你需要把“dexname”这个文件推入到手机的“/data/”文件夹下。在"dexname"的第一行是特征字符串(参照"slide.pptx").第二行是目标APP所在的数据路径(例如,/data/data/com.example.seventyfour.tencenttest/)。dexname文本必须是linux/Unix的风格形式,如果在windows下输入,则需要用winhex修改换行符的十六进制。你可以使用"logcat"命令获得log日志来判断壳是否已经脱下。一旦完成,生成的"whole.dex"文件就是想要的结果。

特征字符串:

360        /data/data/XXX/.jiagu/classes.dex

Ali        /data/data/XXX/files/libmobisecy1.zip

Baidu        /data/data/XXX/.1/classes.jar

Bangcle    /data/data/XXX/.cache/classes.jar

Tencent   /data/app/XXX-1.apk (/data/app/XXX-2.apk)

ijiami       /data/data/XXX/cache/.

注意,他本身的系统img是4.4.3,如果想做到版本通用,只需要单单替换system.img就行。一定不能把他原版的img直接文件夹替换,那样模拟器会直接死翘翘。正在上传…重新上传取消

IDA自动插件源码分析与dexhunter比较:

相同点:

1.本质相同,也就是最根本的自解析重构思想和方法一样,都是主要采 用readsignleb128等自解析函数,进行自解析重构;

2.由于两种工具基本原理一样,所以需要升级,改进,和失效、缺陷的 地方,也是类似的;

3.都是类加载时的通用脱壳机,关键原理函数都是defineClassNative 函数。

不同点:

1.直接dump的方法不同,DexHunter用的是strcpy函数,而IDA脱 壳脚本用的是getword函数;

2.相比来言,IDA脱壳脚本重构的更为彻底一点,它把每个结构都进行 重构,把字段全部先初始化为0,然后利用直接dump或自解析重新获 取的办法填充回去;

3.IDA脱壳脚本得到的是一个ODEX,而DexHunter是一个DEX文 件,IDA脱壳脚本还重构了DEXHEADER头结构,修复了magic等字 段,这一点也比DexHunter较好。

4.使用的方式不同,DexHunter使用的方式是HOOK,而且对类进行了 主动一次性加载和初始化,而IDA脱壳脚本是一个脚本,其当初设计的 想法应该是当动态调试时,得到了正确的clazz结构体后,去使用。

5.总的来说,IDA脱壳脚本比DexHunter显得先进一点,但依然不是更 进一步彻底的重构,如annotionoff字段就是直接dump,但这个地方 往往会偏移出错,如阿里加固。

DexHunter升级:

  1. 它是用DEXHEADER结构的header.stasticsize等来获取静态字段数 量,然而我们初始化类后,只能保证clazz结构是正确的,我们应该尽 量用clazz结构中的内容。
  2. 对于百度加固来说,由于真实指令只在运行时才出现,此时重构过早。 试想当classdef都是不完整情况下,得到的data数据区肯定也是缺失 的,因为data数据是代码的真实数据区。DEXHUNTER采用直接 dump data区明显是不行的,我们先把oncreate001中指令骗出来, 再去dump data,接着重构。
  3. DEXHUNTER采取以修复为主的重构,明显是不彻底的,其可以看到在 dump时,DexClassDefItem结构中的anonotionoff等偏移也存在错 误,我们要利用重构的办法对这个地方也进行重构。

脱壳神器ZjDroid:

1.介绍

zj是一个比较特殊的通用脱壳工具,是第一个利用系统组件漏洞来进行脱壳的脱壳机,也就是发广播,当zj接受到正确广播后,会根据pid,把广播发给pid,另pid进程返回信息。zj之所以特殊,它无法按照我说的划分为第几代脱壳,乃至现在依然可以风骚使用。这对于一个2014年就诞生的脱壳机而言是不可思议的。zj的核心是mcookie文件,而这个文件却介于解密后文件和解密后内存之间的中间状态。如果我们深入系统源码,就会发现cookie会被直接用于类结构体的生成,如果按照此定义,它应属于第2代-第3代脱壳机。但奇妙之处在于,只要存在解密,无论放不放在文件,也无论是解密的是dex还是jar、odex,理所应当都会有一个cookie出现。因此,除非真正的vmp,即完全通过编译器so壳去解释一个完全虚拟的文件或内存中的指令,否则zj都会有效果。zj很强大,但缺点也很明显,太容易被防。如果壳做好了系统组件保护策略,不允许第三方广播,或者对xpossed框架和类似zj插件进行保护,那么zj就无效。

2.zj使用全攻略:

zj不适合模拟器,适合真机,我们的调式机就非常理想,不同机器,运行效率差别很大。

安装xpossed框架:

adb install d:\xpossed.apk

安装框架,软重启

安装zj插件:

adb install d:\ZjDroid.apk

安装插件,勾选模块,软重启

安装目标游戏:

adb install d:\捕鱼达人3.apk

打开一个cmd,专门用于查看动态逆向信息:

adb shell

logcat | grep zjdroid-shell-org.cocos2d.fishingjoy3

记下PID,建议一定要把命令先写好

再打开一个cmd,运行zj命令

adb shell

su

查看内存中存在的dex的cookie信息:

am broadcast -a com.zjdroid.invoke --ei target 4755 --es cmd '{action:dump_dexinfo}'

观察log的cmd窗口,记下选择的dexpath信息,如果有dex就选dex,其次是jar,最后是apk

查看cookie的可加载类,顺便看看是否有自己想要的类:

am broadcast -a com.zjdroid.invoke --ei target 4755 --es cmd '{"action":"dump_class","dexpath":"/data/app/org.cocos2d.fishingjoy3-1.apk"}'

dump出dex文件:

am broadcast -a com.zjdroid.invoke --ei target 4755 --es cmd '{"action":"dump_dexfile","dexpath":"/data/app/org.cocos2d.fishingjoy3-1.apk"}'

dump出smali文件:

am broadcast -a com.zjdroid.invoke --ei target 4755 --es cmd '{action:backsmali, "dexpath":"/data/app/org.cocos2d.fishingjoy3-1.apk"}'

等待一段时间,查看脱壳后的dex和smali文件:

ll /data/data/org.cocos2d.fishingjoy3/files

ll /data/data/org.cocos2d.fishingjoy3/files/smali/

把smali文件夹拷贝到sd卡,然后传到电脑:

adb pull /mnt/sdcard/smali/ d:\1

zj另外还可以:

内存dump,由于我们有dd,和更好的工具,一般不用zj去dump内存:

adb shell am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"dump_mem","start":1234567,"length":123}'

运行自编写lua脱壳插件,找到解密函数,用lua调用java:

由于这需要我们编写lua代码,还要分析解密函数,如果做到了这样,我们有更好的办法去处理,一般也不用运行lua代码

adb shell am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"invoke","filepath":"****"}'

3.zj拓展

做如下修改即可解除一定的防zj保护:

a.在设备上创建特定目录(如/data/local)并 chmod 为777

b.复制zjdroid.apk到该目录,并修改文件名为zjdroid.jar

c.修改/data/data/de.robv.android.xposed.installer/conf/modules.list,模块代码文件修改为zjdroid.jar,然后重启设备即可。

DD大法:

dd if=/dev/zero of=sun.txt bs=1 count=1

if 代表输入文件。如果不指定if,默认就会从stdin中读取输入,/dev/zero 是一个字符设备,会不断返回0值字节(\0)。

of 代表输出文件。如果不指定of,默认就会将stdout作为默认输出。

bs 代表字节为单位的块大小。

count 代表被复制的块数。

抠DEX:

dex是看0x20处找大小,odex是看0x32处就有。

dd if=/proc/2175/mem of=/data/local/tmp/dump.dex skip=3077606936‬ bs=1 count=43576

GDB调试:

adb push d:\gdbserver /data/local/tmp/gdbserver

adb shell

su

chmod 777 /data/local/tmp/gdbserver

ps | grep com.zyx.wifi

ls /proc/1964/task

/data/local/tmp/gdbserver :31928 --attach 2968

adb forward tcp:31928 tcp:31928

启动本地gdb

target remote :31928

gcore,一直等待完成,时间比较久

b 下断点

c 继续运行到断点

s 等价于step into

n 等价于step over

bt 查看堆栈

info registers查看寄存器内容

info b 查看断点信息

delete break [n] 删除编号为n的断点

disas 0xFFFF,+20 显示这个地址后面 20 行内的汇编指令

kill 终止进程

脱掉梆梆的壳:

梆梆是把原dex文件加密放到了secData0.jar,所以直接拿到dex文件,修复配置文件的程序入口点就可以重打包完美运行。

open、mmap

dexfileopenpartial

dvmRawdexFileOpen

脱掉爱加密的壳:

爱加密在fopen,fget原因

dexfileopenpartial

openDexFileNative

defineClassNative

脱掉360的壳:

1.识别360加固的代数

2.第一代360脱壳:xposed插件脱壳

3.第二代360脱壳:so手动dump并修复、mmap手动脱壳、open+memcmp手动脱壳

4.第三代360脱壳:drizzledumper脱壳、dex2oat脱壳

VM修复:

一个结构,

fix (){

  Method

  offset

}

结合dex文件结构,opcode,偏移地址

00-FF 0-255

确定00 vm的opcode

00-A8 168

01-A9

02-AA

03-AB

脱掉百度的壳:

1.加密流程:

采用动态加载assets下的baiduprotect.jar。然后采用重写onCreate,用onCreate001代替,onCreate内容为修复onCreate001代码、执行onCreate001代码、清楚onCreate001代码。修复代码不能连续运行两次。

3.采用Hook DexParse来获取Dex相关数据,然后遍历ClassDef将所有onCreate001类直接解码。

4.Dump出修复好的Dex。

5.然而Dump的Dex还要修复(可以根据ClassDef自动修改)

Lcom/baidu/protect/A;->d(Ljava/lang/String;)V->解密方法

Lcom/baidu/protect/A;->e(Ljava/lang/String;)V->加密方法

Lcom/qsq/qianshengqian/XXXXX;->

onCreate001(Landroid/os/Bundle;)V->加解密传入参数

xdex脱壳机与骗出jni_onload的oncreate抽取指令

vm一维置换表和二维置换表

脱掉腾讯的壳:

libart.so

OpenMemory

R1是dex文件的地址,R2是dex文件的大小

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/872290
推荐阅读
相关标签
  

闽ICP备14008679号