`
dss16694
  • 浏览: 148410 次
社区版块
存档分类
最新评论

全面认识Android手机(MIUI ROM适配之旅第三天——反编译)

 
阅读更多

首先说句抱歉,今天事情比较多,教程出来的比较晚,请包含。今后几天也会稍晚一点,但是我会每天更新的。

    今天我们来详细的看看反编译,想要修改一个系统自带的应用程序和它的代码,在没有源码的情况下,我们就不得不用反编译来修改。

    和很多书籍一样,为了向经典的"Hello, World"致敬,我们也从一个简单的程序开始HelloActivity.apk。当你把这个APK安装到手机上运行后,在屏幕上就显示一行文字"Hello, World!"(世界我来了!是的,兄弟姐妹们,从今天起我们真正进入反编译的世界,我们来了!)

1. 反编译
    为了介绍方便,从现在起,我会用cracker~$作为命令提示符,其后的文字表示我们需要运行的命令。如果其后有斜体字,表示命令的输出结果。

cracker~$ apktool d HelloActivity.apk
这条命令运行完后,在当前目录下会生成一个名为HelloActivity的目录。
该目录的结构为(名称后跟/表示这是一个目录):
HelloActivity/
       |--------------AndroidManifest.xml
       |--------------apktool.yml
       |--------------res/
       |--------------smali/
apktool.yml是apktool生成的一个配置文件,基本上你不需要修改这个文件。下面的章节我们逐个介绍剩下的AndroidManifest.xml文件和res, smali目录。

2. AndroidManifest.xml
    要想完全理解这个文件,你得对Android的内部运作机制非常清楚。幸好我们修改一个APK的时候基本上不改这个文件。这里帮助你有个大致的了解。
    
    Android安装程序一般叫apk文件(apk是Android Package的缩写,表示Android安装包)。一般来说,程序都会有一个或多个Activity, Activity是什么呢,从概念说它是一个和用户交互的窗口,你每天使用Android手机的时候基本上你打交道的每个界面都是一个Activity。AndroidManifest.xml是一个xml格式的清单文件,就像你去超市买东西会打印出一个购物清单,AndroidManifest.xml也起着一个清单的作用,它告诉系统,我有这些Activity。(实际情况远比这复杂,想学Android编程的同学请看这个http://developer.android.com/guide/index.html,好好学习其中的内容)。
    
    具体到HelloActivity下的AndroidManifest.xml文件,大家可以找到如下内容:
    <application 
    android:label="@string/app_name" android:icon="@drawable/ic_launcher_hello">
            <activity android:name="HelloActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    其中有一行<category android:name="android.intent.category.LAUNCHER" />,包含这一行的Activity会显示在桌面中,就是说你可以通过桌面显示的图标启动这个Activity。里面还有android:label="@string/app_name" android:icon="@drawable/ic_launcher_hello"。这两个属性是做什么的呢,android:label表示程序显示在桌面上的名字,android:icon表示程序显示在桌面上的图标。如果想要改显示的名字和图标,修改其后的两个资源,如何修改资源,下一节详细介绍。

3. 资源
    res目录下放置了程序所需要的所有资源。资源是什么呢,一般来说,一个图形用户界面(GUI)程序总是会使用一些图片,或者显示的文字的大小和颜色等。或者界面的布局,比如显示的界面上面是文字,下面是两个按钮等等。这些程序的一个重要特点就是用户界面和代码逻辑的分离。当我们需要替换图片或者简单修改界面布局的时候,不需要改变代码。而Android程序会将这些代码中需要用到的文件都放在res目录下,称之为资源。

    可以看到res目录的内容为:
res/
|--------drawable-hdpi/
             |-----------ic_launcher_hello.png
|--------layout/
         |---------hello_activity.xml
|--------values/
         |---------ids.xml
         |---------public.xml
         |---------strings.xml
    对于HelloActivity来说,res目录下有三个子目录drawable-hdpi, layout, values。由于HelloActivity比较简单,因此res下内容不多,但是一个复杂的程序res目录下内容相应的也会比较多,但是基本原理都是一样的。
    
    res下面的子目录基本上是按照资源类型来分类组织的,以drawable开头的表示图片资源,大家可能会看到drawable-hdpi, drawable-mdpi, drawable-ldpi等,这些hdpi,mdpi,lpid分别表示高/中/低分辨率,会根据不同的屏幕分辨率选择不同的图片。要想替换图片,替换这些目录下的图片就可以了。(替换图片比这稍复杂点,一般替换图片,最好保持和原图片兼容,比如说色系,尺寸以及点9图片的一些参数等)。
    
    以layout开头的表示布局文件,用来描述程序的界面。anim子目录存放程序使用到的动画,xml开头的目录存放程序用到的一些xml文件等。
    
    values开头的目录下面存放一些我们称之为基本元素的定义,比如说colors.xml给出颜色值的定义,dimens.xml给出一些大小的定义。strings.xml是一些字符串的定义。我们看看HellloActivity的strings.xml文件。

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="hello_activity_text_text">Hello, World!</string>
        <string name="app_name">HelloWorld</string>
    </resources>
    
    其中的以<string开头便是这是一个字符串,name是给这个资源起一个名字,后面的字符串表示这个字符串的值。Android的资源大致按这种形式来组织的,先将资源分成几种类型,然后每一种类型的所有资源取一个名字,这个名字对应了这个资源的值/内容。
    
    我们一般修改资源通常情况下是修改图片或者汉化。汉化比较简单,values/strings.xml文件存放程序用到的所有英文字符串值。要汉化,首先在values下建立一个目录values-zh-rCN。然后将values/strings.xml拷贝到该目录中,将每一个字符串翻译成中文。我们现在将strings.xml拷贝到values-zh-rCN目录下,并将文件内容改为:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="hello_activity_text_text">你好,世界!</string>
        <string name="app_name">你好世界</string>
    </resources>
    
    现在我们需要把修改后的文件在编回apk文件,运行如下命令:
    cracker~$ apktool b HelloActivity HelloActivity.apk
    这条命令表示编译HelloActivity目录的内容,输出文件为HelloActivity.apk,如果你不想覆盖原有的文件,可以换一个名字或者放在另外一个目录下。
    
    接下来我们需要对生成的APK进行签名,下载附件中的压缩包sign.zip, 解压后有一个脚本sign.sh。假定你把解压后的文件都放在/home/cracker/tools目录中。运行如下命令:
    cracker~$ export KEY_PATH=/home/cracker/tools
    cracker~$ /home/cracker/tools/sign.sh HelloActivity.apk
    cracker~$ adb install -r HelloActivity.apk.signed.aligned
注意最后一条命令如果失败,如果你不是用我们提供的HelloActivity做实验的话,会发生签名不一致的错误,这个时候先卸载原来的,再安装。运行看看,对的,现在显示在你面前的是“你好,世界!”

    汉化成功了,是的,汉化就这么简单。如果你只想停留在汉化或者替换图片这个阶段,从这里开始以后的文章不用看了。如果你没有Android编程基础,从这里开始以后的文章也不用看了。
    
    到底发生了什么魔法,为什么这样替换一下图片或者改字符串就能改变程序最终运行的结果呢,想要理解这个,我们就的大致的了解一下资源的编译过程。首先我们看看values目录下一个有意思的文件publics.xml,它的内容如下:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <public type="drawable" name="ic_launcher_hello" id="0x7f020000" />
        <public type="layout" name="hello_activity" id="0x7f030000" />
        <public type="string" name="hello_activity_text_text" id="0x7f040000" />
        <public type="string" name="app_name" id="0x7f040001" />
        <public type="id" name="text" id="0x7f050000" />
    </resources>
每一行的id后面都有一个看起来很奇怪的数字,这个数字是干嘛的呢?Android下有一个资源编译器会编译res目录下的所有文件,它为每一个资源名字分配一个数字标识符,这个标识符分成3个部分,最前面的1个字节表示包名,所有的apk这个字节都是7f。表示这些资源是非共享的,其它APK访问不到。所有那些可以共享的资源放在system/framework/framework-res.apk下。/system/framework往往还有其它共享的资源包。这些共享的资源包前面的1个字节从0x1开始,依次增加。中间的一个字节表示资源的类型,每一个类型的数字标识符是不一样的,最后的2个字节是资源的序号,统一类型的资源序号从0依次往上递增。一般来说,资源id是由资源编译器(aapt)自动产生的,但是定义在publics.xml中的值告诉编译器,你必须为这个id使用这个值。apktool会为所有的资源名称定义这个值在publics.xml里,这样可以保证替换资源后资源的id不会变化。

    为啥资源的id这么重要,如果变了,会怎么样呢,这得结合代码理解。我们在Java代码里通常这样引用资源,比如R.string.app_name。这个Java代码经过编译后,这条引用直接变成了资源id,即0x7f040001,所以你在下面反编译后的smali代码里面是看不到R.string.app_name这个东西的,只能看到0x7f040001。资源编译器会生成一个查找表,对于每一个id,查找表中保存了这个id对应的名字和值(如果是文件,则为文件所在路径)。程序在运行的时候,会根据id去查询这个查找表找到对应的资源的值或文件。
    
    最后说一句,资源的ID非常重要,运行adb pull /system/framework/framework-res.apk反编译这个文件,好好的消化一下这一节的内容吧。

4. smali
    终于迎来我们最重要的部分了smali目录,smali目录存放的是反编译后的Java代码,文件名以smali结尾,故称作smali文件。这些代码比一般的Java代码可读性差太多了,但是和传统的x86或者其他体系结构下的汇编文件那又是好读多了。虽然有工具可以直接把这些反汇编成java代码,单是好不了太多,我们还是直接读取修改smali文件。从这里我们才真正的开始是一名程序员。
    
    我们来看一下反编译后的smali目录下的HelloActivity.smali文件,和Java组织源代码的方式一样,smali目录下的文件也是按文件包的包名结构组织目录结构的,文件的内容如下:
    
    .class public Lcom/example/android/helloactivity/HelloActivity;
    .super Landroid/app/Activity;
    .source "HelloActivity.java"
    
    # direct methods
    .method public constructor <init>()V
        .locals 0
    
        .prologue
        .line 27
        invoke-direct {p0}, Landroid/app/Activity;-><init>()V
    
        return-void
    .end method

    # virtual methods
    .method public onCreate(Landroid/os/Bundle;)V
        .locals 2
        .parameter "savedInstanceState"
    
        .prologue
        .line 33
        invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
    
        .line 37
        const/high16 v1, 0x7f03
    
        invoke-virtual {p0, v1}, 
    Lcom/example/android/helloactivity/HelloActivity;->setContentView(I)V
    
        .line 38
        const/high16 v1, 0x7f05
    
        invoke-virtual {p0, v1}, 
     Lcom/example/android/helloactivity/HelloActivity;->findViewById(I)Landroid/view/View;
    
        move-result-object v0
    
        check-cast v0, Landroid/widget/TextView;
    
        .line 39
        .local v0, txtView:android/widget/TextView;
        const/high16 v1, 0x7f04
    
        invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(I)V
    
        .line 40
        return-void
    .end method
    
    文件中的以#开头的文字表示注释, 以.开头的叫做annotations,其中的.line表示对应的源代码的行号,这个对调试很重要。.metho和.end method表示一个方法定义的开始和结束。Smali文件中的这些指令的功能请参照http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html,有一些不懂没关系,在接下来得两章我们会接触到大部分指令。
    
    其中.line 39的代码对应的源代码是
    txtView.setText(R.string.hello_activity_text_text)
    
    我们现在想将这行代码改成txtView.setText("Happy, Cracker!"),将.line 39到.line 40行的代码改为:
     .line 39
     .local v0, txtView:android/widget/TextView;
     const-string v1, "Happy, Cracker!"
     invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
再按照上一节所说得重新编译,签名,安装运行,好了,现在出现在你面前的是Happy, Cracker!了,真happy!

    接下来的两章我们都会介绍如何直接修改smali代码从而改变程序的功能,这种方法我们叫做代码插桩,接下来的两章我们将会用代码插桩的方法将MIUI的功能加到原生ROM中去。

分享到:
评论

相关推荐

    小米手机刷第三方rom教程

    【小米手机刷第三方ROM教程详解】 刷机,对于许多安卓手机用户来说,是一种提升设备个性化体验和优化系统性能的方式。小米手机因其开放性,深受广大用户的喜爱,而刷入第三方ROM则是其中的一大特色。本教程将针对...

    适配小米手机的拍照相册选择方案

    2. **小米手机特有的适配**:小米手机可能有自己的定制化ROM,这可能导致系统级别的行为与其他Android设备有所不同。例如,小米手机可能对存储路径、相册访问方式或者拍照接口有特殊处理。适配方案需要考虑到这些...

    安卓Android源码——小米系列之小米文件管理器.zip

    【标题】"安卓Android源码——小米系列之小米文件管理器.zip" 提供的是关于小米公司MIUI系统中内置文件管理器的源代码分析。这个压缩包可能包含了用于理解和研究小米文件管理器运行机制的各个组件和功能的源代码。在...

    MIUI_V4定制教程完全版_MIUI适配教程_MIUI第三方开发环境借鉴.pdf

    MIUI_V4定制教程完全版_MIUI适配教程_MIUI第三方开发环境借鉴.pdf

    安卓Android源码——MIUI文件管理器.zip

    【安卓Android源码——MIUI文件管理器】 在Android操作系统中,MIUI是小米公司推出的一个深度定制的用户界面,它以其丰富的功能和独特的设计深受用户喜爱。本压缩包文件包含的是MIUI文件管理器的源代码,对于开发者...

    判断android手机是华为小米魅族系统

    不同厂商如华为(EMUI)、小米(MIUI)和魅族(Flyme)会基于Android源码进行深度定制,形成自己独特的ROM,提供了各自特有的功能和用户体验。 在实现这个工具类时,开发者通常会依赖Android提供的`Build`类,该类...

    小米ROM提取工具

    小米ROM,全称为“MIUI ROM”,是小米公司基于Android系统深度定制的操作界面,以其丰富的功能和独特的设计风格深受用户喜爱。提取小米ROM的过程中,用户需要获取到官方发布的固件升级包,这些通常是以.zip或.simg...

    MIUI_ROM定制教程

    这一过程涉及众多的技术知识点,包括但不限于操作系统的选择、环境搭建、对Android手机系统结构的认识、寻找合适的原厂ROM、ROM的反编译、MIUI Framework和APP的移植,以及最终制作ZIP刷机包。 首先,MIUI ROM定制...

    Android 悬浮窗权限各机型各系统适配大全(总结)

    3. 依旧利用上面的方法,找到 activity 的名字,然后 root 准备适配的手机,直接在相关目录 /system/app 下把源码 APK 拷贝出来,反编译,根据 activity 的名字找到相关代码,之后的事情就简单了; 4. 还有一个方法...

    史上最全 最新 安卓 android 手机刷机教程 root MIUI ROM 卡编程资料刷 机刷.docx

    ### 安卓手机刷机教程:详解...通过本文的介绍,相信您已经对安卓手机刷机有了一个较为全面的认识,尤其是针对HTC G12卡刷MIUI ROM的操作流程。希望这些知识能够帮助您更好地掌握刷机技巧,享受个性化手机带来的乐趣。

    小米1S稳定第三方ROM

    【小米1S稳定第三方ROM】是一款专为小米1S手机设计的第三方操作系统,它提供了出色的用户体验,强调稳定性与节能性。对于那些寻求超越原厂MIUI系统体验的用户来说,这是一个理想的选择。本文将深入探讨这款ROM的特点...

    MIUI ROM定制教程

    #### 第二章:认识Android手机 - **Bootloader**:解释了Bootloader的概念及其在Android设备启动过程中的作用。 - **正常启动流程**:概述了Android设备的启动过程,包括从Bootloader加载kernel到System分区的初始...

    Android源码——MIUI小米录音机源码.zip

    MIUI小米录音机是小米公司为其定制的Android操作系统MIUI中的一个重要组件,它为用户提供录音功能,具有良好的用户界面和高效的操作体验。本压缩包包含了MIUI小米录音机的源代码,这对于Android开发者来说是一份宝贵...

    Android源码——MIUI小米录音机源码.7z

    MIUI小米录音机是小米公司为其定制的Android操作系统开发的一款录音应用,它的源码对于开发者来说是一份宝贵的学习资源,可以深入理解Android音频处理、UI设计以及应用优化等多个方面的技术。下面将详细解析MIUI小米...

    安卓Android源码——小米系列之小米便签.zip

    《安卓Android源码——小米系列之小米便签》是一份深度剖析小米便签应用程序源代码的资源集合。这个压缩包包含了一系列的图片文件,可能是为了辅助理解源代码中的关键概念和设计模式。从标签"安卓 android 源码"我们...

    ApkIDE——安卓反编译

    小米人APK改之理是一款可视化的用于修改安卓Apk程序文件的工具,集成了ApkTool、Dex2jar、JD-GUI等Apk修改工具,集Apk反编译、Apk打包、Apk签名,支持语法高亮的代码编辑器,基于文件内容的关键字(支持单行代码或...

    Android源码——小米系统之便签源码.zip

    在本压缩包“Android源码——小米系统之便签源码.zip”中,我们主要探讨的是小米手机系统中便签应用的源代码。这个源代码分析对于深入理解Android开发,尤其是定制系统应用的开发有着重要的价值。以下是关于Android...

    安卓Android源码——小米系列之小米录音机.zip

    本文将以“安卓Android源码——小米系列之小米录音机”为主题,深入探讨小米录音机的源码实现,帮助读者了解安卓录音功能的底层机制和优化策略。 首先,小米录音机作为一款内置在小米手机中的应用,其源码为我们...

Global site tag (gtag.js) - Google Analytics