Android之基于Xposed的模擬位置模塊實現(xiàn)

引言

前段時間看到朋友圈有人在短時間內(nèi)發(fā)了幾條狀態(tài)航唆,定位都在不同國家的首都仔雷。問了一下,才知道用了一款能夠模擬位置的軟件葛碧。最近學習Xposed框架借杰,就試著利用Xposed框架開發(fā)了一款能夠模擬安卓手機位置的應用模塊。

開發(fā)環(huán)境

  • 測試機:Android 4.4
  • Xposed框架
  • AndroidStudio

實現(xiàn)原理

1.Android手機定位原理

手機常用的定位方式有:

  • 衛(wèi)星定位(GPS进泼,北斗蔗衡,伽利略,Glonass)
  • 移動基站定位
  • WiFi輔助定位
  • AGPS定位
* 衛(wèi)星定位

GPS(Global Positioning System)即全球定位系統(tǒng)缘琅,是由美國建立的一個衛(wèi)星導航定位系統(tǒng)粘都,利用該系統(tǒng),用戶可以在全球范圍內(nèi)實現(xiàn)全天候刷袍、連續(xù)翩隧、實時的三維導航定位和測速;另外呻纹,利用該系統(tǒng)堆生,用戶還能夠進行高精度的時間傳遞和高精度的精密定位。

* 基站定位

移動電話測量不同基站的下行導頻信號雷酪,得到不同基站下行導頻的TOA(到達時刻)或 TDOA(到達時間差)淑仆,根據(jù)該測量結果并結合基站的坐標,一般采用三角公式估計算法哥力,就能夠計算出移動電話的位置蔗怠。實際的位置估計算法需要考慮多基站(3個或3個以上)定位的情況墩弯,因此算法要復雜很多。一般而言寞射,移動臺測量的基站數(shù)目越多渔工,測量精度越高,定位性能改善越明顯桥温。

* WiFi定位
  • 每一個無線AP(路由器)都有一個全球唯一的MAC地址引矩,并且一般來說無線AP在一段時間內(nèi)不會移動;
  • 設備在開啟Wi-Fi的情況下侵浸,無線路由器默認都會進行SSID廣播(除非用戶手動配置關閉該功能)旺韭,在廣播幀包含了該路由器的MAC地址;
  • 采集裝置可以通過接收周圍AP發(fā)送的廣播信息獲取周圍AP的MAC信息和信號強度信息掏觉,將這些信息上傳到服務器区端,經(jīng)過服務器的計算,保存為“MAC-經(jīng)緯度”的映射履腋,當采集的信息足夠多時候就在服務器上建立了一張巨大的WiFi信息網(wǎng)絡珊燎;
  • 當一個設備處在這樣的網(wǎng)絡中時,可以將收集到的這些能夠標示AP的數(shù)據(jù)發(fā)送到位置服務器遵湖,服務器檢索出每一個AP的地理位置悔政,并結合每個信號的強弱程度,計算出設備的地理位置并返回到用戶設備延旧,其計算方式和基站定位位置計算方式相似谋国,也是利用三點定位或多點定位技術;
  • 位置服務商要不斷更新迁沫、補充自己的數(shù)據(jù)庫芦瘾,以保證數(shù)據(jù)的準確性。當某些WiFi信息不在數(shù)據(jù)庫中時集畅,可以根據(jù)附近其他的WiFi位置信息推斷出未知WiFi的位置信息近弟,并上傳服務器。
* AGPS定位

AGPS(AssistedGPS:輔助全球衛(wèi)星定位系統(tǒng))是結合GSM/GPRS與傳統(tǒng)衛(wèi)星定位挺智,利用基地臺代送輔助衛(wèi)星信息祷愉,以縮減GPS芯片獲取衛(wèi)星信號的延遲時間,受遮蓋的室內(nèi)也能借基地臺訊號彌補赦颇,減輕GPS芯片對衛(wèi)星的依賴度二鳄。AGPS利用手機基站的信號,輔以連接遠程定位服務器的方式下載衛(wèi)星星歷 (英語:Almanac Data)媒怯,再配合傳統(tǒng)的GPS衛(wèi)星接受器订讼,讓定位的速度更快。是一種結合網(wǎng)絡基站信息和GPS信息對移動臺進行定位的技術扇苞,既利用全球衛(wèi)星定位系統(tǒng)GPS欺殿,又利用移動基站寄纵,解決了GPS覆蓋的問題,可以在2代的G祈餐、C網(wǎng)絡和3G網(wǎng)絡中使用擂啥。

1.偽裝定位思路

在了解到上述手機定位原理后,結合平時對手機的使用我們可以得知手機定位最常用的幾種方式分別是:

  • WiFi
  • GPS定位
  • 基站定位

Xposed的便利之處就是提供方法使得我們可以改變系統(tǒng)函數(shù)和應用中的函數(shù)執(zhí)行前和執(zhí)行后的結果帆阳。所以設想是否可以利用XPosed框架提供的功能編寫一個Hook模塊,勾取系統(tǒng)調(diào)用中和定位相關的函數(shù)并篡改返回值呢屋吨?

2.相關函數(shù)

經(jīng)過查閱資料和閱讀安卓源碼蜒谤,粗略找到以下幾個類和相關的方法和定位有關,并對其進行Hook操作至扰。下面是我進行Hook的類及其中的方法名:

  • android.telephony.TelephonyManager
    • getCellLocation
    • getPhoneCount
    • getNeighboringCellInfo
    • getAllCellInfo
  • android.telephony.PhoneStateListener
    • onCellLocationChanged
    • onCellInfoChanged
  • android.net.wifi.WifiManager
    • getScanResults
    • getWifiState
    • isWifiEnabled
  • android.net.wifi.WifiInfo
    • getMacAddress
    • getSSID
    • getBSSID
  • android.net.NetworkInfo
    • getTypeName
    • isConnectedOrConnecting
    • isConnected
    • isAvailable
  • android.telephony.CellInfo
    • isRegistered
  • LocationManager.class
    • getLastLocation
    • getLastKnownLocation
    • getProviders
    • getBestProvider
    • addGpsStatusListener
    • addNmeaListener
  • android.location.LocationManager
    • getGpsStatus

3.解釋

由于上述方法太多鳍徽,這里只解釋基本的思想。這些方法的作用及參數(shù)和返回值都能在Android開發(fā)手冊中找到敢课,逐條hook并修改返回值即可阶祭。我們要做的其實就是利用Hook手段,讓手機認為gps是目前最好的位置提供器直秆,并修改其返回值為我們想要的位置濒募,從而達到偽裝位置的目的。但是為什么上面列出如此眾多的方法需要我們Hook呢圾结?這是因為手機中的定位是一連串比較復雜的過程瑰剃,是一套各參數(shù)匹配的過程。任何一個相關函數(shù)的返回值和最終我們填入的結果不吻合筝野,都可能導致偽裝定位的失敗晌姚。所以我們要做的就是找到并Hook定位流程相關的方法并攔截修改返回值。
附上:Android開發(fā)手冊

4.效果截圖

選擇偽裝地點

上圖是我將核心Hook模塊實現(xiàn)后利用百度地圖做了一個簡單的欺騙位置小軟件歇竟。


偽裝微信定位

5.核心Hook模塊代碼

package com.example.administrator.hook;

import android.location.Criteria;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.SystemClock;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityWcdma;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.CellLocation;
import android.telephony.gsm.GsmCellLocation;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

/**
 * Created by CaptainXero on 2016/8/31 0031.
 */



public class HookUtils {
    public static void HookAndChange(ClassLoader classLoader, final double latitude, final double longtitude, final int lac, final int cid) {

        XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader,
                "getCellLocation", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        GsmCellLocation gsmCellLocation = new GsmCellLocation();
                        gsmCellLocation.setLacAndCid(lac, cid);
                        param.setResult(gsmCellLocation);
                    }
                });

        XposedHelpers.findAndHookMethod("android.telephony.PhoneStateListener", classLoader,
                "onCellLocationChanged", CellLocation.class, new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        GsmCellLocation gsmCellLocation = new GsmCellLocation();
                        gsmCellLocation.setLacAndCid(lac, cid);
                        param.setResult(gsmCellLocation);
                    }
                });

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
            XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader,
                    "getPhoneCount", new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            param.setResult(1);
                        }
                    });
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader,
                    "getNeighboringCellInfo", new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            param.setResult(new ArrayList<>());
                        }
                    });
        }

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
            XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader,
                    "getAllCellInfo", new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            param.setResult(getCell(460, 0, lac, cid, 0, 0));
                        }
                    });
            XposedHelpers.findAndHookMethod("android.telephony.PhoneStateListener", classLoader,
                    "onCellInfoChanged", List.class, new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            param.setResult(getCell(460, 0, lac, cid, 0,0));
                        }
                    });
        }

        XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "getScanResults", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult(new ArrayList<>());
            }
        });

        XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "getWifiState", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult(1);
            }
        });

        XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "isWifiEnabled", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult(true);
            }
        });

        XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getMacAddress", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult("00-00-00-00-00-00-00-00");
            }
        });

        XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getSSID", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult("null");
            }
        });

        XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getBSSID", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult("00-00-00-00-00-00-00-00");
            }
        });


        XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader,
                "getTypeName", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        param.setResult("WIFI");
                    }
                });
        XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader,
                "isConnectedOrConnecting", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        param.setResult(true);
                    }
                });

        XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader,
                "isConnected", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        param.setResult(true);
                    }
                });

        XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader,
                "isAvailable", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        param.setResult(true);
                    }
                });

        XposedHelpers.findAndHookMethod("android.telephony.CellInfo", classLoader,
                "isRegistered", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        param.setResult(true);
                    }
                });

        XposedHelpers.findAndHookMethod(LocationManager.class, "getLastLocation", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                Location l = new Location(LocationManager.GPS_PROVIDER);
                l.setLatitude(latitude);
                l.setLongitude(longtitude);
                l.setAccuracy(100f);
                l.setTime(System.currentTimeMillis());
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                    l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
                }
                param.setResult(l);
            }
        });

        XposedHelpers.findAndHookMethod(LocationManager.class, "getLastKnownLocation", String.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                Location l = new Location(LocationManager.GPS_PROVIDER);
                l.setLatitude(latitude);
                l.setLongitude(longtitude);
                l.setAccuracy(100f);
                l.setTime(System.currentTimeMillis());
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                    l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
                }
                param.setResult(l);
            }
        });


        XposedBridge.hookAllMethods(LocationManager.class, "getProviders", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                ArrayList<String> arrayList = new ArrayList<>();
                arrayList.add("gps");
                param.setResult(arrayList);
            }
        });

        XposedHelpers.findAndHookMethod(LocationManager.class, "getBestProvider", Criteria.class, Boolean.TYPE, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult("gps");
            }
        });

        XposedHelpers.findAndHookMethod(LocationManager.class, "addGpsStatusListener", GpsStatus.Listener.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                if (param.args[0] != null) {
                    XposedHelpers.callMethod(param.args[0], "onGpsStatusChanged", 1);
                    XposedHelpers.callMethod(param.args[0], "onGpsStatusChanged", 3);
                }
            }
        });

        XposedHelpers.findAndHookMethod(LocationManager.class, "addNmeaListener", GpsStatus.NmeaListener.class, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                param.setResult(false);
            }
        });

        XposedHelpers.findAndHookMethod("android.location.LocationManager", classLoader,
                "getGpsStatus", GpsStatus.class, new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        GpsStatus gss = (GpsStatus) param.getResult();
                        if (gss == null)
                            return;

                        Class<?> clazz = GpsStatus.class;
                        Method m = null;
                        for (Method method : clazz.getDeclaredMethods()) {
                            if (method.getName().equals("setStatus")) {
                                if (method.getParameterTypes().length > 1) {
                                    m = method;
                                    break;
                                }
                            }
                        }
                        if (m == null)
                            return;

                        //access the private setStatus function of GpsStatus
                        m.setAccessible(true);

                        //make the apps belive GPS works fine now
                        int svCount = 5;
                        int[] prns = {1, 2, 3, 4, 5};
                        float[] snrs = {0, 0, 0, 0, 0};
                        float[] elevations = {0, 0, 0, 0, 0};
                        float[] azimuths = {0, 0, 0, 0, 0};
                        int ephemerisMask = 0x1f;
                        int almanacMask = 0x1f;

                        //5 satellites are fixed
                        int usedInFixMask = 0x1f;

                        XposedHelpers.callMethod(gss, "setStatus", svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask);
                        param.args[0] = gss;
                        param.setResult(gss);
                        try {
                            m.invoke(gss, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask);
                            param.setResult(gss);
                        } catch (Exception e) {
                            XposedBridge.log(e);
                        }
                    }
                });

        for (Method method : LocationManager.class.getDeclaredMethods()) {
            if (method.getName().equals("requestLocationUpdates")
                    && !Modifier.isAbstract(method.getModifiers())
                    && Modifier.isPublic(method.getModifiers())) {
                XposedBridge.hookMethod(method, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        if (param.args.length >= 4 && (param.args[3] instanceof LocationListener)) {

                            LocationListener ll = (LocationListener) param.args[3];

                            Class<?> clazz = LocationListener.class;
                            Method m = null;
                            for (Method method : clazz.getDeclaredMethods()) {
                                if (method.getName().equals("onLocationChanged") && !Modifier.isAbstract(method.getModifiers())) {
                                    m = method;
                                    break;
                                }
                            }
                            Location l = new Location(LocationManager.GPS_PROVIDER);
                            l.setLatitude(latitude);
                            l.setLongitude(longtitude);
                            l.setAccuracy(10.00f);
                            l.setTime(System.currentTimeMillis());
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                                l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
                            }
                            XposedHelpers.callMethod(ll, "onLocationChanged", l);
                            try {
                                if (m != null) {
                                    m.invoke(ll, l);
                                }
                            } catch (Exception e) {
                                XposedBridge.log(e);
                            }
                        }
                    }
                });
            }

            if (method.getName().equals("requestSingleUpdate ")
                    && !Modifier.isAbstract(method.getModifiers())
                    && Modifier.isPublic(method.getModifiers())) {
                XposedBridge.hookMethod(method, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        if (param.args.length >= 3 && (param.args[1] instanceof LocationListener)) {

                            LocationListener ll = (LocationListener) param.args[3];

                            Class<?> clazz = LocationListener.class;
                            Method m = null;
                            for (Method method : clazz.getDeclaredMethods()) {
                                if (method.getName().equals("onLocationChanged") && !Modifier.isAbstract(method.getModifiers())) {
                                    m = method;
                                    break;
                                }
                            }

                            try {
                                if (m != null) {
                                    Location l = new Location(LocationManager.GPS_PROVIDER);
                                    l.setLatitude(latitude);
                                    l.setLongitude(longtitude);
                                    l.setAccuracy(100f);
                                    l.setTime(System.currentTimeMillis());
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                                        l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
                                    }
                                    m.invoke(ll, l);
                                }
                            } catch (Exception e) {
                                XposedBridge.log(e);
                            }
                        }
                    }
                });
            }
        }
    }

    private static ArrayList getCell(int mcc, int mnc, int lac, int cid, int sid, int networkType) {
        ArrayList arrayList = new ArrayList();
        CellInfoGsm cellInfoGsm = (CellInfoGsm) XposedHelpers.newInstance(CellInfoGsm.class);
        XposedHelpers.callMethod(cellInfoGsm, "setCellIdentity", XposedHelpers.newInstance(CellIdentityGsm.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(
                lac), Integer.valueOf(cid)}));
        CellInfoCdma cellInfoCdma = (CellInfoCdma) XposedHelpers.newInstance(CellInfoCdma.class);
        XposedHelpers.callMethod(cellInfoCdma, "setCellIdentity", XposedHelpers.newInstance(CellIdentityCdma.class, new Object[]{Integer.valueOf(lac), Integer.valueOf(sid), Integer.valueOf(cid), Integer.valueOf(0), Integer.valueOf(0)}));
        CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) XposedHelpers.newInstance(CellInfoWcdma.class);
        XposedHelpers.callMethod(cellInfoWcdma, "setCellIdentity", XposedHelpers.newInstance(CellIdentityWcdma.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(lac), Integer.valueOf(cid), Integer.valueOf(300)}));
        CellInfoLte cellInfoLte = (CellInfoLte) XposedHelpers.newInstance(CellInfoLte.class);
        XposedHelpers.callMethod(cellInfoLte, "setCellIdentity", XposedHelpers.newInstance(CellIdentityLte.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(cid), Integer.valueOf(300), Integer.valueOf(lac)}));
        if (networkType == 1 || networkType == 2) {
            arrayList.add(cellInfoGsm);
        } else if (networkType == 13) {
            arrayList.add(cellInfoLte);
        } else if (networkType == 4 || networkType == 5 || networkType == 6 || networkType == 7 || networkType == 12 || networkType == 14) {
            arrayList.add(cellInfoCdma);
        } else if (networkType == 3 || networkType == 8 || networkType == 9 || networkType == 10 || networkType == 15) {
            arrayList.add(cellInfoWcdma);
        }
        return arrayList;
    }
}


最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挥唠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子焕议,更是在濱河造成了極大的恐慌宝磨,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件号坡,死亡現(xiàn)場離奇詭異懊烤,居然都是意外死亡,警方通過查閱死者的電腦和手機宽堆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門腌紧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人畜隶,你說我怎么就攤上這事壁肋『排撸” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵浸遗,是天一觀的道長猫胁。 經(jīng)常有香客問我,道長跛锌,這世上最難降的妖魔是什么弃秆? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮髓帽,結果婚禮上菠赚,老公的妹妹穿的比我還像新娘。我一直安慰自己郑藏,他們只是感情好衡查,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著必盖,像睡著了一般拌牲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上歌粥,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天塌忽,我揣著相機與錄音,去河邊找鬼阁吝。 笑死砚婆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的突勇。 我是一名探鬼主播装盯,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼甲馋!你這毒婦竟也來了埂奈?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤定躏,失蹤者是張志新(化名)和其女友劉穎账磺,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痊远,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡垮抗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了碧聪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冒版。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逞姿,靈堂內(nèi)的尸體忽然破棺而出辞嗡,到底是詐尸還是另有隱情捆等,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布续室,位于F島的核電站栋烤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏挺狰。R本人自食惡果不足惜明郭,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望她渴。 院中可真熱鬧达址,春花似錦、人聲如沸趁耗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽苛败。三九已至,卻和暖如春径簿,著一層夾襖步出監(jiān)牢的瞬間罢屈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工篇亭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缠捌,地道東北人。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓译蒂,卻偏偏與公主長得像曼月,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子柔昼,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

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