逆向


Android逆向

AndroidKiller安装


AndroidKiller/cfgs目录下的injectcode换成新的injectcode;

新建文件夹AndroidKiller/apktool,将apktool.jar拷贝进去;

打开AndroidKiller,在主页/配置/Java,中配置jdk;

打开AndroidKiller,在Android/APKTOOL管理器中配置apktool.jar。


dalvik字节码


.java 编译成 .class 在编译成 .dex 最后反编译得到 samli文件。

dx.jar:将.class打包.dex
    dx --dex --output=Decrypt.dex com/yijinda/demo/Decrypt.class

Baksmali.jar:将.dex反编译成smali
    java -jar baksmali.jar -o smali_out/ classes.dex

Samli.jar:将.smali打包成.dex
    java -jar smali.jar smali_out/ -o classes.dex

dalvik字节码类型对应java:

Dalvik  →	java
B			byte
C			char
S			short
I			int
J			long
F			float
D			double
Z			boolean
V			void
L			java类类型
[			数组类型

寄存器的命名法:

v:局部变量寄存器 v0-vn  参数寄存器 vn-vn+m  	
p:参数寄存器p0 -pn     变量寄存器  v0-vn
p0没有被定义成参数,那么它代表this

字段:

Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
字段格式:包名/类名;->字段名称:字段类型;

方法:

Lpackage/name/ObjectName;->MethodName (III) Z
包名/类名;->方法名(参数):返回值类型

dalvik指令


格式:

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

格式解释:

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

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

目的寄存器始终在源寄存器前面
目的寄存器的取值范围是v0-v255
源寄存器的取值范围是v0-v65535

A/B/C/D/E/F/G/H代表一个4位的数值
AA/BB/CC/DD/EE/FF/GG/HH代表一个8位的数值
AAAA/BBBB/CCCC/DDDD/EEEE/FFFF/GGGG/HHHH代表一个16位的数值

13种dalvik指令:

1、空操作指令:

nop

2、数据操作指令:

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

object是对象的意思-为对象赋值。
move指令的三种作用:赋值;move-result接收方法返回操作;处理异常。

3、返回指令(重点):

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

4、数据定义指令(重点):定义程序中用到常量

const(-wide/-string/-class)
const/4(数值符号扩展为32位) 
const/16(数据符号扩展为64位)
const(-wide)/16
const(-wide)/32
const(-wide)/high16

5、实例操作指令:

check-cast(类型转换)
instance-of(检查)  
new-instance(新建) 

6、数组操作指令:

array-length(获取数组长度)
new-array(新建数组)
filled-new-array(定义数组并初始化)
filled-new-array/range(定义数组并初始化/指定取值范围)
filled-array-data(数组元素取值与赋值)

7、异常指令:

throw

8、跳转指令(重点):

goto 紧跟一个标签直接跳转到标签所在位置
packed-switch(有规律)、sparse-switch(无规律)
if-eq(等于)/if-ne(不等于)
if-lt(小于)/if-le(小于等于)
if-gt(大于)/if-ge(大于等于)
if-eqz(等于零)/if-nez(不等于零)
if-ltz(小于0)/if-lze(小于等于0)
if-gtz(大于0)/if-gez(大于等于0)

9、比较指令(cmp):

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

10、字段操作指令:

普通字段=>iget(读)/iput(写)
静态字段=>sget(读)/sput(写)

get(读):从后往前读
put(写):从前往后走

11、方法调用指令(重点):

invoke-virtual(调用实例的虚方法) Java当中的普通方法
invoke-super(调用实例的父类/基类方法) 
invoke-direct(调用实例的直接方法) 调用java当中的构造方法
invoke-static(调用实例的静态方法)
invoke-interface(调用实例的接口方法)

12、数据转换指令:

neg-数据类型=>求补
not-数据类型=>求反
数据类型1-to-数据类型2=>将数据类型1转换为数据类型2

13、数据运算指令:

add/sub/mul/div/rem	 加/减/乘/除/模
and/or/xor  与/或/非
sh1/shr/ushr	有符号左移/有符号右移/无符号右移

实战案例技巧


1、修改bean里get的int值:

//原smali代码
return v0
//修改后
const v0, 0x1
return v0

2、修改判断条件,判断条件取反:

//原smali代码
if-eqz v1, :cond 4
//修改后
if-nez v1, :cond 4

3、DDMS使用

/sdk/tools/ 目录下双击 monitor.bat 即可。

4、Log日志插入

AndroidKiller中,右键/插入代码/Log信息输出。

但是注意:locals 要大于0 ,不能在等于零的地方插桩。在 .prologue 之后插入

5、栈跟踪和方法抛析

AndroidKiller中,右键/插入代码/StackTrace栈跟踪。然后调用顺序是从下往上。

Traceview的使用,查看调用,可以看到Parents和Children。

6、JEB2的静态分析动态调试

7、AS+smalidea插件动态调试

安装本地插件: File/Settings/Plugins/ 。设置AndroidManifest文件中 android:debuggable="true"。然后在 File/Import Settings中导入Smali代码。右击项目中的smali Mark Directory as/Sources Root。配置远程调试,菜单栏 Run/Edit Configurations 添加Remote,配置name、port、classpath。

获取PID:adb shell ps查找注册机PID。

转发:adb forward tcp:你设置的端口号 jdwp:你的PID号


adb常用命令


monkey测试

adb shell monkey -p 包名 -v 次数

启动adb、关闭adb

adb start-server
adb kill-server

获取手机的系统版本

adb shell getprop ro.build.version.release

清除apk的数据和缓存

adb shell pm clear 包名

安装和卸载apk

adb install 文件路径
adb uninstall 包名

电脑和手机文件互传

adb push C:\Users\win\Desktop\xx.png /sdcard
adb pull /sdcard/xx.png C:\Users\win\Desktop

查看保存app错误日志

adb logcat *:E | grep "包名" > 电脑路径 //mac
adb logcat *:E | find "包名" > 电脑路径 //win

获取当前app包名和当前页面名(⼿机打开对应app)

adb shell dumpsys window windows | grep mFocusedApp //mac
adb shell dumpsys window windows | findstr mFocusedApp //win

log获取app的包名和activity名称

adb logcat | grep START //mac
adb logcat | findstr START //win
然后点击app 

关闭app后,获取app启动时间

关闭app
adb shell am start -W 包名/启动名
adb shell am start -W com.xxx.xxx/.LaunchActivity
//TotalTime: app⾃身启动时间,WaitTime: 系统启动应⽤时间

Appium

官⽹: www.appium.io,

Appium是由nodejs的express框架写的Http Server,Appium使⽤WebDriver的json wire协议,来驱动Apple系统的UIAutomation库、Android系统的UIAutomator框架。


ARM汇编指令


1.跳转指令

B 无条件跳转       
BL 带链接的无条件跳转。LR和pc会变。  
BX 带状态切换的无条件跳转   根据目标地址最低位切换状态(arm/thumb)。T和pc会变。
BLX 带链接和状态切换的无条件跳转。LR、T、pc会变。
B loc_地址
BEQ,BNE

2.存储器与寄存器交互数据指令(核心)

存储器(主存,内存)
寄存器中放的数据:可以是字符串,可以是数,也可以是一个地址,它可以放各种类型的数据 
存储地址单元:地址(如0x00004000)与地址中存在的值

LDR:从存储器中加载数据到寄存器 ← Load
LDR R8,[R9,#4] R8为待加载数据的寄存器,加载值为R9+0x4所指向的存储单元 R8=*(R9+4)

STR:将寄存器的数据存储到存储器 → Store
STR R8,[R9,#4] 将R8寄存器的数据存储到R9+0x4指向的存储单元  *(R9+4)=R8

LDM:将存储器的数据加载到一个寄存器列表 →
LDM R0,{R1-R3}将R0指向的存储单元的数据依次加载到R1,R2,R3寄存器 

STM:将一个寄存器列表的数据存储到指定的存储器  ←

PUSH:将寄存器值推入堆栈  压栈--》
POP:将堆栈值推出到寄存器   出栈 《--

SWP:将寄存器与存储器之间的数据进行交换
SWP R1, R1 [R0] 将R1寄存器与R0指向的存储单元的内容进行交换

堆,队列:数据结构,栈是竖的,后进先出,且只能从栈顶依次填入数据

3.数据传送指令

MOV:将立即数或寄存器的数据传送到目标寄存器 ←
MOV R0, #8        R0=8

4.数据算术运算指令

←
ADD,SUB,MUL,DIV
有符号,无符号运算;带进位运算

5.数据逻辑运算指令

与:AND
或:ORR
异或:EOR                                    
移位:实质是乘,除,类似于小数点移位,但相反。小数点左移,数变小;右移变大。
但逻辑移位,左移变大,右移变小,且按2的倍数进行,因为是2进制。
LSL:逻辑左移←
LSR:逻辑右移←

LSL R0,R1,#2 R0=R1*4   
LSR R0,R1,#2   R0=R1*2

6.比较指令

CMP:比较
CMP R0 #0 		R0寄存器中的值与0比较
标志位:如z位,这个都可以在动态调试时,寄存器窗口看到

7.其他指令

协处理器指令:SWT (切换用户模式)
伪指令:DCB

8.寄存器寻址方式

立即寻址:MOV R0,#1234 R0=0X1234
寄存器寻址:MOV R0,R1 R0=R1
寄存器移位寻址:MOV R0,R1,LSL #2 	R0=R1*4
寄存器间接寻址:LDR R0,[R1] 将R1寄存器中的值作为地址,取出地址中的值赋予R0
寄存器间接基址偏移寻址:LDR R0,[R1,#-4]将R1寄存器的值-0x4的值作为地址,取出地址中的值给R0

int a=0; 这一句简单高级语言的汇编理解,首先会开辟一个内存存储单元,然后把0x0这个数放入R0寄存器,然后再把R0寄存器的数据放入内存存储单元。所以:

MOV R0,#0
STR R0,[R11,#0x14+var_20]

IDA工具


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动态调试


dbgsrv/android_serverpush到手机。

adb push ...\dbgsrv\android_server data/local/tmp

查看是否成功并给权限:

adb shell
su
cd data/local/tmp
ls
如果改名字,android_server可以运行:  mv android_server as ab
如果想改端口号,可以运行:  ./android_server -p端口号
chmod 777 android_server

新打开cmd,端口转发:

adb forward tcp:端口号 tcp:端口号

安装apk

打开ddms(红色甲壳虫)

挂起程序:

adb shell am start -D -n 包名/.类名

打开IDA,Debugger -> Attach -> Remote ARMLinux/Android debugger 设置:

127.0.0.1  端口
不用输入密码

选择app进程即可使用了。

设置 Debugger -> Debugger options 勾选:

Suspend on process entry point
Suspend on thread start/exit
Suspend on library load/unload 

执行命令:

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=端口号

ddms的红色甲壳虫自动变成了绿色

点击IDA左上角运行。

等待so库加载,在IDA模块中找到该so库,在so库中找方法 jni_onload (动态注册) 或者 java开头的方法 (静态注册)。f2下断点,f9运行。


加密算法


散列函数:用于数据完整性校验

MD  消息摘要算法
SHA 安全散列算法
MAC 消息认证算法
CRC 循环冗余校验算法

对称加密算法:加密密钥==解密密钥。

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
服务器数字证书


文章作者:
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 !
  目录