高版本Android真机逆向测试环境搭建

高版本Android真机逆向测试环境搭建

618购入了新机Xiaomi K50,真滴便宜又好用,续航很强界面很丝滑。正好拿来做逆向测试机?

高版本Android真机逆向测试环境搭建

怎么可能!这也太奢侈了!不过淘汰的Xiaomi Note 7 pro正好可以胜任这个工作,之前使用的老爷机Samsung SM-N9009 可以退居二线,进仓库吃灰了。

老爷机虽然用起来很卡(跟虚拟机有一拼),但有它的好处,360一键root这种玩意儿就可以随便搞定,轻松打造测试环境,毕竟只有Android6.0,还是好欺负。但是新手机Android版本号直接飙到了Android9,老方法不太好使了,而且小米系统还被魔改过,系统文件结构跟正常机子不一样,比如boot.img中解包不出default.prop(老鸟应该懂),这使得很多脚本工具都用不了了,因此必须重新研究测试环境怎么搭。

而且之前的老机子Hook框架没搭起来,就靠一个断点调试手撸太费劲了,这次怎么说也得把Xposed整明白。

高版本真机Root方案-Magisk框架

跟主流的一键root不同,magisk可以管理整个系统的root权限树,并且可以选择性地加装或卸载安全选项,比如你可以将手机在可调式和不可调试间切换。然而magisk安装需要重刷系统镜像,也就导致了门槛较高,但我却认为这是一劳永逸的事情,对系统进行越权操作时,重刷系统是迟早地事。然而由于Magisk对原有的文件系统做了蒙版(内存覆盖),使得很多对系统权限要求较高的操作,如xposed Hook框架需要改写系统system文件,又比如设置真机可调式需要解包boot.img重写default.prop配置文件等等,依托于面具框架蒙版机制,都可以轻松执行,因此Magisk是我最推荐的高版本root方案

在没有面具框架之前,Hook框架从头装,default.prop从头刷,而在面具框架中,你只需要导入几个zip包就能把这些事情一键解决。

所谓”磨刀不误砍柴工“,面具框架就是最重要的刀具,装了就可以砍瓜切菜,否则就要跟垃圾虚拟机纠缠不清、纠结于system系统文件编辑权限不足、为xposed无法联网问题而苦恼。

刷系统

一般网上第一步会告诉你如何dump出原版boot.img文件然后用fastboot刷入手机,我绝对不推荐这个方法,安全测试面临很多越权需求,要求对手机文件系统做出较大变更,你无法保证每一步都是对的,即便是”老江湖“也会因为疲劳而犯错,因此必须要学会如何从存档点开始玩,否则手机变砖了早晚还得重刷系统,之前修改的boot.img还得重新弄。这里以红米Note7 pro为例,简单讲解一下手机系统开发版fastboot线刷流程。

解锁BootLoader

首先需要在开发者选项中设置设备解锁状态,需要SIM卡联网绑定小米账号,获取解锁权限,注意小米账号的注册手机必须与联网SIM卡手机号一致,否则会解锁失败。解锁后关机,按住**电源键+音量-**键,进入FastBoot模式。

在小米官网申请解锁手机,无需审核即可下载Bootloader解锁工具(申请了个寂寞),打开工具登录账号一键解锁。

下载官方系统包

之后到官网上下载对应机型的系统开发版镜像,一般是压缩包格式的不要被第三方平台骗了,官网就有开发版,而且是免费的,那些收费的平台给的镜像纯纯nt,买下来后发现机型不适配,直接吐血,我承认我被坑的很惨

fastboot刷机

最后下载好小米刷机工具导入系统文件夹即可一键刷机,这里注意系统解压路径中不要带空格,最好直接解压在硬盘根目录下,我没有特意测过,反正因为工具要调用fastboot命令行,因此对路径的要求比较苛刻。

Magisk安装教程

目前安卓12、11、10、9、8、7通用。

FastBootMagisk的优点

  1. 无需第三方Recovery

  2. 不影响系统升级(完整包升级)

环境准备

  1. BootLoader已解锁(必须解锁,小米手机参考:magiskcn.com/unlock-mi)

  2. 小米10Pro12+512

  3. MIUI12.5开发版21.5.20(安卓11)(支持稳定版,解锁BL一样可刷)

  4. Windows电脑一台

系统包启动镜像修补

  • 从系统安装文件夹(如:D:\xiaomi\images)下找到boot.img镜像文件,使用adb命令上传到手机
adb push boot.img /storage/emulated/0/
  • 想纯用手机操作,可以打开MT管理器,找到我们下载好的系统包,点开zip包,长按 boot.img 提取出来到 Dowmload 目录

  • 如果系统包里面没有boot.img,只有payload.bin,请参考这个教程提取:magiskcn.com/payload-boot

  • 手机下载安装:Magisk最新版

  • 打开Magisk【安装 – 选择并修补一个文件 – 弹窗文件管理窗口(找到刚刚提取的boot.img)- 开始】

  • 修补结束,会生成一个名字为(magisk_patched-版本号_随机字符.img)的文件(每次生成的随机字符都不一样)

    手机连接到电脑,

  • boot.imgmagisk_patched-2X000_xxxxx.img两个文件复制到电脑

刷入面具镜像

  • 按住**电源键+音量-**键,进入FastBoot模式。数据线连接手机,输入命令:
fastboot flash boot magisk_patched-2X000_xxxxx.img

  • 出现下面这三行代码,就是成功刷入了。
Sending 'boot' (131072 KB) OKAY [ 3.049s]
Writing 'boot'             OKAY [ 0.587s]
Finished. Total time: 4.582s
  • 重启手机(开机有震动基本没问题了)耐心等手机开机。(显示Magisk的版本,就是刷好了的)

    (A/B)(Ramdisk)(SAR)
    这是手机分区,老款手机会显示“否”。新出的手机一般都显示“是”。不影响使用。

  • PS:很多人可能不知道fastboot工具怎么下载,看见各种教程在那秀操作,自己却连工具在哪都不知道,多气啊。其实这玩意儿就算AndroidSDK工具组件platform-tools中的一个,和ADB放在一起,只要你安装了AndroidSDK,这些工具基本都有了,也可以在Android官网单独下载platform-tools,这样可以随意更换工具版本,还是很重要的

开启真机可调式

动态调试对App逆向有多重要呢?就像民以食为天,有调试才能谈逆向,否则就是闹着玩。安装面具框架后,开启调试权限就会简单很多,安装MagiskHide Props Config 模块即可永久修改真机可调式权限。

一般机型开启调试流程

  • 官网下载:[MODULE] MagiskHide Props Config - SafetyNet, prop edits, and more - v6.1.2 | XDA Forums

  • 通过命令将zip包推送到手机上

  • 从Magisk→模块→本地安装→选择zip包即可安装

  • 重启手机,进入adb shell,执行props

  • 选择需要操作的选项即可:Edit MagiskHide props→ro.debuggable

  • getprop ro.debuggable查看属性值

  • 重启后再次查看,如果不是1则:设置ro.debuggable=1,ro.secure=0,安装adbd-Insecure-v2.00之后再执行adb root就可以啦。

解决boot.img的ramdisk无default.prop文件的问题

死用教程自然是走不远的,笔者在开启调试权限时就遇到了boot.img镜像中无法解包出default.prop文件的问题,这一问题进而导致了默认的MagiskHide props中没有ro.debuggable这个选项的问题,一度被这个问题卡了很久,测试了很多方法都以失败告终,多次变砖搞得人心力憔悴。

然功夫不负有心人,经过研究发现,上述所谓MagiskHide Props Config永久映射方案,相当于再启动前帮你自动运行如下面具的props Mask命令,其本质上是一种props变量的动态覆盖方案。

adb shell #adb进入命令行模式
su #切换至超级用户
magisk resetprop ro.debuggable 1
stop;start; #一定要通过该方式重启

如果查看default.prop文件可以发现,依然为ro.debuggable=0。小米手机系统经过特殊魔改,boot.img下无法直接解包出default.prop文件,小米系统会从其他位置获取default.prop文件属性,我们不知道这个文件在哪,因此静态default.prop覆盖方案肯定行不通。既然这样,何不使用MagiskHide Props Config进行动态覆盖,你default.prop爱咋地咋地,我直接改内存去了。

理解了原理就好办,只需要自己重新定义一个custom props 名字就叫ro.debuggable,把原先的环境变量值覆盖掉,这事儿就解决了,就这么简单。

EDXposed Hook框架搭建

Hook相比调试权限没有那么必要,但在逆向大项目时也变得必不可少,它可谓效率神器。调试器虽然可以动态运行Java方法,但劣势在于只能针对一两个入口点做测试,Smali插座可以任意位置插入代码,但它的缺点却多得数不过来,重新打包App耗时长、App签名保护问题、要熟练掌握Smali语法,批量插入代码难度大,代码功能复杂时很难插入等等。

那么Hook就是一个可以快速、批量插入代码片段且无需打包App的代码修改方案,而且使用Java语言即可编写,开发效率非常高,也没有代码长度限制,想开发多长都行,唯一的缺点就是没法打包Apk发给别人用,害,到时候用smali重新写一下不久完了,有些App业务逻辑都得摸索半天,还各种加密,还想改两下就给别人用,别做梦了。

EDXposed和Xposed的区别

EDXposed和Xposed就是一个东西,只是前者能支持在高版本的android上运行,得益于面具框架支持,无需入侵系统的system文件夹即可发挥Xposed的功能,在网上搜索一下EDXposed的模块开发教程,你会发现几乎没有,因为它和Xposed的模块开发方式一模一样,有些人可能不明白为什么Android换了这么多代,启动器也换成EDXposed了,原有的Xposed模块也不用升级就能兼容呢?还不是因为底层几乎没变过,xposed直接与虚拟机通信,这属于很底层的机制了,这玩意儿要是大改那还不得闹翻天。

EDXposed安装

安装本身没什么难度,难在找资源,不要以为Xposed和Magisk人人都提,它们就是大平台产品了。充其量也就是个人爱好者开发的项目,单纯因为好用所以被大家传的广,个人项目的特点就是:服务不稳定、更新不稳定。原作者的资源链说不定啥时候就失效了,它们的从属模块更是没有一个所谓官网进行统一管理,都是些工程师自己写着玩的,很多模块仓库都是个人建的,说没就没,所以把这些资源收集好,说不定哪天链接就GG了。

自从新版面具下架了模块搜索功能之后,面具的模块下载位置就成了信息差,你知道有这个模块不难,但你就是不知道在哪下载,应该有第三方搜索工具可以解决这个问题,不过我懒得弄了,直接下载别人分享的资源:

https://pan.baidu.com/s/1Bfop9zcA6eccDy8Y5i09Gg 提取码:o6s0

  • 打开Magisk - 模块 - 从本地导入模块 - 选择riru.zip和edxposed.zip进行安装,这里注意一定要先装riru.zip,否则edxposed.zip装不上,然后重启手机

  • 重启后安装EdXposedInstaller.apk,进入App提示已激活,就安装成功了

编写一个Xposed模块

前言

在互联网上,关于Xposed模块编写的教程可谓是一抓一大把。但由于时间的推移,很多工具和方法都发生了变化(如Eclipse退出安卓编程舞台,AndroidStudio 不断升级导致其一些设置也随之变化等)也正因此,网上的教程往往有一些时限性,比如现如今 provide 这个关键字已经被舍弃了却仍有人在用,还有些说要把jar包放到lib文件夹而非libs文件夹……种种错误或者落伍的教程对新手产生了很大的误导。 笔者近日收到过朋友初学Xposed模块编写时的求助,看了一些他找的参考教程,觉得多多少少都存在点问题,因此萌生了写一篇关于在最新AndriodStudio 开发环境下实现Xposed模块开发入门的文章。

Xposed 模块编写简介

Xposed 框架的原理就不多说了,它部署在ROOT后的安卓手机上,通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。可以让我们在不修改APK源码的情况下,通过自己编写的模块来影响程序运行的框架服务,实现类似于自动抢红包、微信消息自动回复等功能。

其实,从本质上来讲,Xposed 模块也是一个 Android 程序。但与普通程序不同的是,想要让写出的Android程序成为一个Xposed 模块,要额外多完成以下四个硬性任务:

1、让手机上的xposed框架知道我们安装的这个程序是个xposed模块。

2、模块里要包含有xposed的API的jar包,以实现下一步的hook操作。

3、这个模块里面要有对目标程序进行hook操作的方法。

4、要让手机上的xposed框架知道,我们编写的xposed模块中,哪一个方法是实现hook操作的。

这就引出我即将要介绍的四大件(与前四步一一对照):

1、AndroidManifest.xml

2、XposedBridgeApi-xx.jar 与 build.gradle

3、实现hook操作的具体代码

4、xposed_Init

牢记以上四大件,按照顺序一个一个实现,就能完成我们的第一个Xposed模块编写。下面我们就开始吧!

迈开第一步,新建项目并编辑AndroidManifest.xml

  • 首先打开AndroidStudio(以版本3.1为例,还在用老版本的请升级),建立一个工程,提示我们选择“Activity”,那就选一个Empty Activity吧。(这个是模块的界面,随意选择即可)。

  • 我们可以把项目查看方式设置为Project模式,以方便查看。然后在 “项目名称/app/src/main/”目录下找到AndroidManifest.xml,双击之,并在指定位置插入以下三段代码:

    <meta-data android:name="xposedmodule" android:value="true" />
    
    <meta-data android:name="xposeddescription" android:value="这是一个Xposed例程" />
    
    <meta-data android:name="xposedminversion" android:value="82" />
    

  • 插入之后,如果你把手机连上AndroidStudio ,点击“编译”或者“运行”的话,手机就会启动刚刚编写的这个程序。而在手机里的Xposed框架中也会显示出这个模块:

    说明Xposed框架已经认出了我们写的程序。但先别高兴太早——虽然框架已经觉得他是一个Xposed模块了,但我们自己心里清楚,这个模块还啥都不会干呢。下一步,我们让这个模块长点本事。

    搞定XposedBridgeApi-xx.jar 与 build.gradle

我们知道,Xposed模块主要功能是用来Hook其他程序的各种函数。但是,如何让前一步中的那个“一穷二白”的模块长本事呢?那就要引入 XposedBridgeApi.jar 这个包,你可以理解为一把兵器,模块有了这把宝刀才能施展出Hook本领。以前,都需要手动下载诸如XposedBridgeApi-54.jar 、 XposedBridgeApi-82.jar 等jar包,然后手工导入到libs目录里,才能走下一步道路。其实在AndroidStudio 3.1里面,我们完全不用这么麻烦,只需要多写一行代码,就让AndroidStuido自动给我们配置XposedBridgeApi.jar !下面操作开始(序号接着上一节):

  • 在 “项目名称/app/src/main/”目录下找到build.gradle,在图示位置加上:

    repositories {
    
        jcenter()
    
    }
    

    以及

    compileOnly 'de.robv.android.xposed:api:82'
    
    compileOnly 'de.robv.android.xposed:api:82:sources'
    
  • 这句代码是告诉AndroidStuido使用jcenter作为代码仓库,从这个仓库里远程寻找 de.robv.android.xposed:api:82 这个API。这个网上很少有Xposed教程介绍它的!(我们不用自己找XposedBridgeApi.jar了。注意!此处要用compileOnly这个修饰符!网上有些写的是provide ,现在已经停用了!)如图:

  • 写完之后, build.gradle会提示文件已经修改,是否同步。点击 “sync now”,同步即可:

  • 【ps:如果网络不通,或者同步不畅,就不要进行第三步的repositories { jcenter()}这个步骤了,改做这个步骤:】

    手动下载XposedBridgeApi-82.jar ,拖放到“项目名称/app/libs/”里面(不是网上说的单独建立lib文件夹,那是很久以前的故事了!),然后右键“Add As Library” 自行添加这个jar包。而compileOnly 'de.robv.android.xposed:api:82’和 compileOnly 'de.robv.android.xposed:api:82:sources’这两句仍然照常添加。

实现hook操作的具体代码

  • 在“施展刀法”(编写hook代码)之前,我们先要立一个靶子。在界面上画一个按钮,并在MainAcitiviy里写代码如下:

    package com.example.root.xposd_hook_new;
    
    import android.support.v7.app.AppCompatActivity;
    
    import android.os.Bundle;
    
    import android.view.View;
    
    import android.widget.Button;
    
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        private Button button;
    
        @Override
    
        protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_main);
    
            button = (Button) findViewById(R.id.button);
    
            button.setOnClickListener(new View.OnClickListener() {
    
                public void onClick(View v) {
    
                    Toast.makeText(MainActivity.this, toastMessage(), Toast.LENGTH_SHORT).show();
    
                }
    
            });
    
        }
    
        public String toastMessage() {
    
            return "我未被劫持";
    
        }
    
    }
    

  • 这个靶子很简单:MainActivity界面有个按钮,点击按钮后会弹出一个toast提示,该提示的内容由 toastMessage() 方法提供,而toastMessage()的返回值为“我未被劫持”:

    下面我们正式开始“施展刀法”(编写hook代码) 来hook我们的MainActivity并修改这个类的toastMessage()方法,让它的返回值为“你已被劫持”:

  • 在MainActivity的同级路径下新建一个类“HookTest.java”,代码如下:

    package com.example.root.xposd_hook_new;
    
    import de.robv.android.xposed.IXposedHookLoadPackage;
    
    import de.robv.android.xposed.XC_MethodHook;
    
    import de.robv.android.xposed.XposedBridge;
    
    import de.robv.android.xposed.XposedHelpers;
    
    import de.robv.android.xposed.callbacks.XC_LoadPackage;
    
    public class HookTest implements IXposedHookLoadPackage {
    
        public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
    
            if (loadPackageParam.packageName.equals("com.example.root.xposd_hook_new")) {
    
                XposedBridge.log(" has Hooked!");
    
                Class clazz = loadPackageParam.classLoader.loadClass(
    
                        "com.example.root.xposd_hook_new.MainActivity");
    
                XposedHelpers.findAndHookMethod(clazz, "toastMessage", new XC_MethodHook() {
    
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
    
                        super.beforeHookedMethod(param);
    
                        //XposedBridge.log(" has Hooked!");
    
                    }
    
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
    
                        param.setResult("你已被劫持");
    
                    }
    
                });
    
            }
    
        }
    
    }
    
  • 由代码可知,我们是通过IXposedHookLoadPackage接口中的handleLoadPackage方法来实现Hook并篡改程序的输出结果的。代码中“com.example.root.xposd_hook_new ”是目标程序的包名,“com.example.root.xposd_hook_new.MainActivity” 是想要Hook的类, "toastMessage"是想要Hook的方法。我们在afterHookedMethod方法(用来定义Hook了目标方法之后的操作)中,修改了toastMessage()方法的返回值为“你已被劫持”。

最后一步,添加入口点

  • 右键点击 “main ” 文件夹 , 选择new --> Folder -->Assets Folder,新建assets 文件夹:

  • 然后右键点击 assets文件夹, new–> file,文件名为xposed_init(文件类型选text),并在其中写上入口类的完整路径(就是自己编写的那一个Hook类),这样, Xposed框架就能够从这个 xposed_init 读取信息来找到模块的入口,然后进行Hook操作了:

  • 然后点击小三角“运行”!在Xposed框架里找到自己写的模块,打上勾,重启——点开自己的程序看看,是不是toast的提示已经变了?

版权声明:如无特殊标注,文章均来自网络,本站编辑整理,转载时请以链接形式注明文章出处,请自行分辨。

本文链接:https://www.shbk5.com/dnsj/75011.html