[Free column] Android security Android Xposed plug-in development, a tutorial that Xiaobai can understand


Maybe everyone is born thinking that the world exists only for him, and when he finds out that he is wrong, he begins to grow up

If you avoid detours, you will miss the scenery. Anyway, thanks for the experience


Notice of transfer publishing platform: new articles will no longer be published on the CSDN blog, please move to Knowledge Planet

Thank you for your attention and support to my CSDN blog, but I have decided not to publish new articles here. In order to provide you with better services and more in-depth exchanges, I have opened a knowledge planet, which will provide more in-depth and practical technical articles. These articles will be more valuable and can help you better solve practical problems. question. Looking forward to you joining my knowledge planet, let us grow and progress together


The Android security paid column is updated for a long time. For the latest content of this article, please go to:

0x01 Preface

1.1 Android operating system architecture

Android is a free and open source operating system based on Linux. The Android system architecture is the architecture of the Android system. Its system architecture is the same as its operating system. It adopts a layered architecture and is divided into four layers and five parts. The four layers refer to the Android application layer from high to low. Android application framework layer, Android system operation layer and Linux kernel layer; the five parts refer to Linux Kernel, Android Runtime, Libraries, Application Framework, Applications.

1.1.1 Linux Kernel

At the bottom of all layers is Linux, which provides basic system functions, such as process management, memory management, device management (such as camera, keyboard, monitor).

1.1.2 Android Runtime

The Android runtime also provides a series of core libraries for Android application developers to use the standard Java language to write Android applications. The Dalvik virtual machine makes each Android application run in its own independent virtual machine process. The executable file format of the Dalvik virtual machine is .dex. The dex format is a compressed format specially designed for Dalvik, suitable for systems with limited memory and processor speed.

1.1.3 Libraries

Android includes a collection of C/C++ libraries for use by various components of the Android system. These functions are exposed to developers through Android's application framework.

1.1.4 Application Framework

By providing an open development platform, Android enables developers to compile extremely rich and innovative applications.

1.1.5 Applications

The application framework layer provides many high-level services to the application in the form of Java classes.

1.2 Android application components

Application components are the basic building blocks of an Android application. Each component of the application and how they interact is described in AndroidManifest.xml.

1.2.1 Four main components in Android application

component name describe
Activities Describes the UI and handles user interaction with the machine screen
Services Handles background operations associated with the application
Broadcast Receivers Handles communication between the Android OS and applications
Content Providers Dealing with data and database management issues

1.2.2 Add-ons

component name describe
Fragments Represents a behavior or part of the user interface in an activity
Views UI elements drawn on the screen, including buttons, lists, etc.
Layouts Inheritance of View that controls the screen format and displays the appearance of the view
Intents Message wiring between components
Resources External elements, such as string resources, constant resources, and image resources, etc.
Manifest Application configuration files

1.3 What is Hook?

Hook is also called "hook", it can intercept and monitor the transmission of events during the process of event transmission, and integrate its own code with system methods

In this way, when these methods are called, we can also execute our own code, which is also the idea of ​​aspect-oriented programming (AOP)

1.4 Hook classification

1) According to the Android development mode, Native mode (C/C++) and Java mode (Java) are distinguished, on the Android platform

  • Hooks at the Java level
  • Hooks at the Native level

2) The root Hook object is different from the Hook post-processing event method, and the Hook is also divided into:

  • Message Hook
  • API Hook

3) For the different processes of Hook, it can also be divided into:

  • Global Hook
  • Single Process Hook

1.5 Hook principle

The essence of Hook technology is a function call. Because it is in the Linux user state, each process has its own independent process control, so it must be injected into the process space of the desired Hook, modify the process code in its memory, replace the symbol address of the process table, and pass the ptrace function Attach process, inject so library into remote process, so as to achieve monitoring and remote process key function hook

Hook workflow:

  • Android related kernel functions:

    • ptrace function: track a target process, end tracking a target process, get memory bytes, like memory write address
    • dlopen function: open the specified dynamic link library file in the specified mode
    • mmap function: allocate a temporary memory to complete the storage of code
  • After injecting code into the target process, the summarized steps are divided into the following steps:

    • Use the ptrace function to attch the target process
    • Found that the shared library so function is loaded
    • Load the specified .so
    • Let the execution flow of the target process jump to the injected code execution
    • Release target integration using detach of ptrace function

1.6 Common Hook Framework

In Android development, there are some common Hook frameworks:

1)Xposed

Xposed is a tool developed by Daniel abroad. Xposed achieves the purpose of modifying the behavior of the program by intercepting the running process of the Android program. There is no need to modify the Android source files, but to intercept and affect the running conditions by analyzing the running of the program. Specifically, it is necessary to reverse the Android apk and then analyze the code, locate specific classes, methods, etc., and then use xposed to intercept modification methods, etc.

Two conditions for using the Xposed module:

  • The phone must be rooted (Xposed needs to write something into /system)
  • Install Xposed Installer

Control the Zygote process by replacing the /system/bin/app_process program, so that app_process will load the Jar package XposedBridge.jar during startup, thereby completing the hijacking of the Zygote process and the Dalvik virtual machine it creates.

Xposed completes the hijacking of all Hook Functions when it is turned on, and adds custom codes before and after the execution of the original Function.

download link:

The following one is only available for root access on Android 4.0.3 to Android 4.4
https://repo.xposed.info/module/de.robv.android.xposed.installer

For Android 5.0 or later use this instead
https://forum.xda-developers.com/t/official-xposed-for-lollipop-marshmallow-nougat-oreo-v90-beta3-2018-01-29.3034811/

2)Cydia Substrate

Cydia Substrate is a code modification framework based on Hook, which can be used on Android and iOS platforms, and can modify the default code of the system

The Cydia Substrate framework provides a jailbreak-related service framework for Apple users, and of course an Android version is also available. Cydia Substrate is a code modification platform that can modify the code of any process.

No matter it is written in Java or C/C++ (native code), Xposed only supports Java functions in Hook app_process.

download link:

http://www.cydiasubstrate.com

3)Legend

Legend is an Apk Hook framework for Android in a root-free environment. The code design of the framework is simple and versatile, and it is suitable for some Hook scenarios during reverse engineering. Most of the functions are placed in the Java layer, so the compatibility is very good

The principle is this, directly construct the virtual machine data structure corresponding to the old and new methods, and then write the replacement information into the memory

download link:

https://github.com/asLody/legend

4)VirtualXposed

VirtualXposed is based on VirtualApp and epic to run Xposed module in non-ROOT environment (support 5.0~10.0).

Compared with Xposed, VirtualXposed currently has two limitations:

Does not support modifying the system (you can modify the calls to the system API in ordinary APPs), so Gravity Toolbox, application controllers, etc. cannot be used

Resource HOOK is not supported for now, so resource hooks will not have any effect; modules that use resource HOOK, the corresponding functions will not take effect

download link:

https://github.com/android-hacker/VirtualXposed

1.7 Hook must master the knowledge

  • reflection

  • Dynamic proxy for java

Dynamic proxy refers to the dynamic generation of proxy classes at runtime, without the need for us to manually write proxy classes one by one like static proxies. In java, InvocationHandler can be used to implement dynamic proxy

1.8 Key points of Hook selection

Hook's choice point: try to static variables and singletons, because once the object is created, they are not easy to change and very easy to locate

Hook process:

  • Looking for Hook points, the principle is to try to use static variables or singleton objects, and try to hook public objects and methods
  • Choose the appropriate proxy method, if it is an interface, you can use dynamic proxy
  • Swapping—replacing the original object with a proxy object

Android has many API versions, and the methods and classes may be different, so it is necessary to do a good job of API compatibility

1.9 Introduction to some classes of Xposed

  • IXposedHookLoadPackage.java

Load the callback interface, inherit it from the xposed entry class, and implement the handleLoadPackage method

IXposedHookLoadPackage interface. This interface provides a method called handleLoadPackage, which is called every time the Android system loads a package

handleLoadPackage Used to perform user actions when loading an application's package
LoadPackageParam loadPackageParam Contains some basic information about the loaded application
  • IXposedHookInitPackageResources.java

Load the callback interface, used to modify the resource file of the app, inherited from the xposed entry class, and implement the handleInitPackageResources(InitPackageResourcesParam resparam) method

handleInitPackageResources Used to perform user actions when loading an application's package
InitPackageResourcesParam resparam Contains some resource basic information of the loaded application
  • XposedHelpers.java

Some helper methods to simplify connecting and calling methods/constructors, getting and setting fields

HOOK has no parameters. The XposedHelpers.findAndHookMethod() method generally has four parameters, which are the full class name, ClassLoader object, method name, and a callback interface.

XposedHelpers.findAndHookMethod("com.example.demo.MortgageActivity", loadPackageParam.classLoader,
        "showLoan", new XC_MethodHook() {
    
    
	//……
});

HOOK has a parameter method, for example, if you want to pass in two int parameters, then:

XposedHelpers.findAndHookMethod("com.example.demo.MortgageActivity", loadPackageParam.classLoader,
        "showLoan", int.class, int.class, new XC_MethodHook() {
    
    
	//……
});

PS : new XC_MethodHook() has two important internal functions, beforeHookedMethod() and afterHookedMethod(), which can be hooked to any method by rewriting them. The difference between them is whether the Hook is called before or after it is called.

beforeHookedMethod 该方法在hook目标方法执行前调用,
其中,参数param指的是目标方法的相关参数、回调、方法等信息

afterHookedMethod 该方法在hook目标方法执行后调用,
其中,参数param指的是目标方法的相关参数、回调、方法等信息。

Xposed运行多个模块对同一个方法进行hook时,
框架就会根据Xposed模块的优先级来排序

The hookAllMethods and log methods in the XposedBridge class are mainly used to hook all methods of each class or create functions

hookAllMethods(
	Class<?> hookClass,//需要进行hook的类
	String methodName,//需要进行hook的方法名
	XC_MethodHook callback//回调函数
)

The handleLoadPackage method in XposedHookLoadPackage is mainly used to perform user operations when loading an application package.

findAndHookMethod hook a method in a class
className The class of the method to be hooked
classloader The classLoader of the package to be hooked is generally written as loadPackageParam.classLoader
methodName The method to hook
parameterTypesAndCallback Method Parameters and Listeners
callMethod Call the method in the target app
Object The class to call the method on
methodName the method name to call
args method parameters
findClass Get class class instance
className class name
classLoader class loader
  • XposedBridge.java
log Output logs in the log function of Xposed app
text what to output
  • The callback method is defined in XC_MethodHook

1.10 Description of each part of the Android application

1.10.1 MainActivity.java file

The main activity code, the actual application file, will be converted into a Dalvik executable and run. R.layout.activity_mainReferenced res/layout/activity_main.xmldocuments.

onCreate() One of many methods called after the activity is loaded.

insert image description here

1.10.2 AndroidManifest.xml file

The AndroidManifest.xml file is the information description file of the entire application, which defines the Activity, Service, Content provider and BroadcastReceiver component information contained in the application. Each application must contain an AndroidManifest.xml file in the root directory, and the file name cannot be modified. In the AndroidManifest.xml file, first see <manifest>the node, which is the basic attribute of the entire application, covering the default process name, application identification, installation location, system requirements, and application version.

  • android:icon is a normal icon
  • android:roundIcon is a round icon
  • The android:label attribute specifies the name of the application
  • The android:name attribute specifies the full name of an Activity class subclass

The action of the intent filter is named to android.intent.action.MAINindicate that this activity is used as the entry point of the application.

The category of the intent filter is named to android.intent.category.LAUNCHERindicate that the application can be launched from the icon in the device launcher.

@stringIt refers to strings.xml, so @string/app_nameit refers to the app_name defined in strings.xml, which is actually "HO22K"

insert image description here
insert image description here

1.10.3 activity_main.xml file

activity_main.xmlIt is likely that this file will be modified frequently to change the layout of the application.

TextView is an Android control for building graphical user interfaces. It contains many different properties, such as android:layout_width, android:layout_heightetc. used to set its width and height. Here we show it a sentence "Orange Fragrance Hook", quoted from the strings.xml file

insert image description here

1.11 Android layout attribute collection

Activity_main.xml needs to be used when writing

1.11.1 The first category: attribute value true or false

Attributes describe
android:layout_centerHrizontal center horizontally
android:layout_centerVertical vertical center
android:layout_centerInparent Fully centered relative to parent element
android:layout_alignParentBottom Snap to the bottom edge of the parent element
android:layout_alignParentLeft Snap to the left edge of the parent element
android:layout_alignParentRight Snap to the right edge of the parent element
android:layout_alignParentTop Snap to the top edge of the parent element
android:layout_alignWithParentIfMissing If the corresponding sibling element cannot be found, the parent element is used as the reference
android:layout_alignParentStart start close to the end of the parent element
android:layout_alignParentEnd Close to the end of the parent element
android:animateLayoutChanges Whether to animate when the layout changes
android:clipChildren 定义子布局是否一定要在限定的区域内
android:clipToPadding 定义布局间是否有间距
android:animationCache 定义子布局也有动画效果
android:alwaysDrawnWithCache 定义子布局是否应用绘图的高速缓存
android:addStatesFromChildren 定义布局是否应用子布局的背景
android:splitMotionEvents 定义布局是否传递touch事件到子布局
android:focusableInTouchMode 定义是否可以通过touch获取到焦点
android:isScrollContainer 定义布局是否作为一个滚动容器 可以调整整个窗体
android:fadeScrollbars 滚动条自动隐藏
android:fitsSystemWindows 设置布局调整时是否考虑系统窗口(如状态栏)
android:visibility 定义布局是否可见
android:requiresFadingEdge 定义滚动时边缘是否褪色
android:clickable 定义是否可点击
android:longClickable 定义是否可长点击
android:saveEnabled 设置是否在窗口冻结时(如旋转屏幕)保存View的数据
android:filterTouchesWhenObscured 所在窗口被其它可见窗口遮住时,是否过滤触摸事件
android:keepScreenOn 设置屏幕常亮
android:duplicateParentState 是否从父容器中获取绘图状态(光标,按下等)
android:soundEffectsEnabled 点击或触摸是否有声音效果
android:hapticFeedbackEnabled 设置触感反馈

1.11.2 第二类:属性值必须为id的引用名“@id/id-name”

属性 描述
android:layout_alignBaseline 本元素的文本与父元素文本对齐
android:layout_below 在某元素的下方
android:layout_above 在某元素的的上方
android:layout_toLeftOf 在某元素的左边
android:layout_toRightOf 在某元素的右边
android:layout_toStartOf 本元素从某个元素开始
android:layout_toEndOf 本元素在某个元素结束
android:layout_alignTop 本元素的上边缘和某元素的的上边缘对齐
android:layout_alignLeft 本元素的左边缘和某元素的的左边缘对齐
android:layout_alignBottom 本元素的下边缘和某元素的的下边缘对齐
android:layout_alignRight 本元素的右边缘和某元素的的右边缘对齐
android:layout_alignStart 本元素与开始的父元素对齐
android:layout_alignEnd 本元素与结束的父元素对齐
android:ignoreGravity 指定元素不受重力的影响
android:layoutAnimation 定义布局显示时候的动画
android:id 为布局添加ID方便查找
android:tag 为布局添加tag方便查找与类似
android:scrollbarThumbHorizontal 设置水平滚动条的drawable
android:scrollbarThumbVertical 设置垂直滚动条的drawable
android:scrollbarTrackHorizontal 设置水平滚动条背景(轨迹)的色drawable
android:scrollbarTrackVertical 设置垂直滚动条背景(轨迹)的色drawable
android:scrollbarAlwaysDrawHorizontalTrack 设置水平滚动条是否含有轨道
android:scrollbarAlwaysDrawVerticalTrack 设置垂直滚动条是否含有轨道
android:nextFocusLeft 设置左边指定视图获得下一个焦点
android:nextFocusRight 设置右边指定视图获得下一个焦点
android:nextFocusUp 设置上边指定视图获得下一个焦点
android:nextFocusDown 设置下边指定视图获得下一个焦点
android:nextFocusForward 设置指定视图获得下一个焦点
android:contentDescription 说明
android:OnClick 点击时从上下文中调用指定的方法

1.11.3 第三类:属性值为具体的像素值,如30dip,40px,50dp

属性 描述
android:layout_width 定义本元素的宽度
android:layout_height 定义本元素的高度
android:layout_margin 本元素离上下左右间的距离
android:layout_marginBottom 离某元素底边缘的距离
android:layout_marginLeft 离某元素左边缘的距离
android:layout_marginRight 离某元素右边缘的距离
android:layout_marginTop 离某元素上边缘的距离
android:layout_marginStart 本元素里开始的位置的距离
android:layout_marginEnd 本元素里结束位置的距离
android:scrollX 水平初始滚动偏移
android:scrollY 垂直初始滚动偏移
android:background 本元素的背景
android:padding 指定布局与子布局的间距
android:paddingLeft 指定布局左边与子布局的间距
android:paddingTop 指定布局上边与子布局的间距
android:paddingRight 指定布局右边与子布局的间距
android:paddingBottom 指定布局下边与子布局的间距
android:paddingStart 指定布局左边与子布局的间距与android:paddingLeft相同
android:paddingEnd 指定布局右边与子布局的间距与android:paddingRight相同
android:fadingEdgeLength 设置边框渐变的长度
android:minHeight 最小高度
android:minWidth 最小宽度
android:translation X水平方向的移动距离
android:translation Y垂直方向的移动距离
android:transformPivot X相对于一点的水平方向偏转量
android:transformPivot Y相对于一点的垂直方向偏转量

1.11.4 第四类:属性值为Android内置值

属性 描述
android:gravity 控件布局方式
android:layout_gravity 布局方式
android:persistentDrawingCachehua 定义绘图的高速缓存的持久性
android:descendantFocusability 控制子布局焦点获取方式 常用于listView的item中包含多个控件点击无效
android:scrollbars 设置滚动条的状态
android:scrollbarStyle 设置滚动条的样式
android:fitsSystemWindows 设置布局调整时是否考虑系统窗口(如状态栏)
android:scrollbarFadeDuration 设置滚动条淡入淡出时间
android:scrollbarDefaultDelayBeforeFade 设置滚动条N毫秒后开始淡化,以毫秒为单位
android:scrollbarSize 设置滚动调大小
android:fadingEdge 设置拉滚动条时,边框渐变的放向
android:drawingCacheQuality 设置绘图时半透明质量
android:OverScrollMode 滑动到边界时样式
android:alpha 设置透明度
android:rotation 旋转度数
android:rotation X水平旋转度数
android:rotation Y垂直旋转度数
android:scale X设置X轴缩放
android:scale Y设置Y轴缩放
android:verticalScrollbarPosition 摄者垂直滚动条的位置
android:layerType 设定支持
android:layoutDirection 定义布局图纸的方向
android:textDirection 定义文字方向
android:textAlignment 文字对齐方式
android:importantForAccessibility 设置可达性的重要行
android:labelFor 添加标签

0x02 Xposed环境搭建

下载Xposed APK:

https://dl-xda.xposed.info/modules/de.robv.android.xposed.installer_v33_36570c.apk

insert image description hereinsert image description here

打开刚刚安装好的Xposed

insert image description hereinsert image description here

这里为了方便选择永久记住

insert image description here
insert image description here

安装Xposed可能会出现如下情况:

insert image description here

安装完毕后可能会出现未激活, 拉入JustTrustMe.apk, 然后重启模拟器就可以了
然后修改wifi的ip和端口

insert image description here

  • 下载xposed-x86_64.zip

下载xposed作者模拟器是x86_64的

https://github.com/youling257/XposedTools/files/1931996/xposed-x86_64.zip

如果模拟器是x86下载下面这个

https://dl-xda.xposed.info/framework/

  • 下载script.sh

找到安卓对应版本,作何雷电模拟器是7.1,搜索对应为安卓7.1 sdk

x86_64的下载这个:

https://forum.xda-developers.com/attachment.php?attachmentid=4489568&d=1525092710

x86的下载这个,script.txt:

https://forum.xda-developers.com/attachments/script-txt.4489568/,改名为script.sh

创建文件夹xposed,然后解压一下xposed压缩包,最后把xposed压缩包中的system文件夹和script.sh放入刚刚创建的xposed文件夹,最后的最后执行如下命令:

adb.exe remount
adb.exe push D:\test\xposed  /system
adb.exe shell
cd /system
mount -o remount -w /system
chmod 777 script.sh
sh script.sh

insert image description here

0x03 Xposed原理分析

Xposed框架的原理是修改系统文件,替换了/system/bin/app_process可执行文件,在启动Zygote时加载额外的jar文件(/data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar),并执行一些初始化操作(执行XposedBridge的main方法)。然后开发人员就可以在这个Zygote上下文中进行某些Hook操作。

在Android中,zygote是整个系统创建新进程的核心进程。zygote进程在内部会先启动Dalvik虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。

在之后的运作中,当其他系统模块(比如AMS)希望创建新进程时,只需向zygote进程发出请求,zygote进程监听到该请求后,会相应地fork出新的进程,于是这个新进程在初生之时,就先天具有了自己的Dalvik虚拟机以及系统资源。

zygote进程是由init进程启动起来,由init.rc 脚本中关于zygote的描述可知:zygote对应的可执行文件就是/system/bin/app_process,也就是说系统启动时会执行到这个可执行文件的main()函数里

Xposed 提供了几个接口类供xposed模块继承,不同的接口类对应不同的hook时机 IXposedHookZygoteInit zygote 初始化前就执行挂钩,即loadModule执行时就挂钩了 IXposedHookLoadPackage apk包加载的时候执行挂钩,先将挂钩函数保存起来,等加载apk函数执行后触发callback (这里的callback是xposed框架自己挂钩的函数),再执行模块注册的挂钩函数 IXposedHookInitPackageResources apk资源实例化时执行挂钩,同上

0x03 编写Xposed 模块

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

  • 让手机上的xposed框架知道我们安装的这个程序是个xposed模块
  • 模块里要包含有xposed的API的jar包,以实现下一步的hook操作
  • 这个模块里面要有对目标程序进行hook操作的方法
  • 要让手机上的xposed框架知道,我们编写的xposed模块中,哪一个方法是实现hook操作的

这就引出如下的四大件(与前四步一一对照):

  • AndroidManifest.xml
  • XposedBridgeApi-xx.jar 与 build.gradle
  • 实现hook操作的具体代码
  • xposed_Init

PS:牢记以上四大件,按照顺序一个一个实现,就能完成Xposed模块编写

3.1 创建一个Android项目

官网下载地址:https://developer.android.com/studio?hl=zh-cn

傻瓜式一键点点安装,安装过程忽略不写,不懂的可百度自行搜索

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

insert image description here

新建完成后下载依赖时,可能会出现如下报错(是没有科学上网导致的,要么你科学上网,要么你把gradle版本下载到本地来安装

insert image description here
insert image description hereinsert image description here

改为如下地址:

distributionUrl=file:///C:/Users/xxxxx/.gradle/wrapper/dists/gradle-7.2-bin.zip

然后又有可能发现gradle插件下载又出现问题,解决办法如下:

insert image description here

如上图,注释掉google(),新增如下maven:

        //google()
        maven {
    
     url 'https://maven.aliyun.com/repository/google'}
        maven {
    
     url 'https://maven.aliyun.com/repository/jcenter'}
        maven {
    
     url 'https://maven.aliyun.com/repository/public'}

以及如下位置:

insert image description here

最后关闭Android Studio,再重新打开项目会自动加载,此时如果没有再有红色警示就代表OK了,然后直接编译一个Demo的APK(app/build/outputs/apk/debug目录下,可以看到app-debug.apk),看看是否能正常运行,如下图:

insert image description here

放到模拟器中,发现能正常安装并运行,如下图:

insert image description here

3.2 配置AndroidManifest.xml

为了让Xposed 识别出这是个Xposed模块,需要添加如下内容:

        <!--告诉xposed框架这是一个xposed模块 -->
        <meta-data
            android:name="xposedmodule"
            android:value="true"/>

        <!--关于xposed模块的描述 -->
        <meta-data
            android:name="xposeddescription"
            android:value="XposeHook例程"/>

        <!--xposed模块支持的最低版本(以为54为例) -->
        <meta-data
            android:name="xposedminversion"
            android:value="54"/>

insert image description here

修改文本内容为:橙留香的HooK

insert image description here
insert image description here

此时把编译好的APK丢进去,打开后,如下

insert image description here

PS:从上图已看出,Xposed框架已经认出了刚刚写的程序,但是现在这个模块什么都没有做,因为我们还没有做出修改

3.3 配置XposedBridgeApi-xx.jarbuild.gradle

Xposed模块主要功能是用来Hook其他程序的各种函数。

  • 接下来,如何让刚刚创建的那个Xposed“一穷二白”的模块增加一些其它的功能呢?

引入 XposedBridgeApi.jar包,可理解该包是一把兵器,Xposed模块有了这把绝世神器才能施展出Hook武功。

3.x以前,都需要手动下载诸如XposedBridgeApi的jar包,然后手工导入到libs目录里

  • XposedBridgeApi-54下载

https://forum.xda-developers.com/attachment.php?s=5903ce1b3edb1032faba7292b21e1801&attachmentid=2748878&d=1400342298

PS:除了XposedBridgeApi-54,还有XposedBridgeApi-82.jar、XposedBridgeApi-87.jar、XposedBridgeApi-89.jar等版本

官网下载:https://bintray.com/rovo89/de.robv.android.xposed/api

在AndroidStudio 3.1里面,只需要一行代码,AndroidStuido就会自动配置XposedBridgeApi.jar

  • 方法1:
    Android Studio的依赖:

Xposed框架需要用到第三方库,在 app --> build-gradle 添加依赖(最后一行)

repositories {
    
    
    // 告诉AndroidStuido使用jcenter作为代码仓库,
    // 从这个仓库里远程寻找 
    // de.robv.android.xposed:api:82 这个API
    // 但最新版的3.x版本已不推荐使用
    jcenter();
}

dependencies {
    
    
    provided 'de.robv.android.xposed:api:82'
}
注:
   此处要用compileOnly这个修饰符,
   网上有些写的是provide,
   已经停用了
    compileOnly 'de.robv.android.xposed:api:82'
    compileOnly 'de.robv.android.xposed:api:82:sources'

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

insert image description here

3.4 实现hook操作修改

在MainActivity的同级路径下新建一个类“HO22K.java”,操作如下图:

insert image description here
insert image description here

代码如下:

package com.example.ho22k;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class HO22K implements IXposedHookLoadPackage
{
    
    
    /**
     * xpose插件入口点
     * @param lpparam
     * @throws Throwable
     */
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
    
    
        // 获取加载的apk程序包名
        XposedBridge.log("当前启动的应用程序是: " + loadPackageParam.packageName);
        XposedBridge.log("Hook成功咯,宝们~_~!");
    }
}

insert image description here

3.5 添加入口点xposed_Init

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

insert image description here

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

insert image description here
insert image description here

xposed_init里写当前类的路径 如果存在多个类,那么每行写一个,多个写多行

insert image description here

编译APK,在如下路径:

insert image description here

PS:编译的时候需要关闭Android Studio的instant Run功能(不太清楚为什么要关闭,我没有关闭一样可以正常使用),注意注意Android Studio 3.5往后的版本,Instant Run被HotSwap代替,如下图

insert image description here

安装apk,在Xposed模块中勾选插件,重启,此时插件已经可正常使用

insert image description here

观察日志,可通过Xposed框架内部日志模块或LogCat 查看

insert image description here

PS:Windows CMD查看日志可能是会有乱码,解决方法如下:

执行如下命令后,代码页就被变成UTF-8
chcp 65001 

insert image description here

然后修改窗口属性,改变字体在命令行标题栏上点击右键,选择"属性"->“字体”,将字体修改为True Type字体"Lucida Console",然后点击确定将属性应用到当前窗口

adb.exe shell

logcat

insert image description here

  • 方法2:下载jar文件,存放至libs目录,其它细节自行百度了解

不是网上说的单独建立lib文件夹,那是很久以前的方法,然后右键“Add As Library” 自行添加这个jar包。而compileOnly 'de.robv.android.xposed:api:82'compileOnly 'de.robv.android.xposed:api:82:sources'仍然照常添加

0x04 其它一些案例

4.1 按钮劫持Hook

实现一个APK,基础功能就是点击界面的按钮,就会弹出消息你未被劫持的消息,具体完整代码如下(test APK代码):

  • MainActivity:

import androidx.appcompat.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;

    public 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 "想啥呢?同学,我未被劫持";
    }
}
  • activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按一下按钮,确认是否被劫持"
        tools:layout_editor_absoluteX="78dp"
        tools:layout_editor_absoluteY="364dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

insert image description here

然后在HO22K 项目里面创建Xposed插件,这里博主为了偷懒,直接在一个项目里面写了,所以不加载Xposed,只要APK执行就会调用HO22K类,达到类似HO22K效果(不建议跟博主一样,自己重新创建一个APK和插件APK,不要两个都写在一起),代码和效果如下:

package com.example.ho22k;


import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class HO22K implements IXposedHookLoadPackage
{
    
    

    //Module继承了IXposedHookLoadPackage接口,当系统加载应用包的时候回回调 handleLoadPackage;
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
    
    
        //过滤包名,定位要Hook的包名
        if (loadPackageParam.packageName.equals("com.example.ho22k")) {
    
    

            //定位要Hook的具体的类名
            Class clazz = loadPackageParam.classLoader.loadClass("com.example.ho22k.MainActivity");
            //Hook的方法为toastMessage,XposedHelpers的静态方法 findAndHookMethod就是hook函数的的方法,其参数对应为   类名+loadPackageParam.classLoader(照写)+方法名+参数类型(根据所hook方法的参数的类型,即有多少个写多少个,加上.class)+XC_MethodHook回调接口;
            XposedHelpers.findAndHookMethod(clazz, "toastMessage", new XC_MethodHook() {
    
    
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
    
    
                    super.beforeHookedMethod(param);
                }

                protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
    
    
                    //param.setResult("你已被劫持")将返回的结果设置成了你已被劫持
                    param.setResult("哦吼,同学你已被劫持");
                }
            });
        }
    }
}

insert image description here
insert image description here
insert image description here
insert image description here

4.2 登陆劫持

登陆劫持密码这样的操作,首先写一个简单的登陆程序,完整代码如下:

  • MainActivity:
package com.example.ho22k;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    
    
    EditText Name;   //定义Plain Test控件第一个输入框的名字
    EditText Pass;   //定义Plain Test控件第二个输入框的名字

    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Name = (EditText) findViewById(R.id.TEXT_NAME); //通过findViewById找到输入框控件对应的id并给它起一个名字
        Pass = (EditText) findViewById(R.id.TEXT_PASS);//通过findViewById找到输入框控件对应的id并给它起一个名字
        Button Login = (Button) findViewById(R.id.BTN_Login);//通过findViewById找到按钮控件对应的id并给它起一个名字
        Login.setOnClickListener(new View.OnClickListener() {
    
      //监听有没有点击按钮控件 如果点击了就会执行onClick函数
            @Override
            public void onClick(View view) {
    
    
                check(Name.getText().toString().trim(),Pass.getText().toString().trim()); //调用check函数
            }
        });
    }
    public void check(String name,String pass)   //自定义函数check 这里用来检查用户名和密码是否是cck和1234
    {
    
    
        if(name.equals("Orangey")&&pass.equals("123456"))
        {
    
    
            Toast.makeText(MainActivity.this,"登录成功", Toast.LENGTH_SHORT).show();//弹框
        }
        else
            Toast.makeText(MainActivity.this,"登录失败", Toast.LENGTH_SHORT).show();//弹框
    }
}
  • activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="23dp"
        android:text="账号:"
        app:layout_constraintBaseline_toBaselineOf="@+id/TEXT_NAME"
        app:layout_constraintEnd_toStartOf="@+id/TEXT_NAME"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        tools:ignore="MissingConstraints" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="23dp"
        android:text="密码:"
        app:layout_constraintBaseline_toBaselineOf="@+id/TEXT_PASS"
        app:layout_constraintEnd_toStartOf="@+id/TEXT_PASS"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        tools:ignore="MissingConstraints" />

    <EditText
        android:id="@+id/TEXT_NAME"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/textView"
        android:layout_marginTop="180dp"
        android:layout_marginEnd="1dp"
        android:layout_toEndOf="@+id/textView"
        android:layout_toRightOf="@+id/textView"
        android:ems="10"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="MissingConstraints" />

    <EditText
        android:id="@+id/TEXT_PASS"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/textView2"
        android:layout_marginTop="35dp"
        android:layout_marginEnd="1dp"
        android:layout_toEndOf="@+id/textView2"
        android:layout_toRightOf="@+id/textView2"
        android:ems="10"
        android:inputType="textPassword"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView2"
        app:layout_constraintTop_toBottomOf="@+id/TEXT_NAME"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/BTN_Login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="42dp"
        android:text="登录"
        app:layout_constraintEnd_toEndOf="@+id/TEXT_PASS"
        app:layout_constraintStart_toStartOf="@+id/TEXT_PASS"
        app:layout_constraintTop_toBottomOf="@+id/TEXT_PASS" />


</androidx.constraintlayout.widget.ConstraintLayout>

账号:Orangey 密码:123456

正确的账号密码登录如下图:

insert image description here

账号:a 密码:123456
错误的账号或密码登录如下图:

insert image description here

PS:如果出现界面布局混乱,只需要设置一下约束即可,如下图:

insert image description here

目的:不管输入什么都会显示登陆成功,Hook对应的方法,并对相应的参数进行修改,还是使用上面的回调方法来实现

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;

public class HO22K implements IXposedHookLoadPackage {
    
    

    /**
     * 包加载时候的回调
     */
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
    
    

        // 将包名不是 com.example.ho22k 的应用剔除掉,可以减少管理的类
        if (!lpparam.packageName.equals("com.example.ho22k"))
            return;
        XposedBridge.log("当前APP应用程序是: " + lpparam.packageName);

        //第一个参数是className,表示被注入的方法所在的类
        //第二个参数是类加载器,照抄就行
        //第三个参数是被注入的方法名
        //第四五个参数是第三个参数的两个形参的类型
        //最后一个参数是匿名内部类
        findAndHookMethod("com.example.ho22k.MainActivity", lpparam.classLoader, "check", String.class,
                String.class, new XC_MethodHook() {
    
    

                    /**
                     * 该方法在check方法调用之前被调用,输出一些日志,并且捕获参数的值。
                     * 最后两行的目的是改变参数的值。也就是说无论参数是什么值,都会被替换为name为Orangey,pass为123456
                     * @param param
                     * @throws Throwable
                     */
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
    
    
                        XposedBridge.log("同学,你正在被人开始劫持");
                        XposedBridge.log("参数1 = " + param.args[0]);
                        XposedBridge.log("参数2 = " + param.args[1]);
                        param.args[0] = "Orangey";
                        param.args[1] = "123456";
                    }
                    /**
                     * 该方法在check方法调用之后被调用
                     * @param param
                     * @throws Throwable
                     */

                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
    
    
                        XposedBridge.log("哦吼,同学劫持已结束");
                        XposedBridge.log("参数1 = " + param.args[0]);
                        XposedBridge.log("参数2 = " + param.args[1]);

                    }
                });
    }

}

通过对方法的参数进行了重赋值,效果如下图:

insert image description here

Look in the log

Github上的一些Xposed案例APK地址:

  • 原始程序:https://github.com/Gordon0918/XposedHookTarget
  • hook修改源程序地址:https://github.com/Gordon0918/XposedHook

参考链接

https://blog.csdn.net/gdutxiaoxu/article/details/81459830

https://eastmoon.blog.csdn.net/article/details/103810710

https://blog.csdn.net/SouthWind0/article/details/100669530

https://blog.csdn.net/JBlock/article/details/84202240

https://www.cnblogs.com/mukekeheart/p/5662842.html

https://blog.csdn.net/song_lee/article/details/103299353


You think you have many paths to choose, but you only have one path to take


Guess you like

Origin blog.csdn.net/Ananas_Orangey/article/details/126219878