Android逆向学习(八)Xposed快速上手(上)

Android逆向学习(八)Xposed快速上手(上)

前言

xposed是一个用来hook的工具,简而言之,通过替换/system/bin/app_process程序控制zygote进程,这样的话,app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程以及创建的Dalvik虚拟机的劫持。

看起来有点烧脑是不是,没关系,会用就行!

之前的博客中我们讲解了frida这个框架(个人比较喜欢用这个来分析),但是一个问题是frida框架需要通过电脑端进行控制,也就是我们需要在电脑端运行python程序,然后通过这个程序进行hook。

如果说我们想要长久的使用一个hook程序,也就是不使用电脑也能hook,frida是很难实现的,但是xposed可以实现,只需要编写好插件,xposed就能根据这个插件长久的执行hook操作,不需要再使用电脑连接。

不过xposed现在已经不再支持最新的系统,所以本章节在手机端主要用到的是Lsposed框架。

原理

首先讲解一下xposed原理,这就要涉及到android的基本的原理。

Dalvik 是 Android 系统最初使用的虚拟机,用于执行 Android 应用程序。它不是 Java 虚拟机(JVM),但可以运行将 Java 源码编译成 .dex(Dalvik Executable)格式的字节码文件。每个 Android 应用都在一个独立的 Dalvik 实例中运行。

注意:从 Android 5.0(Lollipop)开始,Dalvik 被新的 ART(Android Runtime)替代了,但原理上是类似的,都是"虚拟机"或"运行时环境"。

每个 Android 应用在运行时都会拥有一个独立的虚拟机实例(在 Dalvik 时代如此,后来的 ART 运行时也是一样的概念)。

更准确地说:

  • 每个 App 运行在 自己的进程中
  • 这个进程内有一个独立的虚拟机实例(Dalvik 或 ART);
  • 各个 App 之间的虚拟机 互相隔离,互不影响。

所以说,相当于每个虚拟机中负责保存变量等信息,具体执行的时候,再放到CPU上

Xposed 的本质:修改 ART/Dalvik 的方法调用流程

1. Android 应用运行流程复习(简化版):

  1. Java/Kotlin 代码编译成 .dex
  2. 运行时被 ART(或老版本的 Dalvik)虚拟机加载;
  3. 虚拟机会调用类的方法;
  4. 方法的执行依赖虚拟机内部的"方法表"(method table)和类元信息。

2. Xposed 的关键做法:

在方法被调用前,修改其在虚拟机中的元数据指针,插入你自己的代码逻辑。

换句话说,就是把这个"指向原始函数"的指针,改为"指向你自己的 Hook 逻辑"。

环境准备

手机环境

首先在Magisk中开启Zygisk。

之后下载LSposed软件:https://github.com/LSPosed/LSPosed

下载安装完成后重启手机

下载后桌面上可能不会出现图标,这时候在拨号键输入代号码 *#*#5776733#*#*

就可以显示出LSposed控制面板,然后勾选强制显示就可以显示出桌面图标,方便进入:

到这里,LSposed就安装完成

电脑环境

首先使用Android Studio创建一个空activity

之后的配置默认就好,如果习惯用java可以用java,因为现在google强推kotlin以替换java语言,所以这次我用的直接就是kotlin

创建完成后,对目录结构进行配置,首先是下载xposed的包,可能有小伙伴要问,不是用的LSposed吗,为什么要用xposed。

原因是LSposed兼容了原来的xposed插件,也就是可以利用原来xposed包开发LSposed包。

下载包的话主要在以下几个文件内修改:

settings.gradle.kts
kotlin 复制代码
pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
        maven { url =  uri("https://maven.aliyun.com/repository/public/") } //添加这一行
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        maven { url =  uri("https://maven.aliyun.com/repository/public/") } //添加这一行
        google()
        mavenCentral()
    }
}

rootProject.name = "LSposedHook"
include(":app")
build.gradle.kts(app目录下的那个)
kotlin 复制代码
dependencies {
    compileOnly("de.robv.android.xposed:api:82") //添加这一行
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.appcompat)
    implementation(libs.material)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
}

之后Sync以下,就可以下载包了

下载完成之后,开始编写包,首先创建以下几个文件:

  1. assets下的xposed_init
  2. HookEntry
  3. 在src/main/res/values下面创建一个arrays.xml文件

!

创建完成这三项之后,在AndroidManifest.xml下加入这些meta-data:

xml 复制代码
<meta-data
    android:name="xposedmodule"
    android:value="true" />
<meta-data
    android:name="xposeddescription"
    android:value="Hook isVip() always return true" />
<meta-data
    android:name="xposedminversion"
    android:value="54" />
<meta-data
    android:name="xposedscope"
    android:resource="@array/xposedscope"/>

如下图所示,加入到application的标签中,这样LSposed才能识别到这是一个xposed插件:

然后xposed_init中加入kt文件的包名,比如创建的kt文件叫HookEntry,那么xposed_init中就写入一个这个(就是包名加上类名):

java 复制代码
com.example.lsposedhook.HookEntry

这样LSposed就知道这个类里面有插件的代码。

之后在arrays.xml中加入以下内容:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="xposedscope" >
        <!-- 这里填写模块的作用应用的包名,能填多个,这里就填一个。 -->
        <item>com.zj.wuaipojie</item>
    </string-array>
</resources>

这可以表明该模块是用于这个应用的。

编写LSposed脚本

目标

通过hook完成挑战二

脚本编写

在HookEntry中写入:

kotlin 复制代码
package com.example.lsposedhook // 定义当前类的包名,和项目结构对应

// 引入 Xposed 框架提供的接口和工具类
import de.robv.android.xposed.IXposedHookLoadPackage // Xposed 的主接口,用于处理加载的包
import de.robv.android.xposed.callbacks.XC_LoadPackage // 包加载时的回调参数
import de.robv.android.xposed.XposedBridge // 提供日志输出等功能
import de.robv.android.xposed.XC_MethodReplacement // 用于替换目标方法的实现
import de.robv.android.xposed.XposedHelpers // 提供方法查找和 Hook 的辅助工具类

class HookEntry : IXposedHookLoadPackage { // 实现 Xposed 的主入口接口
    override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
        // 判断当前加载的包是否是我们要 Hook 的目标 App
        if (lpparam.packageName != "com.zj.wuaipojie") return // 如果不是目标包则直接返回,不做处理

        XposedBridge.log("程序开始执行") // 打日志,说明模块开始执行 hook 操作

        try {
            // Hook 目标类中的 isvip 方法,并替换它的返回值为 true
            XposedHelpers.findAndHookMethod(
                "com.zj.wuaipojie.ui.ChallengeSecond", // 要 hook 的类的完整类名(含包名)
                lpparam.classLoader,                   // 类加载器,用于加载目标类
                "isvip",                               // 要 hook 的方法名
                XC_MethodReplacement.returnConstant(true) // 替换方法,始终返回 true
            )
            XposedBridge.log("Hook isvip 成功") // Hook 成功的日志
        } catch (e: Throwable) {
            // 捕获异常并打印日志,便于调试
            XposedBridge.log("Hook isvip 失败: ${e.message}")
        }
    }
}

安装这个模块的方式也很简单,直接点击运行就可以了

需要注意的是,要勾选上这个,不然更新脚本很麻烦。

运行结果

通过执行可以看到,最后isvip被成功hook,而且在LSposed的应用中也能够看到输出的日志。

相关推荐
翻滚丷大头鱼4 小时前
android View详解—View的刷新流程源码解析
android
zhangphil4 小时前
Android adb shell命令分析应用内存占用
android·adb
二向箔reverse4 小时前
深度学习中的学习率优化策略详解
人工智能·深度学习·学习
悠哉悠哉愿意5 小时前
【机器学习学习笔记】线性回归实现与应用
笔记·学习·机器学习
漠缠5 小时前
Android AI客户端开发(语音与大模型部署)面试题大全
android·人工智能
Lei活在当下6 小时前
一个基础问题:关于SDK初始化时机的选择
android
Rocky4016 小时前
在线测评系统---第n天
学习
qq_172805596 小时前
GO : cannot find module
学习·go
沐小侠8 小时前
软件设计师——软件工程学习笔记
笔记·学习·软件工程
GEO_JYB8 小时前
BERT家族进化史:从BERT到LLaMA,每一次飞跃都源于对“学习”的更深理解
学习·bert·llama