Skip to content

安卓环境准备

更新: 2025/2/24 字数: 0 字 时长: 0 分钟

介绍

通过在实操中,熟悉常用的工具和明白常用套路,常用分析方法,并在熟悉和练习的过程中做到对安卓系统和安卓系统类的了解。

环境准备

安装 Java

因为后面用到的反编译工具依赖 Java,所以我们首先准备 Java 环境,Java 官方下载地址:https://www.oracle.com/java/technologies/downloads/

安装完成后还需将 Java 可执行文件的路径配置到环境变量中

检查安装成功:

image-20250102224847856

手机一台:nexus 6p(因为要用 Firda,所以要刷机 root)找商家刷系统。

如果没有手机,前期可以用网易的 mumu 模拟器(安卓6系统)代替练习,下载地址为:https://mumu.163.com。但是到中后期必须使用手机,因为有些应用会检测模拟器,不然出现状况去排查也是浪费自己的时间。

电脑内存越大越好,应用安装包apk反编译后的体积会膨胀很快

apk安装包

安卓系统几乎所有的应用包都是 .apk 格式文件,这是一种压缩格式,如果你的电脑上安装了解压软件的话,你可以用解压软件直接 .apk 格式文件,里面基本都会包含的如下内容:

  • classes.dex:包含app 的 Java 代码编译后的代码(安卓手机就是运行应用就是运行的 dex 文件,也是后面需要反编译研究的代码)。
  • AndroidManifest.xml:重要配置文件,APP启动入口,界面信息等等(APP加载的时候就会读取该文件)。内容基本都是被编译了的,要想清楚的看到里面的内容需要进行反编译。
  • assets:资源目录(静态资源文件,例如图片、证书等),没被编译,在电脑可以直接双击打开。
  • lib:库(包含 so 文件),安卓APP主要用Java开发,也有部分叫NDK开发,就是说它允许把一部分代码使用C、C++来开发,编译成为一个so文件,然后在APP中可以调用这个so文件,
  • res:资源目录,里面所有的文件都被编译了,打开都是编译后内容。
  • resources.arsc:资源文件索引(就是res目录里面的资源文件索引,可以想象为字典,比如索引001,对应的就是res目录下某张图片的路径,当后面需要换图片时,直接改动索引即可,就不用去改路径了)

java是一个跨平台的语言,只用编译一次,在装有java环境的电脑上,不管是windows系统还是Linux系统,都可以运行。

在lib目录中还会包含很多的目录,例如arm64、mips、x86等等,这些目录就是针对不同底层硬件(主要就是CPU所使用的指令集)所作的适配,因为 so 文件中会包含C、C++的代码,然而C、C++是编译型语言,跨平台能力差,因此就需要针对不同的平台专门进行适配。一般越大的厂所开发出来的app,在这个目录下所包含的目录就越多,因为它要让app尽可能的适配更多的硬件设备。

安卓逆向其实就是分析 .apk 文件,

应用里面所有的代码、配置文件、资源文件都在里面包含,

源代码也是反编译的它

有的app会把代码写到so文件里面,这也是提高逆向难度的地方。

apk执行需要安卓虚拟机,具体分为两类 davlink虚拟机(安卓4),art虚拟机(安卓5以后)

工具使用

adb是谷歌开发的用于调试安卓的一个命令行工具

ADB调试桥

**ADB调试桥即Android Debug Bridge(安卓调试桥) 。它就是一个命令行窗口,运行在5037端口,用于通过电脑端与模拟器或者真实设备交互。**比如说你的手机不能开机了,手机又不能装sd卡,这种情况下你在其他模式连接手机,通过adb命令把rom推送到手机内存(手机内置存储),然后卡刷就可以了,如果没有adb命令的话根本无法操作手机导入rom,因为手机进不了系统,更何况不能装sd卡。

1f03436b04d1492967d1a0a763e5eceeacbc7ef2

acfda02f47704618da807d8fb08602214e5776f2

!> 注意:上面说了ADB是安卓调试桥,也就是说调试只能是安卓系统的设备。

下载安装

官网下载地址:https://adbshell.com/downloads

QQ截图20210516125124

下载好以后,解压到指定路径下面:

QQ截图20210516151434

将解压路径配置到 system-path 环境变量里面:

QQ截图20210516151648

在命令行里面就可以使用adb驱动了:

image-20210516151738898

常用命令

# 启动adb服务
adb start-server

# adb挂载
adb remount

# 显示可连接设备列表
adb devices

# 进入手机
adb shell

# 成为管理员
su

# 安装apk
adb install xxx.apk

# 卸载
adb uninstall

# 删除手机中文件
adb shell rm -rf sdcard/路径/文件

# 在屏幕坐标(0,0)处按压100ms
adb shell input swipe 0 0 0 0 100

# 900ms内从屏幕坐标(100,200)滑动到(500,600)坐标处
adb shell input swipe 100 200 500 600 900

# 屏幕截图为screencap.pn文件,存放在手机中的/mnt/sdcard路径下
adb shell screencap -p /mnt/sdcard/screencap.png

# 从手机sdcard中传送文件到电脑上
adb pull sdcard 电脑路径

# 将手机中的screencap.png文件传送到电脑的临时文件夹下,文件名称仍然为screenshot.png(需要导入tempfile模块)
adb pull /mnt/sdcard/screencap.png {} >> {}/jump.out".format(tempfile.gettempdir() + "/screenshot.png", tempfile.gettempdir())

# 从电脑上传送文件到手机中(最好把文件放在/sdcard/目录下面)
adb push 电脑端源文件路径 手机端目标路径
# 从电脑上传送文件到手机中(最好把文件放在/sdcard/目录下面)
adb pull 电脑端源文件路径 电脑端目标路径

# 查看日志
adb logcat

# 关闭adb服务
adb kill-server

开启权限

使用ADB连接手机就需要开放手机上的一些权限,操作流程如下(针对小米手机):

1.将手机通过USB数据线连接到电脑

2.开启手机开发者模式(设置——我的设备——全部参数——MIUI版本(点击5次))

3.开启USB调试(设置——系统和设备——更多设置——开发者选项——USB调试打开)

4.开启安全设置(设置——系统和设备——更多设置——开发者选项——USB调试(安全设置)打开)

连接手机

**我们常说的Shell实际就是Linux系统的字符交互界面,而Android设备底层刚好就是Linux系统。**我们将开启权限的手机连接上电脑,执行 adb devices 命令就可以看到当前可连接设备列表,然后执行 adb shell 命令进入Android设备的Shell字符交互界面:

QQ截图20210530235542

如果出现下图的 adb devices unauthorized 则是连接失败。这个问题主要是调试授权没有成功(未授权状态);一般出现这个问题时,打开你的手机,就会看到连接后弹出授权提示,需要你点击同意的密钥授权连接;没有的话,关掉usb连接,重新连接,开发者模式,usb调试打开,同意授权提示,最后重启adb服务进行查看。

874326-20180110153533738-689451892

拷贝手机文件

使用 adb pull 命令我们还可以将手机文件传送到电脑上,下图中的 [ 2%] 代表已传输的进度,最后的 69% 代表传输当前单个文件的进度。

QQ截图20210531001525

**但有一个遗憾,就是adb不支持传输文件名称中包含有中文的文件,会将中文判定为非法字符。**主要是编码的原因,中文在Windows中使用的GBK编码,而adb使用的是UTF-8编码。解决办法就是改掉中文名称或者打包英文名称的压缩文件。

QQ截图20210531001812

游戏辅助代码

既然adb是一个命令行窗口的调试工具,那么我们就可以通过Python程序来执行adb命令,进而操作Android移动端的设备。

python
import os

# 输出可连接设备列表
print(os.popen('adb devices').read())
'''
输出:
List of devices attached
设备编号	连接状态
21a767fa   device
'''

# 相当于执行adb shell命令,进入shell交互界面,又执行了ls命令查看文件夹
dir_file = os.popen('adb shell "ls"').read().split('\n')
print(dir_file)
'''
输出:
ls: ./vndservice_contexts: Permission denied
ls: ./verity_key: Permission denied
ls: ./ueventd.rc: Permission denied
...
['acct', 'bt_firmware', 'bugreports', 'cache', 'charger', 'config', 'cust', 'd', 'data', 'dev', 'dsp', 'etc', 'firmware', 'mnt', 'nonplat_file_contexts', 'nonplat_property_contexts', 'nonplat_seapp_contexts', 'nonplat_service_contexts', 'oem', 'persist', 'plat_file_contexts', 'plat_property_contexts', 'plat_seapp_contexts', 'plat_service_contexts', 'proc', 'res', 'root', 'sbin', 'sdcard', 'sepolicy', 'storage', 'sys', 'system', 'tombstones', 'vendor', '']
解释:这里输出了手机中所有的文件夹,其中手机的绝大部分文件存储在sdcard(sd卡)文件夹中
'''

使用adb还不仅仅局限于上面的文件的传输拷贝,还可以写一些游戏的辅助型代码,下面的代码是针对《棍子英雄》的辅助性代码,可以叫外挂。

python
import os
import tempfile
import time
from PIL import Image

# 截图保存到临时文件夹的screenshot.png图片中
SCREENSHOT_PATH = tempfile.gettempdir() + "/screenshot.png"

# 截图裁剪并计算距离
def screenshot_crop():
    # 保存截图到手机
    os.system("adb shell screencap -p /mnt/sdcard/screencap.png")
    # 将手机截图上传到电脑
    os.system("adb pull /mnt/sdcard/screencap.png {} >> {}/jump.out".format(SCREENSHOT_PATH, tempfile.gettempdir()))
    # 读取图片
    origin_image = Image.open(SCREENSHOT_PATH)
    # 裁剪图片有效区域
    crop_image = origin_image.crop(left=260, top=1000, right=1080, bottom=1620)
    for x in range(0, crop_image.size[0] - 2):
        for y in range(0, crop_image.size[1] - 2):
            # 黑色像素
            black = (250, 250, 250)
            # 判断连续的三个像素是否是黑色
            pixel1 = image.load()[x, y]
            pixel2 = image.load()[x, y + 1]
            pixel3 = image.load()[x, y + 2]
            if sum(sum(pixel1) + sum(pixel2) + sum(pixel3)) >= 3 * black:
                return x
    return 0

# 计算按压时间
def distance2time(distance):
    if distance <= 100:
        DISTANCE_TO_TIME_RATIO = 2.50
        return int(distance * DISTANCE_TO_TIME_RATIO)
    elif distance <= 200:
        DISTANCE_TO_TIME_RATIO = 1.70
        return int(distance * DISTANCE_TO_TIME_RATIO)
    elif distance <= 300:
        DISTANCE_TO_TIME_RATIO = 1.35
        return int(distance * DISTANCE_TO_TIME_RATIO)
    elif distance <= 400:
        DISTANCE_TO_TIME_RATIO = 1.28
        return int(distance * DISTANCE_TO_TIME_RATIO)
    elif distance <= 500:
        DISTANCE_TO_TIME_RATIO = 1.25
        return int(distance * DISTANCE_TO_TIME_RATIO)
    elif distance <= 600:
        DISTANCE_TO_TIME_RATIO = 1.15
        return int(distance * DISTANCE_TO_TIME_RATIO)
    elif distance <= 700:
        DISTANCE_TO_TIME_RATIO = 1.10
        return int(distance * DISTANCE_TO_TIME_RATIO)


flag = True
while flag:
    distance = screenshot_crop()
    touch_time = distance2time(distance)
    if distance:
        # 执行屏幕按压操作
        os.system("adb shell input swipe 0 0 0 0 {}".format(touch_time))
        # 等待人物移动
        time.sleep(2)
    else:
        print('识别失败,程序退出!')
        flag = False

gunziyingxiong