Frida 安装和使用

0x01 简介

frida 是一款基于 python+javascript 的 hook 框架,可运行在 android、ios、linux、win等各个平台,主要使用的动态二进制插桩技术。

0x02 插桩技术

是指将额外的代码注入程序中以收集运行时的信息,可分为源代码插桩 SCI 和二进制插桩 BI。

  • 源代码插桩 SCI

    Source Code Instrumentation,额外代码注入到程序源代码中。

  • 二进制插桩 BI

    Binary Instrumentation,额外代码注入到二进制可执行文件中。

    1. 静态二进制插桩 SBI,Static Binary Instrumentation,在程序执行前插入额外的代码和数据,生成一个永久改变的可执行文件。

    2. 动态二进制插桩 DBI
      ,Dynamic Binary Instrumentation,在程序运行时实时插入额外代码和数据,对可执行文件没有任何永久改变。

0x03 Frida安装

官方地址
github地址

  • PC 端
    python 安装
    编译安装
  • Android 端
    已 root 设备
    非 root 设备

一、PC端

安装 frida CLI(command-line interface,命令行界面)

python 安装

pip3 install frida

pip 安装 frida CLI,pip install frida,过程遇到Running setup.py bdist_wheel for frida ...\较慢,请耐心等候

源码编译安装

git clone git://github.com/frida/frida.git
cd frida
make

注意安装版本,系列工具版本号要一致

查看 frida 版本号

frida --version 
12.2.27

frida 共有6个工具:firda CLI,frida-ps,frida-trace,frida-discover,frida-ls-devices,frida-kill

二、Android 端

电脑 USB 连接安卓手机,针对设备是否 root 采用不同的方式

1. 已 root 设备

已经 root 的设备采用安装 frida-server 的方式

1. 查看手机型号,下载系统对应版本的 frida-server

adb shell getprop ro.product.cpu.abi

例如型号为 arm64-v8a,则下载 frida-server-12.2.27-android-arm64.xz

2. 将其解压缩生成 frida-server-12.2.27-android-arm64 文件

3. 将解压之后的文件push 到设备中,指定到 /data/local/tmp 路径下重命名为 frida-server

adb push frida-server-12.2.27-android-arm64 /data/local/tmp/frida-server

4. 运行Android 设备中的 frida-server

adb shell
su
cd /data/local/tmp
chmod 755 frida-server
./frida-server

执行完毕后为运行状态。

保留此窗口 shell,以保证服务运行,关闭该shell 或者停止ctrl+c 则服务关闭。接下来的操作可另起shell 或该步骤命令另起 shell 执行。

5. 进行端口转发监听

adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043

27042 用于与frida-server通信的默认端口号,之后的每个端口对应每个注入的进程,检查27042端口可检测 Frida 是否存在。

6. 检查是否成功

执行frida-ps -U 命令成功输出进程列表,如下所示

$> frida-ps -U
PID  Name
-----  ----------------------------------------
 4275  com.android.keyguard
 4629  com.android.phone
 5182  com.android.contacts:cacheservice
 ...

执行frida -U -f com.xxx.xxx 进行连接,选择一个进程,等待一段时间则进入该应用

$> frida -U -f com.xxx.xx
     ____
    / _  |   Frida 12.2.27 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://www.frida.re/docs/home/
Spawned `com.xxx.xxx`. Use %resume to let the main thread start executing!

2. 非 root 设备

没有 root 的设备采用安装 frida-gadget 的方式,需要对目标应用 apk 进行反编译注入和调用

手动注入frida-gadget

1. 反编译 apk

apktool d target_app.apk -o target_app_floder

反编译之后生成 target_app_floder 文件夹

2. 下载系统对应版本的 frida-gadget,解压并放到指定位置

下载之后将其进行解压,然后放到target_app_floder//lib/armeabi/libfrida-gadget.so,注意修改名字以 lib 开头 .so 结尾,对应下一步的代码中的frida-gadger

注:本人手机是 arm64-v8a,所以下载 frida-gadget-12.2.27-android-arm64.so.xz,但最后回编译打包之后,运行总是奔溃,不断的尝试之后才发现使用 frida-gadget-12.2.27-android-arm.so.xz 可以正常运行

3. 代码中加载上一步so 文件,建议在应用的入口文件中执行
根据 AndroidManifest.xml 文件找到程序的入口文件,例如 MainActivity,在反编译生成的代码 smali 中的 onCreate 方法中注入如下代码

const-string v0, "frida-gadget"
invoke-static {v0}, Ljava/lang/System;>loadLibrary(Ljava/lang/String;)V

4. 检查AndroidManifest.xml清单文件的网络权限

<uses-permission android:name="android.permission.INTERNET" />

忌重复添加,会导致回编译包出错

5. 回编译 apk
a. 重新打包

apktool b -o repackage.apk target_app_floder

b. 创建签名文件,有的话可忽略此步骤

keytool -genkey -v -keystore mykey.keystore -alias mykeyaliasname -keyalg RSA -keysize 2048 -validity 10000                

c. 签名,以下任选其一

jarsigner 方式

jarsigner -sigalg SHA256withRSA -digestalg SHA1 -keystore mykey.keystore -storepass 你的密码 repackaged.apk mykeyaliasname

apksigner 方式

apksigner sign --ks mykey.keystore --ks-key-alias mykeyaliasname repackaged.apk

如需要禁用 v2签名 添加选项--v2-signing-enabled false

d. 验证,以下任选其一

jarsigner方式

jarsigner -verify repackaged.apk

apksigner 方式

apksigner verify -v --print-certs repackaged.apk

keytool方式

keytool -printcert -jarfile repackaged.apk

e. 对齐

4字节对齐优化

zipalign -v 4 repackaged.apk final.apk

检查是否对齐

zipalign -c -v 4 final.apk

注:zipalign可以在V1签名后执行,但zipalign不能在V2签名后执行,只能在V2签名之前执行

6. 安装 apk

adb install final.apk

7. 检查是否成功
打开运行 final.apk,在注入代码位置进入停止等待页面

执行frida-ps -U 命令,只显示Gadget一个进程如下:

$> frida-ps -U
  PID  Name
-----  ------
16251  Gadget

执行frida -U gadget命令进行连接

$> frida -U gadget
     ____
    / _  |   Frida 12.2.27 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://www.frida.re/docs/home/

[HUAWEI ALE-UL00::gadget]->
使用objection自动完成frida gadget注入到apk中
pip3 install -U objection
objection patchapk -s target_app.apk

如果包里有错误会生成失败

网上另一种非 root 方式

未实践
https://bbs.pediy.com/thread-229970.htm


至此环境配置完成,接下来使用

使用方式说明

命令行方式

在命令行使用 API 进行操作

$> frida -U --no-pause -f com.android.chrome
     ____
    / _  |   Frida 12.2.27 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://www.frida.re/docs/home/
Spawned `com.android.chrome`. Resuming main thread!
[HUAWEI ALE-UL00::com.android.chrome]-> Java
{
    "androidVersion": "5.0",
    "available": true
}
[HUAWEI ALE-UL00::com.android.chrome]-> Java.perform(function(){Java.enumerateLo
adedClasses({"onMatch":function(className){ console.log(className) },"onComplete
":function(){}})})
android.app.NativeActivity
java.security.cert.CertificateExpiredException
android.util.EventLog
android.os.storage.StorageVolume$1
android.system.StructStat
com.android.org.conscrypt.AbstractSessionContext
sun.misc.Unsafe
....

frida-ps 命令:
eg: frida-ps -U frida-ps -U -i

$> frida-ps -h
Usage: frida-ps [options]

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -D ID, --device=ID    connect to device with the given ID
  -U, --usb             connect to USB device
  -R, --remote          connect to remote frida-server
  -H HOST, --host=HOST  connect to remote frida-server on HOST
  -a, --applications    list only applications
  -i, --installed       include all installed applications

frida-trace 方式操作

frida-trace -i open -U com.android.chrome

执行之后会在当前目录,生成__handlers__ 文件夹,open.js 对应命令中 -i open 的名字,结构如下所示

.
├── __handlers__
│   └── libc.so
│       ├── close.js
│       └── open.js

open.js 内容如下(注释已去掉),可修改该文件改变输出内容

# !javascript
{
  onEnter: function (log, args, state) {
    log("open(" +
      "path=\"" + Memory.readUtf8String(args[0]) + "\"" +
      ", oflag=" + args[1] +
    ")");
  },

  onLeave: function (log, retval, state) {
  }
}

最终运行结果,和open.js中 onEnter 方法一致,如下:

 $> frida-trace -i "open" -U com.android.chrome
Instrumenting functions...
open: Auto-generated handler at "/Users/hych/Open/Frida/Workspace/__handlers__/libc.so/open.js"
Started tracing 1 function. Press Ctrl+C to stop.
           /* TID 0x5e80 */
  5556 ms  open(path="/data/data/com.android.chrome/cache/Cache/index-dir/temp-index", oflag=0x241)
           /* TID 0x5cf4 */
  6950 ms  open(path="/proc/vmstat", oflag=0x80000)
           /* TID 0x5e87 */
  7671 ms  open(path="/dev/ashmem", oflag=0x2)
  7674 ms  open(path="/dev/ashmem", oflag=0x2)
           /* TID 0x5cf4 */
 57800 ms  open(path="/proc/23796/cmdline", oflag=0x0)
load js 方式操作

-l : --load

frida -U -l chrome.js com.android.chrome

chrome.js 文件内容如下:

setImmediate(function() {
    console.log("[*] Starting script");
    Java.perform(function () {
        Java.choose("android.view.View", {
             "onMatch":function(instance){
                  console.log("[*] Instance found: " + instance.toString());
             },
             "onComplete":function() {
                  console.log("[*] Finished heap search")
             }
        });
    });
});

执行结果如下,发现创建了4个 View

frida -U -l chrome.js com.android.chrome
     ____
    / _  |   Frida 12.2.27 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://www.frida.re/docs/home/

[HUAWEI ALE-UL00::com.android.chrome]-> [*] Starting script
[*] Instance found: android.view.View{21519670 V.ED.... ........ 0,0-0,0}
[*] Instance found: android.view.View{2338b297 G.ED.... ......ID 0,0-0,0 #7f0a0013 app:id/action_bar_black_background}
[*] Instance found: android.view.View{3e144ce4 V.ED.... ........ 0,1134-0,1134 #7f0a022c app:id/menu_anchor_stub}
[*] Instance found: android.view.View{16335de9 G.ED.... ......I. 0,0-0,0 #7f0a0219 app:id/location_bar_verbose_status_separator}
[*] Finished heap search

python 方式操作

python3  chrome.py

chrome.py 如下:

import frida
import sys

scr = """
setImmediate(function() {
    console.log("[*] Starting script");
    Java.perform(function () {
        Java.choose("android.view.View", {
             "onMatch":function(instance){
                  console.log("[*] Instance found: " + instance.toString());
             },
             "onComplete":function() {
                  console.log("[*] Finished heap search")
             }
        });
    });
}); 
"""

# 采用 remote 方式必须进行端口转发  或者使用get_usb_device()
rdev = frida.get_usb_device()
# 目标应用包名
session = rdev.attach("com.android.chrome")

script = session.create_script(scr)

def on_message(message, data):
    print(message)

script.on("message", on_message)
script.load()

输出如下

$> python3 chrome.py
[*] Starting script
[*] Instance found: android.view.View{25b22a6e V.ED.... ........ 0,0-0,0}
[*] Instance found: android.view.View{1ee5b916 G.ED.... ......ID 0,0-0,0 #7f0a0013 app:id/action_bar_black_background}
[*] Instance found: android.view.View{25d34877 V.ED.... ........ 0,1134-0,1134 #7f0a022c app:id/menu_anchor_stub}
[*] Instance found: android.view.View{14ddc50f G.ED.... ......I. 0,0-0,0 #7f0a0219 app:id/location_bar_verbose_status_separator}
[*] Finished heap search

Hook

Java API 说明

在 Hook 之前,对 JAVA 注入相关的 API 做一个简单介绍,frida 的注入脚本是 JavaScript,因此我们后面都是通过 js 脚本来操作设备上的 Java 代码,如下

// 确保我们的线程附加到 Java 的虚拟机上,function 是成功之后的回调,之后的操作必须在这个回调里面进行,这也是 frida 的硬性要求
Java.perfom(function(){})

Java.use(className) //动态获取一个 JS 包装了的 Java 类
        $new()  // 通过$new方法来调用这个类构造方法
        $dispose()  // 最后可以通过$dispose()方法来清空这个 JS 对象

// 将 JS 包装类的实例 handle 转换成另一种 JS 包装类klass        
Java.cast(handle, kclass)

// 当获取到 Java 类之后,我们直接通过<wrapper>.<method>.implementations = function(){} 的方式来 hook wrapper 类的 method 方法,不管是实例方法还是静态方法都可以
var SQL = Java.use("com.xxx.xxx.database.SQLiteDatabase");
var ContentVaules = Java.use("android.content.ContentValues");
SQL.insert.implementation = function(arg1, arg2, arg3) {
    var values = Java.cast(arg3, ContentVaules);
}

// 由于 js 代码注入时可能会出现超时的错误,为了防止这个问题,我们通常还需要在最外面包装一层 setImmediate(function(){})代码
setImmediate(function(){
    Java.perform(function(){
        // start hook
        ...
    })
})

hook 本地代码示例

Android 示例代码如下:

CoinMoney 类:

public class CoinMoney {

    private int money;
    private String value;
    public int extMoney;

    public CoinMoney(int money) {
        this.money = money;
    }

    public CoinMoney(int money, String value) {
        this.money = money;
        this.value = value;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public int getExtMoney() {
        return extMoney;
    }

    public void setExtMoney(int extMoney) {
        this.extMoney = extMoney;
    }
}

Utils 类:

public class Utils {
    public static String getPwd(String info) {
        return info + "_fourbrother";
    }
}
python 脚本代码

hookNativeCode.py 如下:

# !python
import frida
import sys

scr = """
setImmediate(function() {                
    Java.perform(function(){  
        console.log("[*] Starting script --console");

        var utils = Java.use("com.simple.hookapp.Utils");
        var coinClass = Java.use("com.simple.hookapp.CoinMoney");
        var clazz = Java.use("java.lang.Class");
        var Exception = Java.use("java.lang.Exception");
        
        // hook 构造方法 **init**
        coinClass.$init.overload("int", "java.lang.String").implementation = function(money, value){
            send("money: "+money+ ", value: "+value);
            // 修改方法的参数
            return this.$init(12, "12.0");
        }

        // hook 普通方法
        coinClass.getValue.overload().implementation = function(){
            // 修改方法的返回值
            return this.getValue()+"_hook";
        }

        // hook 静态方法
        utils.getPwd.overload("java.lang.String").implementation = function(pwd){
            
            var arg = arguments[0];
            send("pwd 方式一 参数arguments获取:"+ arg);
            send("pwd 获取方式二 参数声明: "+ pwd)
            
            // 抛出异常查看堆栈信息 adb logcat -s AndroidRuntime
            throw Exception.$new("Utils getPwd Exception...")


            // 修改方法的参数和返回值
            var result = this.getPwd(arg + "_hook_")+"_hook";
            send(result);
            return result;
        }

        // 实例化对象 **new** 方式一
        var testNewCoin1 = coinClass.$new(11, "11.00 - testNewCoin1");
        send("testNewCoin1: "+ testNewCoin1);

        // 实例化对象 **new** 方式二
        var testNewCoin2 = coinClass.$new.overload("int", "java.lang.String").call(coinClass, 22, "22.00 - testNewCoin2");
        send("testNewCoin2: " + testNewCoin2);
        
        // 直接调用方法
        send("直接调用方法 "+testNewCoin2.getValue());
        // 反射调用方法
        // var reflectCoinExtMoney = Java.cast(testNewCoin2.getClass(),clazz).getDeclaredMethod("getValue");

        //  直接调用字段 
        var  directCoinValue = testNewCoin2.value;
        send(directCoinValue);// 输出:{'value': '12.0', 'fieldType': 2, 'fieldReturnType': {'className': 'java.lang.String', 'name': 'Ljava/lang/String;', 'type': 'pointer', 'size': 1}}}
        var  directCoinExtMoney = testNewCoin2.extMoney;
        send("直接调用字段 - public "+directCoinExtMoney);// 输出:直接调用字段 - public [object Object]
        
        //  反射调用字段
        var reflectCoinValueName = Java.cast(testNewCoin2.getClass(),clazz).getDeclaredField("value");
        reflectCoinValueName.setAccessible(true);
        // 反射调用字段 - 获取值
        var reflectCoinValueGet = reflectCoinValueName.get(testNewCoin2);
        send("反射调用字段 - private "+ reflectCoinValueGet);
        // 反射调用字段 - 设置值 **基本类型修改值 setXXX 方法,对象类型都是 set 方法即可**
        reflectCoinValueName.set(testNewCoin2,"set value");
        send(testNewCoin2.value);

        // 静态方法 在本脚本内使用没有调用上方的hook函数
        var newPwd = utils.getPwd("654321");
        send(newPwd);

    });                                                     
}); 
"""

# 采用 remote 方式必须进行端口转发  或者使用get_usb_device()
rdev = frida.get_usb_device()
session = rdev.attach("com.simple.hookapp")

script = session.create_script(scr)

def on_message(message, data):
    print(message)

script.on("message", on_message)
script.load()

sys.stdin.read()
执行
python3 hookNativeCode.py

Hook so 代码

hook 导出代码
android cpp 示例代码

native-lib.cpp

extern "C" JNIEXPORT jstring JNICALL
Java_com_simple_hookapp_JavaMainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello Java from C++";
    return env->NewStringUTF(hello.c_str());
}
python 脚本示例:
import frida
import sys

scr = """
setImmediate(function() {                
    Java.perform(function(){  
        console.log("[*] Starting script --console");
        // hook export function
        var nativePointer = Module.findExportByName("libnative-lib.so", "Java_com_simple_hookapp_JavaMainActivity_stringFromJNI");
        send("hookapp export native pointers: "+ nativePointer);

        Interceptor.attach(nativePointer, {
            onEnter: function(args){
                send("hookapp export so onEnter args: "+ args);
            },
            onLeave: function(retval){
                send("hookapp export so onLeave retval: "+ retval);
                var env = Java.vm.getEnv();
                var jstrings = env.newStringUtf("fourbroeher");

                // 修改返回值方式
                return retval.replace(jstrings);
            }
        });
    });                                                     
}); 
"""
# 采用 remote 方式必须进行端口转发  或者使用get_usb_device()
rdev = frida.get_usb_device()
session = rdev.attach("com.simple.hookapp")
# session = rdev.attach("com.simple.hookapp")

script = session.create_script(scr)

def on_message(message, data):
    print(message)

script.on("message", on_message)
script.load()

sys.stdin.read()
hook 未导出代码
  1. 查看 so 文件的内存基地址
    使用命令行查看 root,下面ec64e000为内存基地址
$ adb shell
shell@hwALE-H:/ # su
root@hwALE-H:/ # ps | grep maker
u0_a5624  31315 2333  1771148 155332 ffffffff f771fdfc S com.smile.gifmaker
u0_a5624  31380 2333  1644536 83624 ffffffff f771fdfc S com.smile.gifmaker:QS
u0_a5624  31455 2333  1640868 85960 ffffffff f771fdfc S com.smile.gifmaker:messagesdk
u0_a5624  31601 2333  1667096 100384 ffffffff f771fdfc S com.smile.gifmaker:pushservice
1|root@hwALE-H:/ # cat /proc/31315/maps | grep libmtp.so
ec64e000-ec661000 r-xp 00000000 103:06 2171                              /system/lib/libmtp.so
ec661000-ec663000 r--p 00012000 103:06 2171                              /system/lib/libmtp.so
ec663000-ec664000 rw-p 00014000 103:06 2171                              /system/lib/libmtp.so
  1. 函数的相对地址
    IDA 打开 so 文件查看,例如 .text:00005070

  2. 上述俩个地址相加,然后+1。 例如下面示例中0xEC644071

setImmediate(function() {                
    Java.perform(function(){  
        console.log("[*] Starting script --console");
        
        // hook unexport function
        var nativePointer = new NativePointer(0xEC644071);
        send("hookapp native pointers: "+ nativePointer);
        var result_pointer;
        Interceptor.attach(nativePointer, {
            onEnter: function(args){
                // result_pointer = args[2].toInt32();
                // send("hookapp so args: "+ Memory.readCString(args[0]) + ", " + args[1] + ", "+ args[2]);
            },
            onLeave: function(retval){
                // memory alloc string  
            }
        });
    });                                                     
}); 

Demo地址:https://github.com/simplehych/HookApp

参考资料:

感谢以下文章作者
http://www.4hou.com/info/news/4113.html
https://baijiahao.baidu.com/s?id=1608313750146067893&wfr=spider&for=pc
https://fuping.site/2017/04/01/Android-HOOK-%E6%8A%80%E6%9C%AF%E4%B9%8BFrida%E7%9A%84%E5%88%9D%E7%BA%A7%E4%BD%BF%E7%94%A8/
https://blog.csdn.net/qingemengyue/article/details/80061491
https://sec.xiaomi.com/article/43
https://blog.csdn.net/jiangwei0910410003/article/details/80372118

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容