DroidPlugin之Hook機制

在DroidPlugin源碼中,作者提供了一份關(guān)于其實現(xiàn)原理的PPT講義青灼,這里我把其中介紹基本實現(xiàn)原理的章節(jié)貼出來徒役。

以下用DP代指DroidPlugin

DP基本原理.png

本文主要介紹Hook機制,看下作者是如何做到“偷天換日”田巴。

Hook機制

我認(rèn)為,DP所指的“Hook”和傳統(tǒng)意義上的Hook是有點區(qū)別的挟秤,例如在API Hook中提到這樣一句話“通過hook‘接觸’到需要修改的api函數(shù)入口點壹哺,改變它的地址指向新的自定義的函數(shù)”。Window上的API Hook可能會導(dǎo)致被hook的函數(shù)不被執(zhí)行(不知道我這樣理解對不對)艘刚。而DP的Hook機制管宵,被hook的函數(shù)是會被執(zhí)行的。閱讀DP源碼過程中我就有這樣的疑問攀甚,那DP的Hook到底做了啥箩朴!

Java動態(tài)代理

再回答上面的疑問之前,我們需要了解“Java動態(tài)代理”這個玩意秋度。關(guān)于動態(tài)代理的資料有很多炸庞,這里我就簡單介紹下。
Java動態(tài)代理是Java反射提供的一個強大功能荚斯,使用動態(tài)代理埠居,我們可以在被hook方法執(zhí)行前后查牌,做些額外操作。也可以修改被hook方法的入?yún)⒗暮荆薷姆椒ǚ祷刂抵窖铡O旅媾e個最簡單的代理例子,來說明代理能做什么绎橘。
首先定義一個接口IShopping胁孙,聲明一個購物的方法shopping。

package com.kisson.proxy;

public interface IShopping {
    void shopping(String money);
}

接著定義一個類GoShopping金踪,實現(xiàn)IShopping的shopping方法浊洞。

package com.kisson.proxy;

public class GoShopping implements IShopping{

    @Override
    public void shopping() {
        // TODO Auto-generated method stub
        System.out.println("我去逛街咯!"+" 我有"+money+"元");
    }
}

接著我們需要利用動態(tài)代理去hook接口IShopping的shopping方法。然后定義一個IShoppingHook類并實現(xiàn)InvocationHandler接口

package com.kisson.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class IShoppingHook implements InvocationHandler {

    private Object mHookedObject;

    public IShoppingHook(Object hookedObject) {
        this.mHookedObject = hookedObject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // 方法執(zhí)行前胡岔,做預(yù)處理
        beforeHook();
        //錢越多越好7ㄏ!!靶瘸!
        args[0] = "2000000";
       //在這里就是執(zhí)行shopping方法的過程苫亦,通過反射來完成
        Object result = method.invoke(mHookedObject, args);
        // 方法執(zhí)行后,做收尾處理
        afterHook();
        return result;
    }

    public void beforeHook() {
        // todo:something
        System.out.println("工作都已經(jīng)做完了怨咪,可以安心購物咯!");
    }

    public void afterHook() {
        // todo:something
        System.out.println("買的真開心!");
    }
}

上面的準(zhǔn)備工作就緒屋剑,接著看如何實現(xiàn)。

package com.kisson.proxy;

import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ProxyTest test = new ProxyTest();
        IShopping shopping = new GoShopping();
        test.newProxyInstance(shopping).shopping("100");;
        
    }

    private IShopping newProxyInstance(IShopping shopping) {
        return (IShopping) Proxy.newProxyInstance(shopping.getClass()
                .getClassLoader(), shopping.getClass().getInterfaces(),
                new IShoppingHook(shopping));
    }

}

執(zhí)行結(jié)果如下:

工作都已經(jīng)做完了诗眨,可以安心購物咯!
我去逛街咯! 我有2000000元
買的真開心!

以上動態(tài)代理的過程我們做了兩件事:
1.在shopping方法執(zhí)行前后唉匾,分別執(zhí)行了beforeHook和afterHook方法。
2.改變了shopping方法的入?yún)⒔吵緛碇挥?00元巍膘,最終結(jié)果卻得到了2000000元!
DP使用Hook機制完成了三個工作:

  1. 動態(tài)代理實現(xiàn)函數(shù)hook芋簿。
  2. Binder代理繞過部分系統(tǒng)服務(wù)限制峡懈。
  3. IO重定向

以后針對這三個點分別介紹下。

Binder代理繞過部分系統(tǒng)服務(wù)限制

原理

        LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

上述代碼与斤,是獲取系統(tǒng)位置服務(wù)肪康。如果我們需要獲取類似的系統(tǒng)服務(wù),都是通過Context的getSystemService方法來獲取撩穿。

getSystemService類圖

getSystemService方法的是在ContextImpl類中實現(xiàn)的磷支。很久沒看源碼,看了下源碼發(fā)現(xiàn)該方法的實現(xiàn)被修改了食寡。

    @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }

這里出現(xiàn)了一個SystemServiceRegistry類齐唆,其作用是用來管理所有通過getSystemService返回的系統(tǒng)服務(wù)。
在類中SystemServiceRegistry類中有很大一坨靜態(tài)代碼塊冻河,用于注冊各種系統(tǒng)服務(wù)箍邮。

//位置服務(wù)的注冊
registerService(Context.LOCATION_SERVICE, LocationManager.class,
                new CachedServiceFetcher<LocationManager>() {
            @Override
            public LocationManager createService(ContextImpl ctx) {
                IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
                return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
            }});

在這里我們可以看到LocationManager的創(chuàng)建過程了,通過調(diào)用ServiceManager的getService方法來創(chuàng)建IBinder對象叨叙,作為LocationManager構(gòu)造方法的參數(shù)锭弊。在ContexImpl類中有個mServiceCache對象,用于保存創(chuàng)建的各種XXManager對象擂错,類似單例模式吧味滞。

public final class ServiceManager {
    private static final String TAG = "ServiceManager";

    private static IServiceManager sServiceManager;
    private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();

    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

    /**
     * Returns a reference to a service with the given name.
     * 
     * @param name the name of the service to get
     * @return a reference to the service, or <code>null</code> if the service doesn't exist
     */
    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
//....省略部分代碼
}

通過ServiceManager源碼,可以知道:

  1. 使用sCache對象來保存系統(tǒng)中已經(jīng)創(chuàng)建的IBinder钮呀。
  2. getService方法中剑鞍,首先會在sCache中去查找是否有緩存,如果沒有爽醋,則調(diào)用IServiceManager的getService方法創(chuàng)建IBinder蚁署。

DP hook系統(tǒng)服務(wù)的原理:

  1. 對ServiceManager進行操作,反射得到sCache對象蚂四,將系統(tǒng)已經(jīng)原有的系統(tǒng)移除掉(Remove方法)光戈,接著再通過反射調(diào)用ServiceManager的getService方法獲取新的服務(wù)(IBinder),并在此加入sCache遂赠。
  2. 將系統(tǒng)服務(wù)中(IBinder)某些有執(zhí)行限制的方法久妆,進行動態(tài)代理處理,在這些方法執(zhí)行的前后進行“欺騙”操作跷睦。

總結(jié)起來就是偷天換日筷弦、欺上瞞下!

源碼分析之偷天換日

首先來看看“偷天換日”的類圖抑诸。


“偷天換日”類圖

結(jié)合類圖烂琴,我們來說明下各個類的作用。

1.Hook類

import android.content.Context;

/**
 * Created by Andy Zhang(zhangyong232@gmail.com) on 2015/3/2.
 * ---------------------------------
 * Hook類是所有需要進行Hook操作類的基類哼鬓,直接子類有BinderHook监右,
 * ServiceManagerCacheBinderHook,ProxyHook异希,SQLiteDatabaseHook等
 */
public abstract class Hook {
    //mEnable用于標(biāo)識是否開啟Hook操作健盒,如果不開啟,則走系統(tǒng)自由流程
    private boolean mEnable = false;
    //宿主的上下文環(huán)境
    protected Context mHostContext;

    protected BaseHookHandle mHookHandles;

    public void setEnable(boolean enable, boolean reInstallHook) {
        this.mEnable = enable;
    }

    public final void setEnable(boolean enable) {
        setEnable(enable, false);
    }

    public boolean isEnable() {
        return mEnable;
    }


    protected Hook(Context hostContext) {
        mHostContext = hostContext;
        mHookHandles = createHookHandle();
    }

    //創(chuàng)建BaseHookHandle對象
    protected abstract BaseHookHandle createHookHandle();

    /**
     * 子類實現(xiàn)onInstall方法称簿,主要用于替換ServiceManager中sCache已經(jīng)存在的系統(tǒng)服務(wù)扣癣。
     * 首先移除已經(jīng)存在的系統(tǒng)服務(wù)IBinder對象,然后自己生成這些系統(tǒng)服務(wù)的IBinder對象憨降,并放入sCache對象中父虑。
     * onInstall方法可以理解為“安裝Fake服務(wù)的過程”
     */
    protected abstract void onInstall(ClassLoader classLoader) throws Throwable;

    protected void onUninstall(ClassLoader classLoader) throws Throwable {

    }
}

2.BaseHookHandle

import android.content.Context;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by Andy Zhang(zhangyong232@gmail.com) on 2015/2/28.
 * 所有IXXXBinderHook的基類,該類的作用主要是負(fù)責(zé)HookedMethodHandler的“載入”授药、“讀取”
 */
public abstract class BaseHookHandle {
    //宿主的上下文
    protected Context mHostContext;
    //HookedMethodHandler的對象緩存集合
    protected Map<String, HookedMethodHandler> sHookedMethodHandlers = new HashMap<String, HookedMethodHandler>(5);

    public BaseHookHandle(Context hostContext) {
        mHostContext = hostContext;
        init();
    }
    //將所有HookedMethodHandler對象存入到sHookedMethodHandlers中
    protected abstract void init();

    //獲取sHookedMethodHandlers中所有key值
    public Set<String> getHookedMethodNames(){
        return sHookedMethodHandlers.keySet();
    }

    //根據(jù)sHookedMethodHandlers的key值獲取對應(yīng)的HookedMethodHandler對象
    public HookedMethodHandler getHookedMethodHandler(Method method) {
        if (method != null) {
            return sHookedMethodHandlers.get(method.getName());
        } else {
            return null;
        }
    }
}

3.HookedMethodHandler

import android.content.Context;
import com.morgoo.helper.Log;
import java.lang.reflect.Method;

/**
 * 該類可以說整個Hook機制的核心士嚎,前面在介紹動態(tài)代理的時候呜魄,我們聲明了IShoppingHook類并實現(xiàn)InvocationHandler接口,
 * 在其invoke方法中莱衩,通過發(fā)射機制調(diào)用被Hook的方法并在其調(diào)用前后分別調(diào)用了beforeHook和afterHook方法爵嗅。
 * 那么本類的作用也是如此:在InvocationHandler的invoke方法需要調(diào)用的被Hook方法的過程,挪到doHookInner中實現(xiàn)笨蚁。
 * 在真正調(diào)用被Hook的方法前后睹晒,做一些處理,以繞過系統(tǒng)限制括细!
 * **/
public class HookedMethodHandler {

    private static final String TAG = HookedMethodHandler.class.getSimpleName();

    protected final Context mHostContext;
    //Hook后的fake服務(wù)(IBinder對象)
    private Object mFakedResult = null;
    //是否使用fake服務(wù)
    private boolean mUseFakedResult = false;

    public HookedMethodHandler(Context hostContext) {
        this.mHostContext = hostContext;
    }


    public synchronized Object doHookInner(Object receiver, Method method, Object[] args) throws Throwable {
        long b = System.currentTimeMillis();
        try {
            mUseFakedResult = false;
            mFakedResult = null;
            boolean suc = beforeInvoke(receiver, method, args);
            Object invokeResult = null;
            if (!suc) {
                invokeResult = method.invoke(receiver, args);
            }
            afterInvoke(receiver, method, args, invokeResult);
            if (mUseFakedResult) {
                return mFakedResult;
            } else {
                return invokeResult;
            }
        } finally {
            long time = System.currentTimeMillis() - b;
            if (time > 5) {
                Log.i(TAG, "doHookInner method(%s.%s) cost %s ms", method.getDeclaringClass().getName(), method.getName(), time);
            }
        }
    }

    public void setFakedResult(Object fakedResult) {
        this.mFakedResult = fakedResult;
        mUseFakedResult = true;
    }

    /**
     * 在某個方法被調(diào)用之前執(zhí)行伪很,如果返回true,則不執(zhí)行原始的方法奋单,否則執(zhí)行原始方法
     */
    protected boolean beforeInvoke(Object receiver, Method method, Object[] args) throws Throwable {
        return false;
    }

    protected void afterInvoke(Object receiver, Method method, Object[] args, Object invokeResult) throws Throwable {
    }

    public boolean isFakedResult() {
        return mUseFakedResult;
    }

    public Object getFakedResult() {
        return mFakedResult;
    }
}

4.ServiceManagerCacheBinderHook

**
 * Created by Andy Zhang(zhangyong232@gmail.com) on 2015/3/2.
 * 本類主要完成對系統(tǒng)ServiceManager類中的對象和方法進行hook操作锉试。
 * 包括:1.從sCache對象中remove掉已經(jīng)存在的系統(tǒng)服務(wù)Binder對象
 * 2.生成fake系統(tǒng)服務(wù)Binder對象,并加入到sCache對象中
 */
public class ServiceManagerCacheBinderHook extends Hook implements InvocationHandler {

    //系統(tǒng)服務(wù)名字辱匿,如ActivityManager的“activity”
    private String mServiceName;

    public ServiceManagerCacheBinderHook(Context hostContext, String servicename) {
        super(hostContext);
        mServiceName = servicename;
        setEnable(true);
    }


    @Override
    protected void onInstall(ClassLoader classLoader) throws Throwable {
        //通過反射獲取sCache對象
        Object sCacheObj = FieldUtils.readStaticField(ServiceManagerCompat.Class(), "sCache");
        //判斷sCacheObj類型是否是Map
        if (sCacheObj instanceof Map) {
            Map sCache = (Map) sCacheObj;
            //通過Service Name獲取對應(yīng)系統(tǒng)服務(wù)的IBinder對象
            Object Obj = sCache.get(mServiceName);
            if (Obj != null && false) {
                //FIXME 已經(jīng)有了怎么處理键痛?這里我們只是把原來的給remove掉,再添加自己的匾七。程序下次取用的時候就變成我們hook過的了絮短。
                //但是這樣有缺陷。
                //add by me
                // 作者這個疑問是需要解決昨忆。因為系統(tǒng)原有的已經(jīng)被替換了丁频,等于后續(xù)其他app使用系統(tǒng)服務(wù)的時候都是被替換的IBinder對象
                //雖然說沒有啥大影響,但是還是要做到善始善終邑贴。how to do席里?
                throw new RuntimeException("Can not install binder hook for " + mServiceName);
            } else {
                //移除掉mServiceName對應(yīng)的系統(tǒng)服務(wù)IBinder對象
                sCache.remove(mServiceName);
                //這里又重新創(chuàng)建了對應(yīng)的系統(tǒng)服務(wù),注意這里不是被Hook過的拢驾,是通過反射調(diào)用ServiceManager的getService方法獲取
                //到的奖磁。這里多這一步的目的,是獲取由系統(tǒng)創(chuàng)建的服務(wù)繁疤,因為上一步被我們remove調(diào)用的系統(tǒng)服務(wù)也有可能是被Hook過的咖为。
                IBinder mServiceIBinder = ServiceManagerCompat.getService(mServiceName);
                if (mServiceIBinder != null) {
                    /**
                     *這里出現(xiàn)一個MyServiceManager類,該類可以理解為類似ServiceManger的存在稠腊。
                     * 將原始的mServiceIBinder對象通過addOriginService加入到緩存中
                     * */
                    MyServiceManager.addOriginService(mServiceName, mServiceIBinder);
                    //以下使用Java動態(tài)代理來完成生成fake IBinder的過程
                    Class clazz = mServiceIBinder.getClass();
                    List<Class<?>> interfaces = Utils.getAllInterfaces(clazz);
                    Class[] ifs = interfaces != null && interfaces.size() > 0 ? interfaces.toArray(new Class[interfaces.size()]) : new Class[0];
                    IBinder mProxyServiceIBinder = (IBinder) MyProxy.newProxyInstance(clazz.getClassLoader(), ifs, this);
                    sCache.put(mServiceName, mProxyServiceIBinder);
                    MyServiceManager.addProxiedServiceCache(mServiceName, mProxyServiceIBinder);
                }
            }
        }
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            //這里比較簡單躁染,就不說明了!
            IBinder originService = MyServiceManager.getOriginService(mServiceName);
            if (!isEnable()) {
                return method.invoke(originService, args);
            }
            HookedMethodHandler hookedMethodHandler = mHookHandles.getHookedMethodHandler(method);
            if (hookedMethodHandler != null) {
                return hookedMethodHandler.doHookInner(originService, method, args);
            } else {
                return method.invoke(originService, args);
            }
        }
        //打印各種異常架忌!
        catch (InvocationTargetException e) {
            Throwable cause = e.getTargetException();
            if (cause != null && MyProxy.isMethodDeclaredThrowable(method, cause)) {
                throw cause;
            } else if (cause != null) {
                RuntimeException runtimeException = !TextUtils.isEmpty(cause.getMessage()) ? new RuntimeException(cause.getMessage()) : new RuntimeException();
                runtimeException.initCause(cause);
                throw runtimeException;
            } else {
                RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();
                runtimeException.initCause(e);
                throw runtimeException;
            }
        } catch (IllegalArgumentException e) {
            try {
                StringBuilder sb = new StringBuilder();
                sb.append(" DROIDPLUGIN{");
                if (method != null) {
                    sb.append("method[").append(method.toString()).append("]");
                } else {
                    sb.append("method[").append("NULL").append("]");
                }
                if (args != null) {
                    sb.append("args[").append(Arrays.toString(args)).append("]");
                } else {
                    sb.append("args[").append("NULL").append("]");
                }
                sb.append("}");

                String message = e.getMessage() + sb.toString();
                throw new IllegalArgumentException(message, e);
            } catch (Throwable e1) {
                throw e;
            }
        } catch (Throwable e) {
            if (MyProxy.isMethodDeclaredThrowable(method, e)) {
                throw e;
            } else {
                RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();
                runtimeException.initCause(e);
                throw runtimeException;
            }
        }
    }

    /**
     * 前面有提到過BaseHookHandle主要是用來管理HookedMethodHandler對象的吞彤。
     * 那么這里的ServiceManagerHookHandle類是handle IBinder中“queryLocalInterface”方法的hook
     * 該類中有一個queryLocalInterface內(nèi)部類,繼承自HookedMethodHandler,前面有提到過饰恕,HookedMethodHandler類作用
     * 主要是在調(diào)用被hook方法前后進行某些處理挠羔。例如這里就是在IBinder調(diào)用queryLocalInterface方法后進行處理:
     * 設(shè)置被hook后的系統(tǒng)服務(wù)。
     * queryLocalInterface返回的是IInterface對象(一定要注意IInterface和IBinder的區(qū)別埋嵌,
     * 在MyServiceManager中針對這兩個對象進行了不同緩存)褥赊,那么在這里就是IServiceManager對象(IServiceManager繼承自IInterface);
     * 花絮:DP中,作者寫了一個ServiceManagerBinderHook類莉恼,其實這個類原本是用來Hook這個IServiceManager對象然后fake。
     * 估計后來發(fā)現(xiàn)通過IBinder的queryLocalInterface方法可以生成IServiceManager速那,就棄用了ServiceManagerBinderHook類俐银,所以在DP
     * 中,這個類沒有被使用過6搜觥4废А!
     */
    private class ServiceManagerHookHandle extends BaseHookHandle {

        private ServiceManagerHookHandle(Context context) {
            super(context);
        }

        @Override
        protected void init() {
            //創(chuàng)建IBinder的方法
            sHookedMethodHandlers.put("queryLocalInterface", new queryLocalInterface(mHostContext));
        }


        class queryLocalInterface extends HookedMethodHandler {
            public queryLocalInterface(Context context) {
                super(context);
            }

            //在queryLocalInterface方法調(diào)用后荔烧,調(diào)用setFakedResult方法吱七,設(shè)置fake過的系統(tǒng)服務(wù)
            @Override
            protected void afterInvoke(Object receiver, Method method, Object[] args, Object invokeResult) throws Throwable {
                Object localInterface = invokeResult;
                Object proxiedObj = MyServiceManager.getProxiedObj(mServiceName);
                if (localInterface == null && proxiedObj != null) {
                    setFakedResult(proxiedObj);
                }
            }
        }
    }

    @Override
    protected BaseHookHandle createHookHandle() {
        return new ServiceManagerHookHandle(mHostContext);
    }
}

Hook、HookedMethodHandler鹤竭、BinderHook這個三基類共同協(xié)作完成了偷天換日的操作踊餐。其實只要理解這個三個類的功能是什么,就很好理解DP中Hook的精髓臀稚!

小結(jié)

越深入閱讀DP源碼吝岭,就越佩服作者思路。雖然原理看起來很簡單吧寺,但是其中所付出時間可見一斑窜管。
這節(jié)筆記就暫時做到這里,因為版面已經(jīng)很長了稚机。希望各位不吝嗇你的喜歡幕帆!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市赖条,隨后出現(xiàn)的幾起案子失乾,更是在濱河造成了極大的恐慌,老刑警劉巖谋币,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仗扬,死亡現(xiàn)場離奇詭異,居然都是意外死亡蕾额,警方通過查閱死者的電腦和手機早芭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诅蝶,“玉大人退个,你說我怎么就攤上這事募壕。” “怎么了语盈?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵舱馅,是天一觀的道長。 經(jīng)常有香客問我刀荒,道長代嗤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任缠借,我火速辦了婚禮干毅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泼返。我一直安慰自己硝逢,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布绅喉。 她就那樣靜靜地躺著渠鸽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柴罐。 梳的紋絲不亂的頭發(fā)上徽缚,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機與錄音丽蝎,去河邊找鬼猎拨。 笑死,一個胖子當(dāng)著我的面吹牛屠阻,可吹牛的內(nèi)容都是我干的红省。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼国觉,長吁一口氣:“原來是場噩夢啊……” “哼吧恃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起麻诀,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤痕寓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蝇闭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呻率,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年呻引,在試婚紗的時候發(fā)現(xiàn)自己被綠了礼仗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖元践,靈堂內(nèi)的尸體忽然破棺而出韭脊,到底是詐尸還是另有隱情,我是刑警寧澤单旁,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布沪羔,位于F島的核電站,受9級特大地震影響象浑,放射性物質(zhì)發(fā)生泄漏蔫饰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一愉豺、第九天 我趴在偏房一處隱蔽的房頂上張望死嗦。 院中可真熱鬧,春花似錦粒氧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至翼雀,卻和暖如春饱苟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狼渊。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工箱熬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狈邑。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓城须,卻偏偏與公主長得像,于是被迫代替她去往敵國和親米苹。 傳聞我的和親對象是個殘疾皇子糕伐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

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