新人想问下arm64arm架构和x86架构分别适用什么手机

Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题
发表于 14:46:38
4560人阅读
分类: Android应用开发
问题描述解决方法
1解决之前的截图2解决后的截图3解决方法为什么你需要重点关注so文件App中可能出错的地方其他地" />
我的Android进阶之旅------&Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题 - CSDN博客
我的Android进阶之旅------&Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题
我的Android进阶之旅------&Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题
分类:&Android应用开发
今天测试人员测试集成版本时除了一个bug:关于华为 Mate 8手机Android 6.0系统运行刚刚提测的版本时,出现闪退的bug,而小米 4 手机Android 6.0系统却没有出现任何bug,运行良好。后来查看本人相关模块的代码,发现本人集成版本相关模块的代码和分支版本相关模块的代码是一模一样的,那就是说本人把分支代码合并到主干代码是没有问题的,所以去查看主干代码的问题。
经过一番查看提交日志,发现有位同事再我合并代码之前,提交了一个关于友盟推送的so文件的记录,原来他加入了一个arm64-v8a文件夹,里面有友盟推送的arm64-v8a的so库文件。而其他的so库文本却没有arm64-v8a对应的版本。
通过百度查到知乎有一段关于arm64-v8a的解释:
arm64-v8a是可以向下兼容的,但前提是你的项目里面没有arm64-v8a的文件夹,如果你有两个文件夹armeabi和arm64-v8a,两个文件夹,armeabi里面有a.so 和 b.so,arm64-v8a里面只有a.so,那么arm64-v8a的手机在用到b的时候发现有arm64-v8a的文件夹,发现里面没有b.so,就报错了,所以这个时候删掉arm64-v8a文件夹,这个时候手机发现没有适配arm64-v8a,就会直接去找armeabi的so库,所以要么你别加arm64-v8a,要么armeabi里面有的so库,arm64-v8a里面也必须有
作者:green jim&
来源:知乎&
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
发现原来华为 Mate 8手机是64位的操作系统,而小米 4 手机是32位的操作系统,所以小米 4 手机手机运行APP没bug,而华为 Mate 8手机运行APP出现闪退bug。
1、解决之前的截图:
从截图可以看出来,第一个项目中有&arm64-v8a,而没有x86目录,第二个项目中没有&arm64-v8a,而有x86目录。第一个项目是作为项目引用导入到第二个项目中的。
2、解决后的截图:
从截图可以看出来,第一个项目中和第二个项目中没有的libs目录下,都是armeabi-v7a、armeabi、x86三个目录,保持一致。第一个项目是作为项目引用导入到第二个项目中的。
3、解决方法:
解决方法是:从友盟官方中去下载x86的相关so文件,放在x86目录下,把arm64-v8a目录删除。将所有关于so文件的都要保持一致,即:如果你要添加一个armeabi-v8a目录,下面放第三方的armeabi-v8a相关的so文件,那么你其他的so文件都要有相应想armeabi-v8a版本,不然就会报错。
下面文章转载于asce1885(简书作者):&
(原文链接:)&
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
早期的Android系统几乎只支持ARMv5的CPU架构,你知道现在它支持多少种吗?7种!
Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。
应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。在Android系统上,每一个CPU架构对应一个ABI:armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64。
为什么你需要重点关注.so文件
如果项目中使用到了NDK,它将会生成.so文件,因此显然你已经在关注它了。如果只是使用Java语言进行编码,你可能在想不需要关注.so文件了吧,因为Java是跨平台的。但事实上,即使你在项目中只是使用Java语言,很多情况下,你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI。
例如,项目中使用RenderScript支持库,OpenCV,Unity,android-gif-drawable,SQLCipher等,你都已经在生成的APK文件中包含.so文件了,而你需要关注.so文件。
Android应用支持的ABI取决于APK中位于lib/ABI目录中的.so文件,其中ABI可能是上面说过的七种ABI中的一种。&
这个应用可以帮助我们理解手机上安装的APK用到了哪些.so文件,以及.so文件来源于哪些函数库或者框架。
当然,我们也可以自己对app反编译来获取这些信息,不过相对麻烦一些。
很多设备都支持多于一种的ABI。例如ARM64和x86设备也可以同时运行armeabi-v7a和armeabi的二进制包。但最好是针对特定平台提供相应平台的二进制包,这种情况下运行时就少了一个模拟层(例如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于最近的架构更新,例如硬件fpu,更多的寄存器,更好的向量化等)。
我们可以通过Build.SUPPORTED_ABIS得到根据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,因为Android包管理器安装APK时,会自动选择APK包中为对应系统ABI预编译好的.so文件,如果在对应的lib/ABI目录中存在.so文件的话。
App中可能出错的地方
处理.so文件时有一条简单却并不知名的重要法则。
你应该尽可能的提供专为每个ABI优化过的.so文件,但要么全部支持,要么都不支持:你不应该混合着使用。你应该为每个ABI目录提供对应的.so文件。
当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。在x86设备上,libs/x86目录中如果存在.so文件的话,会被安装,如果不存在,则会选择armeabi-v7a中的.so文件,如果也不存在,则选择armeabi目录中的.so文件(因为x86设备也支持armeabi-v7a和armeabi)。
其他地方也可能出错
当你引入一个.so文件时,不止影响到CPU架构。我从其他开发者那里可以看到一系列常见的错误,其中最多的是”UnsatisfiedLinkError”,”dlopen: failed”以及其他类型的crash或者低下的性能:
使用android-21平台版本编译的.so文件运行在android-15的设备上
使用NDK时,你可能会倾向于使用最新的编译平台,但事实上这是错误的,因为NDK平台不是后向兼容的,而是前向兼容的。推荐使用app的minSdkVersion对应的编译平台。
这也意味着当你引入一个预编译好的.so文件时,你需要检查它被编译所用的平台版本。
混合使用不同C++运行时编译的.so文件
.so文件可以依赖于不同的C++运行时,静态编译或者动态加载。混合使用不同版本的C++运行时可能导致很多奇怪的crash,是应该避免的。作为一个经验法则,当只有一个.so文件时,静态编译C++运行时是没问题的,否则当存在多个.so文件时,应该让所有的.so文件都动态链接相同的C++运行时。
这意味着当引入一个新的预编译.so文件,而且项目中还存在其他的.so文件时,我们需要首先确认新引入的.so文件使用的C++运行时是否和已经存在的.so文件一致。
没有为每个支持的CPU架构提供对应的.so文件
这一点在前文已经说到了,但你应该真的特别注意它,因为它可能发生在根本没有意识到的情况下。
例如:你的app支持armeabi-v7a和x86架构,然后使用Android Studio新增了一个函数库依赖,这个函数库包含.so文件并支持更多的CPU架构,例如新增android-gif-drawable函数库:
‘.droidsonroids.gif:android-gif-drawable:1.1.+’1
发布我们的app后,会发现它在某些设备上会发生Crash,例如Galaxy S6,最终可以发现只有64位目录下的.so文件被安装进手机。
解决方案:重新编译我们的.so文件使其支持缺失的ABIs,或者设置
ndk.abiFilters1
显示指定支持的ABIs。
最后一点:如果你是一个SDK提供者,但提供的函数库不支持所有的ABIs,那你将会搞砸你的用户,因为他们能支持的ABIs必将只能少于你提供的。
将.so文件放在错误的地方
我们往往很容易对.so文件应该放在或者生成到哪里感到困惑,下面是一个总结:
Android Studio工程放在jniLibs/ABI目录中(当然也可以通过在build.gradle文件中的设置jniLibs.srcDir属性自己指定)Eclipse工程放在libs/ABI目录中(这也是ndk-build命令默认生成.so文件的目录)AAR压缩包中位于jni/ABI目录中(.so文件会自动包含到引用AAR压缩包的APK中)最终APK文件中的lib/ABI目录中通过PackageManager安装后,在小于Android 5.0的系统中,.so文件位于app的nativeLibraryPath目录中;在大于等于Android 5.0的系统中,.so文件位于app的nativeLibraryRootDir/CPU_ARCH目录中。
只提供armeabi架构的.so文件而忽略其他ABIs的
所有的x86/x86_64/armeabi-v7a/arm64-v8a设备都支持armeabi架构的.so文件,因此似乎移除其他ABIs的.so文件是一个减少APK大小的好技巧。但事实上并不是:这不只影响到函数库的性能和兼容性。
x86设备能够很好的运行ARM类型函数库,但并不保证100%不发生crash,特别是对旧设备。64位设备(arm64-v8a, x86_64, mips64)能够运行32位的函数库,但是以32位模式运行,在64位平台上运行32位版本的ART和Android组件,将丢失专为64位优化过的性能(ART,webview,media等等)。
以减少APK包大小为由是一个错误的借口,因为你也可以选择在应用市场上传指定ABI版本的APK,生成不同ABI版本的APK可以在build.gradle中如下配置:
enable true
include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
universalApk true //generate an additional APK that contains all the ABIs
// map for the version code
project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
android.applicationVariants.all { variant -&
// assign different version code for each output
variant.outputs.each { output -&
output.versionCodeOverride =
project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
}12345678910111213141516171819202122
版权声明:本文为【欧阳鹏】原创文章,欢迎转载,转载请注明出处! 【】
本文已收录于以下专栏:
相关文章推荐
Kaltura是一个很优秀的开源视频平台。提供了视频的管理系统,视频的在线编辑系统等等一整套完整的系统,功能甚是强大。
Kaltura不同于其他诸如Brightcove,Ooyala这样的网络视频...
jni中arm64-v8a,armeabi-v7a,armeabi文件夹的意义和用法起因之前并没有关注这块,直到:您的应用被拒绝,原因:xplay5sQ心里点击笑值点击拍照显示停止运行,查看发过来的日...
LZ是一名96年Android小生,从14年9月培训出来到现在,差不多俩年多的时间,由于一些原因,没能好好把技术提升一下,实乃不该啊。
了解起因昨天师傅问,你知道这俩个是什么么?有什么作用么?(如下图...
供稿:阿普奇科技股份有限公司
人气:1036
ARM 摘要:Android本是Go...
早期的Android系统几乎只支持ARMv5的CPU架构,而现在Android平台支持7种不同的CPU架构,他们分别是ARMv5,ARMv7 (从2010年起),x86 (从2011...
Android x86 默认不带houdini,运行纯ARM版会提示:很抱歉,”xxxx”已停止运行设置->应用兼容性->打开终端模拟器$ su
# enable_nativebridge脚本会自动下...
Android5.1上的测试
1、android.security.cts.SELinuxDomainTest# testInitDomain fail
junit.framework....
Android armeabi
armeabi-v7a
拣主要的来了:
理论上仅在armeabi文件夹下生成so文件即可在所有的arm处理器机型上运行,终于找到一点权威的资料了
我遇到一个小问题Android 的 so 库和 ABI 配置我原先也是没有什么概念的,直到上个周,在我尝试跑一个程序的时候,真机运行没问题,但是用伟大的模拟机的时候,遇到了这么一个错误:模拟机的下面显...
java.lang.UnsatisfiedLinkError:dlopen failed: “**/*/arm/*.so” has unexpected e_machine: 3
原因分析ap...
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)我的Android进阶之旅------>Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题 - android-x86 - ITkeyowrd
Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题 - android-x86">
我的Android进阶之旅------>Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题
Android 设备的CPU类型(通常称为”ABIs”)
armeabiv-v7a: 第7代及以上的 ARM 处理器。2011年15月以后的生产的大部分Android设备都使用它.
arm64-v8a: 第8代、64位ARM处理器,很少设备,三星 Galaxy S6是其中之一。
armeabi: 第5代、第6代的ARM处理器,早期的手机用的比较多。
x86: 平板、模拟器用得比较多。
x86_64: 64位的平板。
今天测试人员测试集成版本时除了一个bug:关于华为 Mate 8手机Android 6.0系统运行刚刚提测的版本时,出现闪退的bug,而小米 4 手机Android 6.0系统却没有出现任何bug,运行良好。后来查看本人相关模块的代码,发现本人集成版本相关模块的代码和分支版本相关模块的代码是一模一样的,那就是说本人把分支代码合并到主干代码是没有问题的,所以去查看主干代码的问题。
经过一番查看提交日志,发现有位同事再我合并代码之前,提交了一个关于友盟推送的so文件的记录,原来他加入了一个arm64-v8a文件夹,里面有友盟推送的arm64-v8a的so库文件。而其他的so库文本却没有arm64-v8a对应的版本。
通过百度查到知乎有一段关于arm64-v8a的解释:
arm64-v8a是可以向下兼容的,但前提是你的项目里面没有arm64-v8a的文件夹,如果你有两个文件夹armeabi和arm64-v8a,两个文件夹,armeabi里面有a.so 和 b.so,arm64-v8a里面只有a.so,那么arm64-v8a的手机在用到b的时候发现有arm64-v8a的文件夹,发现里面没有b.so,就报错了,所以这个时候删掉arm64-v8a文件夹,这个时候手机发现没有适配arm64-v8a,就会直接去找armeabi的so库,所以要么你别加arm64-v8a,要么armeabi里面有的so库,arm64-v8a里面也必须有
作者:green jim
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
发现原来华为 Mate 8手机是64位的操作系统,而小米 4 手机是32位的操作系统,所以小米 4 手机手机运行APP没bug,而华为 Mate 8手机运行APP出现闪退bug。
1、解决之前的截图:
从截图可以看出来,第一个项目中有 arm64-v8a,而没有x86目录,第二个项目中没有 arm64-v8a,而有x86目录。第一个项目是作为项目引用导入到第二个项目中的。
2、解决后的截图:
从截图可以看出来,第一个项目中和第二个项目中没有的libs目录下,都是armeabi-v7a、armeabi、x86三个目录,保持一致。第一个项目是作为项目引用导入到第二个项目中的。
3、解决方法:
解决方法是:从友盟官方中去下载x86的相关so文件,放在x86目录下,把arm64-v8a目录删除。将所有关于so文件的都要保持一致,即:如果你要添加一个armeabi-v8a目录,下面放第三方的armeabi-v8a相关的so文件,那么你其他的so文件都要有相应想armeabi-v8a版本,不然就会报错。
来自于博客:给的建议是:
为了减小 apk 体积,只保留 armeabi 和 armeabi-v7a 两个文件夹,并保证这两个文件夹中 .so 数量一致
对只提供 armeabi 版本的第三方 .so,原样复制一份到 armeabi-v7a 文件夹
下面文章转载于asce1885(简书作者):
(原文链接:)
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
早期的Android系统几乎只支持ARMv5的CPU架构,你知道现在它支持多少种吗?7种!
Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。
应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。在Android系统上,每一个CPU架构对应一个ABI:armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64。
为什么你需要重点关注.so文件
如果项目中使用到了NDK,它将会生成.so文件,因此显然你已经在关注它了。如果只是使用Java语言进行编码,你可能在想不需要关注.so文件了吧,因为Java是跨平台的。但事实上,即使你在项目中只是使用Java语言,很多情况下,你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI。
例如,项目中使用RenderScript支持库,OpenCV,Unity,android-gif-drawable,SQLCipher等,你都已经在生成的APK文件中包含.so文件了,而你需要关注.so文件。
Android应用支持的ABI取决于APK中位于lib/ABI目录中的.so文件,其中ABI可能是上面说过的七种ABI中的一种。
这个应用可以帮助我们理解手机上安装的APK用到了哪些.so文件,以及.so文件来源于哪些函数库或者框架。
当然,我们也可以自己对app反编译来获取这些信息,不过相对麻烦一些。
很多设备都支持多于一种的ABI。例如ARM64和x86设备也可以同时运行armeabi-v7a和armeabi的二进制包。但最好是针对特定平台提供相应平台的二进制包,这种情况下运行时就少了一个模拟层(例如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于最近的架构更新,例如硬件fpu,更多的寄存器,更好的向量化等)。
我们可以通过Build.SUPPORTED_ABIS得到根据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,因为Android包管理器安装APK时,会自动选择APK包中为对应系统ABI预编译好的.so文件,如果在对应的lib/ABI目录中存在.so文件的话。
App中可能出错的地方
处理.so文件时有一条简单却并不知名的重要法则。
你应该尽可能的提供专为每个ABI优化过的.so文件,但要么全部支持,要么都不支持:你不应该混合着使用。你应该为每个ABI目录提供对应的.so文件。
当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。在x86设备上,libs/x86目录中如果存在.so文件的话,会被安装,如果不存在,则会选择armeabi-v7a中的.so文件,如果也不存在,则选择armeabi目录中的.so文件(因为x86设备也支持armeabi-v7a和armeabi)。
其他地方也可能出错
当你引入一个.so文件时,不止影响到CPU架构。我从其他开发者那里可以看到一系列常见的错误,其中最多的是”UnsatisfiedLinkError”,”dlopen: failed”以及其他类型的crash或者低下的性能:
使用android-21平台版本编译的.so文件运行在android-15的设备上
使用NDK时,你可能会倾向于使用最新的编译平台,但事实上这是错误的,因为NDK平台不是后向兼容的,而是前向兼容的。推荐使用app的minSdkVersion对应的编译平台。
这也意味着当你引入一个预编译好的.so文件时,你需要检查它被编译所用的平台版本。
混合使用不同C++运行时编译的.so文件
.so文件可以依赖于不同的C++运行时,静态编译或者动态加载。混合使用不同版本的C++运行时可能导致很多奇怪的crash,是应该避免的。作为一个经验法则,当只有一个.so文件时,静态编译C++运行时是没问题的,否则当存在多个.so文件时,应该让所有的.so文件都动态链接相同的C++运行时。
这意味着当引入一个新的预编译.so文件,而且项目中还存在其他的.so文件时,我们需要首先确认新引入的.so文件使用的C++运行时是否和已经存在的.so文件一致。
没有为每个支持的CPU架构提供对应的.so文件
这一点在前文已经说到了,但你应该真的特别注意它,因为它可能发生在根本没有意识到的情况下。
例如:你的app支持armeabi-v7a和x86架构,然后使用Android Studio新增了一个函数库依赖,这个函数库包含.so文件并支持更多的CPU架构,例如新增android-gif-drawable函数库:
compile ‘pl.droidsonroids.gif:android-gif-drawable:1.1.+’
发布我们的app后,会发现它在某些设备上会发生Crash,例如Galaxy S6,最终可以发现只有64位目录下的.so文件被安装进手机。
解决方案:重新编译我们的.so文件使其支持缺失的ABIs,或者设置
ndk.abiFilters
显示指定支持的ABIs。
最后一点:如果你是一个SDK提供者,但提供的函数库不支持所有的ABIs,那你将会搞砸你的用户,因为他们能支持的ABIs必将只能少于你提供的。
将.so文件放在错误的地方
我们往往很容易对.so文件应该放在或者生成到哪里感到困惑,下面是一个总结:
Android Studio工程放在jniLibs/ABI目录中(当然也可以通过在build.gradle文件中的设置jniLibs.srcDir属性自己指定)
Eclipse工程放在libs/ABI目录中(这也是ndk-build命令默认生成.so文件的目录)
AAR压缩包中位于jni/ABI目录中(.so文件会自动包含到引用AAR压缩包的APK中)
最终APK文件中的lib/ABI目录中
通过PackageManager安装后,在小于Android 5.0的系统中,.so文件位于app的nativeLibraryPath目录中;在大于等于Android 5.0的系统中,.so文件位于app的nativeLibraryRootDir/CPU_ARCH目录中。
只提供armeabi架构的.so文件而忽略其他ABIs的
所有的x86/x86_64/armeabi-v7a/arm64-v8a设备都支持armeabi架构的.so文件,因此似乎移除其他ABIs的.so文件是一个减少APK大小的好技巧。但事实上并不是:这不只影响到函数库的性能和兼容性。
x86设备能够很好的运行ARM类型函数库,但并不保证100%不发生crash,特别是对旧设备。64位设备(arm64-v8a, x86_64, mips64)能够运行32位的函数库,但是以32位模式运行,在64位平台上运行32位版本的ART和Android组件,将丢失专为64位优化过的性能(ART,webview,media等等)。
以减少APK包大小为由是一个错误的借口,因为你也可以选择在应用市场上传指定ABI版本的APK,生成不同ABI版本的APK可以在build.gradle中如下配置:
enable true
include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
universalApk true //generate an additional APK that contains all the ABIs
// map for the version code
project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
android.applicationVariants.all { variant -&
// assign different version code for each output
variant.outputs.each { output -&
output.versionCodeOverride =
project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
版权声明:本文为【欧阳鹏】原创文章,欢迎转载,转载请注明出处! 【】
Android 设备的CPU类型通常称为ABIs 问题描述 解决方法 1解决之前的截图 2解决后的截图 3解决方法 4建议 为什么你需要重点关注so文件 App中可能出错的地方 其他地方也可能出错 使用android-21平
相关阅读排行
相关内容推荐
请激活账号
为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。
您的注册邮箱:
如果您没有收到激活邮件,请注意检查垃圾箱。Android arm64(aarch64)中的so注入(inject) - 兼容x86 and arm
时间: 16:53:07
实现Android arm64(aarch64)中的so(inject) ,并且x86和arm。如果没有搞错,这是国内外第一份的arm64注入的针对性~~
代码基于 ariesjzj 的 《Android中的so注入(inject)和(hook)
- For both x86 and arm 》,增加了对arm64的支持。(目前已经开始有64位安卓手机)
,代码由jni中三个文件。
&&& inject.c
&&& Android.mk
&&& Application.mk
其中Android.mk一样,Application.mk中
APP_ABI := arm64-v8ainject.c如下:
#include &stdio.h&
#include &stdlib.h&
#include &asm/user.h&
#include &asm/ptrace.h&
#include &sys/ptrace.h&
#include &sys/wait.h&
#include &sys/mman.h&
#include &dlfcn.h&
#include &dirent.h&
#include &unistd.h&
#include &string.h&
#include &elf.h&
#include &android/log.h&
#include &sys/uio.h&
#if defined(__i386__)
#define pt_regs
user_regs_struct
#elif defined(__aarch64__)
#define pt_regs
user_pt_regs
#define uregs regs
#define ARM_pc pc
#define ARM_sp sp
#define ARM_cpsr pstate
#define ARM_lr
#define ARM_r0
#define PTRACE_GETREGS PTRACE_GETREGSET
#define PTRACE_SETREGS PTRACE_SETREGSET
#define ENABLE_DEBUG 1
#if ENABLE_DEBUG
LOG_TAG &INJECT&
LOGD(fmt, args...)
__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, fmt, ##args)
#define DEBUG_PRINT(format,args...) \
LOGD(format, ##args)
#define DEBUG_PRINT(format,args...)
#define CPSR_T_MASK
( 1u && 5 )
#if defined(__aarch64__)
const char *libc_path = &/system/lib64/libc.so&;
const char *linker_path = &/system/bin/linker64&;
const char *libc_path = &/system/lib/libc.so&;
const char *linker_path = &/system/bin/linker&;
int ptrace_readdata(pid_t pid,
uint8_t *src, uint8_t *buf, size_t size)
long i, j,
size_t bytes_width = sizeof(long);
char chars[bytes_width];
j = size / bytes_
remain = size % bytes_
for (i = 0; i & i ++) {
d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0);
memcpy(laddr, d.chars, bytes_width);
src += bytes_
laddr += bytes_
if (remain & 0) {
d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0);
memcpy(laddr, d.chars, remain);
int ptrace_writedata(pid_t pid, uint8_t *dest, uint8_t *data, size_t size)
long i, j,
size_t bytes_width = sizeof(long);
char chars[bytes_width];
j = size / bytes_
remain = size % bytes_
for (i = 0; i & i ++) {
memcpy(d.chars, laddr, bytes_width);
ptrace(PTRACE_POKETEXT, pid, dest, d.val);
laddr += bytes_
if (remain & 0) {
d.val = ptrace(PTRACE_PEEKTEXT, pid, dest, 0);
for (i = 0; i & i ++) {
d.chars[i] = *laddr ++;
ptrace(PTRACE_POKETEXT, pid, dest, d.val);
#if defined(__arm__) || defined(__aarch64__)
int ptrace_call(pid_t pid, uintptr_t addr, long *params, int num_params, struct pt_regs* regs)
#if defined(__arm__)
int num_param_registers = 4;
#elif defined(__aarch64__)
int num_param_registers = 8;
for (i = 0; i & num_params && i & num_param_ i ++) {
regs-&uregs[i] = params[i];
// push remained params onto stack
if (i & num_params) {
regs-&ARM_sp -= (num_params - i) * sizeof(long) ;
ptrace_writedata(pid, (void *)regs-&ARM_sp, (uint8_t *)¶ms[i], (num_params - i) * sizeof(long));
regs-&ARM_pc =
if (regs-&ARM_pc & 1) {
/* thumb */
regs-&ARM_pc &= (~1u);
regs-&ARM_cpsr |= CPSR_T_MASK;
regs-&ARM_cpsr &= ~CPSR_T_MASK;
regs-&ARM_lr = 0;
if (ptrace_setregs(pid, regs) == -1
|| ptrace_continue(pid) == -1) {
printf(&error\n&);
return -1;
int stat = 0;
waitpid(pid, &stat, WUNTRACED);
while (stat != 0xb7f) {
if (ptrace_continue(pid) == -1) {
printf(&error\n&);
return -1;
waitpid(pid, &stat, WUNTRACED);
#elif defined(__i386__)
long ptrace_call(pid_t pid, uintptr_t addr, long *params, int num_params, struct user_regs_struct * regs)
regs-&esp -= (num_params) * sizeof(long) ;
ptrace_writedata(pid, (void *)regs-&esp, (uint8_t *)params, (num_params) * sizeof(long));
long tmp_addr = 0x00;
regs-&esp -= sizeof(long);
ptrace_writedata(pid, regs-&esp, (char *)&tmp_addr, sizeof(tmp_addr));
regs-&eip =
if (ptrace_setregs(pid, regs) == -1
|| ptrace_continue( pid) == -1) {
printf(&error\n&);
return -1;
int stat = 0;
waitpid(pid, &stat, WUNTRACED);
while (stat != 0xb7f) {
if (ptrace_continue(pid) == -1) {
printf(&error\n&);
return -1;
waitpid(pid, &stat, WUNTRACED);
#error &Not supported&
int ptrace_getregs(pid_t pid, struct pt_regs * regs)
#if defined (__aarch64__)
int regset = NT_PRSTATUS;
struct iovec ioV
ioVec.iov_base =
ioVec.iov_len = sizeof(*regs);
if (ptrace(PTRACE_GETREGSET, pid, (void*)regset, &ioVec) & 0) {
perror(&ptrace_getregs: Can not get register values&);
printf(& io %llx, %d&, ioVec.iov_base, ioVec.iov_len);
return -1;
if (ptrace(PTRACE_GETREGS, pid, NULL, regs) & 0) {
perror(&ptrace_getregs: Can not get register values&);
return -1;
int ptrace_setregs(pid_t pid, struct pt_regs * regs)
#if defined (__aarch64__)
int regset = NT_PRSTATUS;
struct iovec ioV
ioVec.iov_base =
ioVec.iov_len = sizeof(*regs);
if (ptrace(PTRACE_SETREGSET, pid, (void*)regset, &ioVec) & 0) {
perror(&ptrace_setregs: Can not get register values&);
return -1;
if (ptrace(PTRACE_SETREGS, pid, NULL, regs) & 0) {
perror(&ptrace_setregs: Can not set register values&);
return -1;
int ptrace_continue(pid_t pid)
if (ptrace(PTRACE_CONT, pid, NULL, 0) & 0) {
perror(&ptrace_cont&);
return -1;
int ptrace_attach(pid_t pid)
if (ptrace(PTRACE_ATTACH, pid, NULL, 0) & 0) {
perror(&ptrace_attach&);
return -1;
int status = 0;
waitpid(pid, &status , WUNTRACED);
int ptrace_detach(pid_t pid)
if (ptrace(PTRACE_DETACH, pid, NULL, 0) & 0) {
perror(&ptrace_detach&);
return -1;
void* get_module_base(pid_t pid, const char* module_name)
long addr = 0;
char filename[32];
char line[1024];
if (pid & 0) {
/* self process */
snprintf(filename, sizeof(filename), &/proc/self/maps&, pid);
snprintf(filename, sizeof(filename), &/proc/%d/maps&, pid);
fp = fopen(filename, &r&);
if (fp != NULL) {
while (fgets(line, sizeof(line), fp)) {
if (strstr(line, module_name)) {
pch = strtok( line, &-& );
addr = strtoull( pch, NULL, 16 );
if (addr == 0x8000)
fclose(fp) ;
return (void *)
void* get_remote_addr(pid_t target_pid, const char* module_name, void* local_addr)
void* local_handle, *remote_
local_handle = get_module_base(-1, module_name);
remote_handle = get_module_base(target_pid, module_name);
DEBUG_PRINT(&[+] get_remote_addr: local[%llx], remote[%llx]\n&, local_handle, remote_handle);
void * ret_addr = (void *)((uintptr_t)local_addr + (uintptr_t)remote_handle - (uintptr_t)local_handle);
#if defined(__i386__)
if (!strcmp(module_name, libc_path)) {
ret_addr += 2;
return ret_
int find_pid_of(const char *process_name)
pid_t pid = -1;
char filename[32];
char cmdline[256];
struct dirent *
if (process_name == NULL)
return -1;
dir = opendir(&/proc&);
if (dir == NULL)
return -1;
while((entry = readdir(dir)) != NULL) {
id = atoi(entry-&d_name);
if (id != 0) {
sprintf(filename, &/proc/%d/cmdline&, id);
fp = fopen(filename, &r&);
fgets(cmdline, sizeof(cmdline), fp);
fclose(fp);
if (strcmp(process_name, cmdline) == 0) {
/* process found */
closedir(dir);
uint64_t ptrace_retval(struct pt_regs * regs)
#if defined(__arm__) || defined(__aarch64__)
return regs-&ARM_r0;
#elif defined(__i386__)
return regs-&
#error &Not supported&
uint64_t ptrace_ip(struct pt_regs * regs)
#if defined(__arm__) || defined(__aarch64__)
return regs-&ARM_
#elif defined(__i386__)
return regs-&
#error &Not supported&
int ptrace_call_wrapper(pid_t target_pid, const char * func_name, void * func_addr, long * parameters, int param_num, struct pt_regs * regs)
DEBUG_PRINT(&[+] Calling %s in target process.\n&, func_name);
if (ptrace_call(target_pid, (uintptr_t)func_addr, parameters, param_num, regs) == -1)
return -1;
if (ptrace_getregs(target_pid, regs) == -1)
return -1;
DEBUG_PRINT(&[+] Target process returned from %s, return value=%llx, pc=%llx \n&,
func_name, ptrace_retval(regs), ptrace_ip(regs));
int inject_remote_process(pid_t target_pid, const char *library_path, const char *function_name, const char *param, size_t param_size)
int ret = -1;
void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_
void *local_handle, *remote_handle, *
uint8_t *map_base = 0;
uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_
struct pt_regs regs, original_
long parameters[10];
DEBUG_PRINT(&[+] Injecting process: %d\n&, target_pid);
if (ptrace_attach(target_pid) == -1)
if (ptrace_getregs(target_pid, &regs) == -1)
/* save original registers */
memcpy(&original_regs, &regs, sizeof(regs));
mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap);
DEBUG_PRINT(&[+] Remote mmap address: %llx\n&, mmap_addr);
/* call mmap */
parameters[0] = 0;
parameters[1] = 0x4000; // size
parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;
parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // flags
parameters[4] = 0; //fd
parameters[5] = 0; //offset
if (ptrace_call_wrapper(target_pid, &mmap&, mmap_addr, parameters, 6, &regs) == -1)
map_base = ptrace_retval(&regs);
dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen );
dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym );
dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose );
dlerror_addr = get_remote_addr( target_pid, linker_path, (void *)dlerror );
DEBUG_PRINT(&[+] Get imports: dlopen: %llx, dlsym: %llx, dlclose: %llx, dlerror: %llx\n&,
dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);
printf(&library path = %s\n&, library_path);
ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1);
parameters[0] = map_
parameters[1] = RTLD_NOW| RTLD_GLOBAL;
if (ptrace_call_wrapper(target_pid, &dlopen&, dlopen_addr, parameters, 2, &regs) == -1)
void * sohandle = ptrace_retval(&regs);
if(!sohandle) {
if (ptrace_call_wrapper(target_pid, &dlerror&, dlerror_addr, 0, 0, &regs) == -1)
uint8_t *errret = ptrace_retval(&regs);
uint8_t errbuf[100];
ptrace_readdata(target_pid, errret, errbuf, 100);
#define FUNCTION_NAME_ADDR_OFFSET
ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1);
parameters[0] =
parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET;
if (ptrace_call_wrapper(target_pid, &dlsym&, dlsym_addr, parameters, 2, &regs) == -1)
void * hook_entry_addr = ptrace_retval(&regs);
DEBUG_PRINT(&hook_entry_addr = %p\n&, hook_entry_addr);
#define FUNCTION_PARAM_ADDR_OFFSET
ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1);
parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;
if (ptrace_call_wrapper(target_pid, &hook_entry&, hook_entry_addr, parameters, 1, &regs) == -1)
printf(&Press enter to dlclose and detach\n&);
getchar();
parameters[0] =
if (ptrace_call_wrapper(target_pid, &dlclose&, dlclose, parameters, 1, &regs) == -1)
/* restore */
ptrace_setregs(target_pid, &original_regs);
ptrace_detach(target_pid);
int main(int argc, char** argv) {
pid_t target_
target_pid = find_pid_of(&system_server&);
if (-1 == target_pid) {
printf(&Can't find the process\n&);
return -1;
//target_pid = find_pid_of(&/data/test&);
inject_remote_process(target_pid, &/data/libhello.so&, &hook_entry&,
&I'm parameter!&, strlen(&I'm parameter!&));
另外,也用到libhello.so,代码基本不变,只是其中Application.mk中也指定arm64。APP_ABI := arm64-v8a
$T.total > 0 && $T.page <= $T.pageNum}
{#foreach $T.data as r}
{$T.r.formt_tm}{#if $T.r.nickname}{#else}匿名{#/if}
{$T.r.content}
{#if $T.page > 1 && $T.pageNum > 1)
$T.s_num > 2}
{#for index = $T.s_num to $T.e_num}
$T.pageNum > $T.pageNavSize+ 2 && $T.s_num != $T.pageNum - $T.pageNavSize}
{#if $T.pageNum > 1}
{#if $T.pageNum != $T.page && $T.pageNum > 1}
<a href="javascript:void(0);" page="{$T.page 下一页
您的回应...
也许你感兴趣
(window.slotbydup=window.slotbydup || []).push({
id: '3465635',
container: s,
size: '120,240',
display: 'float'
(C)2012 本站提供的内容来源于广大网络用户,我们不保证内容的正确性。如果转载了您的内容,希望删除的请联系我们!

我要回帖

更多关于 arm与x86的区别 的文章

 

随机推荐