资源共享吧|易语言论坛|逆向破解教程|辅助开发教程|网络安全教程|www.zygx8.com|我的开发技术随记

 找回密码
 注册成为正式会员
查看: 1271|回复: 1

[安卓逆向破解] 零基础安卓逆向学习之旅(六-下)

[复制链接]

8

主题

8

帖子

0

精华

新手上路

Rank: 1

资源币
19
积分
16
贡献
0
在线时间
2 小时
注册时间
2020-2-20
最后登录
2020-5-2
发表于 2020-2-24 00:11:11 | 显示全部楼层 |阅读模式
零基础安卓逆向学习之旅(六-下)

解释Dalvik字节码

下载,配置smali反编译器

1.下载工具baksmali的相关文件

访问以下链接:

https://bitbucket.org/JesusFreke/smali/downloads


1.jpg


下载baksmali[version].jar文件的最新版本及baksmali脚本,并保存在同一目录下。

2.配置baksmali工具

    将下载下来的baksmali的jar文件改名为baksmali.jar

    mv baksmali-[version-number].jar baksmali.jar

    确认baksmali脚本拥有可执行权限

    chmod +x 700 baksmali

    运用baksmali反编译.dex文件

    baksmali[Dex filename].dex

    并在生成的out目录下查看反编译后的.smali文件


2.jpg

解释字节码

首先是开头几行代码

.class public LExample;

.super Ljava/lang/Object;

.source "Example.java"

这是被编译后类的元数据,给出了类名,父类以及源文件,由于所有的java类都是继承自java.lang.Object的,所以即使在Example.java的代码中,我们没有显式声明继承这个类,编译后也会显示出来。

接着是Example.java的构造函数的smali代码

#direct methods

.method public constructor <init>()V

    .registers 1

    .prologue

    .line 1

    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void

.end method

.method public constructor <init>()V  //这个方法的声明

即这个方法名为init,返回一个void类型,访问标志位是public。

.registers1

这个方法只使用一个寄存器,一个方法在运行前都需要确定所需寄存器的数量。

.prologue

声明接下来是一个prologue方法,这是每个java方法都有的,它保证这个方法是以继承形式被调用的,这就是在下边一行调用了另一个名为init的方法,这是java.lang.Object的init方法。

invoke-direct{p0}, Ljava/lang/Object;-><init>()V

invoke-direct指令需要两个参数:p0寄存器和被调用方法的指针。

invoke-direct是用来调用一个非静态直接方法(non-static direct method),一个不可重写的,private实例方法或构造方法。

上边代码即是调用java.lang.Object类的构造方法这个非静态直接方法。

return-void   返回一个void类型,并退出当前函数。

.endmethod  标志着这个方法的结束。

    接下来则是main方法的smali代码:

.method public static main([Ljava/lang/String;)V

    .registers 4

    .prologue

    .line 3

    sget-object v0,Ljava/lang/System;->outjava/io/PrintStream;

    const-string v1, "Hello World!\n"

    const/4 v2, 0x0

    new-array v2, v2, [Ljava/lang/Object;

    invoke-virtual {v0, v1, v2},Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;

    .line 4

    return-void

.end method

第一行:.method public static main([Ljava/lang/String;)V

这个方法接收一个java.lang.String类型的数组,返回void类型,且这方法是静态方法,访问属性为public。

sget-object操作:sget-object v0, Ljava/lang/System;

->outjava/io/PrintStream;

官网描述erform the identified object static field operation withthe identified static field, loading or storing into the value register.

执行获取对象静态成员的操作,找静态成员,将其加载/存储到存放值的寄存器中

sget-object接收两个参数:

一个寄存器,用于存储操作的结果

一个是将被存储到上边的寄存器的对象的引用

即这行代码是获取一个对象实例,并将其存放到寄存器中,v0是这方法的栈帧里的第一个寄存器。

const-string指令:const-string v1, "Hello World!\n"

获取一个字符串并将其存储在第一参数指定的寄存器中。

const/4v2, 0x0

将常数0放入第三个寄存器v2中。

new-arrayv2, v2, [Ljava/lang/Object;

new-array指令是构造一个指定类型和元素个数的数组,并将它存放在左起第一个寄存器中,这指令执行后,v2寄存器中存放的应是一个元素个数为0,java.lang.Object类型的数组.上一行const/4v2, 0x0先将0放入v2的原因。

最后是非常常见的指令 :

invoke-virtual{v0, v1, v2},Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;

invoke-virtual指令的官网定义"invoke-virtual is used to invoke a normal virtualmethod (a method that is not private, static, or final, and is also not a constructor)."

invoke-virtual用来调用一个普通的虚方法(方法属性不为private,static或final,且不是构造方法)

其参数格式:

invoke-kind{vC, vD, vE, vF, vG}, meth@BBBB

其中,vC,vD,vE,vF,vG是用来向被调用的方法传递参数的寄存器,方法的具体代码由参数meth@BBBB指定,每个B表示4bit,即这个指令接收一个16位的方法引用

所以实例中的代码,是调用一个名为java.io.PrintStream.printf方法,接收参数:java.lang.String对象和java.lang.Object类型的数组,最后返回java.io.PrintStream类型的对象 。

将DEX反编译为java

1.下载相关工具

Dex2Jarhttps://sourceforge.net/projects/dex2jar/?source=typ_redirect下载最新.zip包

JD-GUI:访问http://jd.benow.ca/  下载最新.jar。

2.运用Dex2Jar将.dex文件转成.jar文件

    [path-of-Dex2Jar]/dex2jar.shExample.dex   //生成Example_dex2jar.jar文件


3.jpg


3.在JD-GUI上打开上边生成的.jar文件,查看java源代码

java-jar jd-gui-[version]  //打开JD-GUI    点击File->Open。

4.jpg

选择上边的.jar文件打开,查看java源代码。
5.jpg

反编译app的原生库

1.获取Android原生库文件(.so)。

Sieve – A password manager app, showcasing some common Android vulnerabilities at

https://www.mwrinfosecurity.com/system/assets/380/original/sieve.apk

下载实例apk文件,将文件改名为sieve.zip,并解压为sieve,在sieve/lib/armeabi/*.so路径下便可找到Android原生库文件。

2.确认工具objdump在AndroidNDK中路径

[android-ndk-path]/toolchains/arm-linux-androideabi-[version]/prebuilt/[arch]/bin/在该目录下找到objdump工具:./arm-linux-androideabi-objdump。



6.jpg


3.反编译原生库

arm-linux-androideabi-objdump–D [native library].so


7.jpg

使用GDB server调试Android进程

1.将Android NDK下的gdbserver文件拷贝到设备上

这需要一部已经root的Android设备或一台Android模拟器。

emulator-avd [avd name]  //启动AVD

adbshell  //进入设备shell

重新挂载系统目录,以读-写权限mount系统目录/system

mount  //查看当前各个块设备的挂载信息,确定/system的挂载信息(mount | grep system)

8.jpg

mount -o rw,remount [device] /system  //重新挂载/system,改为读-写

9.jpg


gdbserver位于[NDK-path]/prebuit/android-arm64/gdbserver/gdbserver

pushgdbserver /system/bin/.   //将gdbserver拷贝到设备上

10.jpg

2.运用gdbserver抓取进程

ps  //查看设备正在运行的进程信息

11.jpg


选取com.android.email进程作为实验进程,其PID为1009
12.jpg

gdbserver:[tcp-port number] –attach [PID]  //抓取进程,连接TCP端口

gdbserver:31337 –attach 1009

3.在本地主机上运行gdb进行调试

adb forward tcp:[device port-number] tcp:[local port-number]  //端口交互

gdb位于[NDK-path]/prebuilt/[system]/bin/gdb

运行gdb

13.jpg

进入gdb后,运行下边命令,调试目标进程

target remote :[PID]  //[PID]为本机TCP交互端口


14.jpg

现在便可与运行在Android设备上的进程中的内存段和寄存器进行交互了。。。。。。





回复

使用道具 举报

2

主题

302

帖子

0

精华

终身高级VIP会员

Rank: 7Rank: 7Rank: 7

资源币
4
积分
309
贡献
0
在线时间
37 小时
注册时间
2020-8-14
最后登录
2023-2-6

终身VIP会员

发表于 2020-9-19 08:38:15 | 显示全部楼层
祝资源共享吧越来越火!
回复 支持 反对

使用道具 举报

 点击右侧快捷回复  

本版积分规则

小黑屋|资源共享吧 ( 琼ICP备2021005790号-1 )

GMT+8, 2024-4-27 08:10 , Processed in 0.047378 second(s), 15 queries , MemCached On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表