热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Smali代码注入

以下的内容是对官方MIUIV4移植教程的补充,其中一些工具的使用就不在这里赘述,请大家参考官方教程。好的,话不多说,进入正题

以下的内容是对官方MIUI V4移植教程的补充,其中一些工具的使用就不在这里赘述,请大家参考官方教程。

  好的,话不多说,进入正题。 

  应用场景

  Smali代码注入只能应对函数级别的移植,对于类级别的移植是无能为力的。具体的说,如果你想修改一个类的继承、包含关系,接口结构等是非常困难的。但对于修改类成员变量访问控制权限,类方法实现,Smali代码注入的方法是可以实现的。这主要是因为Samli级代码的灵活性已经远低于java源代码,而且经过编译优化后,更注重程序的执行效率。

  Smali代码注入

  本质上讲,Smali代码注入就是在已有APK或JAR包中插入一些Dalvik虚拟机的指令,从而改变原来程序执行的路径或行为。

  这个过程大致分为五步——确定需要注入的Samli代码,确定注入位置,注入Smali代码,编译Smali代码,调试Smali代码。

  总体流程如下图:

[转载]MIUI <wbr>V4移植经验分享&#xff08;三&#xff09;鈥斺 <wbr>Smali代码注入

  下面详细说明&#xff1a;

  确定需要注入的Smali代码

  首先&#xff0c;确定基线文件——待移植的APK包或JAR包&#xff0c;使用APKTOOL反汇编&#xff0c;生成原始的Samli文件。

  其次&#xff0c;修改对应的APK包或JAR包的java源代码&#xff0c;使用编译系统重新生成新的APK包或JAR包&#xff0c;并用APKTOOL反汇编&#xff0c;生成包含修改后的Samli文件。

  最后&#xff0c;使用比较工具&#xff08;例如BeyondCompare&#xff09;比较两次Smali文件&#xff0c;即可提取出需要注入的Smali代码。

  例如下图红色区域就是需要注入的Smali代码

[转载]MIUI <wbr>V4移植经验分享&#xff08;三&#xff09;鈥斺 <wbr>Smali代码注入

 

  确定注入位置

  这一步的看似简单&#xff0c;实际工作中有很多难点&#xff0c;主要是有些注入位置比较难确定&#xff0c;需要不断的尝试。

  使用APKTOOL反汇编待注入的APK或JAR包后&#xff0c;首先需要确认需要注入的Smali文件是哪个。这个主要是针对含有匿名内部类的Java文件而言。例如&#xff0c;移植PhoneWindowManager.java文件的修改时&#xff0c;反汇编之后会有很多PhoneWindowManager$1.smali, PhoneWindowManager$2.smali...类似的文件。这些文件就是匿名内部类的Smali代码&#xff0c;由于没有名字&#xff0c;所以编译后只能用$XXX来区分。

  如果带注入的Smali代码是从PhoneWindowManager$5.smali提取的&#xff0c;一般不能够直接将其注入到目标机型的PhoneWindowManager$5.smali文件中&#xff0c;因为不同机型的匿名内部类顺序不同&#xff0c;实现不同&#xff0c;Smali文件也不同。一般需要通过逐个比较PhoneWindowManager$5.smali附近的几个文件的Smali代码&#xff0c;看看其函数调用&#xff0c;函数名字&#xff0c;类继承关系是否相同来确定注入哪个文件。

  当然对于没有匿名内部类的Java文件可以直接使用对应的Smali文件注入即可。

  其次&#xff0c;确定了注入文件之后&#xff0c;就需要进一步确认待注入区域。由于Smali代码中的每个变量的类型是不固定的&#xff0c;再加上编译器的优化&#xff0c;导致不同ROM的APK或JAR包反汇编后&#xff0c;会有很多不同。这个并不影响我们的工作&#xff0c;我们重点关注Smali代码的“行为”——函数调用顺序&#xff0c;逻辑判断顺序&#xff0c;类成员变量访问顺序&#xff0c;即可大致确定注入区域。另外&#xff0c;对于新增的Smali代码区域可以随意些&#xff0c;新增变量直接追加在变量声明尾部即可&#xff0c;新增函数直接增加在文件尾部。总的来说这个工作还是非常经验化的&#xff0c;需要长时间的反复尝试才能更准确的确定注入区域。

  最后&#xff0c;继续上面例子&#xff0c;如图&#xff1a;

[转载]MIUI <wbr>V4移植经验分享&#xff08;三&#xff09;鈥斺 <wbr>Smali代码注入
 图中有很多红色的不同&#xff0c;其中蓝框是我们刚才确定的需要注入的Samli代码。通过上下文匹配&#xff0c;可以发现绿框的位置是Samli代码需要注入的区域。尽管上下有很多指令和变量不同&#xff0c;但是这并不影响我们的工作。

 

  注入代码

  首先&#xff0c;将待注入的Smali代码注入对应的区域。

  其次&#xff0c;对注入的Smali代码进行“本地化”——修改变量、跳转标号、逻辑判断标号等&#xff0c;使之符合当前的Smali代码实现&#xff0c;完成“嫁接”工作。当然&#xff0c;如果情况很复杂&#xff0c;需要重写对应的Smali代码或者重构java源代码&#xff0c;来完成最终的代码注入。Dalvik 虚拟机每条指令含义请参见这里。

  最后&#xff0c;继续刚才的例子&#xff0c;如图&#xff1a;

[转载]MIUI <wbr>V4移植经验分享&#xff08;三&#xff09;鈥斺 <wbr>Smali代码注入
  其中蓝框内是最终移植的代码&#xff0c;可以看到其中修改了move-result-object v2和invoke-virtual {v2, v0, v1, v15}, Lmiui/net/FirewallManager;->onStartUsingNetworkFeature(III)V的变量&#xff0c;这主要是因为invoke-virtual {v2, v0, v1, v15}, Lmiui/net/FirewallManager;->onStartUsingNetworkFeature(III)V在新的Smali代码中v15变量有其他的用途&#xff0c;我们需要找一个上下文无关的变量完成函数调用时的变量传递&#xff0c;所以这里将move-result-object v15改为move-result-object v2。并且修改了onStartUsingNetworkFeature()函数参数列表。

  另外&#xff0c;移植中还有一类关于资源ID的代码注入比较特殊&#xff0c;这里举例说明一下&#xff1a;

[转载]MIUI <wbr>V4移植经验分享&#xff08;三&#xff09;鈥斺 <wbr>Smali代码注入

  现在我们需要将蓝框内的代码注入到绿框的位置&#xff0c;但是其中const v6, 0x10403c1 阻挡了前进的步伐。我们不能鲁莽的将蓝框代码合入绿框&#xff0c;这样会导致资源无法找到运行时错误。我们需要使用反汇编原始ROM的framework-res.apk和目标ROM的framework-res.apk&#xff0c;根据0x10403c1 ID值找到原始ROM framework-res.apk中对应的资源名字&#xff0c;再根据资源名字到目标ROM的framework-res.apk中查找对应的资源ID值。而后将其替换为目标ROM中的资源ID值。所以最终移植后的代码如下图&#xff1a;

[转载]MIUI <wbr>V4移植经验分享&#xff08;三&#xff09;鈥斺 <wbr>Smali代码注入

  需要说明的是0x1开头的资源都是framework-res.apk中的资源&#xff0c;0x2开头的一般是厂商自己的资源&#xff0c;例如摩托的是moto-res.apk,HTC的是com.htc.resources.apk。miui自己的资源是0x6开头&#xff0c;位于framework-miui-res.apk中。

 

  编译Smali 代码

  Smali编译过程相对简单&#xff0c;使用apktool b XXX XXX.apk 即可将Smali代码编译成apk或jar包。但是当遇到编译错误时&#xff0c;apktool工具给出的错误信息少之又少&#xff0c;以至于我们只能手动查找哪个文件Samli代码移植错误。

  这里&#xff0c;我总结了一些Smali代码移植时可能遇到的编译错误。希望对各位有用。

  1.函数调用(invoke-virtual等指令)的参数只能使用v0~v15&#xff0c;使用超过v15的变量会报错。修复这个问题有两种方法&#xff1a;

    A.使用invoke-virtual/range {p1 .. p1}指令&#xff0c;但是这里要求变量名称需要连续。

    B.增加move-object/from16 v0, v18类似指令&#xff0c;调整变量名&#xff0c;使之小于等于v15。

  2.函数调用中p0相当于函数可用变量值&#43;1&#xff0c;pN相当于函数可用变量值&#43;N。例如函数.local值为16&#xff0c;表明函数可用变量值为v0~v15&#xff0c;则p0相当于v16&#xff0c;p1相当于v17。

例如&#xff0c;下图左侧蓝框所在代码编译不过&#xff0c;后来检查了代码所在的函数.local为33&#xff0c;p0相当于v33&#xff0c;所以编译不过&#xff0c;修改为右侧绿框才正常。

[转载]MIUI <wbr>V4移植经验分享&#xff08;三&#xff09;鈥斺 <wbr>Smali代码注入

  3.跳转标号重叠。

  这里主要是指出现了两个相同的标号的情况&#xff0c;例如cond_11等&#xff0c;导致无法编译过。解决方法就是修改冲突的标号以及相关跳转语句。其实这个标号叫什么都无所谓&#xff0c;你甚至可以叫ABCD_XXX,只要可以与对应的goto语句呼应即可。

  4.使用没有定义的变量

  每个函数可以使多少变量都在函数体内的第一句.local中声明&#xff0c;例如.local 30表明这个函数可以使用v0~v29&#xff0c;如果使用v30就会编译错误。

 

  调试Smali 代码

  调试Smali代码主要任务是解决注入代码后导致的运行时错误。具体的说&#xff0c;就是使注入后的Smali代码通过dalvik虚拟机的字节码校验。获取错误的方法相对简单&#xff0c;使用下面两条命令即可&#xff1a;

  adb logcat | grep dalvikvm

  adb logcat | grep VFY

  其中VFY的信息会给出Smali代码出错的文件、函数以及错误原因&#xff0c;dalvikvm的信息可以给出调用栈&#xff0c;以及上下文执行过程&#xff0c;都比较贴心。

 

  这里总结一下主要的运行时错误&#xff1a;

  1.函数变量列表与声明不同&#xff0c;这个主要体现在下面两个方面&#xff1a;

    A.函数调用的变量类型与函数声明不同。

      通过追踪变量在上下文的赋值动作来解决。

    B.函数变量列表中变量少于或者多于函数声明的变量。

      通过核对函数声明来解决。

  2.函数调用方式不正确。

  例如&#xff1a;public和包访问函数使用invoke-virtual调用&#xff0c;private函数使用invoke-director调用&#xff0c;接口函数使用invoke-interface调用。如果使用错误&#xff0c;会导致运行时错误。需要调整相关的Smali代码。

  3.类接口没有实现。

  主要是由于增加了新的子类没有实现原有父类接口导致的&#xff0c;只需增加空实现即可修复。

  4.签名不正确。

  可以通过adb logcat | grep mismatch命令确认哪个package签名不正确。只需对签名不正确的包重新签名即可。当然如果有很多签名不一致的错误&#xff0c;建议大家对所有的APK重新签名。

  5.资源找不到。

  这个问题的原因有很多种&#xff0c;我这里列举一些常见的原因&#xff1a;

  A.系统资源文件签名不正确&#xff0c;导致没有加载系统资源&#xff0c;进而无法找到相应的资源。其中&#xff0c;系统资源文件是指system/framework/目录下的apk文件。

  B.Smali代码中的资源ID移植错误&#xff0c;无法在系统资源中找到对应的资源。

  C.资源相关的类移植存在问题&#xff0c;导致无法加载相关资源。

 

  另外&#xff0c;调试时&#xff0c;大家可能需要要追踪代码执行路径&#xff0c;但又苦于无法Debug。我这里分享一些简单的追踪方法&#xff0c;希望对大家有用。

  1.增加简单的Smali日志信息&#xff1a;

    A.修改函数的.local变量&#xff0c;在原来基础上增加两个变量&#xff0c;例如v11,v12。

    B.在需要打印日志的地方增加如下Smali代码

    const-string v11, "&#64;&#64;&#64;&#64;"

    const-string v12, "interceptPowerKeyDown enter"

    invoke-static {v11, v12}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

    如果增加的变量为v28和v29&#xff0c;则需要使用下面的语句。

    invoke-static/range {v28 .. v29}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I

  2.打印程序调用栈的方法&#xff1a;

    A.修改函数的.local变量&#xff0c;在原来基础上增加一个变量&#xff0c;例如v11。

    B.在需要打印调用栈的地方增加如下Smali代码

    new-instance v1 Ljava/lang/Exception;

    invoke-direct {v1, Ljava/lang/Exception;->()V

    invoke-virtual {v1, Ljava/lang/Exception;->printStackTrace()V

 

今天先分享到这里&#xff0c;希望我的这些经验对大家有所帮助。


推荐阅读
  • 本文探讨了 Objective-C 中的一些重要语法特性,包括 goto 语句、块(block)的使用、访问修饰符以及属性管理等。通过实例代码和详细解释,帮助开发者更好地理解和应用这些特性。 ... [详细]
  • MySQL索引详解与优化
    本文深入探讨了MySQL中的索引机制,包括索引的基本概念、优势与劣势、分类及其实现原理,并详细介绍了索引的使用场景和优化技巧。通过具体示例,帮助读者更好地理解和应用索引以提升数据库性能。 ... [详细]
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 解读MySQL查询执行计划的详细指南
    本文旨在帮助开发者和数据库管理员深入了解如何解读MySQL查询执行计划。通过详细的解析,您将掌握优化查询性能的关键技巧,了解各种访问类型和额外信息的含义。 ... [详细]
  • 本文探讨了如何优化和正确配置Kafka Streams应用程序以确保准确的状态存储查询。通过调整配置参数和代码逻辑,可以有效解决数据不一致的问题。 ... [详细]
  • 本教程涵盖OpenGL基础操作及直线光栅化技术,包括点的绘制、简单图形绘制、直线绘制以及DDA和中点画线算法。通过逐步实践,帮助读者掌握OpenGL的基本使用方法。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 本文详细介绍了Linux系统中init进程的作用及其启动过程,解释了运行级别的概念,并提供了调整服务启动顺序的具体步骤和实例。通过了解这些内容,用户可以更好地管理系统的启动流程和服务配置。 ... [详细]
  • dotnet 通过 Elmish.WPF 使用 F# 编写 WPF 应用
    本文来安利大家一个有趣而且强大的库,通过F#和C#混合编程编写WPF应用,可以在WPF中使用到F#强大的数据处理能力在GitHub上完全开源Elmis ... [详细]
  • 本文介绍如何使用 Android 的 Canvas 和 View 组件创建一个简单的绘图板应用程序,支持触摸绘画和保存图片功能。 ... [详细]
  • 本文介绍如何使用 Angular 6 的 HttpClient 模块来获取 HTTP 响应头,包括代码示例和常见问题的解决方案。 ... [详细]
author-avatar
相思和怀恋_811_372
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有