hook技術(shù)實(shí)現(xiàn)免清單注冊activity跳轉(zhuǎn)

百度百科解釋:hook技術(shù)是一種改變api執(zhí)行結(jié)果的技術(shù)垃僚,Microsoft 自身也在Windows操作系統(tǒng)里面使用了這個技術(shù),如Windows兼容模式等规辱。 API HOOK 技術(shù)并不是計算機(jī)病毒專有技術(shù)谆棺,但是計算機(jī)病毒經(jīng)常使用這個技術(shù)來達(dá)到隱藏自己的目的。

通俗的講罕袋,hook其實(shí)就是一個鉤子函數(shù)改淑,在Android中碍岔,所有事件分發(fā)運(yùn)行都有自己的一套機(jī)制,包括應(yīng)用觸發(fā)事件和后臺邏輯處理溅固,也是根據(jù)事件流程一步步走下去付秕。而鉤子的意思就是在事件傳送到終點(diǎn)前截取事件并監(jiān)控事件的傳輸,就像鉤子勾上事件一樣侍郭,并且能在勾上事件時候询吴。處理一些自己需要額外自定義的事件。
hook的這個本領(lǐng)亮元,使它能夠?qū)⒆陨淼拇a融入到被執(zhí)行進(jìn)程中猛计,并成為其中一部分。

hook原理:hook技術(shù)無論是對于安全軟件還是惡意軟件都是一項(xiàng)非常關(guān)鍵的技術(shù)爆捞,其本質(zhì)就是劫持函數(shù)調(diào)用奉瘤,但是由于處于linux用戶態(tài),每個進(jìn)程都有自己獨(dú)立的進(jìn)程空間煮甥,所以必須先注入到所要的hook進(jìn)程空間盗温,修改其內(nèi)存中的進(jìn)程代碼,替換其過程表的符號地址成肘。
Hook技術(shù)的難點(diǎn)卖局,并不在于Hook技術(shù),初學(xué)者借助于資料“照葫蘆畫瓢”能夠很容易就掌握Hook的基本使用方法双霍。如何找到函數(shù)的入口點(diǎn)砚偶、替換函數(shù),這就涉及了理解函數(shù)的連接與加載機(jī)制洒闸。

hook技術(shù)的三要素:
1>現(xiàn)有功能
2>目標(biāo)功能
3>技術(shù)替換

實(shí)現(xiàn)hook技術(shù)的途徑:
1>利用系統(tǒng)內(nèi)部提供的接口染坯,通過實(shí)現(xiàn)該接口,然后注入進(jìn)系統(tǒng)丘逸。(并不通用)
2>動態(tài)代理单鹿。(所有場景)

好了,今天我們是想要通過hook技術(shù)實(shí)現(xiàn)清單免注冊activity跳轉(zhuǎn)深纲。
我們知道安卓中activity的跳轉(zhuǎn)是通過startActivity(intent);這個函數(shù)仲锄,所以我們可以肯定的是這個函數(shù)肯定是作為hook的切入點(diǎn)進(jìn)行事件的攔截的,所以現(xiàn)在我們就來看一下startActivity();的源碼囤萤,尋找hook攔截的方法昼窗。

//ContextWrapper.java
public class ContextWrapper extends Context {
    Context mBase;
    ...省略其他代碼
 @Override
    public void startActivity(Intent intent) {
        mBase.startActivity(intent);
    }
    ...省略其他代碼  
    }

可以看到,startActivity()調(diào)用的是ContextWrapper里面的statactivity方法涛舍,可以看到里面有個mBase屬性對象澄惊。在調(diào)用startActivity的時候會調(diào)用mBase的startActivity方法。這個mBase就是ContextImpl.java
現(xiàn)在來分析ContextImpl.java
我們看看這個類的startActivity的方法的實(shí)現(xiàn)

//ContextImpl.java
    @Override
    public void startActivity(Intent intent) {
        warnIfCallingFromSystemProcess();
        startActivity(intent, null);
    }

直接看startActivity(intent, null);方法,前一個方法是用于進(jìn)程檢測的掸驱。

@Override
    public void startActivity(Intent intent, Bundle options) {
      //...省略代碼 只看方法的重點(diǎn)
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }

可以看到此方法調(diào)用 mMainThread.getInstrumentation()獲取一個對象然后調(diào)用對象的方法啊execStartActivity肛搬。其中 mMainThread對象的聲明為final ActivityThread mMainThread;
mMainThread.getInstrumentation()查看實(shí)現(xiàn)如下,Instrumentation類提供的各種流程控制方法毕贼,它的作用可以把測試包和目標(biāo)測試應(yīng)用加載到同一個進(jìn)程中運(yùn)行温赔,不過它不是我們今天hook技術(shù)實(shí)現(xiàn)的關(guān)鍵點(diǎn),這里不做討論鬼癣。

//ActivtyThread.java
 public Instrumentation getInstrumentation()
    {
        return mInstrumentation;
    }

所以我們繼續(xù)查看Instrumentation 對象的execStartActivity方法

//Instrumentation.java
 public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {
                 //...省略方法其他方法
 int result = ActivityManagerNative.getDefault().startActivity(一堆參數(shù));

//...     
        return null;
    }

我們看到ActivityManagerNative.getDefault()獲取一個對象然后調(diào)用startActivity()陶贼,
ActivityManagerNative.getDefault()方法探究

//ActivityManagerNative.java
  static public IActivityManager getDefault() {
        return gDefault.get();
    }

gDefault是ActivityManagerNative.java屬性對象,聲明如下:

//ActivityManagerNative.java
  private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

Singleton又是什么待秃?這個是一個單例工具類拜秧,當(dāng)你第一次調(diào)用此類的get()會回調(diào)使用則自己實(shí)現(xiàn)的抽象方法create()進(jìn)而進(jìn)行單例操作

//Singleton.java
package android.util;
public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

從上面的例子可以看到,看到ActivityManagerNative.getDefault()返回了遠(yuǎn)程服務(wù)對象IActivityManager 接口章郁。

再回頭看看Instrumentation 對象的execStartActivity方法

//Instrumentation.java
 public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {
                 //...省略方法其他方法
 int result = ActivityManagerNative.getDefault().startActivity(一堆參數(shù));

//...     
        return null;
    }

可以得出以下結(jié)論:獲取一個遠(yuǎn)程服務(wù)對象接口IActivityManager(并且是單例)然后調(diào)用IActivityManager的startActivity方法喻括。此時會回調(diào)到遠(yuǎn)程服務(wù)ActivityManagerServer的真正startActivity接口方法潮针。里面會檢查你傳入的Intent對象的Activity是否在清單內(nèi),如果你的activity不在清單內(nèi),就是一個異常.但是我們不需要再看ActivityManagerServer源碼祈远,因?yàn)樗橇硪粋€app進(jìn)程小泉,所以無法干涉症革。如果可以干涉的話此衅,Android系統(tǒng)就太不穩(wěn)定了误褪,所以我們無法hook到遠(yuǎn)程服務(wù),但是IActivityManager我們卻是可以用手腳的医舆。因?yàn)槟鞘欠?wù)端存在客戶端一個代理接口對象俘侠,這一塊需要大家簡單了解下AIDL的知識象缀。

也就是說我們可以通過hook技術(shù)對IActivityManager動一些手腳蔬将,在IActivityManager把我們intent傳遞給AMS檢測之前,我們攔截這個函數(shù)央星,并且把intent設(shè)置成一個中間合法的ProxyInent對象霞怀,然后在通過AMS檢測后,我們再把它替換回來我們自己非法的Intent莉给,實(shí)現(xiàn)偷梁換柱毙石。

如圖:

動腦學(xué)院提供
動腦學(xué)院提供

我在網(wǎng)上找到一個startActivity的加載時序圖,


20171012175843278.png

我們仔細(xì)看上面的圖IActivityManager調(diào)用的時候會把要啟動的Activity的Intent去給ActivityManagerServer,假設(shè)我們此時用動態(tài)代理在IActivityManager調(diào)用遠(yuǎn)程服務(wù)之前颓遏,把在一個在清單文件注冊過的Activity的Intent替換不就通過校驗(yàn)了徐矩。

所以hook其實(shí)我們已經(jīng)找到了,就是IActivityManager里面的startActivity方法叁幢,在它把startActivity方法丟給ActivityManagerServer之前我們偷偷把非合法intent替換成合法intent滤灯,檢測通過后再偷偷換回來,事情就搞定了。

具體代碼如下鳞骤,這里面用到j(luò)ava反射機(jī)制和Proxy動態(tài)代理類窒百,

首先定義一個HoolUtil.java類

public  void hookStartActivity(Context context) {
        //還原 gDefault 成員變量  反射  調(diào)用一次
        this.context = context;
        try {
            Class<?> ActivityManagerNativecls=Class.forName("android.app.ActivityManagerNative");
            Field gDefault = ActivityManagerNativecls.getDeclaredField("gDefault");
            gDefault.setAccessible(true);
            //因?yàn)槭庆o態(tài)變量  所以獲取的到的是系統(tǒng)值  hook   偽hook
            Object defaltValue=gDefault.get(null);
            //mInstance對象
            Class<?> SingletonClass=Class.forName("android.util.Singleton");

            Field mInstance = SingletonClass.getDeclaredField("mInstance");

            //還原 IActivityManager對象  系統(tǒng)對象
            mInstance.setAccessible(true);
            Object iActivityManagerObject=mInstance.get(defaltValue);
            Class<?> IActivityManagerIntercept = Class.forName("android.app.IActivityManager");
            startActivty startActivtyMethod = new startActivty(iActivityManagerObject);

            //第二參數(shù)  是即將返回的對象 需要實(shí)現(xiàn)那些接口,其中這些接口包含OnClickListener,和IActivityManagerIntercept所實(shí)現(xiàn)的接口豫尽。
            //也就是說IActivityManager和OnClickListener所實(shí)現(xiàn)的接口都動態(tài)替換成startActivtyMethod了
            Object oldIactivityManager = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader()
                    , new Class[]{IActivityManagerIntercept, View.OnClickListener.class}
                    , startActivtyMethod);

            //將系統(tǒng)的iActivityManager  替換成   自己通過動態(tài)代理實(shí)現(xiàn)的對象
            //oldIactivityManager對象 實(shí)現(xiàn)了 IActivityManager這個接口的所有方法
            mInstance.set(defaltValue, oldIactivityManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class startActivty implements InvocationHandler {
        private  Object iActivityManagerObject;

        public startActivty(Object iActivityManagerObject) {
            this.iActivityManagerObject = iActivityManagerObject;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            Log.i("INFO","invoke    "+method.getName());
            if ("startActivity".equals(method.getName())) {
                Log.i("INFO","-----------------startActivity--------------------------");
                //瞞天過海
                //尋找傳進(jìn)來的intent
                Intent intent = null;
                int index=0;
                for (int i=0;i<args.length;i++) {
                //intent
                    Object arg = args[i];
                    if (arg instanceof Intent) {
                        intent = (Intent) args[i];
                        index = i;
                    }
                }
                //目的  ---載入acgtivity  將它還原
                Intent newIntent = new Intent();
                //ProxyActivity是合法意圖篙梢,這里用它通過AMS檢測
                ComponentName componentName = new ComponentName(context, ProxyActivity.class);
                newIntent.setComponent(componentName);
                //真實(shí)的意圖 被我隱藏到了  鍵值對,等待待會繞過AMS后再通過ActivityMH取出來美旧。
                newIntent.putExtra("oldIntent", intent);
                args[index] = newIntent;
            }

            return method.invoke(iActivityManagerObject, args);
        }
    }

這兩個方法其實(shí)就實(shí)現(xiàn)了將ProxyActivity類推送給ActivityManagerServer去檢測渤滞,當(dāng)然這個ProxyActivity必須是在清單文件中注冊了的activity。做完后你每次啟動activity都會打開ProxyActivity榴嗅,到這里你已經(jīng)成功了一半蔼水,但是這并不是我們想要的,所以你還得分析源碼录肯,ActivityManagerServer檢測完intent后會做什么呢趴腋?

網(wǎng)上盜圖如下:


20171012214900310.png

我們知道,安卓進(jìn)程中消息通信是通過handler實(shí)現(xiàn)的论咏,所有的消息都是存放在消息隊列(MessageQueue)中优炬,主線程中有一個Looper循環(huán)器,不斷從對應(yīng)線程MassgaeQueue中死循環(huán)拿取mesaage然后發(fā)送到對應(yīng)的handler厅贪。
handler有消息的會調(diào)用如下方法:

    //Handler.java
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //如果mCallback 不為空并且處理后返回true 那么不會調(diào)用我們自己寫handlerMessage處理消息蠢护。
            handleMessage(msg);
        }
    }

我們后面會用此ActivityMH 就行再次替換Handler.Callback

在java中程序的啟動是在Main方法中,其實(shí)在android中也有一個main方法养涮,只不過系統(tǒng)把它隱藏了我們沒看到而已葵硕,這個main方法在ActivityThread.java中,它是安卓進(jìn)程啟動的入口

//ActivityThread.java
public static void main(String[] args) {

        //...代碼省略
        //Looper類一些初始化贯吓,會從ThreadLocal對象拿取當(dāng)前線程的Looper
        //關(guān)于ThreadLocal不做過多講述懈凹,簡單就是用線程資源拷貝。
        //假設(shè)你有個變量a 你可以拷貝三份到ThreadLocal中不同的線程 
        Looper.prepareMainLooper();
        //...代碼省略 
        ActivityThread thread = new ActivityThread();
         //開啟一個子線程悄谐,又可以叫binder線程用于ams(ActivityManagerServer通AIDL來進(jìn)程間通信介评,如果有信息那么從子線程發(fā)送message給主線程handler進(jìn)行處理)
        thread.attach(false);

       //...代碼省略
           //開啟一個死循環(huán)遍歷messageQueue(里面存放messager),如果有就爬舰,所以前面才開啟一個子線程们陆,不然怎么跟AMS通信?
        Looper.loop();

       //...代碼省略
    }

可以看到這里面開啟了一個線程情屹,這個線程就是安卓的主線程坪仇,這個主線程在
包含在一個Looper中間,這個loop就是一個死循環(huán)不停在消息隊列中取出消息或者任務(wù)交給主線程做垃你,比如UI刷新就是主線程中一個定期定時任務(wù)椅文,所以我一直認(rèn)為其實(shí)主線程和子線程的區(qū)別就是在與它里面存在一個looper而已颈墅,讓它不停工作永葆活力,之前我看到過在某個子線程中我們自定給它綁定一個looper雾袱,那么這個子線程也是可以刷新UI操作的恤筛,但是最好不要這樣做,如果在沒有線程鎖的情況下會存在很大的安全漏洞芹橡。

話歸正題:
通過IActivityManager發(fā)送startActivity方法到ActivityManagerServer中毒坛,然后我們知道知道在ActivityThread類中main方法死循環(huán)前開啟了個子線程,這個線程會接收ActivityManagerServer回饋的信息林说,信息封裝在Message中然后添加主線程MeassgeQueue中煎殷,當(dāng)主線程的Loop遍歷到有信息的時候交給主線程的Handler處理。
當(dāng)ActivityManagerServer收到startActivity信息的信息的時候腿箩,會發(fā)送一個message給Handler處理豪直。其中message.what=LAUNCH_ACTIVITY,LAUNCH_ACTIVITY=100

我們看看Activity中Handler:

public class AcitvityThread{
    final H mH = new H();
    private class H extends Handler {
    //珠移。弓乙。。代碼省略
    }
}
//ActivityThread.java
class H extends Handler{
//.....
public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                   //從msg拿出ActivityClientRecord 對象钧惧,里面包含啟動activity的Intent
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                            //帶著ActivityClientRecord 對象啟動activity
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                }
    }
}

大致可簡單的理解從msg獲取ActivityClientRecord 對象暇韧,內(nèi)包含啟動Intent啟動意圖等信息,還記得我們前面保存一個Intent到一個新的Intent上嗎浓瞪?這時候其實(shí)你可以從這個Intent取出來了懈玻。調(diào)用handleLaunchActivity去啟動。

繞過AMS檢測這只是第一步乾颁,下面我們還得通過hook技術(shù)實(shí)現(xiàn)將我們真實(shí)意圖取出來涂乌,跳轉(zhuǎn)到我們自己真正要跳轉(zhuǎn)的頁面。
其實(shí)就是通過反射機(jī)制取出ActivityThread中mH英岭,并動態(tài)替換成我們自己的方法湾盒。
代碼如下:

 public  void hookHookMh(Context context) {
        this.context = context;

        try {
            Class<?> forName = Class.forName("android.app.ActivityThread");
            Field currentActivityThreadField = forName.getDeclaredField("sCurrentActivityThread");
            currentActivityThreadField.setAccessible(true);
            //還原系統(tǒng)的ActivityTread   mH
            Object activityThreadObj=currentActivityThreadField.get(null);

            Field handlerField = forName.getDeclaredField("mH");
            handlerField.setAccessible(true);
            //hook點(diǎn)找到了
            Handler mH= (Handler) handlerField.get(activityThreadObj);
            Field callbackField = Handler.class.getDeclaredField("mCallback");

            callbackField.setAccessible(true);

            callbackField.set(mH,new ActivityMH(mH));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

class ActivityMH implements Handler.Callback{
        private  Handler mH;

        public ActivityMH(Handler mH) {
            this.mH = mH;
        }

        @Override
        public boolean handleMessage(Message msg) {
            //LAUNCH_ACTIVITY ==100 即將要加載一個activity了,這里是系統(tǒng)的規(guī)范定義的
            if (msg.what == 100) {
                //加工 --完  一定丟給系統(tǒng)真實(shí)intent    -hook->proxyActivity---hook->secondeActivtiy
                handleLuachActivity(msg);
            }
            //做了真正的跳轉(zhuǎn)
            mH.handleMessage(msg);
            return  true;
        }

    class ActivityMH implements Handler.Callback{
        private  Handler mH;

        public ActivityMH(Handler mH) {
            this.mH = mH;
        }

        @Override
        public boolean handleMessage(Message msg) {
            //LAUNCH_ACTIVITY ==100 即將要加載一個activity了,這里是系統(tǒng)的規(guī)范定義的
            if (msg.what == 100) {
                //加工 --完  一定丟給系統(tǒng)真實(shí)intent    -hook->proxyActivity---hook->secondeActivtiy
                handleLuachActivity(msg);
            }
            //做了真正的跳轉(zhuǎn)
            mH.handleMessage(msg);
            return  true;
        }

        private void handleLuachActivity(Message msg) {
            //還原
            Object obj = msg.obj;
            try {
                Field intentField=obj.getClass().getDeclaredField("intent");
                intentField.setAccessible(true);
                //  ProxyActivity   2
                Intent realyIntent = (Intent) intentField.get(obj);
                // 到這里后,其實(shí)已經(jīng)通過AMS檢測了巴席,這里將我們存入的oldIntent取出來历涝,然后用它做真實(shí)跳轉(zhuǎn)诅需。
                Intent oldIntent = realyIntent.getParcelableExtra("oldIntent");
                
                // 登錄  還原  把原有的意圖    放到realyIntent
                realyIntent.setComponent(oldIntent.getComponent());
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

到這里我們算是把這個工具類寫完了漾唉,當(dāng)然我們需要定義一個Application類,在這個類里面去注冊這兩個hook函數(shù)堰塌,

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        HookUtil hookUtil = new HookUtil();
        hookUtil.hookStartActivity(this);
        hookUtil.hookHookMh(this);
    }
}

這就是基本完成了hook技術(shù)實(shí)現(xiàn)免注冊activity跳轉(zhuǎn)赵刑,至于應(yīng)用場景可以在插件化架構(gòu)設(shè)計中用到,還比如你在工程所有activity跳轉(zhuǎn)集中監(jiān)測判斷條件時候也可以用场刑,加入你頁面中每個activity跳轉(zhuǎn)都需要監(jiān)測是否登錄了般此,沒登陸就先跳轉(zhuǎn)登錄頁面蚪战,是不是也可以在這里稍微改動就可以實(shí)現(xiàn)呢?

private void handleLuachActivity(Message msg) {
            //還原
            Object obj = msg.obj;
            try {
                Field intentField=obj.getClass().getDeclaredField("intent");
                intentField.setAccessible(true);
                //  ProxyActivity   2
                Intent realyIntent = (Intent) intentField.get(obj);
                // 到這里后铐懊,其實(shí)已經(jīng)通過AMS檢測了邀桑,這里將我們存入的oldIntent取出來,然后用它做真實(shí)跳轉(zhuǎn)科乎。
                Intent oldIntent = realyIntent.getParcelableExtra("oldIntent");
                if (oldIntent != null) {
                    //集中式登錄
                    SharedPreferences share = context.getSharedPreferences("dcw", Context.MODE_PRIVATE);
                    //oldIntent.getComponent().getClassName().equals(SceondActivity.class.getName())
                    if (share.getBoolean("login",false)) {
                    // 登錄  還原  把原有的意圖    放到realyIntent
                        realyIntent.setComponent(oldIntent.getComponent());
                    }else {
                        ComponentName componentName = new ComponentName(context,LoginActivity.class);
                        realyIntent.putExtra("extraIntent", oldIntent.getComponent().getClassName());
                        realyIntent.setComponent(componentName);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

git地址
https://github.com/duanchangwen/dcw

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壁畸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子茅茂,更是在濱河造成了極大的恐慌捏萍,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件空闲,死亡現(xiàn)場離奇詭異令杈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)碴倾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門逗噩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人跌榔,你說我怎么就攤上這事给赞。” “怎么了矫户?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵片迅,是天一觀的道長。 經(jīng)常有香客問我皆辽,道長柑蛇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任驱闷,我火速辦了婚禮耻台,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘空另。我一直安慰自己盆耽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布扼菠。 她就那樣靜靜地躺著摄杂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪循榆。 梳的紋絲不亂的頭發(fā)上析恢,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天,我揣著相機(jī)與錄音秧饮,去河邊找鬼映挂。 笑死泽篮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的柑船。 我是一名探鬼主播帽撑,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鞍时!你這毒婦竟也來了油狂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤寸癌,失蹤者是張志新(化名)和其女友劉穎专筷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒸苇,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡磷蛹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了溪烤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片味咳。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖檬嘀,靈堂內(nèi)的尸體忽然破棺而出槽驶,到底是詐尸還是另有隱情,我是刑警寧澤鸳兽,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布掂铐,位于F島的核電站,受9級特大地震影響揍异,放射性物質(zhì)發(fā)生泄漏全陨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一衷掷、第九天 我趴在偏房一處隱蔽的房頂上張望辱姨。 院中可真熱鬧,春花似錦戚嗅、人聲如沸雨涛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽替久。三九已至,卻和暖如春医瘫,著一層夾襖步出監(jiān)牢的瞬間侣肄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工醇份, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稼锅,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓僚纷,卻偏偏與公主長得像矩距,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子怖竭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354

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