JavaScript(不可逆加密)近似解密

前言


目前,我们日常浏览的网站中,日常会有防止网站被黑客克隆网站、爬取网站、压缩代码等的需求,都会使用一些方法对源码进行处理。其中,有的使用Webpack对JavaScript代码进行打包,也有使用js代码加密的方法。因此,本篇文章将会对js代码加密进行一个简单的分析,并主要针对不可逆加密提供一些常用的近似解密思路。

JavaScript加密分析


首先,我们能确定的一件事是,无论加密与否,加载的js文件都能够在浏览器其中执行,并得到对应的结果。

有的思路是根据一些参数特殊处理进行加密,也有的是跟后端达成协议,进行加解密的方式得出结果并执行。但是,后者的方案会对我们的服务造成额外的压力,因此使用前者更为主流。因此本篇文章只讨论前者这种的方案。
近似解密的方案是基于代码逻辑正确、提高可读性的方向进行的。

这里列举了一些加密方式(可逆的):

  • 最简单的加密解密
  • 转义字符""的妙用
  • 使用Microsoft出品的脚本编码器Script Encoder来进行编码
  • 任意添加NUL空字符(十六进制00H)
  • 无用内容混乱以及换行空格TAB大法
  • 自写解密函数法
    对应的加解密思路可以看这里,我就不一一列举了

不可逆的加密方式:

根据各种指定的参数混淆+不可逆的算法进行加密https://www.jsjiami.com/
但是,即使是不可逆加密过后,得出的结果也是能正常执行的,符合JavaScript的语法的,因此,我们就可以就此对源码进行翻译。

举个栗子并分享一个思路

举个栗子

var __encode = 'jsjiami.com', _a = {}, _0xb483 = ["\x5F\x64\x65\x63\x6F\x64\x65", "\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"]; (function (_0xd642x1) { _0xd642x1[_0xb483[0]] = _0xb483[1] })(_a); var __Oxb24bc = ["\x6C\x69\x74\x65\x2D\x61\x6E\x64\x72\x6F\x69\x64\x26", "\x73\x74\x72\x69\x6E\x67\x69\x66\x79", "\x26\x61\x6E\x64\x72\x6F\x69\x64\x26\x33\x2E\x31\x2E\x30\x26", "\x26", "\x26\x38\x34\x36\x63\x34\x63\x33\x32\x64\x61\x65\x39\x31\x30\x65\x66", "\x31\x32\x61\x65\x61\x36\x35\x38\x66\x37\x36\x65\x34\x35\x33\x66\x61\x66\x38\x30\x33\x64\x31\x35\x63\x34\x30\x61\x37\x32\x65\x30", "\x69\x73\x4E\x6F\x64\x65", "\x63\x72\x79\x70\x74\x6F\x2D\x6A\x73", "", "\x61\x70\x69\x3F\x66\x75\x6E\x63\x74\x69\x6F\x6E\x49\x64\x3D", "\x26\x62\x6F\x64\x79\x3D", "\x26\x61\x70\x70\x69\x64\x3D\x6C\x69\x74\x65\x2D\x61\x6E\x64\x72\x6F\x69\x64\x26\x63\x6C\x69\x65\x6E\x74\x3D\x61\x6E\x64\x72\x6F\x69\x64\x26\x75\x75\x69\x64\x3D\x38\x34\x36\x63\x34\x63\x33\x32\x64\x61\x65\x39\x31\x30\x65\x66\x26\x63\x6C\x69\x65\x6E\x74\x56\x65\x72\x73\x69\x6F\x6E\x3D\x33\x2E\x31\x2E\x30\x26\x74\x3D", "\x26\x73\x69\x67\x6E\x3D", "\x61\x70\x69\x2E\x6D\x2E\x6A\x64\x2E\x63\x6F\x6D", "\x2A\x2F\x2A", "\x52\x4E", "\x4A\x44\x4D\x6F\x62\x69\x6C\x65\x4C\x69\x74\x65\x2F\x33\x2E\x31\x2E\x30\x20\x28\x69\x50\x61\x64\x3B\x20\x69\x4F\x53\x20\x31\x34\x2E\x34\x3B\x20\x53\x63\x61\x6C\x65\x2F\x32\x2E\x30\x30\x29", "\x7A\x68\x2D\x48\x61\x6E\x73\x2D\x43\x4E\x3B\x71\x3D\x31\x2C\x20\x6A\x61\x2D\x43\x4E\x3B\x71\x3D\x30\x2E\x39", "\x75\x6E\x64\x65\x66\x69\x6E\x65\x64", "\x6C\x6F\x67", "\u5220\u9664", "\u7248\u672C\u53F7\uFF0C\x6A\x73\u4F1A\u5B9A", "\u671F\u5F39\u7A97\uFF0C", "\u8FD8\u8BF7\u652F\u6301\u6211\u4EEC\u7684\u5DE5\u4F5C", "\x6A\x73\x6A\x69\x61", "\x6D\x69\x2E\x63\x6F\x6D"]; function taskUrl(_0x7683x2, _0x7683x3 = {}) { let _0x7683x4 = + new Date(); let _0x7683x5 = `${__Oxb24bc[0x0]}${JSON[__Oxb24bc[0x1]](_0x7683x3)}${__Oxb24bc[0x2]}${_0x7683x2}${__Oxb24bc[0x3]}${_0x7683x4}${__Oxb24bc[0x4]}`; let _0x7683x6 = __Oxb24bc[0x5]; const _0x7683x7 = $[__Oxb24bc[0x6]]() ? require(__Oxb24bc[0x7]) : CryptoJS; let _0x7683x8 = _0x7683x7.HmacSHA256(_0x7683x5, _0x7683x6).toString(); return { url: `${__Oxb24bc[0x8]}${JD_API_HOST}${__Oxb24bc[0x9]}${_0x7683x2}${__Oxb24bc[0xa]}${escape(JSON[__Oxb24bc[0x1]](_0x7683x3))}${__Oxb24bc[0xb]}${_0x7683x4}${__Oxb24bc[0xc]}${_0x7683x8}${__Oxb24bc[0x8]}`, headers: { '\x48\x6F\x73\x74': __Oxb24bc[0xd], '\x61\x63\x63\x65\x70\x74': __Oxb24bc[0xe], '\x6B\x65\x72\x6E\x65\x6C\x70\x6C\x61\x74\x66\x6F\x72\x6D': __Oxb24bc[0xf], '\x75\x73\x65\x72\x2D\x61\x67\x65\x6E\x74': __Oxb24bc[0x10], '\x61\x63\x63\x65\x70\x74\x2D\x6C\x61\x6E\x67\x75\x61\x67\x65': __Oxb24bc[0x11], '\x43\x6F\x6F\x6B\x69\x65': cookie } } } (function (_0x7683x9, _0x7683xa, _0x7683xb, _0x7683xc, _0x7683xd, _0x7683xe) { _0x7683xe = __Oxb24bc[0x12]; _0x7683xc = function (_0x7683xf) { if (typeof alert !== _0x7683xe) { alert(_0x7683xf) }; if (typeof console !== _0x7683xe) { console[__Oxb24bc[0x13]](_0x7683xf) } }; _0x7683xb = function (_0x7683x7, _0x7683x9) { return _0x7683x7 + _0x7683x9 }; _0x7683xd = _0x7683xb(__Oxb24bc[0x14], _0x7683xb(_0x7683xb(__Oxb24bc[0x15], __Oxb24bc[0x16]), __Oxb24bc[0x17])); try { _0x7683x9 = __encode; if (!(typeof _0x7683x9 !== _0x7683xe && _0x7683x9 === _0x7683xb(__Oxb24bc[0x18], __Oxb24bc[0x19]))) { _0x7683xc(_0x7683xd) } } catch (e) { _0x7683xc(_0x7683xd) } })({})

首先

看到上面的内容,分析得出里面包含着\x5F\x64\x65\x63\x6F\x64\x65\u5220\u9664这些特殊字符串,我们可以得出,里面的混淆会是进行过unicode和16进制的转换得出的,因此,我们可以先对此先进行一次转换,最终得出的结果是

var __encode = 'jsjiami.com',
    _a = {},
    _0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"];
(function(_0xd642x1) {
    _0xd642x1[_0xb483[0]] = _0xb483[1]
})(_a);
var __Oxb24bc = ["lite-android&", "stringify", "&android&3.1.0&", "&", "&846c4c32dae910ef", "12aea658f76e453faf803d15c40a72e0", "isNode", "crypto-js", "", "api?functionId=", "&body=", "&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=", "&sign=", "api.m.jd.com", "*/*", "RN", "JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)", "zh-Hans-CN;q=1, ja-CN;q=0.9", "undefined", "log", "删除", "版本号,js会定", "期弹窗,", "还请支持我们的工作", "jsjia", "mi.com"];

function taskUrl(_0x7683x2, _0x7683x3 = {}) {
    let _0x7683x4 = +new Date();
    let _0x7683x5 = `${__Oxb24bc[0x0]}${JSON[__Oxb24bc[0x1]](_0x7683x3)}${__Oxb24bc[0x2]}${_0x7683x2}${__Oxb24bc[0x3]}${_0x7683x4}${__Oxb24bc[0x4]}`;
    let _0x7683x6 = __Oxb24bc[0x5];
    const _0x7683x7 = $[__Oxb24bc[0x6]]() ? require(__Oxb24bc[0x7]) : CryptoJS;
    let _0x7683x8 = _0x7683x7.HmacSHA256(_0x7683x5, _0x7683x6).toString();
    return {
        url: `${__Oxb24bc[0x8]}${JD_API_HOST}${__Oxb24bc[0x9]}${_0x7683x2}${__Oxb24bc[0xa]}${escape(JSON[__Oxb24bc[0x1]](_0x7683x3))}${__Oxb24bc[0xb]}${_0x7683x4}${__Oxb24bc[0xc]}${_0x7683x8}${__Oxb24bc[0x8]}`,
        headers: {
            'Host': __Oxb24bc[0xd],
            'accept': __Oxb24bc[0xe],
            'kernelplatform': __Oxb24bc[0xf],
            'user-agent': __Oxb24bc[0x10],
            'accept-language': __Oxb24bc[0x11],
            'Cookie': cookie
        }
    }
}(function(_0x7683x9, _0x7683xa, _0x7683xb, _0x7683xc, _0x7683xd, _0x7683xe) {
    _0x7683xe = __Oxb24bc[0x12];
    _0x7683xc = function(_0x7683xf) {
        if (typeof alert !== _0x7683xe) {
            alert(_0x7683xf)
        };
        if (typeof console !== _0x7683xe) {
            console[__Oxb24bc[0x13]](_0x7683xf)
        }
    };
    _0x7683xb = function(_0x7683x7, _0x7683x9) {
        return _0x7683x7 + _0x7683x9
    };
    _0x7683xd = _0x7683xb(__Oxb24bc[0x14], _0x7683xb(_0x7683xb(__Oxb24bc[0x15], __Oxb24bc[0x16]), __Oxb24bc[0x17]));
    try {
        _0x7683x9 = __encode;
        if (!(typeof _0x7683x9 !== _0x7683xe && _0x7683x9 === _0x7683xb(__Oxb24bc[0x18], __Oxb24bc[0x19]))) {
            _0x7683xc(_0x7683xd)
        }
    } catch (e) {
        _0x7683xc(_0x7683xd)
    }
})({})

到此

我们大致上已把对应的内容简单地解密出来了。但是,目前而言,源码的可读性比较差,我们可以再观察一下。可以发现,在开头已定义了__Oxb24bc这个数组变量,文中的部分变量也使用到数组中的内容,因此,我们可以根据这样转化一波。可以得出一下:

var __encode = 'jsjiami.com',
  _a = {},
  _0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"];
(function (_0xd642x1) {
  _0xd642x1["_decode"] = "http://www.sojson.com/javascriptobfuscator.html"
})(_a);
var __Oxb24bc = ["lite-android&", "stringify", "&android&3.1.0&", "&", "&846c4c32dae910ef", "12aea658f76e453faf803d15c40a72e0", "isNode", "crypto-js", "", "api?functionId=", "&body=", "&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=", "&sign=", "api.m.jd.com", "*/*", "RN", "JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)", "zh-Hans-CN;q=1, ja-CN;q=0.9", "undefined", "log", "删除", "版本号,js会定", "期弹窗,", "还请支持我们的工作", "jsjia", "mi.com"];

function taskUrl(_0x7683x2, _0x7683x3 = {}) {
  let _0x7683x4 = +new Date();
  let _0x7683x5 = `lite-android&${JSON.stringify(_0x7683x3)}&android&3.1.0&${_0x7683x2}&${_0x7683x4}&846c4c32dae910ef`;
  let _0x7683x6 = "12aea658f76e453faf803d15c40a72e0";
  const _0x7683x7 = $.isNode() ? require("crypto-js") : CryptoJS;
  let _0x7683x8 = _0x7683x7.HmacSHA256(_0x7683x5, _0x7683x6).toString();
  return {
    url: ""+`${JD_API_HOST}api?functionId=${_0x7683x2}&body=${escape(JSON.stringify(_0x7683x3))}&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=${_0x7683x4}&sign=${_0x7683x8}`+"",
    headers: {
      'Host': 'api.m.jd.com',
      'accept': '*/*',
      'kernelplatform': 'RN',
      'user-agent': 'JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)',
      'accept-language': 'zh-Hans-CN;q=1, ja-CN;q=0.9',
      'Cookie': cookie
    }
  }
}
(function (_0x7683x9, _0x7683xa, _0x7683xb, _0x7683xc, _0x7683xd, _0x7683xe) {
  _0x7683xe = 'undefined';
  _0x7683xc = function (_0x7683xf) {
    if (typeof alert !== _0x7683xe) {
      alert(_0x7683xf)
    };
    console.log(console)
    if (typeof console !== _0x7683xe) {
      console.log(_0x7683xf)
    }
  };
  _0x7683xb = function (_0x7683x7, _0x7683x9) {
    return _0x7683x7 + _0x7683x9
  };
  _0x7683xd = _0x7683xb('删除', _0x7683xb(_0x7683xb('版本号,js会定', '期弹窗,'), '还请支持我们的工作'));
  try {
    _0x7683x9 = __encode;
    if (!(typeof _0x7683x9 !== _0x7683xe && _0x7683x9 === _0x7683xb('jsjia', 'mi.com'))) {
      _0x7683xc(_0x7683xd)
    }
  } catch (e) {
    _0x7683xc(_0x7683xd)
  }
})({})

其中,我们可以看到_0x7683xb这个方法,其实实际上处理的操作是在做字符串拼接,对此可以简化整理一下,并得出:

var __encode = 'jsjiami.com',
  _a = {},
  _0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"];
(function (_0xd642x1) {
  _0xd642x1["_decode"] = "http://www.sojson.com/javascriptobfuscator.html"
})(_a);
var __Oxb24bc = ["lite-android&", "stringify", "&android&3.1.0&", "&", "&846c4c32dae910ef", "12aea658f76e453faf803d15c40a72e0", "isNode", "crypto-js", "", "api?functionId=", "&body=", "&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=", "&sign=", "api.m.jd.com", "*/*", "RN", "JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)", "zh-Hans-CN;q=1, ja-CN;q=0.9", "undefined", "log", "删除", "版本号,js会定", "期弹窗,", "还请支持我们的工作", "jsjia", "mi.com"];

function taskUrl(_0x7683x2, _0x7683x3 = {}) {
  let _0x7683x4 = +new Date();
  let _0x7683x5 = `lite-android&${JSON.stringify(_0x7683x3)}&android&3.1.0&${_0x7683x2}&${_0x7683x4}&846c4c32dae910ef`;
  let _0x7683x6 = "12aea658f76e453faf803d15c40a72e0";
  const _0x7683x7 = $.isNode() ? require("crypto-js") : CryptoJS;
  let _0x7683x8 = _0x7683x7.HmacSHA256(_0x7683x5, _0x7683x6).toString();
  return {
    url: ""+`${JD_API_HOST}api?functionId=${_0x7683x2}&body=${escape(JSON.stringify(_0x7683x3))}&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=${_0x7683x4}&sign=${_0x7683x8}`+"",
    headers: {
      'Host': 'api.m.jd.com',
      'accept': '*/*',
      'kernelplatform': 'RN',
      'user-agent': 'JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)',
      'accept-language': 'zh-Hans-CN;q=1, ja-CN;q=0.9',
      'Cookie': cookie
    }
  }
}
(function (_0x7683x9, _0x7683xa, _0x7683xc, _0x7683xd, _0x7683xe) {
  _0x7683xe = 'undefined';
  _0x7683xc = function (_0x7683xf) {
    if (typeof alert !== _0x7683xe) {
      alert(_0x7683xf)
    };
    console.log(console)
    if (typeof console !== _0x7683xe) {
      console.log(_0x7683xf)
    }
  };
  _0x7683xd = '删除版本号,js会定期弹窗,还请支持我们的工作';
  try {
    _0x7683x9 = __encode;
    if (!(typeof _0x7683x9 !== _0x7683xe && _0x7683x9 === 'jsjiami.com')) {
      _0x7683xc(_0x7683xd)
    }
  } catch (e) {
    _0x7683xc(_0x7683xd)
  }
})({})

对此,基本已经翻译完成,剩下的给这些_0x7683开头的变量换个名字,让他看起来更加舒服,在这里,我就大致根据这些变量定义的数据起个名字,并简化一些累赘的代码~
Magic~

var __encode = 'jsjiami.com',
  _a = {};
(function (_0xd642x1) {
  _0xd642x1["_decode"] = "http://www.sojson.com/javascriptobfuscator.html"
})(_a);
var __Oxb24bc = ["lite-android&", "stringify", "&android&3.1.0&", "&", "&846c4c32dae910ef", "12aea658f76e453faf803d15c40a72e0", "isNode", "crypto-js", "", "api?functionId=", "&body=", "&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=", "&sign=", "api.m.jd.com", "*/*", "RN", "JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)", "zh-Hans-CN;q=1, ja-CN;q=0.9", "undefined", "log", "删除", "版本号,js会定", "期弹窗,", "还请支持我们的工作", "jsjia", "mi.com"];

function taskUrl(id, data = {}) {
  let time = +new Date();
  let form = `lite-android&${JSON.stringify(data)}&android&3.1.0&${id}&${time}&846c4c32dae910ef`;
  let code = "12aea658f76e453faf803d15c40a72e0";
  const sha = $.isNode() ? require("crypto-js") : CryptoJS;
  let sign = sha.HmacSHA256(form, code).toString();
  return {
    url: ""+`${JD_API_HOST}api?functionId=${id}&body=${escape(JSON.stringify(data))}&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=${time}&sign=${sign}`+"",
    headers: {
      'Host': 'api.m.jd.com',
      'accept': '*/*',
      'kernelplatform': 'RN',
      'user-agent': 'JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)',
      'accept-language': 'zh-Hans-CN;q=1, ja-CN;q=0.9',
      'Cookie': cookie
    }
  }
}
(function (encode, alarm) {
  alarm = function (msg) {
    if (typeof alert !== 'undefined') {
      alert(msg)
    };
    if (typeof console !== 'undefined') {
      console.log(msg)
    }
  };
  try {
    encode = __encode;
    if (!(typeof encode !== 'undefined' && encode === 'jsjiami.com')) {
      alarm('删除版本号,js会定期弹窗,还请支持我们的工作')
    }
  } catch (e) {
    alarm('删除版本号,js会定期弹窗,还请支持我们的工作')
  }
})({})

就此,解密已经处理好了

或许,写到这里,会有很多朋友会问
Q:为什么_0x7683开头的变量没不能直接解析出他具体的变量名是什么呢?
A:首先,这个变量的生成具体是根据哪些参数算出来的,我们不清楚,想要去解开他需要尝试各种组合,有可能有朋友说,一看就知道是进制转换出来的。这么想,没错,但是,具体是哪个进制,你还要不断的尝试,而且,其实这只是一个变量名,到最后也不会影响里面的逻辑。因此,为了高效而言,还是直接起一个新的名字就好了。(只是审查源码的逻辑,不要太纠结)


工具方法(网上)

下面这个方法可以直接把数组的内容在文中替换,并且,把xxx["yyy"]的格式转为xxx.yyy的格式。其中,__Oxb7f82需要根据实际情况下的字符串数组对应的变量进行替换,以本文的栗子为例是__Oxb24bc,其中code的数据是对应需要解码的js数据。

console.log(code.replace(/__Oxb7f82\[0x[\da-f]+\]/g,a=>{
a=`"${eval(a).replace(/"/g,"\"")}"`;
console.log(a);
return a
}).replace(/\[s*['"][^"']+['"]\s*\]/g,a=>{
a=a.trim();
a=a.substring(2,a.length-2)
console.log(a);
return "."+a
}))

写到最后,这篇文章仅做技术分享,若涉及版权和信息安全问题,请联系小编会马上处理~

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

推荐阅读更多精彩内容