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_main
Referenced res/layout/activity_main.xml
documents.
onCreate() One of many methods called after the activity is loaded.
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.MAIN
indicate that this activity is used as the entry point of the application.
The category of the intent filter is named to android.intent.category.LAUNCHER
indicate that the application can be launched from the icon in the device launcher.
@string
It refers to strings.xml, so @string/app_name
it refers to the app_name defined in strings.xml, which is actually "HO22K"
1.10.3 activity_main.xml file
activity_main.xml
It 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_height
etc. used to set its width and height. Here we show it a sentence "Orange Fragrance Hook", quoted from the strings.xml file
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
打开刚刚安装好的Xposed
这里为了方便选择永久记住
安装Xposed可能会出现如下情况:
安装完毕后可能会出现未激活, 拉入JustTrustMe.apk, 然后重启模拟器就可以了
然后修改wifi的ip和端口
- 下载
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
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吧。(这个是模块的界面,随意选择即可)
新建完成后下载依赖时,可能会出现如下报错(是没有科学上网导致的,要么你科学上网,要么你把gradle版本下载到本地来安装
改为如下地址:
distributionUrl=file:///C:/Users/xxxxx/.gradle/wrapper/dists/gradle-7.2-bin.zip
然后又有可能发现gradle插件下载又出现问题,解决办法如下:
如上图,注释掉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'}
以及如下位置:
最后关闭Android Studio,再重新打开项目会自动加载,此时如果没有再有红色警示就代表OK了,然后直接编译一个Demo的APK(app/build/outputs/apk/debug目录下,可以看到app-debug.apk),看看是否能正常运行,如下图:
放到模拟器中,发现能正常安装并运行,如下图:
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"/>
修改文本内容为:橙留香的HooK
此时把编译好的APK丢进去,打开后,如下
PS:从上图已看出,Xposed框架已经认出了刚刚写的程序,但是现在这个模块什么都没有做,因为我们还没有做出修改
3.3 配置XposedBridgeApi-xx.jar
与build.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”,同步即可,如下:
3.4 实现hook操作修改
在MainActivity的同级路径下新建一个类“HO22K.java”,操作如下图:
代码如下:
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成功咯,宝们~_~!");
}
}
3.5 添加入口点xposed_Init
右键点击 “main” 文件夹 , 选择new --> Folder -->Assets Folder,新建assets 文件夹:
然后右键点击 assets文件夹, new–> file,文件名为xposed_init(文件类型选text),并在其中写上入口类的完整路径(就是自己编写的那一个Hook类),这样, Xposed框架就能够从这个 xposed_init 读取信息来找到模块的入口,然后进行Hook操作了
xposed_init里写当前类的路径 如果存在多个类,那么每行写一个,多个写多行
编译APK,在如下路径:
PS:编译的时候需要关闭Android Studio的instant Run功能(不太清楚为什么要关闭,我没有关闭一样可以正常使用),注意注意Android Studio 3.5往后的版本,Instant Run被HotSwap代替,如下图
安装apk,在Xposed模块中勾选插件,重启,此时插件已经可正常使用
观察日志,可通过Xposed框架内部日志模块或LogCat 查看
PS:Windows CMD查看日志可能是会有乱码,解决方法如下:
执行如下命令后,代码页就被变成UTF-8
chcp 65001
然后修改窗口属性,改变字体在命令行标题栏上点击右键,选择"属性"->“字体”,将字体修改为True Type字体"Lucida Console",然后点击确定将属性应用到当前窗口
adb.exe shell
logcat
- 方法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>
然后在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("哦吼,同学你已被劫持");
}
});
}
}
}
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
正确的账号密码登录如下图:
账号:a 密码:123456
错误的账号或密码登录如下图:
PS:如果出现界面布局混乱,只需要设置一下约束即可,如下图:
目的:不管输入什么都会显示登陆成功,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]);
}
});
}
}
通过对方法的参数进行了重赋值,效果如下图:
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