android_Xposed框架/init.rc语音/jni/android启动

本文深入探讨了Xposed框架的工作原理,包括RootAccess、XposedMods、动态劫持技术等,并展示了其在Android系统中的具体应用案例。此外,文章还介绍了Android初始化init.rc语言、JNI接口以及从手机中备份system.img的方法。





  Xposed框架:
  RootAccess:因为Xposed工作原理是在/system/bin目录下替换文件,在install的时候需要root权限,但是运行时不需要root权限.
  XposedMods:使用Xposed开发的一些Modules,其中AppSettings是一个可以进行权限动态管理的应用
  Xposed是rovo89针对Android平台的动态劫持项目,通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持;
  与采取传统的Inhook方式(详见Dynamic Dalvik Instrumentation分析这篇本章)相比,Xposed在开机的时候完成对所有的HookFunction的劫持,在原Function执行的前后加上自定义代码;
  Xposed框架中起作用的是对方法的hook;在Repackage技术中,如果对APK做修改,则需要修改Smali代码中的指令;而另一种动态修改指令的技术需要在程序运行时基于匹配搜索来替换smali代码,但因为方法声明的多样性与复杂性,该法比较复杂;
  在Android系统启动时,zygote进程加载XposedBridge将所有需要替换的Method通过JNI方法hookMethodNative指向Native方法xposedCallHandler,xposedCallHandler在转入handleHookedMethod这个Java方法执行用户规定的HookFunc;
  1.XposedInstaller:InstallerFragment类private String install();  执行app_process的替换与XposedBridge.jar的写入操作;
  $cp -a /system/bin/app_process /system/bin/app_process.orig;#备份原有  #把自己的app_process_xposed写入;
  $sync;#将有关文件系统的存储器常驻信息送入物理介质内;在暂停系统之前,比如要重新启动机器,一定要去执行sync命令;
  XposedInstaller是Xposed的安装包,负责配置Xposed工作的环境并且提供对基于Xposed框架的Modules的管理;在安装XposedInstaller之后,app_process与XposedBridge.jar放置在了/data/data/de.robv.android.xposed.installer;
  2.Xposed:
  Xposed的C++部分,主要是用来替换/system/bin/app_process,并为XposedBridge提供JNI方法;
  3.XposedBridge:
  XposedBridge.jar文件本质上是由XposedBridge生成的APK文件更名而来;入口,XposedBridge.main();由app_main.cpp的main函数调用;
  XposedBridge.jar是Xposed提供的jar文件,负责在Native层与FrameWork层进行交互;/system/bin/app_process进程启动过程中会加载该jar包,其它的Modules的开发与运行都是基于该jar包的;
  XposedBridge有一个私有的Native(JNI)方法hookMethodNative,这个方法也在app_process中使用;这个函数提供一个方法对象利用Java的Reflection机制来对内置方法覆写;
  XposedBridge类initXbridgeZygote():Hook系统关键函数,主要是调用XposedHelpers类中的findAndHookMethod完成;

  Xposed原理:
  Zygote,在Android系统中,应用程序进程都是由Zygote进程孵化出来的,而Zygote进程是由Init进程启动的;
  Zygote进程在启动时会创建一个Dalvik虚拟机实例,每当它孵化一个新的应用程序进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面去,从而使得每一个应用程序进程都有一个独立的Dalvik虚拟机实例;
  在Android系统启动时,zygote进程加载XposedBridge将所有需要替换的Method通过JNI方法hookMethodNative指向Native方法xposedCallHandler,xposedCallHandler在转入handleHookedMethod这个Java方法执行用户规定的HookFunc;
  在hookMethodNative的实现中,会调用XposedBridge中的handleHookedMethod这个方法来传递参数;
  handleHookedMethod这个方法类似于一个统一调度的Dispatch例程,其对应的底层的C++函数是xposedCallHandler;
  handleHookedMethod实现里面会根据一个全局结构hookedMethodCallbacks来选择相应的hook函数,并调用他们的before,after函数;
  XposedBridge的main()函数,由Zygote跳入XposedBridge执行的第一个函数;
  XposedBridge的java代码中没有so文件,它的native方法是在xposed的c代码中实现的;即在被替换的app_main中加载,通过env->RegisterNatives(*)方式;
  app_main.cpp中onVmCreated(*),调用了xposed.cpp的xposedOnVmCreated(*);  xposedOnVmCreated()调用了RegisterNatives(*);
  app_main.cpp的main函数,根据配置决定调用Xposed;    AppRuntime runtime;
  启动zygote: runtime.start(keepLoadingXposed ? "de.robv.android.xposed.XposedBridge":"com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");
  启动className: runtime.start(keepLoadingXposed ? "de.robv.android.xposed.XposedBridge":"com.android.internal.os.RuntimeInit", application ? "application" : "tool");
  Xposed在onVmCreated(JNIEnv* env)中完成了自身JNI方法的注册;



  xposed已经成型的Demo:
  显示cpu温度;显示cpu使用率;显示网络信号强度;显示内存使用率;statusBar显示wifi名称;双击statusBar进入休眠;Toast中现显示应用Icon;关机弹出多选选择对话框;
  去掉充满电警告;去掉电量低自动关机;修改app名字;app数据保护;向statusBar中添加文字;设置应用的设置参数注入;锁屏壁纸;打电话全屏显示图像;来电拦截;隐藏app;FM选择;
  添加aosp的菜单;下拉日期显示阴历;修改framework-res.apk;禁止Toast提示;修改音量上下的响应;短信SmileyRplacer;去掉截屏延时;隐藏root授权;监控启动程序;去掉设置中帐号;
  展开notification;来电振动;启动管理;修改发送sms成功为Notify提示;去掉位置确认对话框;隐藏adb连接确认;





 
  Android初始化init.rc语言:
  由四大类声明组成:行为类(Actions);命令类(Commands);服务类(Services);选项类(Options);
  初始化语言以行为单位,由以空格间隔的语言符号组成;C风格的反斜杠转义符可以用来插入空白到语言符号;双引号也可以用来防止文本被空格分成多个语言符号;当反斜杠在行末时,作为折行符;
  以#开始(前面允许有空格)的行为注释行;
  Actions和Services隐含声明一个新的段落;所有该段落下Commands或Options的声明属于该段落;第一段落前的Commands或Options被忽略;
  Actions和Services拥有独一无二的命名;在它们之后声明相同命名的类将被当作错误并忽略;
  调试,默认情况下,init执行的程序输出的信息和错误到/dev/null;可以通过Android程序logwrapper执行你的程序,这将复位向输出错误输出到AndroidLogging系统(通过logcat访问);
  $service akmd /system/bin/logwrapper /sbin/akmd;




 
  JNI:
  System.loadLibrary("hello-jni");时会调用JNI_OnLoad();可以使用RegisterNatives注册本地方法;
  JNIEnv是一个与线程相关的变量,不同线程的JNIEnv彼此独立;sdk文档中强调了do not cache JNIEnv*,要用的时候在不同线程中再通过JavaVM *jvm的方法来获取与当前线程相关的JNIEnv*;
  JavaVM是虚拟机在JNI层的代表,在一个虚拟机进程中只有一个JavaVM,因此该进程的所有线程都可以使用这个JavaVM;
  当后台线程需要调用JNINative时,在native库中使用全局变量保存JavaVM尤为重要,这样使得后台线程能通过JavaVM获得JNIEnv;
  在C中,使用JNIEnv* env要这样,(*env)->方法名(env,参数列表);  使用JavaVM* vm要这样,(*vm)->方法名(vm,参数列表);
  在C++中,使用JNIEnv* env要这样,env->方法名(参数列表);  使用JavaVM* vm要这样,vm->方法名(参数列表);
  上面这二者的区别是,在C中必须先对env和vm间接寻址(得到的内容仍然是一个指针),在调用方法时要将env或vm传入作为第一个参数;C++则直接利用env和vm指针调用其成员;
  JavaVM接口,第一种方式,在加载动态链接库的时候,JVM会调用JNI_OnLoad(JavaVM* jvm, void* reserved)(如果定义了该函数);
  第二种方式,在native code中调用JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)可以得到JavaVM指针;
  两种情况下,都可以用全局变量,比如JavaVM* g_jvm来保存获得的指针以便在任意上下文中使用;Android系统是利用第二种方式Invocation interface来创建JVM的;
  JNIEnv接口,当创建的线程需要获取JNIEnv*的时候,最好在刚创建的时候调用一次AttachCurrentThread,不要缓存这个JNIEnv*,每次需要的时候通过JavaVM*获取,不要忘记线程结束的时候执行DettachCurrentThread;


  从手机中备份system.img:
  $cat proc/mtd; #depress.
  $ls -l /dev/block/platform/{your_platform_name_here}/by-name; #查阅文件挂载对应设备;
  #dd if=/dev/block/mmcblk0p22 of=/sdcard/system.img bs=4096; #导出后,$file system.img;$sudo mount ***;即可;
  #dd if=/dev/block/mmcblk0p14 of=/sdcard/boot.img bs=4096; #把指定的输入文件拷贝到指定的输出文件中,并且在拷贝的过程中可以进行格式转换;
  两个特殊的设备: /dev/null,回收站/无底洞; /dev/zero,产生字符;

  Android启动过程:
  ZygoteInit.java,静态函数startSystemServer(*),启动新进程Zygote.forkSystemServer(*);forkSystemServer(*)内部调用nativeForkAndSpecialize();
  由UBOOT传入一个init参数,这个init参数制定了开机的时候运行的第一个运行的程序,默认就是init程序,这个程序就在ramdisk.img中,它的源文件在system/core/init/init.c中;入口,main()函数;
  它会调用init.rc初始化这个文件,这个文件在out/target/product/generic/root下;启动以后,会发现根目录是只读属性的,而且sdcard的owner是system,就是在这个文件中做了些手脚,可以将它改过来,实现根目录的可读写;
  android启动时首先加载的是ramdisk.img镜像,并挂载到/目录下,并进行一系列的初始化动作,包括创建各种需要的目录,初始化console,开启服务等;
  system.img是在init.rc中指定一些脚本命令,通过init.c进行解析并挂载到根目录下的/system目录下的;
  ZygoteInit.java在/frameworks/base/core/java/com/android/internal/os/目录下
  Zygote.java在/libcore/dalvik/src/main/java/dalvik/system/目录下;
  对应jni目录/dalvik/vm/native/dalvik_system_Zygote.cpp;最终调用的是linuxKernel的fork()函数;




<think>我们正在解决Android开发中Xposed模块导入相关类时报错的问题。根据引用内容,我们已经正确配置了AndroidManifest.xml文件,将模块标识为Xposed模块。现在的问题是导入Xposed类时找不到。 原因分析:通常,这是因为项目中没有正确引入Xposed Bridge API库。 解决方案: 1. 在项目的build.gradle(Module级别)中添加Xposed Bridge API的依赖。 由于Xposed Bridge API并不在Maven中央仓库中,我们需要手动下载jar包或者使用JitPack仓库。 方法一(推荐):使用JitPack仓库 步骤: a. 在项目根目录的build.gradle中添加JitPack仓库: allprojects { repositories { ... maven { url 'https://jitpack.io' } } } b. 在模块的build.gradle中添加依赖: dependencies { // 使用Xposed Bridge API compileOnly 'de.robv.android.xposed:api:82' // 如果需要带源码的版本(调试用),可以使用: // compileOnly 'de.robv.android.xposed:api:82:sources' } 方法二:手动下载jar包 步骤: a. 从官网下载API:https://api.xposed.info/reference/packages.html 选择最新版本(例如82)的jar包。 b. 将下载的jar包放入项目的libs目录(如果没有则创建)。 c. 在build.gradle中添加依赖: dependencies { compileOnly files('libs/api-82.jar') } 2. 同步Gradle(点击Sync Now)。 3. 确保在AndroidManifest.xml中已经按照引用[1][2]的说明添加了meta-data标签。 4. 如果仍然报错,检查是否使用了正确的包名(注意:XposedHelpers等类在de.robv.android.xposed包下)。 5. 如果使用手动下载的jar包,可能需要设置jar包为provided(即compileOnly)作用域,因为Xposed框架在运行时已经提供了这些类。 6. 清理并重新构建项目(Build -> Clean Project, Build -> Rebuild Project)。 7. 如果以上步骤都正确,应该可以解决导入报错问题。 注意:在编写Xposed模块时,我们通常不会将Xposed API打包进APK,因为它们在运行时由Xposed框架提供。因此使用compileOnly(或provided)作用域。 示例build.gradle(Module)的部分内容: ``` dependencies { compileOnly 'de.robv.android.xposed:api:82' // 其他依赖... } ``` 如果使用新版本的Android Studio(如使用Gradle 7.0以上),可能需要使用implementation或compileOnly,注意不要使用api(除非需要传递依赖)。 另外,请确保在Xposed模块的入口类(实现IXposedHookLoadPackage等接口的类)中,按照Xposed的要求在assets目录下创建xposed_init文件,并在其中写入入口类的全限定名(例如:com.example.myxposedmodule.MyXposedModule)。 如果问题依然存在,请检查Android Studio的缓存(File -> Invalidate Caches / Restart)并重启。 希望这些步骤能解决您的问题。</think>### 解决Xposed模块导入类报错问题 在Android Studio中导入Xposed类时报错`import de.robv.android.xposed...`找不到,通常是由于**依赖配置错误**或**作用域设置不正确**导致。以下是完整解决方案: --- ### 步骤1:添加Xposed API依赖 在模块的`build.gradle`文件中添加依赖(注意使用`compileOnly`作用域): ```groovy dependencies { // Xposed API核心依赖 compileOnly 'de.robv.android.xposed:api:82' // 可选:包含源码的版本(调试用) compileOnly 'de.robv.android.xposed:api:82:sources' } ``` **关键点说明**: - 使用`compileOnly`而非`implementation`:Xposed框架在运行时已提供这些类,避免打包进APK[^1] - 版本号`82`需匹配Xposed框架版本(可通过[Xposed API文档](https://api.xposed.info/reference/packages.html)查询最新) --- ### 步骤2:配置仓库地址 在项目根目录的`build.gradle`中添加JitPack仓库: ```groovy allprojects { repositories { google() mavenCentral() // 添加Xposed依赖源 maven { url 'https://jitpack.io' } } } ``` --- ### 步骤3:验证AndroidManifest配置 确保已按规范声明Xposed模块元数据(引用自站内示例): ```xml <meta-data android:name="xposedmodule" android:value="true" /> <!-- 模块标识 --> <meta-data android:name="xposeddescription" android:value="模块功能描述" /> <!-- 模块描述 --> <meta-data android:name="xposedminversion" android:value="89" /> <!-- 最低Xposed版本 --> ``` --- ### 步骤4:解决常见问题场景 | 问题现象 | 解决方案 | |---------|---------| | 同步后仍报`ClassNotFound` | 1. 执行 **File > Invalidate Caches**<br>2. 删除`.gradle`和`build`目录后重建 | | 方法钩子运行时失效 | 检查`xposed_init`文件是否在`assets`目录正确声明入口类 | | 新版Android Studio报错 | 将`compileOnly`替换为`compileOnly`(Gradle 7.0+) | --- ### 步骤5:创建模块入口文件 在`src/main/assets/`下新建`xposed_init`文本文件,内容为入口类的**全限定名**: ``` com.example.myhook.HookEntryClass ``` --- ### 验证配置 创建测试钩子类验证导入是否正常: ```java package com.example.myhook; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.callbacks.XC_LoadPackage; public class HookEntry implements IXposedHookLoadPackage { @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { // 模块加载日志(可在Xposed日志中查看) XposedBridge.log("模块已加载到: " + lpparam.packageName); } } ``` > ⚠️ **注意**:无需在代码中显式注册钩子类,Xposed框架通过`xposed_init`自动加载入口类[^2]。 --- ### 最终项目结构 ``` app/ ├── build.gradle # 包含Xposed依赖 ├── src/main/ │ ├── AndroidManifest.xml # 包含<meta-data>配置 │ ├── assets/ │ │ └── xposed_init # 入口类声明文件 │ └── java/ │ └── com/example/myhook/ │ └── HookEntry.java # 钩子实现类 ``` 通过以上步骤,90%的导入报错问题可解决。若仍存在问题,请检查Xposed框架版本兼容性(`xposedminversion`需≤设备安装的Xposed版本)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值