当前位置: 首页 > >

android studio逆向分析apk

发布时间:

新版的android studio在工具栏Build>Analyze APK选择apk(或者直接将apk拖至android studio编辑区)可进入apk解析器界面。




点击classes.dex进行具体class文件的反编译:




比如我们要分析PlainWhiteboardActivity,选择后右键-->ShowByteCode可以查看到smali格式的代码:




OK,到这一步,逆向分析的重点来了,smali文件解析:




一、头信息??类的主体信息


在打开smali文件的时候,它的头三行描述了当前类的一些信息。


.class <访问权限> [关键修饰字] <类名>;
.super <父类名>;
.source <源文件名>


例如:


//===================================================================
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
// ......
}
//===================================================================
# interfaces
.implements Landroid/view/View$OnClickListener;
//===================================================================

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

    三、smali基本语法?


    Davlik字节码中,寄存器都是32位的,能够支持任何类型,64位类型(Long/Double)用2个寄存器表示;?
    Dalvik字节码有两种类型:原始类型;引用类型(包括对象和数组)


    1、原始类型


    V void (只能用于返回值类型)
    Z boolean
    B byte
    S short
    C char
    I int
    J long(64位)
    F float
    D double(64位)

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

      2、对象类型?
      Lpackage/name/ObjectName; 相当于java中的package.name.ObjectName;?
      L 表示这是一个对象类型?
      package/name 该对象所在的包?
      ObjectName 对象名称?
      ; 标识对象名称的结束


      3、数组类型?
      [I :表示一个整形的一维数组,相当于java的int[];?
      对于多维数组,只要增加[ 就行了,[[I = int[][];注:每一维最多255个;


      对象数组的表示形式:?
      [Ljava/lang/String 表示一个String的对象数组;


      4、寄存器与变量?
      android变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型,其中long和double是64为的,需要使用两个寄存器保存。?
      寄存器采用v和p来命名,v表示本地寄存器,p表示参数寄存器。


      例如:


      //===================================================================
      private void print(String string) {
      Log.d(TAG, string);
      }
      //===================================================================
      .method private print(Ljava/lang/String;)V
      .registers 3
      .param p1, "string" # Ljava/lang/String;

      .prologue
      .line 29
      const-string v0, "MainActivity"

      invoke-static {v0, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

      .line 30
      return-void
      .end method
      //===================================================================

      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

        .registers 3 说明该方法有三个寄存器,其中一个本地寄存器v0,两个参数寄存器p0,p1,细心的人可能会注意到没有看到p0,原因是p0存放的是this。如果是静态方法的话就只有2个寄存器了,不需要存this了。


        5、基本指令?
        smali字节码是类似于汇编的,如果你有汇编基础,理解起来是非常容易的。?
        move v0, v3 把v3寄存器的值移动到寄存器v0上?
        const-string v0, “MainActivity” 把字符串”MainActivity”赋值给v0寄存器?
        invoke-super  调用父函数?
        return-void  函数返回void?
        new-instance  创建实例?
        iput-object  对象赋值?
        iget-object  调用对象?
        invoke-static  调用静态函数?
        invoke-direct  调用函数


        例如:


        //===================================================================
        @Override
        public void onClick(View view) {
        String str = "Hello World!";
        print(str);
        }
        //===================================================================
        # virtual methods
        # 参数类型为Landroid/view/View,返回类型为V
        .method public onClick(Landroid/view/View;)V
        # 表示有三个寄存器
        .registers 3
        # 参数View类型的view变量对应的是寄存器p1
        .param p1, "view" # Landroid/view/View;

        .prologue
        .line 24
        #将"Hello World!"字符串放到寄存器v0中
        const-string v0, "Hello World!"

        .line 25
        # 定义一个Ljava/lang/String类型的str变量对应本地寄存器v0
        .local v0, "str":Ljava/lang/String;
        # 调用该类的print方法,该方法的参数类型为Ljava/lang/String,返回值为V
        # 调用print方法传入的参数为{p0, v0},及print(p0, v0),p0为this,v0为"Hello World!"字符串
        invoke-direct {p0, v0}, Ltestdemo/hpp/cn/annotationtest/MainActivity;->print(Ljava/lang/String;)V

        .line 26
        return-void
        .end method
        //===================================================================

        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31

          6、if判断语句


          if判断一共有12条指令:


          if-eq vA, VB, cond_** 如果vA等于vB则跳转到cond_**。相当于if (vA==vB)
          if-ne vA, VB, cond_** 如果vA不等于vB则跳转到cond_**。相当于if (vA!=vB)
          if-lt vA, VB, cond_** 如果vA小于vB则跳转到cond_**。相当于if (vAif-le vA, VB, cond_** 如果vA小于等于vB则跳转到cond_**。相当于if (vA<=vB)
          if-gt vA, VB, cond_** 如果vA大于vB则跳转到cond_**。相当于if (vA>vB)
          if-ge vA, VB, cond_** 如果vA大于等于vB则跳转到cond_**。相当于if (vA>=vB)

          if-eqz vA, :cond_** 如果vA等于0则跳转到:cond_** 相当于if (VA==0)
          if-nez vA, :cond_** 如果vA不等于0则跳转到:cond_**相当于if (VA!=0)
          if-ltz vA, :cond_** 如果vA小于0则跳转到:cond_**相当于if (VA<0)
          if-lez vA, :cond_** 如果vA小于等于0则跳转到:cond_**相当于if (VA<=0)
          if-gtz vA, :cond_** 如果vA大于0则跳转到:cond_**相当于if (VA>0)
          if-gez vA, :cond_** 如果vA大于等于0则跳转到:cond_**相当于if (VA>=0)

          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13

            7、循环语句?
            常用的循环结构有:迭代器循环,for循环,do while循环。


            8、switch分支语句


            9、try/catch语句


            四、字段


            smali文件中,字段的声明使用.field指令,字段分为静态字段和实例字段。


            1、静态字段


            #static fields
            .field <访问权限> static [修饰关键字] <字段名>:<字段类型>

            • 1
            • 2

              可以看到,baksmali在生成smali文件时,会在静态字段声明的起始处添加注释”static fields”,注释是以#开头。


              访问权限包括:private、protected、public(三者之一)?
              修饰关键字为字段的其他属性,例如,final?
              字段名和类型就不用解释了


              例如:


              //===================================================================
              private static final String TAG = "MainActivity";
              //===================================================================
              # static fields
              .field private static final TAG:Ljava/lang/String; = "MainActivity"
              //===================================================================

              • 1
              • 2
              • 3
              • 4
              • 5
              • 6

                2、实例字段?
                相比于静态自动就少了一个static的静态声明而已,其他都一样。


                #instance fields
                .field <访问权限> [修饰关键字] <字段名>:<字段类型>

                • 1
                • 2

                  例如:


                  //===================================================================
                  private Button mButton;
                  //===================================================================
                  # instance fields
                  .field private mButton:Landroid/widget/Button;
                  //===================================================================

                  • 1
                  • 2
                  • 3
                  • 4
                  • 5
                  • 6

                    五、方法?
                    smali的方法声明使用的.method指令,方法分为直接方法和虚方法两种。


                    1、直接方法?
                    直接方法指的是该类中定义的方法。


                    #direct methods
                    .method <访问权限> [修饰关键字] <方法原型>
                    <.registers>
                    [.param]
                    [.prologue]
                    [.line]
                    <.local>
                    <代码体>
                    .end method

                    • 1
                    • 2
                    • 3
                    • 4
                    • 5
                    • 6
                    • 7
                    • 8
                    • 9

                      #direct methods是注释,是baksmali添加的,访问权限和修饰关键字跟字段是一样的。
                      方法原型描述了方法的名称、参数与返回值。
                      .registers 指令指定了方法中寄存器的总数,这个数量是参数和本地变量总和。
                      .param表明了方法的参数,每个.param指令表示一个参数,方法使用了几个参数就有几个.parameter指令。
                      .prologue指定了代码的开始处,混淆过的代码可能去掉了该指令。
                      .line指明了该处代码在源代码中的行号,同样,混淆后的代码可能去掉了行号。
                      .local 使用这个指定表明方法中非参寄存器

                      • 1
                      • 2
                      • 3
                      • 4
                      • 5
                      • 6
                      • 7

                        //===================================================================
                        private void print(String string) {
                        Log.d(TAG, string);
                        }
                        //===================================================================
                        .method private print(Ljava/lang/String;)V
                        .registers 3
                        .param p1, "string" # Ljava/lang/String;

                        .prologue
                        .line 29
                        const-string v0, "MainActivity"

                        invoke-static {v0, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

                        .line 30
                        return-void
                        .end method
                        //===================================================================

                        • 1
                        • 2
                        • 3
                        • 4
                        • 5
                        • 6
                        • 7
                        • 8
                        • 9
                        • 10
                        • 11
                        • 12
                        • 13
                        • 14
                        • 15
                        • 16
                        • 17
                        • 18
                        • 19

                          2、虚方法?
                          虚方法指的是从父类中继承的方法或者实现的接口的方法,它的声明跟直接方法相同,只是起始的初始为virtual methods


                          //===================================================================
                          @Override
                          public void onClick(View view) {
                          String str = "Hello World!";
                          print(str);
                          }
                          //===================================================================
                          # virtual methods
                          .method public onClick(Landroid/view/View;)V
                          .registers 3
                          .param p1, "view" # Landroid/view/View;

                          .prologue
                          .line 24
                          const-string v0, "Hello World!"

                          .line 25
                          .local v0, "str":Ljava/lang/String;
                          invoke-direct {p0, v0}, Ltestdemo/hpp/cn/annotationtest/MainActivity;->print(Ljava/lang/String;)V

                          .line 26
                          return-void
                          .end method
                          //===================================================================

                          • 1
                          • 2
                          • 3
                          • 4
                          • 5
                          • 6
                          • 7
                          • 8
                          • 9
                          • 10
                          • 11
                          • 12
                          • 13
                          • 14
                          • 15
                          • 16
                          • 17
                          • 18
                          • 19
                          • 20
                          • 21
                          • 22
                          • 23
                          • 24

                            3、静态方法


                            //===================================================================
                            public static void setTag(String str) {
                            TAG = str;
                            }
                            //===================================================================
                            .method public static setTag(Ljava/lang/String;)V
                            .registers 1
                            .param p0, "str" # Ljava/lang/String;

                            .prologue
                            .line 64
                            sput-object p0, Ltestdemo/hpp/cn/annotationtest/MainActivity;->TAG:Ljava/lang/String;

                            .line 65
                            return-void
                            .end method
                            //===================================================================

                            • 1
                            • 2
                            • 3
                            • 4
                            • 5
                            • 6
                            • 7
                            • 8
                            • 9
                            • 10
                            • 11
                            • 12
                            • 13
                            • 14
                            • 15
                            • 16
                            • 17
                            • 18

                              六、注解


                              如果一个类使用了注解,那么smali中会使用.annotation指令。


                              #annotations
                              .annotation [注解属性] <注解类名>
                              [注解字段 = 值]
                              .end annotation

                              • 1
                              • 2
                              • 3
                              • 4

                                注解的作用范围可以是类、方法或者字段。如果注解的作用范围是类,.annotation指令会直接定义在smali文件中,如果是方法或者字段,.annotation指令则会包含在方法或者字段的定义中。


                                1、注解类


                                //===================================================================
                                @BindInt(100)
                                public class MainActivity extends AppCompatActivity {

                                }
                                //===================================================================
                                # annotations
                                .annotation build Ltestdemo/hpp/cn/annotationtest/BindInt;
                                value = 0x64
                                .end annotation
                                //===================================================================

                                • 1
                                • 2
                                • 3
                                • 4
                                • 5
                                • 6
                                • 7
                                • 8
                                • 9
                                • 10
                                • 11

                                  2、注解字段


                                  //===================================================================
                                  @BindView(R.id.button)
                                  public Button mButton;
                                  //===================================================================
                                  # instance fields
                                  .field public mButton:Landroid/widget/Button;
                                  .annotation build Lbutterknife/BindView;
                                  value = 0x7f0c0050
                                  .end annotation
                                  .end field
                                  //===================================================================

                                  • 1
                                  • 2
                                  • 3
                                  • 4
                                  • 5
                                  • 6
                                  • 7
                                  • 8
                                  • 9
                                  • 10
                                  • 11
                                  • 12

                                    3、注解方法


                                    //===================================================================
                                    @OnClick(R.id.button)
                                    public void click() {
                                    String str = "Hello World!";
                                    print(str);
                                    }
                                    //===================================================================
                                    # virtual methods
                                    .method public click()V
                                    .registers 2
                                    .annotation build Lbutterknife/OnClick;
                                    value = {
                                    0x7f0c0050
                                    }
                                    .end annotation

                                    .prologue
                                    .line 29
                                    const-string v0, "Hello World!"

                                    .line 30
                                    .local v0, "str":Ljava/lang/String;
                                    invoke-direct {p0, v0}, Ltestdemo/hpp/cn/annotationtest/MainActivity;->print(Ljava/lang/String;)V

                                    .line 31
                                    return-void
                                    .end method
                                    //===================================================================

                                    • 1
                                    • 2
                                    • 3
                                    • 4
                                    • 5
                                    • 6
                                    • 7
                                    • 8
                                    • 9
                                    • 10
                                    • 11
                                    • 12
                                    • 13
                                    • 14
                                    • 15
                                    • 16
                                    • 17
                                    • 18
                                    • 19
                                    • 20
                                    • 21
                                    • 22
                                    • 23
                                    • 24
                                    • 25
                                    • 26
                                    • 27
                                    • 28

                                      学会怎么看懂smali文件后,是不是迫不及待的想找个apk反编译看看呢~











友情链接: