(四) Mach-O 文件的裝載

# 裝載概述
# 裝載理論篇
  ## 創(chuàng)建虛擬地址空間
  ## 讀取可執(zhí)行文件頭,并且建立虛擬空間與可執(zhí)行文件的映射關(guān)系
  ## 將CPU指令寄存器設(shè)置成可執(zhí)行文件入口坏挠,啟動(dòng)運(yùn)行
# Mach-O文件的裝載
# * Linux ELF文件的裝載(了解)

先附上源碼地址:結(jié)合 XNU 源碼(應(yīng)該不是最新的冲茸,且不怎么全,不過(guò)用來(lái)分析學(xué)習(xí)也差不多了)固灵,來(lái)看加載器的流程捅伤,效果更好。重要的兩個(gè)類(lèi):

  • bsd/kern/kern_exec.c:進(jìn)程執(zhí)行的相關(guān)操作:線(xiàn)程創(chuàng)建巫玻、數(shù)據(jù)初始化等丛忆。
  • bsd/kern/mach_loader.c:Mach-O文件解析加載相關(guān)。第二節(jié)中提到的Mach-O文件中的內(nèi)核加載器負(fù)責(zé)處理的load command 對(duì)應(yīng)的內(nèi)核中處理的函數(shù)都在該文件中仍秤,比如處理LC_SEGMET命令的load_segment函數(shù)熄诡、處理LC_LOAD_DYLINKER命令的load_dylinker函數(shù)(負(fù)責(zé)調(diào)用命令指定的動(dòng)態(tài)鏈接器)。

# 裝載概述

在鏈接完成之后诗力,應(yīng)用開(kāi)始運(yùn)行之前粮彤,有一段裝載過(guò)程,我們都知道程序執(zhí)行時(shí)所需要的指令和數(shù)據(jù)必須在內(nèi)存中才能夠被正常運(yùn)行。

最簡(jiǎn)單的辦法就是將程序運(yùn)行所需要的指令和數(shù)據(jù)全都裝入內(nèi)存中导坟,這樣程序就可以順利運(yùn)行屿良,這就是最簡(jiǎn)單的靜態(tài)裝入的辦法。

但是很多情況下程序所需要的內(nèi)存數(shù)量大于物理內(nèi)存的數(shù)量惫周,當(dāng)內(nèi)存的數(shù)量不夠時(shí)尘惧,根本的解決辦法就是添加內(nèi)存。相對(duì)于磁盤(pán)來(lái)說(shuō)递递,內(nèi)存是昂貴且稀有的喷橙,這種情況自計(jì)算機(jī)磁盤(pán)誕生以來(lái)一直如此。所以人們想盡各種辦法登舞,希望能夠在不添加內(nèi)存的情況下讓更多的程序運(yùn)行起來(lái)贰逾,盡可能有效地利用內(nèi)存。后來(lái)研究發(fā)現(xiàn)菠秒,程序運(yùn)行時(shí)是有局部性原理的疙剑,所以我們可以將程序最常用的部分駐留在內(nèi)存中,而將一些不太常用的數(shù)據(jù)存放在磁盤(pán)里面践叠,這就是動(dòng)態(tài)裝入的基本原理言缤。(這也是虛擬地址空間機(jī)制要解決的問(wèn)題,這里不再贅述禁灼,大學(xué)都學(xué)過(guò))

覆蓋裝入(Overlay)和頁(yè)映射(Paging)是兩種很典型的動(dòng)態(tài)裝載方法管挟,它們所采用的思想都差不多,原則上都是利用了程序的局部性原理弄捕。動(dòng)態(tài)裝入的思想是程序用到哪個(gè)模塊,就將哪個(gè)模塊裝入內(nèi)存守谓,如果不用就暫時(shí)不裝入皮璧,存放在磁盤(pán)中。

# 裝載理論篇

在虛擬存儲(chǔ)中分飞,現(xiàn)代的硬件MMU都提供地址轉(zhuǎn)換的功能悴务。有了硬件的地址轉(zhuǎn)換和頁(yè)映射機(jī)制,操作系統(tǒng)動(dòng)態(tài)加載可執(zhí)行文件的方式跟靜態(tài)加載有了很大的區(qū)別譬猫。

事實(shí)上讯檐,從操作系統(tǒng)的角度來(lái)看,一個(gè)進(jìn)程最關(guān)鍵的特征是它擁有獨(dú)立的虛擬地址空間染服,這使得它有別于其他進(jìn)程别洪。很多時(shí)候一個(gè)程序被執(zhí)行同時(shí)都伴隨著一個(gè)新的進(jìn)程的創(chuàng)建,那么我們就來(lái)看看這種最通常的情形:創(chuàng)建一個(gè)進(jìn)程柳刮,然后裝載相應(yīng)的可執(zhí)行文件并且執(zhí)行挖垛。在有虛擬存儲(chǔ)的情況下痒钝,上述過(guò)程最開(kāi)始只需要做三件事情:

  • 創(chuàng)建一個(gè)獨(dú)立的虛擬地址空間。
  • 讀取可執(zhí)行文件頭痢毒,并且建立虛擬空間與可執(zhí)行文件的映射關(guān)系送矩。
  • 將CPU的指令寄存器設(shè)置成可執(zhí)行文件的入口地址,啟動(dòng)運(yùn)行哪替。

首先是創(chuàng)建虛擬地址空間栋荸。一個(gè)虛擬空間由一組頁(yè)映射函數(shù)虛擬空間的各個(gè)頁(yè)映射至相應(yīng)的物理空間,所以創(chuàng)建一個(gè)虛擬空間實(shí)際上并不是創(chuàng)建空間而是創(chuàng)建映射函數(shù)所需要的相應(yīng)的數(shù)據(jù)結(jié)構(gòu)凭舶,在i386 的Linux下晌块,創(chuàng)建虛擬地址空間實(shí)際上只是分配一個(gè)頁(yè)目錄(Page Directory)就可以了,甚至不設(shè)置頁(yè)映射關(guān)系帅霜,這些映射關(guān)系等到后面程序發(fā)生頁(yè)錯(cuò)誤的時(shí)候再進(jìn)行設(shè)置匆背。

讀取可執(zhí)行文件頭,并且建立虛擬空間與可執(zhí)行文件的映射關(guān)系身冀。上面那一步的頁(yè)映射關(guān)系函數(shù)是虛擬空間到物理內(nèi)存的映射關(guān)系钝尸,這一步所做的是虛擬空間與可執(zhí)行文件的映射關(guān)系。我們知道闽铐,當(dāng)程序執(zhí)行發(fā)生頁(yè)錯(cuò)誤時(shí)蝶怔,操作系統(tǒng)將從物理內(nèi)存中分配一個(gè)物理頁(yè)奶浦,然后將該“缺頁(yè)”從磁盤(pán)中讀取到內(nèi)存中兄墅,再設(shè)置缺頁(yè)的虛擬頁(yè)和物理頁(yè)的映射關(guān)系,這樣程序才得以正常運(yùn)行澳叉。

但是很明顯的一點(diǎn)是隙咸,當(dāng)操作系統(tǒng)捕獲到缺頁(yè)錯(cuò)誤時(shí),它應(yīng)知道程序當(dāng)前所需要的頁(yè)在可執(zhí)行文件中的哪一個(gè)位置成洗。這就是虛擬空間與可執(zhí)行文件之間的映射關(guān)系五督。從某種角度來(lái)看,這一步是整個(gè)裝載過(guò)程中最重要的一步瓶殃,也是傳統(tǒng)意義上“裝載”的過(guò)程充包。

由于可執(zhí)行文件在裝載時(shí)實(shí)際上是被映射的虛擬空間,所以可執(zhí)行文件很多時(shí)候又被叫做映像文件(Image)遥椿。

很明顯基矮,這種映射關(guān)系只是保存在操作系統(tǒng)內(nèi)部的一個(gè)數(shù)據(jù)結(jié)構(gòu)。Linux中將進(jìn)程虛擬空間中的一個(gè)段叫做虛擬內(nèi)存區(qū)域(VMA, Virtual Memory Area)冠场;在Windows中將這個(gè)叫做虛擬段(Virtual Section)家浇,其實(shí)它們都是同一個(gè)概念。

VMA是一個(gè)很重要的概念碴裙,它對(duì)于我們理解程序的裝載執(zhí)行和操作系統(tǒng)如何管理進(jìn)程的虛擬空間有非常重要的幫助钢悲。

操作系統(tǒng)在內(nèi)部保存這種結(jié)構(gòu)点额,很明顯是因?yàn)楫?dāng)程序執(zhí)行發(fā)生段錯(cuò)誤時(shí),它可以通過(guò)查找這樣的一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)定位錯(cuò)誤頁(yè)在可執(zhí)行文件中的位置莺琳。

將CPU指令寄存器設(shè)置成可執(zhí)行文件入口还棱,啟動(dòng)運(yùn)行。第三步其實(shí)也是最簡(jiǎn)單的一步芦昔,操作系統(tǒng)通過(guò)設(shè)置CPU的指令寄存器將控制權(quán)轉(zhuǎn)交給進(jìn)程诱贿,由此進(jìn)程開(kāi)始執(zhí)行。這一步看似簡(jiǎn)單咕缎,實(shí)際上在操作系統(tǒng)層面上比較復(fù)雜珠十,它涉及內(nèi)核堆棧和用戶(hù)堆棧的切換、CPU運(yùn)行權(quán)限的切換凭豪。不過(guò)從進(jìn)程的角度看這一步可以簡(jiǎn)單地認(rèn)為操作系統(tǒng)執(zhí)行了一條跳轉(zhuǎn)指令焙蹭,直接跳轉(zhuǎn)到可執(zhí)行文件的入口地址(通常是text區(qū)的地址)。

  • ELF文件頭中嫂伞,有e_entry字段保存入口地址
  • Mach-O文件中的LC_MAIN加載指令作用就是設(shè)置程序主程序的入口點(diǎn)地址和棧大小)

# Mach-O文件的裝載

(二) Mach-O 文件結(jié)構(gòu) 介紹 Mach Heade 中的 Load Command 加載命令孔厉,結(jié)合其用途,就可以簡(jiǎn)單看出可執(zhí)行文件的裝載流程:

  • 首先帖努,是由內(nèi)核加載器(定義在bsd/kern/mach_loader.c文件中)來(lái)處理一些需要由內(nèi)核加載器直接使用的加載命令撰豺。內(nèi)核的部分(內(nèi)核加載器)負(fù)責(zé)新進(jìn)程的基本設(shè)置——分配虛擬內(nèi)存,創(chuàng)建主線(xiàn)程拼余,以及處理任何可能的代碼簽名/加密的工作污桦。(這也是本篇內(nèi)容主要講的)

  • 接著,對(duì)于需要?jiǎng)討B(tài)鏈接(使用了動(dòng)態(tài)庫(kù))的可執(zhí)行文件(大部分可執(zhí)行文件都是動(dòng)態(tài)鏈接的)來(lái)說(shuō)匙监,控制權(quán)會(huì)轉(zhuǎn)交給鏈接器凡橱,鏈接器進(jìn)而接著處理文件頭中的其他加載命令。真正的庫(kù)加載和符號(hào)解析的工作都是通過(guò)LC_LOAD_DY LINKER命令指定的動(dòng)態(tài)鏈接器在用戶(hù)態(tài)完成的亭姥。(下一篇文章再細(xì)講dyld動(dòng)態(tài)鏈接

下面通過(guò)代碼來(lái)看一下具體的過(guò)程稼钩。下面通過(guò)一個(gè)調(diào)用棧圖來(lái)說(shuō)明, 這里面每個(gè)方法都做了很多事情达罗,這里只注釋了到_dyld_start的關(guān)鍵操作坝撑,很簡(jiǎn)略。有興趣可以詳細(xì)看源碼kern_exec.c粮揉、mach_loader.c

▼ execve       // 用戶(hù)點(diǎn)擊了app巡李,用戶(hù)態(tài)會(huì)發(fā)送一個(gè)系統(tǒng)調(diào)用 execve 到內(nèi)核
  ▼ __mac_execve  // 主要是為加載鏡像進(jìn)行數(shù)據(jù)的初始化,以及資源相關(guān)的操作滔蝉,以及創(chuàng)建線(xiàn)程
    ▼ exec_activate_image // 拷貝可執(zhí)行文件到內(nèi)存中击儡,并根據(jù)不同的可執(zhí)行文件類(lèi)型選擇不同的加載函數(shù),所有的鏡像的加載要么終止在一個(gè)錯(cuò)誤上蝠引,要么最終完成加載鏡像阳谍。
      // 在 encapsulated_binary 這一步會(huì)根據(jù)image的類(lèi)型選擇imgact的方法
      /*
       * 該方法為Mach-o Binary對(duì)應(yīng)的執(zhí)行方法蛀柴;
       * 如果image類(lèi)型為Fat Binary,對(duì)應(yīng)方法為exec_fat_imgact矫夯;
       * 如果image類(lèi)型為Interpreter Script鸽疾,對(duì)應(yīng)方法為exec_shell_imgact
       */
      ▼ exec_mach_imgact   
        ?? // 首先對(duì)Mach-O做檢測(cè),會(huì)檢測(cè)Mach-O頭部训貌,解析其架構(gòu)制肮、檢查imgp等內(nèi)容,判斷魔數(shù)递沪、cputype豺鼻、cpusubtype等信息。如果image無(wú)效款慨,會(huì)直接觸發(fā)assert(exec_failure_reason == OS_REASON_NULL); 退出儒飒。
          // 拒絕接受Dylib和Bundle這樣的文件,這些文件會(huì)由dyld負(fù)責(zé)加載檩奠。然后把Mach-O映射到內(nèi)存中去桩了,調(diào)用load_machfile()
        ▼ load_machfile
          ?? // load_machfile會(huì)加載Mach-O中的各種load monmand命令。在其內(nèi)部會(huì)禁止數(shù)據(jù)段執(zhí)行埠戳,防止溢出漏洞攻擊井誉,還會(huì)設(shè)置地址空間布局隨機(jī)化(ASLR),還有一些映射的調(diào)整整胃。
            // 真正負(fù)責(zé)對(duì)加載命令解析的是parse_machfile()
          ▼ parse_machfile  //解析主二進(jìn)制macho
            ?? /* 
               * 首先颗圣,對(duì)image頭中的filetype進(jìn)行分析,可執(zhí)行文件MH_EXECUTE不允許被二次加載(depth = 1)爪模;動(dòng)態(tài)鏈接編輯器MH_DYLINKER必須是被可執(zhí)行文件加載的(depth = 2)
               * 然后欠啤,循環(huán)遍歷所有的load command荚藻,分別調(diào)用對(duì)應(yīng)的內(nèi)核函數(shù)進(jìn)行處理
               *   LC_SEGMET:load_segment函數(shù):對(duì)于每一個(gè)段屋灌,將文件中相應(yīng)的內(nèi)容加載到內(nèi)存中:從偏移量為 fileoff 處加載 filesize 字節(jié)到虛擬內(nèi)存地址 vmaddr 處的 vmsize 字節(jié)。每一個(gè)段的頁(yè)面都根據(jù) initprot 進(jìn)行初始化应狱,initprot 指定了如何通過(guò)讀/寫(xiě)/執(zhí)行位初始化頁(yè)面的保護(hù)級(jí)別共郭。
               *   LC_UNIXTHREAD:load_unixthread函數(shù),見(jiàn)下文
               *   LC_MAIN:load_main函數(shù)
               *   LC_LOAD_DYLINKER:獲取動(dòng)態(tài)鏈接器相關(guān)的信息疾呻,下面load_dylinker會(huì)根據(jù)信息除嘹,啟動(dòng)動(dòng)態(tài)鏈接器
               *   LC_CODE_SIGNATURE:load_code_signature函數(shù),進(jìn)行驗(yàn)證岸蜗,如果無(wú)效會(huì)退出尉咕。理論部分,回見(jiàn)第二節(jié)load_command `LC_CODE_SIGNATURE `部分璃岳。
               *   其他的不再多說(shuō)年缎,有興趣可以自己看源碼
               */
            ▼ load_dylinker // 解析完 macho后悔捶,根據(jù)macho中的 LC_LOAD_DYLINKER 這個(gè)LoadCommand來(lái)啟動(dòng)這個(gè)二進(jìn)制的加載器,即 /usr/bin/dyld
              ▼ parse_machfile // 開(kāi)始解析 dyld 這個(gè)mach-o文件
                ▼ load_unixthread // 解析 dyld 的 LC_UNIXTHREAD 命令单芜,這個(gè)過(guò)程中會(huì)解析出entry_point
                  ▼ load_threadentry  // 獲取入口地址
                    ?? thread_entrypoint  // 里面只有i386和x86架構(gòu)的蜕该,沒(méi)有arm的,但是原理是一樣的
                  ?? //上一步獲取到地址后洲鸠,會(huì)再加上slide堂淡,ASLR偏移,到此扒腕,就獲取到了dyld的入口地址绢淀,也就是 _dyld_start 函數(shù)的地址
        ▼ activate_exec_state
          ?? thread_setentrypoint // 設(shè)置entry_point。直接把entry_point地址寫(xiě)入到用戶(hù)態(tài)的寄存器里面了瘾腰。
          //這一步開(kāi)始更啄,_dyld_start就真正開(kāi)始執(zhí)行了。

▼ dyld
  ▼ __dyld_start  // 源碼在dyldStartup.s這個(gè)文件居灯,用匯編實(shí)現(xiàn)
    ▼ dyldbootstrap::start() 
      ▼ dyld::_main()
        ▼ //函數(shù)的最后祭务,調(diào)用 getEntryFromLC_MAIN,從 Load Command 讀取LC_MAIN入口怪嫌,如果沒(méi)有LC_MAIN入口义锥,就讀取LC_UNIXTHREAD,然后跳到主程序的入口處執(zhí)行
        ▼ 這是下篇內(nèi)容

# * Linux ELF文件的裝載(了解)

首先在用戶(hù)層面岩灭,bash進(jìn)程會(huì)調(diào)用fork()系統(tǒng)調(diào)用創(chuàng)建一個(gè)新的進(jìn)程拌倍,然后新的進(jìn)程調(diào)用 execve()系統(tǒng)調(diào)用執(zhí)行指定的ELF文件,原先的bash進(jìn)程繼續(xù)返回等待剛才啟動(dòng)的新進(jìn)程結(jié)束噪径,然后繼續(xù)等待用戶(hù)輸入命令柱恤。 execve() 系統(tǒng)調(diào)用被定義在unistd.h,它的原型如下:

/*
 * 三個(gè)參數(shù)分別是被執(zhí)行的程序文件名找爱、執(zhí)行參數(shù)和環(huán)境變量梗顺。
 */
int execve(const char *filename, char *const argv[], char *const envp[]); 

Glibc對(duì)該系統(tǒng)調(diào)用進(jìn)行了包裝,提供了 execl()车摄、execlp()寺谤、execle()、execv()吮播、execvp()等5個(gè)不同形式的exec系列API变屁,它們只是在調(diào)用的參數(shù)形式上有所區(qū)別,但最終都會(huì)調(diào)用到 execve() 這個(gè)系統(tǒng)中意狠。

在進(jìn)入 execve() 系統(tǒng)調(diào)用之后粟关,Linux內(nèi)核就開(kāi)始進(jìn)行真正的裝載工作。

  • sys_execve()环戈,在內(nèi)核中闷板,該函數(shù)是execve()系統(tǒng)調(diào)用相應(yīng)的入口获列,定義在arch\i386\kernel\Process.c。 該函數(shù)進(jìn)行一些參數(shù)的檢查復(fù)制之后蛔垢,調(diào)用 do_execve()击孩。

  • do_execve(),該函數(shù)會(huì)首先查找被執(zhí)行的文件鹏漆,如果找到文件巩梢,則讀取文件的前128個(gè)字節(jié)。目的是判斷文件的格式艺玲,每種可執(zhí)行文件的格式的開(kāi)頭幾個(gè)字節(jié)都是很特殊的括蝠,特別是開(kāi)頭4個(gè)字節(jié),常常被稱(chēng)做魔數(shù)(Magic Number)饭聚,通過(guò)對(duì)魔數(shù)的判斷可以確定文件的格式和類(lèi)型忌警。比如:

    • ELF的可執(zhí)行文件格式的頭4個(gè)字節(jié)為0x7F、’e’秒梳、’l’法绵、’f’;
    • Java的可執(zhí)行文件格式的頭4個(gè)字節(jié)為’c’酪碘、’a’朋譬、’f’、’e’兴垦;
    • 如果被執(zhí)行的是Shell腳本或perl徙赢、python等這種解釋型語(yǔ)言的腳本,那么它的第一行往往是 “#!/bin/sh” 或 “#!/usr/bin/perl” 或 “#!/usr/bin/python” 探越,這時(shí)候前兩個(gè)字節(jié)'#''!'就構(gòu)成了魔數(shù)狡赐,系統(tǒng)一旦判斷到這兩個(gè)字節(jié),就對(duì)后面的字符串進(jìn)行解析钦幔,以確定具體的解釋程序的路徑枕屉。

    當(dāng)do_execve()讀取了這128個(gè)字節(jié)的文件頭部之后,然后調(diào)用search_binary_handle()节槐。

  • search_binary_handle()搀庶,該函數(shù)會(huì)去搜索和匹配合適的可執(zhí)行文件裝載處理過(guò)程拐纱。Linux中所有被支持的可執(zhí)行文件格式都有相應(yīng)的裝載處理過(guò)程铜异,此函數(shù)會(huì)通過(guò)判斷文件頭部的魔數(shù)確定文件的格式,并且調(diào)用相應(yīng)的裝載處理過(guò)程秸架。比如:

    • ELF可執(zhí)行文件的裝載處理過(guò)程叫做 load_elf_binary()揍庄;
    • a.out可執(zhí)行文件的裝載處理過(guò)程叫做 load_aout_binary();
    • 裝載可執(zhí)行腳本程序的處理過(guò)程叫做 load_script()东抹。
  • load_elf_binary()蚂子,這個(gè)函數(shù)被定義在fs/Binfmt_elf.c沃测,代碼比較長(zhǎng),它的主要步驟是:

    1. 檢查ELF可執(zhí)行文件格式的有效性食茎,比如魔數(shù)蒂破、程序頭表中段(Segment)的數(shù)量。
    2. 尋找動(dòng)態(tài)鏈接的“.interp”段别渔,設(shè)置動(dòng)態(tài)鏈接器路徑附迷。
    3. 根據(jù)ELF可執(zhí)行文件的程序頭表的描述,對(duì)ELF文件進(jìn)行映射哎媚,比如代碼喇伯、數(shù)據(jù)、只讀數(shù)據(jù)拨与。
    4. 初始化ELF進(jìn)程環(huán)境稻据,比如進(jìn)程啟動(dòng)時(shí)EDX寄存器的地址應(yīng)該是 DT_FINI 的地址(動(dòng)態(tài)鏈接相關(guān))。
    5. 將系統(tǒng)調(diào)用的返回地址修改成ELF可執(zhí)行文件的入口點(diǎn)买喧,這個(gè)入口點(diǎn)取決于程序的鏈接方式捻悯,對(duì)于靜態(tài)鏈接的ELF可執(zhí)行文件,這個(gè)程序入口就是ELF文件的文件頭中 e_entry 所指的地址淤毛;對(duì)于動(dòng)態(tài)鏈接的ELF可執(zhí)行文件秋度,程序入口點(diǎn)是動(dòng)態(tài)鏈接器。

當(dāng) load_elf_binary() 執(zhí)行完畢钱床,返回至 do_execve() 再返回至 sys_execve() 時(shí)荚斯, 上面的第5步中已經(jīng)把系統(tǒng)調(diào)用的返回地址改成了被裝載的ELF程序(或動(dòng)態(tài)鏈接器)的入口地址了。所以當(dāng) sys_execve()系統(tǒng)調(diào)用從內(nèi)核態(tài)返回到用戶(hù)態(tài)時(shí)查牌,EIP 寄存器直接跳轉(zhuǎn)到了ELF程序的入口地址事期,于是新的程序開(kāi)始執(zhí)行,ELF可執(zhí)行文件裝載完成纸颜。

# 參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兽泣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子胁孙,更是在濱河造成了極大的恐慌唠倦,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涮较,死亡現(xiàn)場(chǎng)離奇詭異稠鼻,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)狂票,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)候齿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事慌盯≈苊梗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵亚皂,是天一觀(guān)的道長(zhǎng)俱箱。 經(jīng)常有香客問(wèn)我,道長(zhǎng)灭必,這世上最難降的妖魔是什么匠楚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮厂财,結(jié)果婚禮上芋簿,老公的妹妹穿的比我還像新娘。我一直安慰自己璃饱,他們只是感情好与斤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著荚恶,像睡著了一般撩穿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谒撼,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天食寡,我揣著相機(jī)與錄音,去河邊找鬼廓潜。 笑死抵皱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辩蛋。 我是一名探鬼主播呻畸,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悼院!你這毒婦竟也來(lái)了伤为?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤据途,失蹤者是張志新(化名)和其女友劉穎绞愚,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體颖医,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡位衩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了便脊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚂四。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡光戈,死狀恐怖哪痰,靈堂內(nèi)的尸體忽然破棺而出遂赠,到底是詐尸還是另有隱情,我是刑警寧澤晌杰,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布跷睦,位于F島的核電站,受9級(jí)特大地震影響肋演,放射性物質(zhì)發(fā)生泄漏抑诸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一爹殊、第九天 我趴在偏房一處隱蔽的房頂上張望蜕乡。 院中可真熱鬧,春花似錦梗夸、人聲如沸层玲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辛块。三九已至,卻和暖如春铅碍,著一層夾襖步出監(jiān)牢的瞬間润绵,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工胞谈, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尘盼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓烦绳,卻偏偏與公主長(zhǎng)得像悔叽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子爵嗅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353