Java 反匯編分析(一)

以這段Java代碼為例候醒,反匯編分析一下對(duì)應(yīng)的Java字節(jié)碼铡溪。將該文件保存為BooleanTest.java远荠。

package ex3;

public class BooleanTest {
    public static void create() {
        boolean a = true;
        boolean b = false;
        boolean[] arr = new boolean[100];
        arr[5] = true;
        System.out.println(a);
        System.out.println(b);
        System.out.println(arr);
    }
    public static void print(int a) {
        int b = a;
        System.out.printf("%d %d\n", a, b);
    }
}

使用的Java版本為OpenJDK 1.8.0_171亚铁。

Picked up _JAVA_OPTIONS:   -Dawt.useSystemAAFontSettings=gasp
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (build 1.8.0_171-8u171-b11-2-b11)
OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode)

執(zhí)行javac BooleanTest.java; javap -v BooleanTest.class,會(huì)輸出完整的反匯編代碼苔咪,大致可以分為幾部分:元數(shù)據(jù)+常量池锰悼、一系列方法,我們分開(kāi)來(lái)看团赏。

常量池

public class ex3.BooleanTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#19         // java/lang/Object."<init>":()V
   #2 = Fieldref           #20.#21        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Methodref          #22.#23        // java/io/PrintStream.println:(Z)V
   #4 = Methodref          #22.#24        // java/io/PrintStream.println:(Ljava/lang/Object;)V
   #5 = String             #25            // %d %d\n
   #6 = Class              #26            // java/lang/Object
   #7 = Methodref          #27.#28        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #8 = Methodref          #22.#29        // java/io/PrintStream.printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
   #9 = Class              #30            // ex3/BooleanTest
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               create
  #15 = Utf8               print
  #16 = Utf8               (I)V
  #17 = Utf8               SourceFile
  #18 = Utf8               BooleanTest.java
  #19 = NameAndType        #10:#11        // "<init>":()V
  #20 = Class              #31            // java/lang/System
  #21 = NameAndType        #32:#33        // out:Ljava/io/PrintStream;
  #22 = Class              #34            // java/io/PrintStream
  #23 = NameAndType        #35:#36        // println:(Z)V
  #24 = NameAndType        #35:#37        // println:(Ljava/lang/Object;)V
  #25 = Utf8               %d %d\n
  #26 = Utf8               java/lang/Object
  #27 = Class              #38            // java/lang/Integer
  #28 = NameAndType        #39:#40        // valueOf:(I)Ljava/lang/Integer;
  #29 = NameAndType        #41:#42        // printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
  #30 = Utf8               ex3/BooleanTest
  #31 = Utf8               java/lang/System
  #32 = Utf8               out
  #33 = Utf8               Ljava/io/PrintStream;
  #34 = Utf8               java/io/PrintStream
  #35 = Utf8               println
  #36 = Utf8               (Z)V
  #37 = Utf8               (Ljava/lang/Object;)V
  #38 = Utf8               java/lang/Integer
  #39 = Utf8               valueOf
  #40 = Utf8               (I)Ljava/lang/Integer;
  #41 = Utf8               printf
  #42 = Utf8               (Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;

根據(jù)《Java虛擬機(jī)規(guī)范》箕般,每一個(gè)class文件對(duì)應(yīng)下面這樣一個(gè)ClassFile結(jié)構(gòu)。

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
  • magic:唯一作用是確定這個(gè)文件是否為一個(gè)class文件舔清,值固定為0xCAFEBABE丝里。
  • minor_versionmajor_version用來(lái)表示class文件的版本號(hào)曲初,不同版本的JDK編譯出的版本號(hào)不同,例如主版本號(hào)為52表示是Java 8版本的class杯聚、55表示是Java 11版本的class臼婆,參考
  • constant_pool_count常量池大小幌绍。
  • constant_pool常量池颁褂。
  • access_flags訪問(wèn)標(biāo)志,ACCESS_PUBLIC表示這是個(gè)public類(lèi)傀广,ACCESS_SUPER沒(méi)什么意義颁独,所有jdk 1.0.2之后編譯出的class都帶有這個(gè)標(biāo)志。
  • this_class本類(lèi)在常量池中的一個(gè)索引伪冰。
  • ......

常量池中的每一項(xiàng)都具有如下通用格式誓酒,單字節(jié)的tag表示cp_info的實(shí)際類(lèi)型,后面info數(shù)組的內(nèi)容由類(lèi)型決定贮聂。tag可以表示Class, Fieldref, Methodref, InterfaceMethodref, String, Integer, Float, Long, Double, NameAndType, Utf8, MethodHandle, MethodType, InvokeDynamic靠柑。

cp_info {
    u1 tag;
    u1 info[];
}

Class_info的結(jié)構(gòu)如下,表示一個(gè)類(lèi)或接口吓懈,name_index是常量池中一個(gè)Utf8_info項(xiàng)的下標(biāo)歼冰,表示類(lèi)或接口名。

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

Fieldref_info, Methodref_info的結(jié)構(gòu)如下骄瓣,分別表示字段引用和方法引用停巷,他們包含兩個(gè)字段,class_index表示字段榕栏、方法所在的類(lèi)在常量池中的索引畔勤,name_and_type_index表示當(dāng)前字段或方法的名字和描述符。

CONSTANT_Fieldref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}

String_info的結(jié)構(gòu)如下扒磁,用于表示一個(gè)String類(lèi)型的常量對(duì)象庆揪,string_index是常量池中一個(gè)Utf8_info項(xiàng)的下標(biāo)。

CONSTANT_String_info {
    u1 tag;
    u2 string_index;
}

Utf8_info的結(jié)構(gòu)如下妨托,用于表示一個(gè)Utf8字符串值常量缸榛。

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

NameAndType_info結(jié)構(gòu)如下,用于表示一個(gè)方法或字段兰伤,不包含類(lèi)或接口的信息(無(wú)法得知它屬于的類(lèi)或接口)内颗。name_index是常量池中一個(gè)Utf8_info的下標(biāo),表示方法名稱(chēng)敦腔;descriptor_index也是一個(gè)Utf8_info的下標(biāo)均澳,表示一個(gè)字段描述符(變量類(lèi)型)或方法描述符(方法參數(shù)和返回值類(lèi)型)。

CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}

字段描述符:例如Ljava/lang/Object;表示一個(gè)Object實(shí)例,[[[D表示double[][][]找前。

方法描述符:例如Object m(int i, double d, Thread t)(IDLjava/lang/Thread;)Ljava/lang/Object;糟袁。

現(xiàn)在來(lái)看反匯編代碼中常量池的內(nèi)容,結(jié)構(gòu)為#<index> = cp_info躺盛。

   #1 = Methodref          #6.#19         // java/lang/Object."<init>":()V
   #6 = Class              #26            // java/lang/Object
   #10 = Utf8               <init>
   #11 = Utf8               ()V
   #19 = NameAndType        #10:#11        // "<init>":()V
   #26 = Utf8               java/lang/Object
  • 第1行是一個(gè)Methodref類(lèi)型的项戴,它的class_index為6,name_and_type_index為19槽惫,后面的注釋表明這個(gè)是Object類(lèi)的構(gòu)造方法周叮。
  • 第6行,是Class類(lèi)型界斜,它的name_index為26则吟。
  • 第26行,是Utf8類(lèi)型锄蹂,它的值為java/lang/Object
  • 第19行水慨,是NameAndType類(lèi)型得糜,它的name_index為10,descriptor_index為11晰洒。
  • 第10行朝抖,是Utf8類(lèi)型,它的值為<init>谍珊,因此它表示的方法名稱(chēng)為<init>治宣,這是一個(gè)特殊方法名稱(chēng),是構(gòu)造方法砌滞。
  • 第11行侮邀,是Utf8類(lèi)型,它的值為()V贝润,表明方法沒(méi)有參數(shù)绊茧,返回值為void。

從第1行開(kāi)始打掘,經(jīng)過(guò)一系列的遞歸查表华畏,才能確定這個(gè)方法所屬的類(lèi)、方法名尊蚁、參數(shù)亡笑、返回值。javap將這個(gè)值寫(xiě)在了行末的注釋里横朋,方便閱讀仑乌,但實(shí)際的字節(jié)碼里是沒(méi)有這些的。Methodref這些也是助記符,class文件里只有一條條的字節(jié)碼绝骚。

 #42 = Utf8               (Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;

再來(lái)看一個(gè)例子耐版,這是一個(gè)Utf8類(lèi)型的記錄,可以看出它是一個(gè)方法描述符压汪,有兩個(gè)參數(shù)粪牲,分別為String類(lèi)型和Object[]類(lèi)型,返回值為PrintStream類(lèi)型止剖,這就是System.out.printf的方法描述符腺阳。

虛擬機(jī)指令

研究方法的字節(jié)碼之前需要了解一些基本的字節(jié)碼指令。

在匯編中穿香,一條指令分為操作碼和操作數(shù)亭引,常見(jiàn)的CPU的操作數(shù)都是放在寄存器中的,例如mov eax ecx皮获,將一個(gè)寄存器中的值賦予另一個(gè)寄存器焙蚓。

對(duì)于虛擬機(jī)來(lái)說(shuō),如果把操作數(shù)放在寄存器中洒宝,就稱(chēng)為基于寄存器的虛擬機(jī)购公,如果把操作數(shù)放在棧中,就稱(chēng)為基于棧的虛擬機(jī)雁歌。一般來(lái)說(shuō)宏浩,基于寄存器的虛擬機(jī)更為復(fù)雜,因?yàn)樗cCPU相關(guān)靠瞎,性能會(huì)更好比庄;基于棧的虛擬機(jī)更為簡(jiǎn)單,但性能會(huì)更差乏盐。

JVM是一個(gè)基于棧的虛擬機(jī)佳窑,它的大多指令,都涉及到對(duì)棧的操作父能。例如load系列指令华嘹,會(huì)將變量值壓入棧頂;而store系列指令法竞,會(huì)將棧頂元素出棧耙厚,存入變量;還有的指令如newarray岔霸,它會(huì)將棧上的操作數(shù)出棧薛躬,然后將指令執(zhí)行的結(jié)果(返回值)入棧。

本文中涉及到的指令:

  • iconst_<i>int常量i入棧呆细,i的范圍為-1,0,1,2,3,4,5型宝。
  • bipush <b>byte常量b入棧八匠,在棧中被擴(kuò)展成有符號(hào)整型。iconst_<i>指令與對(duì)應(yīng)的bipush <i>等價(jià)趴酣。
  • astore <index>將棧頂存入下標(biāo)為index的局部變量梨树,引用類(lèi)型必須為referencereturnAddress
  • astore_<n>astore <n>等價(jià)岖寞,n的范圍為0,1,2,3抡四。
  • newarray <type>創(chuàng)建type類(lèi)型的數(shù)組,數(shù)組的長(zhǎng)度count由棧頂?shù)恼椭付ㄕ套唬瑒?chuàng)建完成后數(shù)組的引用會(huì)被push到棧頂指巡。type只能為基本數(shù)據(jù)類(lèi)型。
  • bastorebyteboolean類(lèi)型的數(shù)組賦值隶垮,棧結(jié)構(gòu)為arrayref, index, value藻雪,相當(dāng)于arrayref[index]=value
  • getstatic <byte1> <byte2>獲取類(lèi)的靜態(tài)字段值并壓入棧中狸吞。(byte1<<8)|byte2為該字段在運(yùn)行時(shí)常量池中的下標(biāo)勉耀。
  • iload <index>將index表示的int局部變量加載到棧頂。
  • iload_<n>等價(jià)于iload <n>蹋偏,n的范圍為0,1,2,3瑰排。
  • invokevirtual <byte1> <byte2>調(diào)用實(shí)例方法。操作數(shù)棧中結(jié)構(gòu)是這樣的..., objectref, arg1, arg2 ...暖侨,使用(byte1<<8)|byte2來(lái)索引方法,運(yùn)行時(shí)常量池中的符號(hào)引用包含了方法描述崇渗、方法參數(shù)個(gè)數(shù)等信息字逗。將方法所需的nargs出棧,并被設(shè)置成方法的局部變量宅广,然后切換到方法的棧幀中葫掉,修改PC(程序計(jì)數(shù)器),開(kāi)始執(zhí)行方法中的指令跟狱。
  • ldc <index>將運(yùn)行時(shí)常量池中下標(biāo)為index的entry入棧俭厚,該entry必須為一個(gè)運(yùn)行時(shí)常量,類(lèi)型為int驶臊、long挪挤、字符串字面量引用、符號(hào)引用关翎、方法句柄扛门。
  • anewarray <byte1> <byte2>創(chuàng)建數(shù)組,通過(guò)(byte1<<8)|byte2在常量池中索引類(lèi)纵寝、數(shù)組论寨、接口,由此確定數(shù)組類(lèi)型,棧頂參數(shù)指定數(shù)組長(zhǎng)度葬凳,創(chuàng)建好的數(shù)組引用入棧绰垂。
  • aastore將值存入數(shù)組,棧結(jié)構(gòu)為arrayref, index, value火焰,相當(dāng)于arrayref[index]=value劲装,執(zhí)行完后3個(gè)操作數(shù)全部出棧。
  • pop彈出一個(gè)棧頂操作數(shù)荐健。
  • return返回void酱畅。

create方法

以下代碼是通過(guò)javap -c BooleanTest.class反匯編得來(lái)的,-c不會(huì)輸出方法中的局部變量表等信息江场,更為簡(jiǎn)潔清晰纺酸。

  public static void create();
    Code:
       0: iconst_1
       1: istore_0
       2: iconst_0
       3: istore_1
       4: bipush        100
       6: newarray       boolean
       8: astore_2
       9: aload_2
      10: iconst_5
      11: iconst_1
      12: bastore
      13: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      16: iload_0
      17: invokevirtual #3                  // Method java/io/PrintStream.println:(Z)V
      20: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      23: iload_1
      24: invokevirtual #3                  // Method java/io/PrintStream.println:(Z)V
      27: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      30: aload_2
      31: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      34: return

第一行boolean a = true對(duì)應(yīng)2條指令,iconst_1將整型常量1入棧址否,istore_0將棧頂?shù)囊粋€(gè)整型常量出棧并存入局部變量0餐蔬,也就是變量a

第二行boolean b = false也對(duì)應(yīng)2條指令佑附,iconst_0將0入棧樊诺,istore_1將0出棧存入局部變量1,也就是b音同。

第三行boolean[] arr = new boolean[100]對(duì)應(yīng)3條指令词爬,bipush 100將100入棧,newarray boolean权均,創(chuàng)建一個(gè)長(zhǎng)度為100的boolean類(lèi)型的數(shù)組顿膨,數(shù)組引用放到棧頂,astore_2將棧頂存入局部變量2叽赊,即arr恋沃。

第四行arr[5] = true對(duì)應(yīng)4條指令,aload_2arr引用入棧必指,iconst_5將5入棧囊咏,iconst_1將1入棧,bastore將數(shù)組下標(biāo)為5的位置賦值為1塔橡。

第五行System.out.println(a)對(duì)應(yīng)3條指令梅割,getstatic獲得System.out對(duì)象的引用并入棧,iload_0將局部變量1入棧葛家,invokevirtual索引println方法炮捧,以棧頂為參數(shù)進(jìn)行調(diào)用。

print方法

以下代碼是通過(guò)javap -v BooleanTest.class反匯編得來(lái)的惦银,因?yàn)槲覀冃枰^察局部變量表咆课。

  public static void print(int);
    descriptor: (I)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=6, locals=2, args_size=1
         0: iload_0
         1: istore_1
         2: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         5: ldc           #5                  // String %d %d\n
         7: iconst_2
         8: anewarray     #6                  // class java/lang/Object
        11: dup
        12: iconst_0
        13: iload_0
        14: invokestatic  #7                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        17: aastore
        18: dup
        19: iconst_1
        20: iload_1
        21: invokestatic  #7                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        24: aastore
        25: invokevirtual #8                  // Method java/io/PrintStream.printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
        28: pop
        29: return
      LineNumberTable:
        line 13: 0
        line 14: 2
        line 15: 29
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      30     0     a   I
            2      28     1     b   I

通過(guò)LocalVariableTable可以看出末誓,函數(shù)參數(shù)a也是當(dāng)做局部變量來(lái)處理的,下標(biāo)為0书蚪,局部變量b下標(biāo)為1喇澡。

第一行int b = a包含兩條指令,iload_0a的值入棧殊校,istore_1將棧頂出棧到b晴玖。

第二行System.out.printf("%d %d\n", a, b)包含多條指令

  • getstatic入棧System.out的引用,ldc將常量池中%d %d\n的引用入棧为流,iconst_2int常量2入棧呕屎,anewarray創(chuàng)建一個(gè)Object[2]數(shù)組并入棧;
  • dup復(fù)制棧頂?shù)臄?shù)組引用并入棧敬察,iconst_0int常量0入棧秀睛,iload_0將變量a入棧,invokestatic調(diào)用Integer.valueOf將棧頂裝箱成Integer對(duì)象莲祸,aastore將裝箱后的a設(shè)置到數(shù)組下標(biāo)0的位置蹂安;
  • dup復(fù)制棧頂?shù)臄?shù)組引用并入棧,iconst_1int常量1入棧锐帜,iload_1將變量b入棧田盈,invokestatic調(diào)用Integer.valueOf將棧頂裝箱,aastore將裝箱后的b設(shè)置到數(shù)組下標(biāo)1的位置缴阎;
  • invokevirtual調(diào)用printf方法允瞧;
  • pop指令將printf的返回值出棧

總結(jié)

本文實(shí)踐探索了一個(gè)class文件大致的結(jié)構(gòu):

  • 常量池就是一個(gè)數(shù)組,數(shù)組的每一項(xiàng)都具有指令的類(lèi)型蛮拔,類(lèi)型后面是它的值述暂。常量池中的項(xiàng)目通過(guò)下標(biāo)引用。
  • class中的常量池稱(chēng)為靜態(tài)常量池语泽,在類(lèi)加載的過(guò)程中會(huì)被合并到運(yùn)行時(shí)常量池中。
  • boolean類(lèi)型是當(dāng)做int來(lái)處理的视卢,1表示true踱卵,0表示false
  • boolean[]類(lèi)型不是byte[]來(lái)處理的据过,雖然在使用newarray指令創(chuàng)建的時(shí)候指定的是boolean類(lèi)型惋砂,但是在賦值的時(shí)候使用的是字節(jié)數(shù)組操作指令bastore
  • 在字節(jié)碼層面觀察到了Integer的裝箱绳锅。
  • 局部變量表按照局部變量的聲明順序依次編號(hào)的西饵。
  • 方法參數(shù)也當(dāng)做局部變量來(lái)處理,并且率先編號(hào)鳞芙。
  • 方法參數(shù)的值是由invokevirtual指令設(shè)置好的眷柔,在方法中可以直接使用期虾。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市驯嘱,隨后出現(xiàn)的幾起案子镶苞,更是在濱河造成了極大的恐慌,老刑警劉巖鞠评,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茂蚓,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡剃幌,警方通過(guò)查閱死者的電腦和手機(jī)聋涨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)负乡,“玉大人牍白,你說(shuō)我怎么就攤上這事【戴蓿” “怎么了淹朋?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)钉答。 經(jīng)常有香客問(wèn)我础芍,道長(zhǎng),這世上最難降的妖魔是什么数尿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任仑性,我火速辦了婚禮,結(jié)果婚禮上右蹦,老公的妹妹穿的比我還像新娘诊杆。我一直安慰自己,他們只是感情好何陆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布晨汹。 她就那樣靜靜地躺著,像睡著了一般贷盲。 火紅的嫁衣襯著肌膚如雪淘这。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天巩剖,我揣著相機(jī)與錄音铝穷,去河邊找鬼。 笑死佳魔,一個(gè)胖子當(dāng)著我的面吹牛曙聂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鞠鲜,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼宁脊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼断国!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起朦佩,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤并思,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后语稠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體宋彼,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年仙畦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了输涕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡慨畸,死狀恐怖莱坎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寸士,我是刑警寧澤檐什,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站弱卡,受9級(jí)特大地震影響乃正,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜婶博,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一瓮具、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凡人,春花似錦名党、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至岸晦,卻和暖如春欧啤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背委煤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工堂油, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留修档,地道東北人碧绞。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像吱窝,于是被迫代替她去往敵國(guó)和親讥邻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子迫靖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350