ELF文件長什么樣子(1/2)

和JavaScript這樣的解釋執(zhí)行語言不同,編譯執(zhí)行的語言通過編譯、鏈接最終生成可執(zhí)行文件。

ELF(Executable and Linkable Format),指.o文件和可執(zhí)行文件最铁,本文分析.o文件格式。

1. 示例程序

demo.s

#understanding .obj sections and .elf segments
.section .data
mydata1:
    .ascii "This is my data1 xxx."
mydata2:
    .ascii "This is my data2 xxx."
.section .text
.globl _start
_start:
    movl $mydata1, %edi #replace "xxx" with "1st"
    movb $49, 17(%edi)  #"1st"
    movb $115, 18(%edi)
    movb $116, 19(%edi)
 
    movl $mydata2, %edi #replace "xxx" with "2nd"
    movb $50, 17(%edi)  #"2nd"
    movb $110, 18(%edi)
    movb $100, 19(%edi)
 
    movl $1, %eax   #syscall exit
    movl $0, %ebx   #argument 0, ie. exit(0)
    int $0x80

上述程序的功能是將兩段字符串中"XXX"分別替換為"1st"和"2nd"
編譯
as -o demo.o demo.s
得到demo.o文件

鏈接
ld -o demo demo.o
得到demo可執(zhí)行文件垮兑。

2. 調試

加載到調試器中
gdb demo

設置斷點
break *_start
讓程序在_start處暫停冷尉。

查看當前指令
display/2i $eip
查看eip指針指向的兩條指令。顯示格式為I (instruction)

運行
r
運行系枪,顯示輸出:

1: x/2i $eip 
=> 0x8048074 <_start>:    mov $0x80490a4,%edi 0x8048079 <_start+5>: 
                     movb $0x31,0x11(%edi)

0x80490a4即為mydata1在內存中的起始地址雀哨。

查看mydata
display/5s 0x80490a4
顯示地址0x80490a4開始的5條字符串。輸出格式為s(string)

執(zhí)行下一條指令
ni
輸入ni,執(zhí)行next instruction嗤无。然后一直按回車震束,重復執(zhí)行ni怜庸。
最終顯示輸出:

2: x/5s 0x80490a4
0x80490a4 <mydata1>:     "This is my data1 1st.This is my data2 2nd."
0x80490cf:   ".symtab"
0x80490d7:   ".strtab"
0x80490df:   ".shstrtab"
0x80490e9:   ".text"

"This is…."存放.data節(jié)中,".sysmtab",".strtab"等字符串存放在.shstrtab 節(jié)中垢村。最終加載到內存中割疾,.shstrtab剛好位于.data節(jié)后,所以將.shstrtab中的內容也打印出來了嘉栓。(結論:.shstrtab也是會被加載到內存中的宏榕。)

3. 分析.o文件的結構。

輸出elf文件內容
readelf -a demo.o > elf.demo.o
用readelf工具將 demo3.o的內容輸出到elf.demo3.o中侵佃。

反匯編.text段
objdump -d demo.o > objdump.demo.o
用objdump工具將.text段的代碼反匯編麻昼,輸出到objdump.demo.o中

說明:下面內容中中括[]號內表示文件中的起止位置(包括首尾),單位為byte馋辈,計數(shù)進制為16進制抚芦, 圓括號()表示不包含首尾字節(jié)。

(1) ELF Header [0,33](共52 bytes)

文件開始的52byte為ELF Header迈螟,這52字節(jié)按如下結構進行解釋
elf32_hdr結構體

typedef struct elf32_hdr{
  unsigned char e_ident[EI_NIDENT];
  Elf32_Half    e_type;
  Elf32_Half    e_machine;
  Elf32_Word    e_version;
  Elf32_Addr    e_entry;  /* Entry point */
  Elf32_Off e_phoff;
  Elf32_Off e_shoff;
  Elf32_Word    e_flags;
  Elf32_Half    e_ehsize;
  Elf32_Half    e_phentsize;
  Elf32_Half    e_phnum;
  Elf32_Half    e_shentsize;
  Elf32_Half    e_shnum;
  Elf32_Half    e_shstrndx;
} Elf32_Ehdr;

本實例顯示內容為:
ELF Header

(2) .text [34,61](共46 bytes)

.text存放的是匯編代碼叉抡,共2e(即十進制的46) 字節(jié)。
.text

   0:   bf 00 00 00 00          mov    $0x0,%edi
   5:   c6 47 11 31             movb   $0x31,0x11(%edi)
   9:   c6 47 12 73             movb   $0x73,0x12(%edi)
   d:   c6 47 13 74             movb   $0x74,0x13(%edi)
  11:   bf 15 00 00 00          mov    $0x15,%edi
  16:   c6 47 11 32             movb   $0x32,0x11(%edi)
  1a:   c6 47 12 6e             movb   $0x6e,0x12(%edi)
  1e:   c6 47 13 64             movb   $0x64,0x13(%edi)
  22:   b8 01 00 00 00          mov    $0x1,%eax
  27:   bb 00 00 00 00          mov    $0x0,%ebx
  2c:   cd 80                   int    $0x80

(3) 填充字符 [62,63]

用00 00填充答毫。

(4) .data [64,8D](共42 bytes)

.data段對應匯編語言中的.data段褥民,存放了兩個字符串,共2a (即十進制的42)字節(jié)洗搂。
.text段后有兩個空字符 00 00消返,然后才是.data段。
.data

This is my data1 xxx.This is my data2 xxx.

(5) 填充字符 [62,63]

用 00 00填充耘拇。

(6) .bss (90,90)(共0bytes)

.bss段撵颊,只有section header,沒有對應section驼鞭。所以它對應的section大小設置為0字節(jié)秦驯。.bss段不占用.o文件中的空間,當進程被加載到內存中時挣棕,才為.bss分配空間,并用0填充該空間亲桥。

(7) .shstrtab [90,BF](共48 bytes)

.shstrtab 即 section header string table,存放的是各個section名稱字符串洛心。其中第一個字符串為'\0'. 此處為30 (即十進制的48)字節(jié)。
.shstrtab

""
".symtab"
".strtab"
".shstrtab"
".rel.text"
".data"
".bss"

上面字符串按照標準C語言格式表示的题篷,即 “.symtab”實際由: '.' 's' 'y' 'm' 't' 'a' 'b' '\0' 字符組成词身。每個字符串用'\0'結尾,在文件視圖中顯示為一個點“.”(16進制00)番枚。另外法严,名稱

注意:這些字符串之間并沒有用換行分隔损敷,這里只是為了顯示清晰,每個字符串單獨占一行深啤。

(8) Section Headers [C0,1FF](共320 bytes)

section headers 處存放的是用來描述各個section的section header,每個section header占40 bytes, 這里共有8個section header拗馒。
每個占用40個字節(jié)的section header根據(jù)如下結構體解釋:
Elf32_Shdr

typedef struct {
  Elf32_Word    sh_name;
  Elf32_Word    sh_type;
  Elf32_Word    sh_flags;
  Elf32_Addr    sh_addr;
  Elf32_Off sh_offset;
  Elf32_Word    sh_size;
  Elf32_Word    sh_link;
  Elf32_Word    sh_info;
  Elf32_Word    sh_addralign;
  Elf32_Word    sh_entsize;
} Elf32_Shdr;

本示例中,各個section header的有效信息如下:
section headers

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 00002e 00  AX  0   0  4
  [ 2] .rel.text         REL             00000000 000288 000010 08      6   1  4
  [ 3] .data             PROGBITS        00000000 000064 00002a 00  WA  0   0  4
  [ 4] .bss              NOBITS          00000000 000090 000000 00  WA  0   0  4
  [ 5] .shstrtab         STRTAB          00000000 000090 000030 00      0   0  1
  [ 6] .symtab           SYMTAB          00000000 000200 000070 10      7   6  4
  [ 7] .strtab           STRTAB          00000000 000270 000018 00      0   0  1

第0條對應ELF Header.

(9) .symtab [200,26F](共112 bytes)

.symtab 存放的是代碼中使用到的符號字符串索引以及它對應的地址溯街、屬性(local,global,weak global)等信息诱桂。在這里共占用0x70(即十進制的112)字節(jié)。
其中每一項占用16個字節(jié)呈昔,這里共有7項挥等,所以占用112字節(jié)。每項都通過如下結構體進行解釋
Elf32_Sym

typedef struct elf32_sym{
  Elf32_Word    st_name;
  Elf32_Addr    st_value;
  Elf32_Word    st_size;
  unsigned char st_info;
  unsigned char st_other;
  Elf32_Half    st_shndx;
} Elf32_Sym;

在本示例中堤尾,.symtab中7項內容的有效信息如下:

Symbol table '.symtab' contains 7 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 SECTION LOCAL  DEFAULT    1 
     2: 00000000     0 SECTION LOCAL  DEFAULT    3 
     3: 00000000     0 SECTION LOCAL  DEFAULT    4 
     4: 00000000     0 NOTYPE  LOCAL  DEFAULT    3 mydata1
     5: 00000015     0 NOTYPE  LOCAL  DEFAULT    3 mydata2
     6: 00000000     0 NOTYPE  GLOBAL DEFAULT    1 _start

1~3條分別表示索引號為1肝劲、3、4的section的名稱郭宝,即.text,.data和.bss涡相。第0條默認為STN_UNDEF(undefined)類型

其中,后三項對應代碼中的三個符號剩蟀。

(10) .strtab [270,287](共24 bytes)

.strtab即 string table 用來存放在代碼中定義的符號的字符串催蝗。
和.shstrtab一樣,第一個字符串為'\0'育特,每個字符串以'\0'結尾丙号。

.strtab

""?"mydata1"?"mydata2"?"_start"

(11) .rel.text [288,297](共16 bytes)

.rel.text存放的是.text節(jié)的重定位信息,缰冤。其中每一項占8個字節(jié)犬缨,這里共兩項所以占16字節(jié)。
PS: .rel.XXX節(jié)為.XXX節(jié)的重定位表棉浸,如:.data段的重定位表為.rel..data

每一項通過如下結構解釋:
Elf32_Rel

typedef struct elf32_rel {
  Elf32_Addr    r_offset;
  Elf32_Word    r_info;
} Elf32_Rel;

本示例中怀薛,有效信息如下:
.rel.text

Relocation section '.rel.text' at offset 0x288 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000001  00000201 R_386_32          00000000   .data
00000012  00000201 R_386_32          00000000   .data

(12) 重定位

在源碼中定義的符號代碼一個地址,在.o文件中迷郑,該地址指向對應符號所在文件中的相對位置枝恋。鏈接過程中需要將這個相對位置替換為虛擬內存地址,才能使得程序正常運行嗡害。
匯編代碼

movl $mydata1, %edi 
movb $49, 17(%edi)      
movb $115, 18(%edi)
movb $116, 19(%edi)
 
movl $mydata2, %edi 
movb $50, 17(%edi)  
movb $110, 18(%edi)
movb $100, 19(%edi)
 
movl $1, %eax   #syscall exit
movl $0, %ebx   #argument 0, ie. exit(0)
int $0x80

.o文件中的.text段

00000000 <_start>:
   0:   bf 00 00 00 00          mov    $0x0,%edi
   5:   c6 47 11 31             movb   $0x31,0x11(%edi)
   9:   c6 47 12 73             movb   $0x73,0x12(%edi)
   d:   c6 47 13 74             movb   $0x74,0x13(%edi)
  11:   bf 15 00 00 00          mov    $0x15,%edi
  16:   c6 47 11 32             movb   $0x32,0x11(%edi)
  1a:   c6 47 12 6e             movb   $0x6e,0x12(%edi)
  1e:   c6 47 13 64             movb   $0x64,0x13(%edi)
  22:   b8 01 00 00 00          mov    $0x1,%eax
  27:   bb 00 00 00 00          mov    $0x0,%ebx
  2c:   cd 80                   int    $0x80

可執(zhí)行文件中的.text段

08048074 <_start>:
 8048074:   bf a4 90 04 08          mov    $0x80490a4,%edi
 8048079:   c6 47 11 31             movb   $0x31,0x11(%edi)
 804807d:   c6 47 12 73             movb   $0x73,0x12(%edi)
 8048081:   c6 47 13 74             movb   $0x74,0x13(%edi)
 8048085:   bf b9 90 04 08          mov    $0x80490b9,%edi
 804808a:   c6 47 11 32             movb   $0x32,0x11(%edi)
 804808e:   c6 47 12 6e             movb   $0x6e,0x12(%edi)
 8048092:   c6 47 13 64             movb   $0x64,0x13(%edi)
 8048096:   b8 01 00 00 00          mov    $0x1,%eax
 804809b:   bb 00 00 00 00          mov    $0x0,%ebx
 80480a0:   cd 80                   int    $0x80
        

觀察上面代碼中綠色陰影標記部分焚碌,在.o文件中,使用的是mydata1和mydata2在.data段中的相對位置霸妹。在可執(zhí)行文件中十电,使用的是mydata1和mydata2的虛擬內存地址。

在.rel.text中可以看到,.o文件中將匯編源碼中使用了mydata1和mydata2的地方標記為需要重定位鹃骂,重定位類型為:R_386_32台盯。
一個符號就代表一個地址,這兩個符號代表的值是它們在.data段中的偏移量畏线,分別為0和15(即十進制 的21)静盅。所以.o中兩條mov指令使用的分別是0x1和0x15。

已經初始化的數(shù)據(jù)存放在.data section中象踊。這些數(shù)據(jù)實際上引用的是.data的地址温亲。例如,定義了一個變量static int x = 10. 我們知道符號實際上代表一個地址而已杯矩,在這里引用x時,實際上是這樣的:.symtab中記錄了x在.data section中的偏移量(假設是12)栈虚,其他地方要用到x變量時,實際上是通過 .data地址+偏移量 來進行引用的史隆。
對于上面的 movl $mydata1, %edi 指令也是如此魂务。因此,在重定位表中記錄的需要重定位的項不是mydata1和mydata2而是.data泌射。

 Offset     Info    Type            Sym.Value  Sym. Name
00000001  00000201 R_386_32          00000000   .data
00000012  00000201 R_386_32          00000000   .data
offset 表示要更改的地方在.text section中起始地址粘姜。要更改的內容默認為為該處的4個字節(jié);
info 
    1. 表示更改的方式為:0X01 即:R_386_32
    2. 被引用的符號在.symtab中的索引為: 0x000002熔酷,即.data

需要重定位的地方如上表所示孤紧,offset為需要重定位的字段(四字節(jié))在.text section中的偏移量(.rel.text是.text section的重定位信息表)。被引用的symbol為.data(因為它是已經初始化的數(shù)據(jù)拒秘,因此被引用符號為.data而不是mydata1和mydata2). info字段中号显,低八位表示重定位類型(上面顯示的是十六進制),因此這里是01即R_386_32 . 高24位表示的是被引用字符在.symtab中的索引,這里高24位為2,查找上面的.symtab可以發(fā)現(xiàn)它對應第三條(粗體顯示):

Symbol table '.symtab' contains 7 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 SECTION LOCAL  DEFAULT    1 
     2: 00000000     0 SECTION LOCAL  DEFAULT    3  
     3: 00000000     0 SECTION LOCAL  DEFAULT    4 
     4: 00000000     0 NOTYPE  LOCAL  DEFAULT    3 mydata1
     5: 00000015     0 NOTYPE  LOCAL  DEFAULT    3 mydata2
     6: 00000000     0 NOTYPE  GLOBAL DEFAULT    1 _start

1~3條分別表示索引號為1躺酒、3押蚤、4的section的名稱,即.text,.data和.bss羹应。第0條默認為STN_UNDEF(undefined)類型 第三條中的Ndx字段為3,表示它是第三節(jié)(即.data)中的符號揽碘。

R_386_32重定位方式:
.text section中偏移量為0x1和偏移量為0x12處的四字節(jié)需要更改為.data section在內存中的起始地址+它原來的值(分別為0x0和0x15)。(生成的.o文件中园匹。匯編器(as命令)已經將我們匯編代碼中引用到的mydata1和mydata2分別替換為了這兩個符號在.data中的偏移地址了)
細節(jié)情況如下:
R_386_32:重定位一個使用32位絕對地址的引用雳刺。其地址計算方法為.symtab中對應的value值加上原始值。鏈接過程中先將.symtab中索引為2的項(即.data)的value設置為它的虛擬地址(本示例是:80490a4)偎肃。用該虛擬地址加上原值煞烫,便得到了新的值,這也就是之前所說的那個過程累颂。

重定位的方式還有很多種,這里只討論其中之一,也是最常用的一種紊馏。注意:當被引用的符號是未初始化的變量時料饥,它和上面的過程一樣,整個過程僅僅是把上面涉及的.data符號改為被引用的符號而已朱监。

總結:

編譯器將程序的入口地址設置為標號_start的地址岸啡。所以匯編程序必須提供_start符號,C程序由glibc自動提供赫编,因此在C程序中不能定義新的_start全局符號巡蘸。

image.png

附錄

輸出文件

elf.demo.o

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          192 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         8
  Section header string table index: 5

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 00002e 00  AX  0   0  4
  [ 2] .rel.text         REL             00000000 000288 000010 08      6   1  4
  [ 3] .data             PROGBITS        00000000 000064 00002a 00  WA  0   0  4
  [ 4] .bss              NOBITS          00000000 000090 000000 00  WA  0   0  4
  [ 5] .shstrtab         STRTAB          00000000 000090 000030 00      0   0  1
  [ 6] .symtab           SYMTAB          00000000 000200 000070 10      7   6  4
  [ 7] .strtab           STRTAB          00000000 000270 000018 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

There are no program headers in this file.

Relocation section '.rel.text' at offset 0x288 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000001  00000201 R_386_32          00000000   .data
00000012  00000201 R_386_32          00000000   .data

There are no unwind sections in this file.

Symbol table '.symtab' contains 7 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 SECTION LOCAL  DEFAULT    1 
     2: 00000000     0 SECTION LOCAL  DEFAULT    3 
     3: 00000000     0 SECTION LOCAL  DEFAULT    4 
     4: 00000000     0 NOTYPE  LOCAL  DEFAULT    3 mydata1
     5: 00000015     0 NOTYPE  LOCAL  DEFAULT    3 mydata2
     6: 00000000     0 NOTYPE  GLOBAL DEFAULT    1 _start

No version information found in this file.

objdump.demo.o

demo.o:     file format elf32-i386
 
Disassembly of section .text:
 
00000000 <_start>:
   0:   bf 00 00 00 00          mov    $0x0,%edi
   5:   c6 47 11 31             movb   $0x31,0x11(%edi)
   9:   c6 47 12 73             movb   $0x73,0x12(%edi)
   d:   c6 47 13 74             movb   $0x74,0x13(%edi)
  11:   bf 15 00 00 00          mov    $0x15,%edi
  16:   c6 47 11 32             movb   $0x32,0x11(%edi)
  1a:   c6 47 12 6e             movb   $0x6e,0x12(%edi)
  1e:   c6 47 13 64             movb   $0x64,0x13(%edi)
  22:   b8 01 00 00 00          mov    $0x1,%eax
  27:   bb 00 00 00 00          mov    $0x0,%ebx
  2c:   cd 80                   int    $0x80

文件視圖

image.png
image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市擂送,隨后出現(xiàn)的幾起案子悦荒,更是在濱河造成了極大的恐慌,老刑警劉巖嘹吨,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搬味,死亡現(xiàn)場離奇詭異,居然都是意外死亡蟀拷,警方通過查閱死者的電腦和手機碰纬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來问芬,“玉大人悦析,你說我怎么就攤上這事〈诵疲” “怎么了强戴?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長炕柔。 經常有香客問我酌泰,道長,這世上最難降的妖魔是什么匕累? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任陵刹,我火速辦了婚禮,結果婚禮上欢嘿,老公的妹妹穿的比我還像新娘衰琐。我一直安慰自己,他們只是感情好炼蹦,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布羡宙。 她就那樣靜靜地躺著,像睡著了一般掐隐。 火紅的嫁衣襯著肌膚如雪狗热。 梳的紋絲不亂的頭發(fā)上钞馁,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音匿刮,去河邊找鬼僧凰。 笑死,一個胖子當著我的面吹牛熟丸,可吹牛的內容都是我干的训措。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼光羞,長吁一口氣:“原來是場噩夢啊……” “哼绩鸣!你這毒婦竟也來了?” 一聲冷哼從身側響起纱兑,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤呀闻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后萍启,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體总珠,經...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年勘纯,在試婚紗的時候發(fā)現(xiàn)自己被綠了局服。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡驳遵,死狀恐怖淫奔,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情堤结,我是刑警寧澤唆迁,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站竞穷,受9級特大地震影響唐责,放射性物質發(fā)生泄漏。R本人自食惡果不足惜瘾带,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一鼠哥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧看政,春花似錦朴恳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嚷兔,卻和暖如春森渐,著一層夾襖步出監(jiān)牢的瞬間做入,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工章母, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留母蛛,地道東北人翩剪。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓乳怎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親前弯。 傳聞我的和親對象是個殘疾皇子蚪缀,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351