開始學習LLDB命令(第七章:鏡像)

現(xiàn)在, 你已經(jīng)有了堅實的調(diào)試基礎.你可以找到并附加到你感興趣的程序上, 高效的創(chuàng)建正則表達式斷點來覆蓋一個寬泛的范圍, 在棧幀中導航并且使用expression命令查看變量.
然而, 是時候通過強大的LLDB來查看感興趣的代碼了.在本章中, 你會深入的學習image命令.
image命令是target modules命令的別名. image是專門用來查詢模塊(modules)相關信息的; 更確切的說, 代碼被加載到一個線程里面執(zhí)行.模塊可以包含許多事情, 包含主要的執(zhí)行代碼, 框架或者插件.然而, 大多數(shù)的模塊都來自動態(tài)庫.比如iOS的UIKit和macOS的AppKit都是常見的動態(tài)庫.
image命令用來查詢?nèi)魏嗡接锌蚣艿男畔⒑退锩鏇]有在頭文件里公開的類和方法都是非常有用的.

等一下...模塊?

你將繼續(xù)用到Signals項目.打開這個項目, 用iPhone7模擬器構建并運行.
暫停調(diào)試器并在LLDB控制臺輸入下面的命令:

(lldb) image list

這條命令將會列出當前加載的所有的模塊. 你會看到許多!這個列表的開頭看起來應該是下面這個樣子:

[  0] 13A9466A-2576-3ABB-AD9D-D6BC16439B8F 0x00000001013aa000 /usr/lib/
dyld
[  1] 493D07DF-3F9F-30E0-96EF-4A398E59EC4A 0x000000010118e000 /
Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/
dyld_sim
[  2] 4969A6DB-CE85-3051-9FB2-7D7B2424F235 0x000000010115c000 /Users/
derekselander/Library/Developer/Xcode/DerivedData/Signals-
bqrjxlceauwfuihjesxmgfodimef/Build/Products/Debug-iphonesimulator/
Signals.app/Signals

頭兩個是動態(tài)加載器:一個是基于系統(tǒng)的另一個是專門為模擬器添加的. 這些都是必要的代碼, 它們允許你的程序將動態(tài)庫加載到內(nèi)存中用于程序的執(zhí)行.第三個是APP的主二進制文件, Signals.
但是在這個列表中還有其他更多的內(nèi)容!你可以只過濾出那些你感興趣的內(nèi)容.在LLDB中輸入下面命令:

(lldb) image list Foundation

你會得到類似于下面的輸出:

[  0] 4212F72C-2A19-323A-84A3-91FEABA7F900 0x0000000101435000 /
Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk//System/
Library/Frameworks/Foundation.framework/Foundation

這對于只顯示你想要查看的模塊的信息是非常有用的.
讓我們看一下這些輸出. 這里有一些有趣的內(nèi)容:

  1. 首先打印出來的是模塊的UUID(4212F72C-2A19-323A-84A3-91FEABA7F900).這個UUID對于捕獲符號信息和唯一標示Foundation模塊是非常重要的.
    2.緊接著UUID的是加載地址(0x0000000101435000).這標明了Foundation模塊加載到Signals可執(zhí)行進程空間后的地址.
    3.最后, 你會得到這個模塊的二進制文件在本地的全路徑.
    讓我們深入到另一個常用的模塊UIKit中看一下.在LLDB中輸入下面的命令:
(lldb) image dump symtab UIKit -s address

這條命令會提取出UIKit中所有可用的符號表信息. 這條命令輸出的內(nèi)容是按照函數(shù)在UIKit中實現(xiàn)的順序排列的, 這是-s address的作用.
這里有很多有用的信息, 但是你不可能把所有的內(nèi)容都讀一遍. 你需要一個高效的方法在UIKit中查詢你感興趣的代碼.
image lookup命令可以完美的過濾出所有的數(shù)據(jù).輸入下面的命令:

(lldb) image lookup -n "-[UIViewController viewDidLoad]"

這回提取出只與UIViewControllerviewDidLoad實例方法相關的內(nèi)容.你會看到與這個方法相關的符號的名字, 還有那個方法在UIKit框架中實現(xiàn)的代碼.
這很好并且很全, 但是輸入這些文字有些乏味并且這只能提取出指定的實例.
然而這正是正則表達式要做的事情.-r選項將能夠讓你使用正則表達式查詢. 在LLDB中輸入下面的命令:

(lldb) image lookup -rn UIViewController

這條指令不僅僅會提取出所有的UIViewController方法, 而且會輸類似UIViewControllerBuiltinTransitionViewAnimator這樣包含有UIViewController字樣的方法.你也可以使用這則表達式只輸出UIViewController的方法.在LLDB中輸入下面的內(nèi)容:

(lldb) image lookup -rn '\[UIViewController\ '

這當然很好, 但是怎么處理分類呢?他們是UIViewController(CategoryName)的形式.嘗試搜索UIViewController的所有分類:

(lldb) image lookup -rn '\[UIViewController\(\w+\)\ '

現(xiàn)在指令開始變得復雜了. 開頭的反斜杠表明你是想要使用[的字面意, 然后是UIViewController. 最后是(的字面意, 然后是一個或多個文字數(shù)字或下劃線字符(w+的含義)., 然后是), 最后跟著一個空格.
正則表達式的知識將會幫助你創(chuàng)造性的查詢加載到二進制文件中的任何模塊的公有或者私有的代碼.
這不僅會打印出公有和私有的方法, 而且會給出UIViewController類覆蓋的父類的方法.

捕獲代碼

無論你捕獲的是公有的代碼還是私有代碼, 有時只想弄明白編譯器是如何生成一個特定函數(shù)的函數(shù)名的.你已經(jīng)簡單的使用上面的image lookup命令找到了UIViewController的方法.你也在第四章中用它找到了swift屬性的settersgetter方法.
然而, 這里還有許多例子可以幫助你更好的理解代碼是如何生成的以及如何在你感興趣的地方設置斷點. 一個特殊的例子就是查看 Objective-C代碼塊的方法聲明.
那么搜索Objective-C代碼塊方法聲明的最好的方法是什么呢?鑒于你沒有任何線索來尋找代碼塊是在那里被命名的, 所以一個好的方法就是在代碼塊的內(nèi)部創(chuàng)建一個斷點然后從那里開始檢查.
打開UnixSignalHandler.m, 然后找到單例方法sharedHandler.在這個函數(shù)中找到下面的代碼:

dispatch_once(&onceToken, ^{
  sharedSignalHandler = [[UnixSignalHandler alloc] initPrivate];
});

在Xcode中在sharedSignalHandler的起始位置設置一個斷點. 然后構建并運行. Xcode現(xiàn)在將會停在你設置斷點的地方.在調(diào)試窗口中查看棧幀的頂部.

page82image1080.png

你可以找到你在Xcode中的函數(shù)的名字. 在調(diào)試欄中你將會看到棧追蹤并且可以看到frame 0. 要復制粘貼的話有點小難. 我們可以用下面的命令替代:

(lldb) frame info

你將會得到類似下面的輸出:

frame #0: 0x0000000100cb20a0 Commons`__34+[UnixSignalHandler
sharedHandler]_block_invoke((null)=0x0000000100cb7210) + 16 at
UnixSignalHandler.m:68

正如你看到的, 函數(shù)的全名是__34+[UnixSignalHandler sharedHandler]_block_invoke.
函數(shù)名中有一個很有趣的部分, _block_invoke. 這也許就是在Objective-C中幫助你標識一個代碼塊的標志.在LLDB中輸入下面的命令:

(lldb) image lookup -rn _block_invoke

這條命令用正則表達式搜索關鍵詞_block_invoke. 它會將_block_invoke作為通配符處理包含_block_invoke的內(nèi)容.
但是等一下!實際上你打印出所有加載到程序中的Objective-C代碼快.這個搜索包含UIKit,Foundation,iPhoneSimulator SDK等等中的所有代碼塊.你應該將你的搜索范圍限定在Signals模塊中.在LLDB在中輸入下面的命令:

(lldb) image lookup -rn _block_invoke Signals

什么都沒有打印出來.發(fā)生了什么事呢?打開Xcode右側的File Inspector面板. 或者按下? + Option + 1.

page83image8096.png

如果你看到UnixSignalHandler.m被編譯的地方, 你就會發(fā)現(xiàn)它實際上被編譯進了Commons框架. 所以, 重新搜索并在Commons模塊中搜索Objective-C代碼塊. 在LLDB中輸入下面命令:

(lldb) image lookup -rn _block_invoke Commons

最后, 你會看到一些輸出.
現(xiàn)在你會看到你再Commons框架中找到的所有Objective-C代碼塊的輸出.
現(xiàn)在, 讓我們在你找到的代碼塊的一個子集上創(chuàng)建一個斷點.
在LLDB中輸入下面的命令:

(lldb) rb appendSignal.*_block_invoke -s Commons
注意: 在模塊中搜索代碼和在代碼中搜索模塊有一些細微的不同.用上面的命令做一個例子.當你想要搜索`Commons`框架中所有的代碼塊, 你應該使用`image lookup -rn _block_invoke Commons`.當你想要為`Commons`框架中的代碼塊設置一個斷點, 你應該使用`rb appendSignal.*block_invoke -s Commons`.注意`-s`參數(shù)后面的空格.

這條指令會在所有appendSignal方法的代碼塊處設置斷點.
在LLDB中輸入continue繼續(xù)運行程序.跳進終端并輸入下面的命令:

pkill -SIGIO Signals

你發(fā)送給程序的信號將會被處理.然而, 在這個信號被更新到tableview之前, 你的正則斷點就會被觸發(fā).
觸發(fā)的第一個斷點應該是:

__38-[UnixSignalHandler appendSignal:sig:]_block_invoke

繼續(xù)運行調(diào)試器并跳過這一步.
接下來你會觸發(fā)另一個斷點:

__38-[UnixSignalHandler appendSignal:sig:]_block_invoke_2

這個函數(shù)名與第一個函數(shù)名相比有一個有趣的地方; 注意到數(shù)字2.編譯器使用<FUNCTION_NAME>_block_invoke的格式定義叫做<FUNCTION_NAME>blocks.然而, 在函數(shù)中不只有一個block時, 就會在尾部添加一個數(shù)字.
正如你在前面學到的內(nèi)容, frame variable命令將會打印出指定函數(shù)中所有已知的實例變量. 現(xiàn)在嘗試執(zhí)行一下這個命令來看一下這個block的引用.輸入下面的命令:

(lldb) frame variable

輸出的內(nèi)容應該像下面這個樣子:

(__block_literal_5 *)  = 0x0000608000275e80
(int) sig = <read memory from 0x41 failed (0 of 4 bytes read)>
(siginfo_t *) siginfo = <read memory from 0x39 failed (0 of 8 bytes
read)>
(UnixSignalHandler *const) self = <read memory from 0x31 failed (0 of 8
bytes read)>

這些讀內(nèi)存時的故障看起來很不友好!步過一次, 即可以使用Xcode也可以在LLDB 中輸入next.接下來, 再次在LLDB中執(zhí)行frame variable.
這一次你會看到類似下面的輸出:

(__block_literal_5 *)  = 0x0000608000275e80
(int) sig = 23
(siginfo_t *) siginfo = 0x00007fff587525e8
(UnixSignalHandler *) self = 0x000061800007d440
(UnixSignal *) unixSignal = 0x000000010bd9eebe

你需要步過函數(shù)的聲明, 以便代碼塊可以執(zhí)行一些初始化邏輯來設置這個函數(shù). 函數(shù)聲明是與匯編相關的內(nèi)容, 你會在第二部分學到.

這實際上非常有趣. 首先你看到了一個引用著這個代碼塊的對象, 那是被調(diào)用的地方.在這里是__block_literal_5. 然后是一些傳到調(diào)用這個代碼塊的Objective-C方法里的sig 和 siginfo 參數(shù). 這些是如何傳到代碼塊里的呢?
好, 當一個代碼塊創(chuàng)建的時候, 編譯器聰明到足以弄明白它會用到哪些參數(shù).然后它會創(chuàng)建一個函數(shù)并把這些參數(shù)帶進去. 當代碼快被調(diào)用的時候, 就是這個函數(shù)被調(diào)用, 并將相關的參數(shù)穿進去.
在LLDB中輸入下面命令:

  (lldb) image dump symfile Commons

你將會看到許多輸出. 使用? + F 通過編譯器搜索block類型的聲明:__block_literal_5. 有一個比較重要的東西要提醒你的是當LLVM更新的時候你得到的類型可能有細微的不同, 所以請確保你從frame variable 命令的輸出中得到了正確的類型.
在搜索block類型的聲明時, 會有幾種不同情形. 搜索與block的行號相匹配的結構體的聲明. 例如, 你最初創(chuàng)建的123行的斷點, 同樣也可以在聲明中搜索. 最終你會得到一些類似下面的輸出:

0x7fefe24bcf90:   Type{0x100000e06} , name = "__block_literal_5", size =
52, decl = UnixSignalHandler.m:123, compiler_type = 0x00007fefd86d0410
struct __block_literal_5 {
        void *__isa;
        int __flags;
        int __reserved;
        void (*__FuncPtr)();
        __block_descriptor_withcopydispose *__descriptor;
        UnixSignalHandler *const self;
        siginfo_t *siginfo;
int sig; 
}

這就是定義代碼塊的那個對象!
正如你看到的, 這就如同有一個頭文件在告訴你如何在代碼塊的內(nèi)存中自由的找到你想要的東西. 只要提供你找到的__block_literal_5在內(nèi)存中的應用, 你就可以輕松的打印出這個block引用的所有變量.通過輸入下面的命令再次獲取棧幀的變量信息:

  (lldb) frame variable

接下來, 找到__block_literal_5 對象的內(nèi)存地址并用下面的方式打印出來:

(lldb) po ((__block_literal_5 *)0x0000618000070200)

你將會看到類似下面的輸出:

<__NSMallocBlock__: 0x0000618000070200>

如果你的輸出與上面的不一樣, 確保你使用的__block_literal_5 的內(nèi)存地址是你的block的地址,每一次運行的時候內(nèi)存地址都會有些許不同.
現(xiàn)在你可以查詢__block_literal_5的內(nèi)存結構了. 在LLDB中輸入:

(lldb) p/x ((__block_literal_5 *)0x0000618000070200)->__FuncPtr

這條指令會提取出這個block的函數(shù)指針的位置.輸出的內(nèi)容看起來應該是下面這個樣子:

(void (*)()) $1 = 0x000000010756d8a0 (Commons`__38-[UnixSignalHandler appendSignal:sig:]_block_invoke_2 at UnixSignalHandler.m:123)

block的函數(shù)指針指向, 運行時block被調(diào)用時的函數(shù). 現(xiàn)在被執(zhí)行的時候他們是同樣的地址! 你可以輸入下面的命令進行確認, 用你最近一次的命令打印出來的函數(shù)指針的地址替換下面的地址:

(lldb) image lookup -a 0x000000010756d8a0

這里在image lookup后面用了-a(address)選項來查看給定地址相關的符號.回到block結構體的成員變量, 你依然可以打印出傳遞給block的所有的參數(shù).
輸入下面的命令, 再次用你的block的地址替換下面的地址:

(lldb) po ((__block_literal_5 *)0x0000618000070200)->sig

這將會輸出作為block的父函數(shù)的參數(shù)的signal的序號.在結構體的成員變量里還有一個UnixSignalHandler的引用叫做self.
為什么會那樣呢? 看一下這個 block 并且 捕獲下面這行代碼:

[(NSMutableArray *)self.signals addObject:unixSignal];

它是block捕獲的self的引用., 是用來找到signals數(shù)組的偏移的.因此block需要知道self 是什么. 很酷, 對吧?
image dump symfile命令與module聯(lián)合起來是用來學習某種未知數(shù)據(jù)類型的好方法. 它還是用來學編譯器是如何用你的源代碼生成代碼的好工具.
此外, 你可以檢查blocks是如何持有指向外部的block的引用的-當出現(xiàn)運行循環(huán)的時候會是一個非常有用的工具.

窺探

你已經(jīng)知道了如何用靜態(tài)的方式檢查一個私有類的實例變量, 但是把block的內(nèi)存地址單獨留下來是在太折磨人了. 嘗試著把他打印出來并用動態(tài)分析的方法查看它.輸入下面的內(nèi)容, 用你block的地址替換下面的地址:

po 0x0000618000070200

LLDB會提取出一個表明自己是Objective-C類的類:

<__NSMallocBlock__: 0x618000070200>

這很有趣. 這是一個__NSMallocBlock__類.現(xiàn)在你已經(jīng)學習了如何提取出一個類的共有方法和私有方法, 現(xiàn)在是時候查看一下__NSMallocBlock__實現(xiàn)的方法了.在LLDB中輸入:

(lldb) image lookup -rn __NSMallocBlock__

什么都沒有發(fā)生. 這說明__NSMallocBlock__沒有覆蓋它的父類的任何方法. 輸入下面的命令來查看__NSMallocBlock__的父類:

(lldb) po [__NSMallocBlock__ superclass]

這回產(chǎn)生一個類似的名字叫做__NSMallocBlock的類--注意尾部缺少的下劃線. 你可以找出這個類的哪些信息呢?這個類是否實現(xiàn)或者覆蓋了一些方法呢? 在LLDB中輸入下面的命令:

(lldb) image lookup -rn __NSMallocBlock

用這條命令提取出來的方法表明__NSMallocBlock是負責內(nèi)存管理的, 因為它實現(xiàn)了像retainrelease這樣的方法.__NSMallocBlock的父類又是什么呢?在LLDB中輸入下面的命令:

(lldb) po [__NSMallocBlock superclass]

你會得到另一個類NSBlock.這個類是干什么?它又實現(xiàn)了哪些方法呢?在LLDB中輸入下面的命令:

(lldb) image lookup -rn 'NSBlock\ '

注意最后的反斜杠和空格. 記住-這能確保沒有其它類能夠匹配這次查詢, 如果沒有它的話, 那么其它一些包含NSBlock名字的類也會被匹配到.一些方法將會被輸出.其中有一個叫做invoke的方法, 看起來極為有趣:

Address: CoreFoundation[0x000000000018fd80] (CoreFoundation.__TEXT.__text
+ 1629760)
        Summary: CoreFoundation`-[NSBlock invoke]

現(xiàn)在你將會嘗試著在block中調(diào)用這個方法.然而, 你并不想讓持有這個block的的引用在release的時候消失, release減少它的retainCount, 所以block有被釋放的風險.
有一個非常簡單的方法可以保留這個block-只需要retain一下!輸入下面的命令, 用你的block的地址替換下面代碼中的地址:

(lldb) po id $block = (id)0x0000618000070200
(lldb) po [$block retain]
(lldb) po [$block invoke]

在最后一行你將會看到下面這些輸出:

 Appending new signal: SIGIO
 nil

這表明你的block已經(jīng)被調(diào)用了一次. 干凈漂亮!
它之所以會生效是應為當block被調(diào)用的時候所有設置都已經(jīng)準備就緒了, 因為你當前已經(jīng)正確的停在了block開始的位置.
這種類型的方法來查看公有和私有類的, 然后查看它們實現(xiàn)的方法, 是一種學習程序底層實現(xiàn)的好方法.后面你會用同樣的過程來查找方法并分析這些方法執(zhí)行時的匯編代碼, 會給到你一個非常接近源始方法的源代碼.

調(diào)試私有方法

image lookup命令在尋找私有方法以及公有方法上面做的很漂亮, 他會貫穿你的整個apple開發(fā)生涯.
然而, 這里還有一些隱藏的方法在調(diào)試你自己的代碼的時候非常有用.例如, 以_開頭的方法通常都表明它是一個私有(并且是潛在的很重要的)方法.
讓我們搜索一下所有模塊中的所有包含下劃線字符并包含description關鍵字的的Objective-C的方法.
再次構建并運行項目. 當sharedHandler處的斷點被觸發(fā)的時候, 在LLDB中輸入下面的內(nèi)容:

(lldb) image lookup -rn (?i)\ _\w+description\]

這個表達式有點復雜所以讓我們解析一下.
這個表達式會搜索空格(前面需要有一個)后面跟著下劃線, 接下來是, 一個或多個字母或數(shù)字后面跟著description單詞, 最后跟著]字符的方法.
在這個正則表達式開始的地方有一個有趣的字符集(?i). 這表明在搜索的時候不區(qū)分大小寫.
這個表達式有一個反斜杠前綴符. 這表明你想使用字符的字面量而不是字符在正則表達式中的含義.這叫做'escaping'.例如, 在一個正則表達式中, ]字符是有特定含義的, 所以你需要是使用\].
在上面的正則表達式中\w字符是個例外. 它指定的搜索內(nèi)容是下劃線, 字母或數(shù)字(例如, _, a- z, A-Z, 0-9).
如果你在閱讀這行代碼的時候依然有不理解的地方, 強烈推薦你看一下https://docs.python.org/2/library/re.html深入了理解正則表達式查詢.往后去正則表達式只會變得更加復雜.
仔細查看image lookup的輸出. 在找到最佳答案之前查找是很乏味的, 因此確保你查看了所有的輸出.
你可能會注意到幾個UIKit中的一個NSObject的分類IvarDescription中幾個比較有趣的方法.
嘗試只將這個分類的內(nèi)容打印出來.在LLDB中輸入下面的內(nèi)容:

(lldb) image lookup -rn NSObject\(IvarDescription\)

控制臺將會輸出這個分類實現(xiàn)的所有方法. 在打印出來的這些方法中, 有幾個比較有趣的方法:

_ivarDescription
_propertyDescription
_methodDescription

因為這是NSObject的分類, 所以所有NSObject的子類都能調(diào)用這些方法. 這讓一切都變得更完美, 當然!
嘗試在UIApplication上調(diào)用這些方法. 在LLDB中輸入下面的命令:

(lldb) po [[UIApplication sharedApplication] _ivarDescription]

因為UIApplication持有很多實例變量所以你會得到很多輸出.仔細察看并且找到你感興趣的內(nèi)容. 不用返回來繼續(xù)閱讀, 直到你找到感興趣的東西. 這很重要!
在仔細察看了輸出之后, 你會看到引用了一個私有類UIStatusBar. UIStatusBar的Objective-C 的setter方法在那里呢, 我聽到你問?讓我們來看一下! 在LLDB中輸入下面的內(nèi)容:

(lldb) image lookup -rn '\[UIStatusBar\ set'

這會提取出UIStatusBar所有可用的setter方法.此外還有UIStatusBar中聲明的和覆蓋的方法, 你可以訪問到它父類的所有可有的方法.查看一下UIStatusBar是否是UIView的子類.

(lldb) po (BOOL)[[UIStatusBar class] isSubclassOfClass:[UIView class]]

提示一下, 你可以重復使用superclass方法這繼承樹上往上爬.正如你看到了, UIStatusBar看起來是UIView的子類, 因此在這個類中backgroundColor屬性是可以用的. 讓我們練習一下.
首先, 在LLDB中輸入下面的指令:

(lldb) po [[UIApplication sharedApplication] statusBar]

你將會看到一些類似下面的輸出;

 <UIStatusBar: 0x7fb8d400d200; frame = (0 0; 375 20); opaque = NO;
autoresize = W+BM; layer = <CALayer: 0x61800003aec0>>

這回打印出你APP的UIStatusBar實例.接下來使用, status bar的地址, 在LLDB中輸出下面的命令:

(lldb) po [0x7fb8d400d200 setBackgroundColor:[UIColor purpleColor]]

在LLDB中, 刪除你之前創(chuàng)建的所有斷點:

(lldb) breakpoint delete

繼續(xù)運行APP并看看你用指尖創(chuàng)造出來的美好世界!


page91image1048.png

現(xiàn)在還不是最漂亮的APP, 但是至少你已經(jīng)找到了一個私有方法并用它做了一些有趣的事情!

我們?yōu)槭裁匆獙W習這些呢?

作為一個挑戰(zhàn), 試著用image lookup命令找出Signals模塊中所有的閉包. 一旦你做到了, 在每一個Signals模塊的每一個Swift閉包中創(chuàng)建一個斷點. 如果它對你來說太簡單了, 嘗試著找到可以在didSet/willSet屬性時停下來的代碼, 或者做一些/try/catch``blocks的操作.
也可以, 找出更多隱藏在Foundation或者UIKit中的私有方法. 學習愉快!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唤蔗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖彰触,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亲澡,死亡現(xiàn)場離奇詭異唉地,居然都是意外死亡,警方通過查閱死者的電腦和手機岳守,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碌冶,“玉大人湿痢,你說我怎么就攤上這事∑伺樱” “怎么了譬重?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長罐氨。 經(jīng)常有香客問我臀规,道長,這世上最難降的妖魔是什么栅隐? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任塔嬉,我火速辦了婚禮,結果婚禮上租悄,老公的妹妹穿的比我還像新娘谨究。我一直安慰自己,他們只是感情好泣棋,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布胶哲。 她就那樣靜靜地躺著,像睡著了一般潭辈。 火紅的嫁衣襯著肌膚如雪鸯屿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天把敢,我揣著相機與錄音碾盟,去河邊找鬼。 笑死技竟,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的屈藐。 我是一名探鬼主播榔组,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼联逻!你這毒婦竟也來了搓扯?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤包归,失蹤者是張志新(化名)和其女友劉穎锨推,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡换可,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年椎椰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沾鳄。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡慨飘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出译荞,到底是詐尸還是另有隱情瓤的,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布吞歼,位于F島的核電站圈膏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏篙骡。R本人自食惡果不足惜稽坤,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望医增。 院中可真熱鬧慎皱,春花似錦、人聲如沸叶骨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忽刽。三九已至天揖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間跪帝,已是汗流浹背今膊。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伞剑,地道東北人斑唬。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像黎泣,于是被迫代替她去往敵國和親恕刘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

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