奇門遁甲之字節(jié)碼與JVM指令

奇門遁甲之字節(jié)碼與JVM指令
奇門遁甲之ASM操縱字節(jié)碼
奇門遁甲之Transform API

最近在研究ASM 字節(jié)碼增強(qiáng)技術(shù),要掌握ASM 必須要先連接Java字節(jié)碼結(jié)構(gòu)茎毁、JVM棧幀和常用JVM指令退疫。

本章就Java字節(jié)碼和JVM棧幀和JVM指令做一些梳理和整理加以沉淀,方便將來(lái)復(fù)習(xí)查閱万伤。

一肪笋、ByteCode字節(jié)碼

1.1月劈、字節(jié)碼碼結(jié)構(gòu)

Java代碼最終都會(huì)被編譯成class文件(字節(jié)碼),這些字節(jié)碼可以被JVM正確識(shí)別和解析。

JVM 對(duì)java字節(jié)碼有嚴(yán)格的規(guī)定,如下圖所示:

字節(jié)碼結(jié)構(gòu)圖.png
字節(jié)碼結(jié)構(gòu)示意圖
  • Magic: 該項(xiàng)存放了一個(gè) Java 類文件的魔數(shù)(magic number)和版本信息藤乙。一個(gè) Java 類文件的前 4 個(gè)字節(jié)被稱為它的魔數(shù)猜揪。每個(gè)正確的 Java 類文件都是以 0xCAFEBABE 開頭的,這樣保證了 Java 虛擬機(jī)能很輕松的分辨出 Java 文件和非 Java 文件坛梁。
  • Version: 該項(xiàng)存放了 Java 類文件的版本信息而姐,它對(duì)于一個(gè) Java 文件具有重要的意義。因?yàn)?Java 技術(shù)一直在發(fā)展划咐,所以類文件的格式也處在不斷變化之中拴念。類文件的版本信息讓虛擬機(jī)知道如何去讀取并處理該類文件。
  • Constant Pool: 該項(xiàng)存放了類中各種文字字符串褐缠、類名政鼠、方法名和接口名稱、final 變量以及對(duì)外部類的引用信息等常量队魏。虛擬機(jī)必須為每一個(gè)被裝載的類維護(hù)一個(gè)常量池公般,常量池中存儲(chǔ)了相應(yīng)類型所用到的所有類型、字段和方法的符號(hào)引用器躏,因此它在 Java 的動(dòng)態(tài)鏈接中起到了核心的作用俐载。常量池的大小平均占到了整個(gè)類大小的 60% 左右。
  • Access_flag: 該項(xiàng)指明了該文件中定義的是類還是接口(一個(gè) class 文件中只能有一個(gè)類或接口)登失,同時(shí)還指名了類或接口的訪問(wèn)標(biāo)志遏佣,如 public,private, abstract 等信息揽浙。
  • This Class: 指向表示該類全限定名稱的字符串常量的指針状婶。
  • Super Class: 指向表示父類全限定名稱的字符串常量的指針。
  • Interfaces: 一個(gè)指針數(shù)組馅巷,存放了該類或父類實(shí)現(xiàn)的所有接口名稱的字符串常量的指針膛虫。
  • Fields: 該項(xiàng)對(duì)類或接口中聲明的字段進(jìn)行了細(xì)致的描述。需要注意的是钓猬,fields 列表中僅列出了本類或接口中的字段稍刀,并不包括從超類和父接口繼承而來(lái)的字段。
  • Fields: 該項(xiàng)對(duì)類或接口中聲明的字段進(jìn)行了細(xì)致的描述。需要注意的是账月,fields 列表中僅列出了本類或接口中的字段综膀,并不包括從超類和父接口繼承而來(lái)的字段。
  • Class attributes: 該項(xiàng)存放了在該文件中類或接口所定義的屬性的基本信息局齿。

1.2剧劝、舉個(gè)栗子

以TestCost 為例

package com.sogou.iot.trplugin;

/**
 * 文件名:TestCost
 * 創(chuàng)建者:baixuefei
 * 創(chuàng)建日期:2021/1/21 9:52 AM
 * 職責(zé)描述:
 */


class TestCost {

    public int add(int a,int b) {
        return a+b;
    }
}

生成字節(jié)碼

javac -g TestCost.java

 -g 參數(shù)表示生成所有調(diào)試信息

生成TestCoast.class文件

查看字節(jié)碼的信息

javap -verbose TestCost.class

-verbose 表示輸出輸出附加信息

TestCost.class 解析后的信息


Classfile /Users/feifei/Desktop/TM/Demo/TrPlugin/app/src/main/java/com/sogou/iot/trplugin/TestCost.class
  Last modified 2021-1-24; size 401 bytes
  MD5 checksum 684202ea0bfc50a7d404275086566aaf
  Compiled from "TestCost.java"
class com.sogou.iot.trplugin.TestCost
  minor version: 0
  major version: 52
  flags: ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#18         // java/lang/Object."<init>":()V
   #2 = Class              #19            // com/sogou/iot/trplugin/TestCost
   #3 = Class              #20            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lcom/sogou/iot/trplugin/TestCost;
  #11 = Utf8               add
  #12 = Utf8               (II)I
  #13 = Utf8               a
  #14 = Utf8               I
  #15 = Utf8               b
  #16 = Utf8               SourceFile
  #17 = Utf8               TestCost.java
  #18 = NameAndType        #4:#5          // "<init>":()V
  #19 = Utf8               com/sogou/iot/trplugin/TestCost
  #20 = Utf8               java/lang/Object
{
  com.sogou.iot.trplugin.TestCost();
    descriptor: ()V
    flags:
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 13: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/sogou/iot/trplugin/TestCost;

  public int add(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: iload_1
         1: iload_2
         2: iadd
         3: ireturn
      LineNumberTable:
        line 16: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  this   Lcom/sogou/iot/trplugin/TestCost;
            0       4     1     a   I
            0       4     2     b   I
}
SourceFile: "TestCost.java"

TestCost.class文件如何解讀呢?這還需要先了解JVM的棧幀結(jié)構(gòu)

1.3、JVM棧幀

JVM中每調(diào)用一個(gè)方法 就會(huì)生成一個(gè)棧幀抓歼。棧幀中包含的內(nèi)容包括:局部變量表讥此、操作棧、動(dòng)態(tài)鏈接谣妻、和方法返回地址四部分萄喳。


image

棧幀是用來(lái)存儲(chǔ)數(shù)據(jù)和部分過(guò)程結(jié)果的數(shù)據(jù)結(jié)構(gòu),同時(shí)也用來(lái)處理動(dòng)態(tài)連接蹋半、方法返回值和異常分派取胎。
棧幀隨著方法調(diào)用而創(chuàng)建,隨著方法結(jié)束而銷毀——無(wú)論方法正常完成還是異常完成都算作方法結(jié)束湃窍。
棧幀的存儲(chǔ)空間由創(chuàng)建它的線程分配在Java虛擬機(jī)棧之中,每一個(gè)棧幀都有自己的本地變量表(局部變量表)匪傍、操作數(shù)棧和指向當(dāng)前方法所屬的類的運(yùn)行時(shí)常量池的引用您市。

1.3.1、局部變量表

局部變量表(Local Variable Table)是一組變量值存儲(chǔ)空間役衡,用于存放方法參數(shù)和方法內(nèi)定義的局部變量茵休。局部變量表的容量以變量槽(Variable Slot)為最小單位,Java虛擬機(jī)規(guī)范并沒(méi)有定義一個(gè)槽所應(yīng)該占用內(nèi)存空間的大小手蝎,但是規(guī)定了一個(gè)槽應(yīng)該可以存放一個(gè)32位以內(nèi)的數(shù)據(jù)類型榕莺。
虛擬機(jī)通過(guò)索引定位的方法查找相應(yīng)的局部變量,索引的范圍是從0~局部變量表最大容量棵介。

在Java程序編譯為Class文件時(shí),就在方法的Code屬性中的max_locals數(shù)據(jù)項(xiàng)中確定了該方法所需分配的局部變量表的最大容量钉鸯。

 public int add(int a,int b) {
        return a+b;
    }

以add方法為例,其局部變量有幾個(gè)?a、b分別算一個(gè),類的實(shí)例方法通常還有有一個(gè)隱藏的參數(shù)就是this邮辽。所以add方法有三個(gè)參數(shù)唠雕,分別是this,a,b。
所以add方法堆棧對(duì)應(yīng)的局部變量表大小為3,如LocalVariableTable所示:

 public int add(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: iload_1
         1: iload_2
         2: iadd
         3: ireturn
      LineNumberTable:
        line 16: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  this   Lcom/sogou/iot/trplugin/TestCost;
            0       4     1     a   I
            0       4     2     b   I
1.3.2吨述、操作數(shù)棧

操作數(shù)棧(Operand Stack)也常稱為操作棧岩睁,它是一個(gè)后入先出棧(LIFO)。同局部變量表一樣揣云,操作數(shù)棧的最大深度也在編譯的時(shí)候?qū)懭氲椒椒ǖ腃ode屬性的max_stacks數(shù)據(jù)項(xiàng)中捕儒。

當(dāng)一個(gè)方法剛剛開始執(zhí)行時(shí),其操作數(shù)棧是空的邓夕,隨著方法執(zhí)行和字節(jié)碼指令的執(zhí)行刘莹,會(huì)從局部變量表或?qū)ο髮?shí)例的字段中復(fù)制常量或變量寫入到操作數(shù)棧阎毅,再隨著計(jì)算的進(jìn)行將棧中元素出棧到局部變量表或者返回給方法調(diào)用者,也就是出棧/入棧操作栋猖。一個(gè)完整的方法執(zhí)行期間往往包含多個(gè)這樣出棧/入棧的過(guò)程净薛。

JVM指令
  • load 命令:用于將局部變量表的指定位置的相應(yīng)類型變量加載到操作數(shù)棧頂;
  • store命令:用于將操作數(shù)棧頂?shù)南鄳?yīng)類型數(shù)據(jù)保入局部變量表的指定位置蒲拉;
  • invokevirtual:調(diào)用實(shí)例方法
  • ireturn: 當(dāng)前方法返回int
a = b + c 的字節(jié)碼執(zhí)行過(guò)程中操作數(shù)棧以及局部變量表的變化如下圖所示
image

image

1.3.3肃拜、動(dòng)態(tài)連接

在一個(gè)class文件中,一個(gè)方法要調(diào)用其他方法雌团,需要將這些方法的符號(hào)引用轉(zhuǎn)化為其在內(nèi)存地址中的直接引用燃领,而符號(hào)引用存在于方法區(qū)中的運(yùn)行時(shí)常量池.

Java虛擬機(jī)棧中,每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧所屬方法的符號(hào)引用锦援,持有這個(gè)引用的目的是為了支持方法調(diào)用過(guò)程中的動(dòng)態(tài)連接(Dynamic Linking)猛蔽。

這些符號(hào)引用一部分會(huì)在類加載階段或者第一次使用時(shí)就直接轉(zhuǎn)化為直接引用,這類轉(zhuǎn)化稱為靜態(tài)解析灵寺。另一部分將在每次運(yùn)行期間轉(zhuǎn)化為直接引用曼库,這類轉(zhuǎn)化稱為動(dòng)態(tài)連接。

1.3.4略板、方法返回

當(dāng)一個(gè)方法開始執(zhí)行時(shí)毁枯,可能有兩種方式退出該方法:正常完成出口和異常完成出口。

  • 正常完成出口是指方法正常完成并退出叮称,沒(méi)有拋出任何異常(包括Java虛擬機(jī)異常以及執(zhí)行時(shí)通過(guò)throw語(yǔ)句顯示拋出的異常)种玛。
  • 異常完成出口 是指方法執(zhí)行過(guò)程中遇到異常,并且這個(gè)異常在方法體內(nèi)部沒(méi)有得到處理瓤檐,導(dǎo)致方法退出赂韵。

無(wú)論是Java虛擬機(jī)拋出的異常還是代碼中使用athrow指令產(chǎn)生的異常,只要在本方法的異常表中沒(méi)有搜索到相應(yīng)的異常處理器挠蛉,就會(huì)導(dǎo)致方法退出祭示。

方法退出過(guò)程實(shí)際上就等同于把當(dāng)前棧幀出棧,因此退出可以執(zhí)行的操作有:恢復(fù)上層方法的局部變量表和操作數(shù)棧碌秸,把返回值(如果有的話)壓如調(diào)用者的操作數(shù)棧中绍移,調(diào)整PC計(jì)數(shù)器的值以指向方法調(diào)用指令后的下一條指令。

二讥电、常用的JVM指令

2.1蹂窖、棧操作相關(guān)

load和store

  • load 命令:用于將局部變量表的指定位置的相應(yīng)類型變量加載到棧頂;
  • store命令:用于將棧頂?shù)南鄳?yīng)類型數(shù)據(jù)保入局部變量表的指定位置恩敌;
變量進(jìn)棧 含義 變量保存 含義
iload 第1個(gè)int型變量進(jìn)棧 istore 棧頂int數(shù)值存入第1局部變量
iload_0 第1個(gè)int型變量進(jìn)棧 istore_0 棧頂int數(shù)值存入第1局部變量
iload_1 第2個(gè)int型變量進(jìn)棧 istore_1 棧頂int數(shù)值存入第2局部變量
iload_2 第3個(gè)int型變量進(jìn)棧 istore_2 棧頂int數(shù)值存入第3局部變量
iload_3 第4個(gè)int型變量進(jìn)棧 istore_3 棧頂int數(shù)值存入第4局部變量
lload 第1個(gè)long型變量進(jìn)棧 lstore 棧頂long數(shù)值存入第1局部變量
fload 第1個(gè)float型變量進(jìn)棧 fstore 棧頂float數(shù)值存入第1局部變量
dload 第1個(gè)double型變量進(jìn)棧 dstore 棧頂double數(shù)值存入第1局部變量
aload 第1個(gè)ref型變量進(jìn)棧 astore 棧頂ref對(duì)象存入第1局部變量
const瞬测、push和ldc
  • const、push:將相應(yīng)類型的常量放入棧頂
  • ldc:則是從常量池中將常量壓入操作數(shù)棧棧頂
變量進(jìn)棧 含義 變量保存 含義
iload 第1個(gè)int型變量進(jìn)棧 istore 棧頂int數(shù)值存入第1局部變量
iload_0 第1個(gè)int型變量進(jìn)棧 istore_0 棧頂int數(shù)值存入第1局部變量
iload_1 第2個(gè)int型變量進(jìn)棧 istore_1 棧頂int數(shù)值存入第2局部變量
iload_2 第3個(gè)int型變量進(jìn)棧 istore_2 棧頂int數(shù)值存入第3局部變量
iload_3 第4個(gè)int型變量進(jìn)棧 istore_3 棧頂int數(shù)值存入第4局部變量
lload 第1個(gè)long型變量進(jìn)棧 lstore 棧頂long數(shù)值存入第1局部變量
fload 第1個(gè)float型變量進(jìn)棧 fstore 棧頂float數(shù)值存入第1局部變量
dload 第1個(gè)double型變量進(jìn)棧 dstore 棧頂double數(shù)值存入第1局部變量
aload 第1個(gè)ref型變量進(jìn)棧 astore 棧頂ref對(duì)象存入第1局部變量
常量池操作 含義
ldc int、float或String型常量從常量池推送至棧頂
ldc_w int穷躁、float或String型常量從常量池推送至棧頂(寬索引)
ldc2_w long或double型常量從常量池推送至棧頂(寬索引)
pop和dup
  • pop用于棧頂數(shù)值出棧操作问潭;
  • dup用于復(fù)制棧頂?shù)闹付▊€(gè)數(shù)的數(shù)值婚被,并將其壓入棧頂指定次數(shù)
棧頂操作 含義
pop 棧頂數(shù)值出棧(不能是long/double)
pop2 棧頂數(shù)值出棧(long/double型1個(gè)址芯,其他2個(gè))
dup 復(fù)制棧頂數(shù)值谷炸,并壓入棧頂
dup_x1 復(fù)制棧頂數(shù)值旬陡,并壓入棧頂2次
dup_x2 復(fù)制棧頂數(shù)值季惩,并壓入棧頂3次
dup2 復(fù)制棧頂2個(gè)數(shù)值画拾,并壓入棧頂
dup2_x1 復(fù)制棧頂2個(gè)數(shù)值青抛,并壓入棧頂2次
dup2_x2 復(fù)制棧頂2個(gè)數(shù)值蜜另,并壓入棧頂3次
swap 棧頂?shù)膬蓚€(gè)數(shù)值互換举瑰,且不能是long/double

dup2對(duì)于long、double類型的數(shù)據(jù)就是一個(gè)蔬螟,對(duì)于其他類型的數(shù)據(jù)此迅,才是真正的兩個(gè),這個(gè)的2代表的是2個(gè)slot的數(shù)據(jù)。

2.2耸序、對(duì)象相關(guān)

字段調(diào)用
字段調(diào)用 含義
getstatic 獲取類的靜態(tài)字段,將其值壓入棧頂
putstatic 給類的靜態(tài)字段賦值
getfield 獲取對(duì)象的字段坎怪,將其值壓入棧頂
putfield 給對(duì)象的字段賦值
方法調(diào)用
方法調(diào)用 作用 解釋
invokevirtual 調(diào)用實(shí)例方法 虛方法分派
invokestatic 調(diào)用類方法 static方法
invokeinterface 調(diào)用接口方法 運(yùn)行時(shí)搜索合適方法調(diào)用
invokespecial 調(diào)用特殊實(shí)例方法 包括實(shí)例初始化方法搅窿、父類方法
invokedynamic 由用戶引導(dǎo)方法決定 運(yùn)行時(shí)動(dòng)態(tài)解析出調(diào)用點(diǎn)限定符所引用方法
方法返回
方法返回 含義 解釋
ireturn 當(dāng)前方法返回int 虛方法分派
lreturn 當(dāng)前方法返回long static方法
freturn 當(dāng)前方法返回float 運(yùn)行時(shí)搜索合適方法調(diào)用
dreturn 當(dāng)前方法返回double 包括實(shí)例初始化方法、父類方法
areturn 當(dāng)前方法返回ref 運(yùn)行時(shí)動(dòng)態(tài)解析出調(diào)用點(diǎn)限定符所引用方法
對(duì)象和數(shù)組
  • 創(chuàng)建類實(shí)例: new
  • 創(chuàng)建數(shù)組:newarray戈钢、anewarray痹仙、multianewarray
  • 數(shù)組元素 加載到 操作數(shù)棧:xaload (x可為b,c,s,i,l,f,d,a)
  • 操作數(shù)棧的值 存儲(chǔ)到數(shù)組元素: xastore (x可為b,c,s,i,l,f,d,a)
  • 數(shù)組長(zhǎng)度:arraylength
  • 類實(shí)例類型:instanceof、checkcast

2.3殉了、運(yùn)算指令

運(yùn)算指令是用于對(duì)操作數(shù)棧上的兩個(gè)數(shù)值進(jìn)行某種運(yùn)算开仰,并把結(jié)果重新存入到操作棧頂

運(yùn)算 int long float double
加法 iadd ladd fadd dadd
減法 isub lsub fsub dsub
乘法 imul lmul fmul dmul
除法 idiv ldiv fdiv ddiv
求余 irem lrem frem drem
取反 ineg lneg fneg dneg

其他運(yùn)算:

  • 位移:ishl,ishr,iushr,lshl,lshr,lushr
  • 按位或: ior,lor
  • 按位與: iand, land
  • 按位異或: ixor, lxor
  • 自增:iin
  • 比較:dcmpg,dcmpl,fcmpg,fcmpl,lcmp

2.4、類型轉(zhuǎn)換

類型轉(zhuǎn)換用于將兩種不同類型的數(shù)值進(jìn)行轉(zhuǎn)換薪铜。
類型轉(zhuǎn)換指令:i2b, i2c,f2i等等众弓。

2.5、流程控制

控制指令是指有條件或無(wú)條件地修改PC寄存器的值隔箍,從而達(dá)到控制流程的目標(biāo)

  • 條件分支:ifeq谓娃、iflt、ifnull蜒滩、ifnonnull等
  • 復(fù)合分支:tableswitch滨达、lookupswitch
  • 無(wú)條件分支:goto、goto_w俯艰、jsr捡遍、jsr_w、ret

2.6竹握、同步與異常

  • Java程序顯式拋出異常: athrow指令画株。
  • Java虛擬機(jī)的指令集中通過(guò)monitorenter和monitorexit兩條指令來(lái)完成synchronized的功能

三庸推、參考文章

http://gityuan.com/2015/10/24/jvm-bytecode-grammar/

https://zhuanlan.zhihu.com/p/45354152

https://zhuanlan.zhihu.com/p/94498015?utm_source=wechat_timeline

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子着绊,更是在濱河造成了極大的恐慌疆液,老刑警劉巖攀圈,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件现喳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡犬辰,警方通過(guò)查閱死者的電腦和手機(jī)嗦篱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門灸促,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人涵卵,你說(shuō)我怎么就攤上這事浴栽。” “怎么了轿偎?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵典鸡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我坏晦,道長(zhǎng)萝玷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任英遭,我火速辦了婚禮间护,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挖诸。我一直安慰自己汁尺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布多律。 她就那樣靜靜地躺著痴突,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狼荞。 梳的紋絲不亂的頭發(fā)上缩赛,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天鲁冯,我揣著相機(jī)與錄音,去河邊找鬼。 笑死施无,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的企垦。 我是一名探鬼主播涎永,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼一死!你這毒婦竟也來(lái)了肛度?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤投慈,失蹤者是張志新(化名)和其女友劉穎承耿,沒(méi)想到半個(gè)月后冠骄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡加袋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年凛辣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锁荔。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蟀给,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阳堕,到底是詐尸還是另有隱情跋理,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布恬总,位于F島的核電站前普,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏壹堰。R本人自食惡果不足惜拭卿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贱纠。 院中可真熱鬧峻厚,春花似錦、人聲如沸谆焊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辖试。三九已至辜王,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間罐孝,已是汗流浹背呐馆。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留莲兢,地道東北人汹来。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像改艇,于是被迫代替她去往敵國(guó)和親收班。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容