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,
-
singleTop模式
调用onNewIntent方法
-
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指令
-
空操作指令
空指令就是nop,值是00,通常nop指令别用来作对齐代码之用,无实际操作。
-
数据操作指令
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
-
return 返回
return-void 表示函数从一个void方法返回。返回为空
return vAA 返回值寄存器位8位
return-wide vAA 表示返回一个64位值到8位vAA中
return-object vAA 返回一个独享到八位vAA
-
数据定义指令
const/4 vA,#+B 将数值符号扩展到32位后赋给vA
const定义出A来 如
const-string/jumbo vAA,string@BBBBBBBB
就是AA再次用到就是string类型
-
实例操作指令
check-cast vAA,type@BBBB
instance-of vA,vB
类型转换 如果可以转换 vA赋1 否则0
new-instance vAA,type@BBBB
构造一个指定类型的对象的实例,并且对象引用赋值给vAA,type不能是数组
-
数组操作指令
数组操作包括获取数组长度,新建数组,数组赋值,数组元素取值与赋值。
array-length vA,vB
获取vB寄存器的长度给vA
new-array vA,vB type@CCCC
构建指定类型type@CCCC与大小(vB)的数组,并将值给vA寄存器
filled-new-array {vC}
-
异常指令
throw vAA 抛出vAA寄存器遇到的异常
-
跳转指令
<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
-
比较指令
大于(1)/等于(0)/小于(-1) -> cmpg cmp
大于(-1)/等于(0)/小于(1) -> cmpl
cmp-long vA,vB,vC
10.字段操作指令
普通字段 iget读 iput写
静态字段 sget都 sput写
-
方法调用指令
invoke-virtual 调用实例的虚方法(普通方法)
invoke-super 调用实例的父类/基类方法
invoke-direct 调用实例的直接方法 (构造方法)
invoke-static 调用实例的静态方法
invoke-interface 调用实例的接口方法
-
数据转换质量
neg-数据类型 求补 not-数据类型 求反
数据类型1-to-数据类型2
-
数据运算指令
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循环
快速定位关键代码
-
分析流程
搜索特征字符串
搜索关键Api
通过方法名来判断方法的功能
-
快速定位关键代码
反编译APK程序 xml找包名/系统版本/组件
程序的主activity(程序入口界面)
每个Android程序有且仅有一个主Activity
分析执行流程
需重点关注application
application执行时间
授权验证
-
定位关键代码技巧
信息反馈法
特征函数发
顺序查看发
代码注入发
栈跟踪法
方法剖析
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