专栏首页刘晓杰class文件字节码解析

class文件字节码解析

本篇文章将介绍 .class 文件的结构,通过一个简单的例子认识 .class 文件。 首先写一个java文件(本人选择在Android平台,主要是接下来一篇会讲到dex文件,方便做对比)

package com.example.liuxiaojie.smalietest;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView textView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.tv);
        textView.setText("smali");
    }
}

然后运行,可以在对应的文件夹下得到class文件.放到Android Studio里面是这样的

package com.example.liuxiaojie.smalietest;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private TextView textView;

    public MainActivity() {
    }

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(2131296284);
        this.textView = (TextView)this.findViewById(2131165325);
        this.textView.setText("smali");
    }
}

其实这不能算class文件本来的样子.因为用Notepad++或者Sublime打开,内容大致如下

cafe babe 0000 0033 0037 0a00 0e00 200a
000e 0021 0700 2303 7f09 001c 0a00 0d00
2607 0027 037f 0700 8d0a 000d 0029 0700
2a09 000d 002b 0800 2c0a 0009 002d 0700
2e07 002f 0100 0874 6578 7456 6965 7701
0019 4c61 6e64 726f 6964 2f77 6964 6765
742f 5465 7874 5669 6577 3b01 0006 3c69
6e69 743e 0100 0328 2956 0100 0443 6f64
6501 000f 4c69 6e65 4e75 6d62 6572 5461
626c 6501 0012 4c6f 6361 6c56 6172 6961
626c 6554 6162 6c65 0100 0474 6869 7301
0030 4c63 6f6d 2f65 7861 6d70 6c65 2f6c
6975 7869 616f 6a69 652f 736d 616c 6965
7465 7374 2f4d 6169 6e41 6374 6976 6974
793b 0100 086f 6e43 7265 6174 6501 0016
284c 616e 6472 6f69 642f 6f73 2f42 756e
646c 653b 2956 0100 1273 6176 6564 496e
7374 616e 6365 5374 6174 6501 0013 4c61
6e64 726f 6964 2f6f 732f 4275 6e64 6c65
3b01 0024 5275 6e74 696d 6549 6e76 6973
6962 6c65 5061 7261 6d65 7465 7241 6e6e
6f74 6174 696f 6e73 0100 254c 616e 6472
6f69 642f 7375 7070 6f72 742f 616e 6e6f
7461 7469 6f6e 2f4e 756c 6c61 626c 653b
0100 0a53 6f75 7263 6546 696c 6501 0011
4d61 696e 4163 7469 7669 7479 2e6a 6176
610c 0011 0012 0c00 1800 1907 0030 0100
2a63 6f6d 2f65 7861 6d70 6c65 2f6c 6975
7869 616f 6a69 652f 736d 616c 6965 7465
7374 2f52 246c 6179 6f75 7401 0006 6c61
796f 7574 0100 0c49 6e6e 6572 436c 6173
7365 730c 0031 0032 0100 2663 6f6d 2f65
7861 6d70 6c65 2f6c 6975 7869 616f 6a69
652f 736d 616c 6965 7465 7374 2f52 2469
6401 0002 6964 0c00 3300 3401 0017 616e
6472 6f69 642f 7769 6467 6574 2f54 6578
7456 6965 770c 000f 0010 0100 0573 6d61
6c69 0c00 3500 3601 002e 636f 6d2f 6578
616d 706c 652f 6c69 7578 6961 6f6a 6965
2f73 6d61 6c69 6574 6573 742f 4d61 696e
4163 7469 7669 7479 0100 2861 6e64 726f
6964 2f73 7570 706f 7274 2f76 372f 6170
702f 4170 7043 6f6d 7061 7441 6374 6976
6974 7901 0023 636f 6d2f 6578 616d 706c
652f 6c69 7578 6961 6f6a 6965 2f73 6d61
6c69 6574 6573 742f 5201 000e 7365 7443
6f6e 7465 6e74 5669 6577 0100 0428 4929
5601 000c 6669 6e64 5669 6577 4279 4964
0100 1628 4929 4c61 6e64 726f 6964 2f76
6965 772f 5669 6577 3b01 0007 7365 7454
6578 7401 001b 284c 6a61 7661 2f6c 616e
672f 4368 6172 5365 7175 656e 6365 3b29
5600 2100 0d00 0e00 0000 0100 0200 0f00
1000 0000 0200 0100 1100 1200 0100 1300
0000 2f00 0100 0100 0000 052a b700 01b1
0000 0002 0014 0000 0006 0001 0000 0008
0015 0000 000c 0001 0000 0005 0016 0017
0000 0004 0018 0019 0002 0013 0000 0066
0003 0002 0000 0022 2a2b b700 022a 1204
b600 052a 2a12 07b6 0008 c000 09b5 000a
2ab4 000a 120b b600 0cb1 0000 0002 0014
0000 0016 0005 0000 000e 0005 000f 000b
0011 0018 0012 0021 0013 0015 0000 0016
0002 0000 0022 0016 0017 0000 0000 0022
001a 001b 0001 001c 0000 0007 0100 0100
1d00 0000 0200 1e00 0000 0200 1f00 2500
0000 1200 0200 0300 2200 2400 1900 0600
2200 2800 19

这里我全部贴出来了.可以看到都是由16进制数据组成.接下来,我们就可以根据一文让你明白Java字节码来解析整个文件 (整个过程其实挺累的,花了将近2个小时.难倒是不难,主要是一个一个要对照好挺困难的)

魔数(4)固定为 ca fe ba be
版本号(4)00 00 00 33,前面的0000是次版本号,后面的0033是主版本号.0x33=51(十进制)=jdk1.7。可用java --version验证
常量池(2+n)00 37,去除掉第0项,还有0x36=54个常量
    Constant1       0a(10)      MethodRef_info
                    000e(14)    Class_info索引项#14
                    0020(32)    NameAndType索引项#32
    Constant2       0a(10)      MethodRef_info
                    000e(14)    Class_info索引项#14
                    0021(33)    NameAndType索引项#33
    Constant3       07(7)       Class_info
                    0023(35)    全局限定名常量索引为#35
    Constant4       03(3)       高位在前的Integer
                    7f09001c    
    Constant5       0a(10)      MethodRef_info
                    000d(13)    Class_info索引项#13
                    0026(38)    NameAndType索引项#38
    Constant6       07(7)       Class_info
                    0027(39)    全局限定名常量索引为#39
    Constant7       03(3)       高位在前的Integer
                    7f07008d    
    Constant8       0a(10)      MethodRef_info
                    000d(13)    Class_info索引项#13
                    0029(41)    NameAndType索引项#41
    Constant9       07(7)       Class_info
                    002a(42)    全局限定名常量索引为#42
    Constant10      09(9)       FieldRef_info
                    000d(13)    Class_info索引项#13
                    002b(43)    NameAndType索引项#43
    Constant11      08(8)       字符串索引
                    002c(44)    索引项#44
    Constant12      0a(10)      MethodRef_info
                    0009(9)     Class_info索引项#9
                    002d(45)    NameAndType索引项#45
    Constant13      07(7)       Class_info
                    002e(42)    全局限定名常量索引为#46
    Constant14      07(7)       Class_info
                    002f(47)    全局限定名常量索引为#47               
    Constant15      01(1)       utf-8 info
                    0008(8)     长度为8
                    7465787456696577                                                textView
    Constant16      01(1)       utf-8 info
                    0019(25)    长度为25
                    4c616e64726f69642f7769646765742f54657874566965773b              Landroid/widget/TextView;
    Constant17      01(1)       utf-8 info
                    0006(6)     长度为6
                    3c696e69743e                                                    <init>
    Constant18      01(1)       utf-8 info
                    0003(3)     长度为3
                    282956                                                          V()
    Constant19      01(1)       utf-8 info
                    0004(4)
                    436f6465                                                        Code
    Constant20      01(1)       utf-8 info
                    000f=15
                    4c696e654e756d6265725461626c65                                  LineNumberTable
    Constant21      01(1)       utf-8 info
                    0012=18
                    4c6f63616c5661726961626c655461626c65                            LocalVariableTable
    Constant22      01(1)       utf-8 info
                    0004=4
                    74686973                                                        this
    Constant23      01(1)       utf-8 info
                    0030=48
                    4c63......793b                                                  Lcom/example/liuxiaojie/smalietest/MainActivity;
    Constant24      01(1)       utf-8 info
                    0008=8
                    6f6e437265617465                                                onCreate
    Constant25      01(1)       utf-8 info
                    0016=22
                    ......                                                          (Landroid/os/Bundle;)V
    Constant26      01(1)       utf-8 info
                    0012=18
                    ......                                                          saveInstanceState
    Constant27      01(1)       utf-8 info
                    0013=19
                    ......                                                          Landroid/os/Bundle;
    (接下来是一堆的string,我只写最终结果了)
    Constant28                                                                      RuntimeInvisibleParameterAnnotations
    Constant29                                                                      Landroid/support/annotation/Nullable;
    Constant30                                                                      SourceFile              
    Constant31                                                                      MainActivity.java

    Constant32      0c(12)
                    对应索引#17,#18                                             <init>    V()
    Constant33      0c(12)  NameAndType索引项#12
                    对应索引#24,#25                                             Lcom/example/liuxiaojie/smalietest/MainActivity;   onCreate
    Constant34      07(7)       Class_info
                    0030(48)    全局限定名常量索引为#48
    Constant35                                                                      com/example/liuxiaojie/smalietest/R$layout
    Constant36                                                                      layout
    Constant37                                                                      InnerClasses
    Constant38      0c(12)
                    对应索引#49,#50
    Constant39                                                                      com/example/liuxiaojie/smalietest/R$id
    Constant40                                                                      id
    Constant41      0c(12)
                    对应索引#51,#52
    Constant42                                                                      android/widget/TextView     
    Constant43      0c(12)
                    对应索引#15,#16                                             textView       Landroid/widget/TextView;
    Constant44                                                                      smali
    Constant45      0c(12)
                    对应索引#53,#54
    Constant46                                                                      com/example/liuxiaojie/smalietest/MainActivity
    Constant47                                                                      android/support/v7/app/AppCompatActivity
    Constant48                                                                      com/example/liuxiaojie/smalietest/R
    Constant49                                                                      setContentView
    Constant50                                                                      (I)V
    Constant51                                                                      findViewById
    Constant52                                                                      (I)Landroid/view/View;
    Constant53                                                                      setText
    Constant54                                                                      (Ljava/lang/CharSequence;)V
    
    通过常量池的解析,基本有了java文件内容的轮廓

Access_Flag 访问标志   0021   (0020和0001的并集)
-------------------------------------------------------------
类索引(用于确定类的全限定名)000d=13然后找到46(com/example/liuxiaojie/smalietest/MainActivity)
父类索引 000e=14找到47(android/support/v7/app/AppCompatActivity)
接口索引(这个java文件没有接口,应该是0000)
字段表集合(用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包括方法内部声明的局部变量。)
    0001表示一共有1个变量。0002表示private。一个是000f=15,查到是textView  0010=16(Landroid/widget/TextView;) 0000表示没有属性表
方法(理论上我们只有一个onCreate。为啥会是2呢?因为init)0002表示两个方法
    第一个方法0001(ACC_PUBLIC)0011(<init>)0012(V())0001(一个属性表)
        这个属性表索引是0013(Code)length=0000002f(47)
        max_stack=0001
        max_locals=0001
        codelength=00000005
        code=2ab70001b1    具体可参考文档
        exception_table_length=0000
        attribute_count=0002
            0014(LineNumberTable)00000006(长度为6)0001 0000 0008
            0015(LocalVariableTable)0000000c(12)0001  0000 0005 0016 0017 0000
    第二个方法0004(protected)0018(onCreate)0019((Landroid/os/Bundle;)V)0002(两个属性表)
        第一个属性表索引是0013(Code)length=0000 0066(102)
        max_stack=0003
        max_locals=0002
        codelength=0000 0022(34)
        code=2a2b......
        attribute_count=0002(2)
            0014(LineNumberTable)0000 0016(长度为22)0005 (一共5个table_info,每个占两个u2类型)
            0015(LocalVariableTable)0000 0016(22) 0002 (2个variable_info)

解析到这里其实已经差不多了,至少已经对class文件的字节码有所了解了.可以看到,整个class文件的字节码都是一段一段对应好的了,每一块数据开始都是数据量,然后跟着数据,相对于dex文件而言,不用去查找偏移地址.下一篇会解析一下dex文件,解析完了就可以看到两者的区别

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Oracle数据库易遗漏的知识点(二)

    我们区分in和exists主要是驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询,所以我们...

    提莫队长
  • Android开发环境的搭建

    现在Android开发环境大多是eclipse+adt来搭建的,但是按照网上的教程通常搭建不起来。在这里我推荐一个压缩包,直接解压就可以运行了,不需要配置。

    提莫队长
  • UNPv1第十九章:多播

    单播地址标识单个接口,广播地址标识所有接口,多播地址标识一组接口。多播数据报仅对感兴趣的接口接收。

    提莫队长
  • 数据仓库中如何使用索引

    数据仓库的索引是个棘手的问题。如果索引太多,数据插入很快但是查询响应就会很慢。如果太多索引,数据导入就很慢并且数据存储空间更大,但是查询响应更快。数据库中索引的...

    用户1217611
  • [NewLife.XCode]反向工程(自动建表建库大杀器)

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netstandard,由新生命团队(2002~2019)开发完成并维护至今,以下简...

    大石头
  • 【SQL Server】系统学习之二:索引优化

    页大小8192个字节,行限制为8060字节(大型对象除外)。 包含varchar nvarchar varbinary sql_variant(8012,obj...

    小端
  • 利用Lucene打造站内搜索引擎的思路

    1.为什么要用Lucene,而不用直接从数据库里搜索记录? 主要是考虑到几个因素:(1)性能问题,Lucene是基于文件索引的搜索机制,性能要比数据库里检索更...

    菩提树下的杨过
  • 如何在SAP Fiori应用里使用React component

    在MyApp.jsx里引入UI5针对React框架的开发的Card web Component:

    Jerry Wang
  • 如何在SAP Fiori应用里使用React component

    在MyApp.jsx里引入UI5针对React框架的开发的Card web Component:

    Jerry Wang
  • 一个不可思议的MySQL慢查分析与解决

    前言 开发需要定期的删除表里一定时间以前的数据,SQL如下 mysql > delete from testtable WHERE biz_date <= '2...

    程序猿DD

扫码关注云+社区

领取腾讯云代金券