0
点赞
收藏
分享

微信扫一扫

安卓逆向基础(动态调试,静态调试)

cnlinkchina 2022-02-21 阅读 105

apk文件结构

assest文件 存在需打包到安卓程序的静态资源文件

res文件 程序的资源文件(每一个文件都会有资源ID)

lib文件 当前APP所用到的so文件(利用C/C++去实现的

META-INF 签名文件

MAINFEST.MF 记录哈希算法值

RSA 开发者私钥的签名文件 SF

AndroidManifest.xml 配置文件

classes.dex 可执行文件

resources.arsc 资源索引表 用来描述具有ID值的资源配置信息

apk打包流程

apk安装流程

解压到 data/app 中 解析apk的资源文件 解析AndroidManifest.xml文件 同时在data/data创建应用数据目录 在dalvik-cache中保存dex 将Manifest中的四大组件解析 发送广播

虚拟机

java虚拟机 java字节码 基于栈结构

Java虚拟机 - > Java字节码

JNI_GetDefaultJavaVMInitArgs 获取虚拟机初始化参数

JNI_GreatJavaVM 创建虚拟机实例

JNI_GetCreatedJavaVMs 获取创建的实例

Dalvik虚拟机

jit机制 /system/bin/dexopt

compiler

Art虚拟机

aot机制 /system/bin/dex2oat

系统启动 /sytem/app /data/app /sytem/framework

修改apk的名称和图标

AndroidManifest文件打开之后 “:

package 包名

permission 权限

第一个application 是程序入口

icon 图标

label 名字

name 入口界面

provider 发布者签名

activity 活动界面

搜索在original-签名文件夹 搜/icon.png /是精准搜索

修改包名实现分身

在AndroidManifest.xml中头部找到package在字符串尾部添加一个数组(如6)

然后搜索<provider在所有provider的字符串后加入数字一个

随后保存 编译 即可实现双开

去广告

删除user-permission中的NETWORK_STATE 和WIFI_STATE

只留下android.permission.INTERNET

Activity中看到 MAIN 和 LAUNCHER在一起 就断定 这个Activity就是程序入口活动

打开cmd 输入

adb devices (可以多几次)

adb shell dumpsys activity top 找到进入时活动名

然后找到广告的活动名

然后将主界面活动末尾替换为LAUNCHER

删除广告活动的 <intent-filter>

JAVA学习

JAVA变量和数据类型

变量:为了保存数据(全局变量也叫成员变量)

基本数据类型

整数型byte short int long

浮点型float double

字符型char

布尔型boolean

修饰符

访问修饰符

default 默认 在同一包内可见,不适用任何修饰符 适用对象:类、接口、变量、方法

private

public

protected

static 静态修饰

final 不能被子类重写

abstract 抽象类

synchronized 同一时间只能被一个线程访问

transient 预处理类和变量的数据类型

volatile 每次被访问都强制更新

运算符

+ - * /

接口继承和多态

interface Animal

{

public void eat();

public void travel();

}

public class MammalInt implements Animal

{

public void eat()

{

System.out.println("我的世界");

}

}

Java实战破解内购

进入游戏发现 点击支付然后取消 出现支付取消字样

之后再jadx中点击放大镜搜索“支付” 发现出现了支付成功 支付失败 支付取消三个字样

所以转到去查看 发现最后支付成功和支付失败都调用了 zombie这个类 因此Ctrl+点击跳转到该类

发现逻辑被抽象了 然后再点击返回

跳转到buysuccess 可以将失败改成成功 调用不了 可以修改代码

将failed改成Buysuccess 无法修改 只能去改Davilk指令集 smali代码完成修改

四大组件

活动(activity) 表现功能

服务(service) 后台运行服务

广播接受着(Broadcast Receive) 用于接收广播

Content Provider 数据库 支持读取数据

Activity

一、如何创建:

Activity:

新建一个类 继承来自Activity

二、Activity的生命周期从创建到销毁的过程所执行的方法

1、创建Activity要执行的方法

a. onCreate() 第一次被创建时调用 初始化

b. onStart() 由不可见到可见时候调用

c. onResume() 在活动准备好和用户进行交互的时候调用。此时活动一定要位于返回栈的栈顶,并且处于 运行状态。

2、Activity被销毁时所执行的方法

a. onPause()

这个方法在系统准备去启动或恢复另一个活动的时候调用,我们通常会子啊这个方法中将一些消耗PCU资源的一些释放掉,保存关键数据,但这个方法的执行速度要快,不然会影响到栈顶的活动的使用

b.onStop()

这个方法再活动完全不可见的时候调用,塔克onPause的主要区别在于,如果启动的新活动是一个对话框的活动,那么onPause()方法会得到执行,而onStop并不会被执行

c. onDestroy()

这个方法再活动被销毁之前调用,之后活动的状态会变为销毁状态

d. onRestart()

这个方法有停止到运行前调用,也就是活动被重新启动了

三 Activity的四种启动模式

安卓采用Task来管理多个Activity 当启动一个APP的时候,Andorid就会为之创建一个Task,然后每启动一个activity,就会把当前的activity压到栈顶。比如以此启动页面A->B->C,栈里面

C ---- 栈顶

B

A ---- 栈底

1、standard模式

他是活动默认的启动模式,在不进行显示制定的情况下,所有活动都会自动使用这种启动模式来启动activity,

  1. singleTop模式

    调用onNewIntent方法

  2. singleTaks模式

    调用

    四、Activity的数据传递

    1 Intent

    Intent即将进行操作的抽象,Android应用程序中的三种其他应用基本组件-Activity Service Broadcast Receiver 都是使用Intent的消息来激活的

    2 如果是两个相邻的activity之间的传值,使用Intent传值

    3 使用startActivityForResult(intnt,code) 实现传值

    intent开启方式 new一个intnet 然后利用intent链接两个类 之后启动Activity

Service

Service的概念

Android服务,不可与用户交互,不能自启动,后台运行程序退出时,Service未结束。(后台听音乐)

生命周期

1.继承onCreate() onStart() onDestroy()方法

第一次启动 onCreate() onStart()

停止Service onDestroy()

启动状态的Service再次启动不会调用onStart()

2.StartService启动Service生命周期

执行startService时,Service会经历onCreate->onStartCommand。当执行stopService时,直接调用onDestroy方法

3.bindService启动Service的生命周期

执行bindService时,Service会经历onCreate->onBind . 调用者和Service绑定。调用者调用unbindService

或调用Context不存在了(如Activity被结束),Service就会调用onUnbind->onDestroy. 这里所谓的绑定在一起就是两者共存亡。

BroadcastReceiver

静态注册和动态注册

静态:xml中注册

动态:代码中实现

NotificationManager 系统的Service

Notification

内容提供者

实现跨程序共享数据的标准方式,不同文件存储和Sharedpreferences

存储中的两种全局可读写操作模式,内容提供者可选择只对一部分数据共享,从而保证不被泄露隐私数据

两种方法

1.使用现有的读取操作相应程序中的数据

2.创建自己的提供者给我们程序数据提供外部访问接口

存储方式

1.SharedPreference 存储数据 利用xml Key-value方式存储数据

SharedPreference.Editor clear() 清空数据

SharedPreference.Editor putXxx(String key,xxx value) 存入数据

2.文件存储

最基本文件存储

Davik

Davik寄存器: 32位,所有类型 ,<=32 一个寄存器 64:两个相邻的寄存器

寄存器命名法

v 局部变量寄存器 v0-vn 参数寄存器: vn - v(n+m)

p 参数寄存器 p0-pn 变量寄存器 v0-vn

static public DecryptDemo-> getHelloWorld(Ljava/lang/String ; I) Ljava/lang/String;

regisize : 寄存器数量 ([5] 就是五个寄存器)

registers(寄存器列表): v0 v1 v2 v3 v4

首先参数寄存器需要两个

.dex文件反编译工具

.java - .class - .dex - smali

Dalvik字节码类型

B byte

C char

S short

I int

J long

F float

D double

Z boolean

V void

L java类型

[ 数组

字段

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

package/name/ObjectName 下的 一个 String类型的名为FieldName的变量

相当于:

class ObjectName{
•   String FieldName;
​

方法:Lpackage/name/ObjectName;->MethodName

Davik指令格式

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

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

后缀是from16 表示源寄存器为16位

move-wide/from16 vAA,VBBBB

move为基础字节码 (opcode)

wide 表示是操作64位的数据

from16为字节码后缀 表示源为一个16为寄存器引用变量

VAA为目的寄存器 在源前面 取值0-255

VBBBB是源寄存器 取值范围0-65535

move-wide/from16 vAA,vBBBB

13种dalvik指令

  1. 空操作指令

    空指令就是nop,值是00,通常nop指令别用来作对齐代码之用,无实际操作。

  2. 数据操作指令

    move

    Move vA,vB 将vB寄存器的值赋给vA寄存器,源寄存器与目标寄存器都为4位

    Move/from16 vAA,vBBBB 将vBBBB的寄存器的值赋给vAA 16- 8

    Move-wide vA,vB move-object vA,vB

    Move-object/from16 vAA,vBBBB

    Move-object/16 vAA,vBBBB Move-result vAA 返回将上一个invoke指令中的非对象结果赋给vAA

    Move-result-wide vAA上一个invoke指令双字非对象(前一个位单字)

    Move-result-object vAA 将invoke指令对象传到vAA

    move-exception vAA 异常传为vAA

  3. return 返回

    return-void 表示函数从一个void方法返回。返回为空

    return vAA 返回值寄存器位8位

    return-wide vAA 表示返回一个64位值到8位vAA中

    return-object vAA 返回一个独享到八位vAA

  4. 数据定义指令

    const/4 vA,#+B 将数值符号扩展到32位后赋给vA

    const定义出A来 如

    const-string/jumbo vAA,string@BBBBBBBB

    就是AA再次用到就是string类型

  5. 实例操作指令

    check-cast vAA,type@BBBB

    instance-of vA,vB

    类型转换 如果可以转换 vA赋1 否则0

    new-instance vAA,type@BBBB

    构造一个指定类型的对象的实例,并且对象引用赋值给vAA,type不能是数组

  6. 数组操作指令

    数组操作包括获取数组长度,新建数组,数组赋值,数组元素取值与赋值。

    array-length vA,vB

    获取vB寄存器的长度给vA

    new-array vA,vB type@CCCC

    构建指定类型type@CCCC与大小(vB)的数组,并将值给vA寄存器

    filled-new-array {vC}

  7. 异常指令

    throw vAA 抛出vAA寄存器遇到的异常

  8. 跳转指令

    <1 goto: 无条件跳转

    <2 switch: 分支跳转

    packed-switch: 有规律跳转

    sparse-switch: 无规律跳转

    <3 if: 条件跳转

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

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

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

    if-eqz 等于0/if-nez 不等于0

    if-ltz 小于0 /if-lez 小于等于0

    if-gtz 大于0/ if-gez 大于等于0

  9. 比较指令

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

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

    cmp-long vA,vB,vC

10.字段操作指令

普通字段 iget读 iput写

静态字段 sget都 sput写

  1. 方法调用指令

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

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

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

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

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

  2. 数据转换质量

    neg-数据类型 求补 not-数据类型 求反

    数据类型1-to-数据类型2

  3. 数据运算指令

    add/sub/mul/div/rem

    加减乘除模

    and or xor

    shl shr ushr

Smali实战

p0代表this

location 前面出现表示寄存器数目

: + goto_x 半标签 需要其他方式跳转至此

cosnt-class v2(定义类),Hahtable(类型);

很多code 出现末尾goto到一个goto 就表示可能为for循环

快速定位关键代码

  1. 分析流程

    搜索特征字符串

    搜索关键Api

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

  2. 快速定位关键代码

    反编译APK程序 xml找包名/系统版本/组件

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

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

    分析执行流程

    需重点关注application

    application执行时间

    授权验证

  3. 定位关键代码技巧

    信息反馈法

    特征函数发

    顺序查看发

    代码注入发

    栈跟踪法

    方法剖析

log插桩

prologue 属于smali中的入口

分清入口点和入口界面 插桩在prologue下插入代码

需知: 先入口点 后入口界面

onCreate

栈跟踪

System.err 栈

从下向上看

在prologue下方插入栈跟踪 会调用两个寄存器

AS调试

PPID 父进程

VSIZE 虚拟内存大小

RSS 进程真实大小

WCHAN 系统的函数名

PC 电脑内核函数名称

3334

adb shell ps

adb forward tcp:[调试器端口] jdwp:[PID]

adb shell am start -D -n com.qianyu.zhuceji/.MainActivity

adb forward tcp:8788 jdwp:2311

e610ce9d89b3ad7c

举报

相关推荐

0 条评论