【JS 逆向百例】webpack 改寫實戰(zhàn)油猫,G 某游戲 RSA 加密

聲明

本文章中所有內(nèi)容僅供學(xué)習(xí)交流稠茂,抓包內(nèi)容、敏感網(wǎng)址、數(shù)據(jù)接口均已做脫敏處理睬关,嚴(yán)禁用于商業(yè)用途和非法用途诱担,否則由此產(chǎn)生的一切后果均與作者無關(guān),若有侵權(quán)电爹,請聯(lián)系我立即刪除蔫仙!

逆向目標(biāo)

  • 目標(biāo):G某游戲登錄
  • 主頁:aHR0cHM6Ly93d3cuZ205OS5jb20v
  • 接口:aHR0cHM6Ly9wYXNzcG9ydC5nbTk5LmNvbS9sb2dpbi9sb2dpbjM=
  • 逆向參數(shù):
    Query String Parameters:
    password: kRtqfg41ogc8btwGlEw6nWLg8cHcCW6R8JaeM......
    

逆向過程

抓包分析

來到首頁,隨便輸入一個賬號密碼丐箩,點擊登陸摇邦,抓包定位到登錄接口為 aHR0cHM6Ly9wYXNzcG9ydC5nbTk5LmNvbS9sb2dpbi9sb2dpbjM=,GET 請求屎勘,Query String Parameters 里施籍,密碼 password 被加密處理了。

01.png

加密入口

直接搜索關(guān)鍵字 password 會發(fā)現(xiàn)結(jié)果太多不好定位概漱,使用 XHR 斷點比較容易定位到加密入口丑慎,有關(guān) XHR 斷點調(diào)試可以查看 K 哥往期的教程:【JS 逆向百例】XHR 斷點調(diào)試,Steam 登錄逆向瓤摧,如下圖所示立哑,在 home.min.js 里可以看到關(guān)鍵語句 a.encode(t.password, s)t.password 是明文密碼姻灶,s 是時間戳铛绰。

02.png

跟進(jìn) a.encode() 函數(shù),此函數(shù)仍然在 home.min.js 里产喉,觀察這部分代碼捂掰,可以發(fā)現(xiàn)使用了 JSEncrypt,并且有 setPublicKey 設(shè)置公鑰方法曾沈,由此可以看出應(yīng)該是 RSA 加密这嚣,具體步驟是將明文密碼和時間戳組合成用 | 組合,經(jīng)過 RSA 加密后再進(jìn)行 URL 編碼得到最終結(jié)果塞俱,如下圖所示:

03.png

RSA 加密找到了公鑰姐帚,其實就可以直接使用 Python 的 Cryptodome 模塊來實現(xiàn)加密過程了,代碼如下所示:

import time
import base64
from urllib import parse
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_v1_5


password = "12345678"
timestamp = str(int(time.time() * 1000))
encrypted_object = timestamp + "|" + password
public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB"
rsa_key = RSA.import_key(base64.b64decode(public_key))  # 導(dǎo)入讀取到的公鑰
cipher = PKCS1_v1_5.new(rsa_key)                        # 生成對象
encrypted_password = base64.b64encode(cipher.encrypt(encrypted_object.encode(encoding="utf-8")))
encrypted_password = parse.quote(encrypted_password)
print(encrypted_password)

即便是不使用 Python障涯,我們同樣可以自己引用 JSEncrypt 模塊來實現(xiàn)這個加密過程(該模塊使用方法可參考 JSEncrypt GitHub)罐旗,如下所示:

/*
引用 jsencrypt 加密模塊,如果在 PyCharm 里直接使用 require 引用最新版 jsencrypt唯蝶,
運行可能會提示 jsencrypt.js 里 window 未定義九秀,直接在該文件定義 var window = this; 即可,
也可以使用和網(wǎng)站用的一樣的 2.3.1 版本:https://npmcdn.com/jsencrypt@2.3.1/bin/jsencrypt.js
也可以將 jsencrypt.js 直接粘貼到此腳本中使用粘我,如果提示未定義鼓蜒,直接在該腳本中定義即可。
*/

JSEncrypt = require("jsencrypt")

function getEncryptedPassword(t, e) {
    var jsEncrypt = new JSEncrypt();
    jsEncrypt.setPublicKey('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB');
    var i = e ? e + "|" + t : t;
    return encodeURIComponent(jsEncrypt.encrypt(i));
}

var password = "12345678";
var timestamp = (new Date).getTime();
console.log(getEncryptedPassword(password, timestamp));

webpack 改寫

本文的標(biāo)題是 webpack 改寫實戰(zhàn),所以很顯然本文的目的是為了練習(xí) JavaScript 模塊化編程 webpack 代碼的改寫都弹,現(xiàn)在大多數(shù)站點都使用了這種寫法娇豫,然而并不是所有站點都像本文遇到的站點一樣,可以很容易使用其他方法來實現(xiàn)的畅厢,往往大多數(shù)站點需要你自己扒下他的源碼來還原加密過程锤躁,有關(guān) JavaScript 模塊化編程,即 webpack或详,在 K 哥往期的文章中有過詳細(xì)的介紹:爬蟲逆向基礎(chǔ)系羞,理解 JavaScript 模塊化編程 webpack

一個標(biāo)準(zhǔn)的 webpack 整體是一個 IIFE 立即調(diào)用函數(shù)表達(dá)式,其中有一個模塊加載器霸琴,也就是調(diào)用模塊的函數(shù)椒振,該函數(shù)中一般具有 function.call() 或者 function.apply() 方法,IIFE 傳遞的參數(shù)是一個列表或者字典梧乘,里面是一些需要調(diào)用的模塊澎迎,寫法類似于:

!function (allModule) {
    function useModule(whichModule) {
        allModule[whichModule].call(null, "hello world!");
    }
}([
    function module0(param) {console.log("module0: " + param)},
    function module1(param) {console.log("module1: " + param)},
    function module2(param) {console.log("module2: " + param)},
]);

觀察這次站點的加密代碼,會發(fā)現(xiàn)所有加密方法都在 home.min.js 里面选调,在此文件開頭可以看到整個是一個 IIFE 立即調(diào)用函數(shù)表達(dá)式夹供,function e 里面有關(guān)鍵方法 .call(),由此可以判斷該函數(shù)為模塊加載器仁堪,后面?zhèn)鬟f的參數(shù)是一個字典哮洽,里面是一個個的對象方法,也就是需要調(diào)用的模塊函數(shù)弦聂,這就是一個典型的 webpack 寫法鸟辅,如下圖所示:

04.png

接下來我們通過 4 步完成對 webpack 代碼的改寫,將原始代碼扒下來實現(xiàn)加密的過程莺葫。

1匪凉、找到 IIFE

IIFE 立即調(diào)用函數(shù)表達(dá)式,也稱為立即執(zhí)行函數(shù)捺檬,自執(zhí)行函數(shù)再层,將源碼中的 IIFE 框架摳出來,后續(xù)將有用的代碼再往里面放:

!function (t) {
    
}({
    
})

2堡纬、找到模塊加載器

前面我們已經(jīng)講過聂受,帶有 function.call() 或者 function.apply() 方法的就是模塊加載器,也就是調(diào)用模塊的方法隐轩,在本例中饺饭,function e 就是模塊加載器,將其摳下來即可职车,其他多余的代碼可以直接刪除,注意里面用到了 i,所以定義 i 的語句也要摳下來:

!function (t) {
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
            n.loaded = !0,
            n.exports
    }
    var i = {};
}({
    
})

3悴灵、找到調(diào)用的模塊

重新來到加密的地方扛芽,第一個模塊是 3,n 里面的 encode 方法最終返回的就是加密后的結(jié)果积瞒,如下圖所示:

05.png

第二個模塊是 4川尖,可以看到模塊 3 里面的 this.jsencrypt.encrypt(i) 方法實際上是調(diào)用的第 3340 行的方法,該方法在模塊 4 里面茫孔,這里定位在模塊 4 的方法叮喳,可以在瀏覽器開發(fā)者工具 source 頁面,將鼠標(biāo)光標(biāo)放到該函數(shù)前面缰贝,一直往上滑動馍悟,直到模塊開頭,也可以使用 VS Code 等編輯器剩晴,將整個 home.min.js 代碼粘貼過去锣咒,然后選擇折疊所有代碼,再搜索這個函數(shù)赞弥,即可快速定位在哪個模塊毅整。

06.png

確定使用了 3 和 4 模塊后,將這兩個模塊的所有代碼扣下來即可绽左,大致代碼架構(gòu)如下(模塊 4 具體的代碼太長悼嫉,已刪除):

!function (t) {
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
            n.loaded = !0,
            n.exports
    }
    var i = {};
}(
    {
        4: function (t, e, i) {},
        3: function (t, e, i) {
            var s;
            s = function (t, e, s) {
                function n() {
                    "undefined" != typeof r && (this.jsencrypt = new r.JSEncrypt,
                        this.jsencrypt.setPublicKey("-----BEGIN PUBLIC KEY-----略-----END PUBLIC KEY-----"))
                }

                var r = i(4);
                n.prototype.encode = function (t, e) {
                    var i = e ? e + "|" + t : t;
                    return encodeURIComponent(this.jsencrypt.encrypt(i))
                },
                    s.exports = n
            }.call(e, i, e, t),
                !(void 0 !== s && (t.exports = s))
        }
    }
)

這里需要我們理解一個地方,那就是模塊 3 的代碼里有一行 var r = i(4);拼窥,這里的 i3: function (t, e, i) {}承粤,傳遞過來的 i,而模塊 3 又是由模塊加載器調(diào)用的闯团,即 .call(n.exports, n, n.exports, e) 里面的某個參數(shù)就是 i辛臊,前面在講解基礎(chǔ)的時候已經(jīng)說過,.call 的第一個參數(shù)指定的是函數(shù)體內(nèi) this 對象的指向房交,并不代表真正參數(shù)彻舰,所以第一個 n.exports 并不是參數(shù),從第二個參數(shù)即 n 開始算候味,那么 i 其實就是 .call(n.exports, n, n.exports, e) 里面的 e刃唤,所以 var r = i(4); 實際上就是模塊加載器 function e 調(diào)用了模塊 4,由于這里模塊 4 是個對象白群,所以這里最好寫成 var r = i("4");尚胞,這里是數(shù)字,所以可以成功運行帜慢,如果模塊 4 名字變成 func4 或者其他名字笼裳,那么調(diào)用時就必須要加引號了唯卖。

4、導(dǎo)出加密函數(shù)

目前關(guān)鍵的加密代碼已經(jīng)剝離完畢了躬柬,最后一步就是需要把加密函數(shù)導(dǎo)出來供我們調(diào)用了拜轨,首先定義一個全局變量,如 eFunc允青,然后在模塊加載器后面使用語句 eFunc = e橄碾,把模塊加載器導(dǎo)出來:

var eFunc;

!function (t) {
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
            n.loaded = !0,
            n.exports
    }
    var i = {};
    eFunc = e
}(
    {
        4: function (t, e, i) {},
        3: function (t, e, i) {}
    }
)

然后定義一個函數(shù),傳入明文密碼颠锉,返回加密后的密碼:

function getEncryptedPassword(password) {
    var timestamp = (new Date).getTime();
    var encryptFunc = eFunc("3");
    var encrypt = new encryptFunc;
    return encrypt.encode(password, timestamp)
}

其中 timestamp 為時間戳法牲,因為我們最終需要調(diào)用的是模塊 3 里面的 n.prototype.encode 這個方法,所以首先調(diào)用模塊 3琼掠,返回的是模塊 3 里面的 n 函數(shù)(可以在瀏覽器運行代碼拒垃,一步一步查看結(jié)果),然后將其 new 出來眉枕,調(diào)用 n 的 encode 方法恶复,返回加密后的結(jié)果。

自此速挑,webpack 的加密代碼就剝離完畢了谤牡,最后調(diào)試會發(fā)現(xiàn) navigator 和 window 未定義,定義一下即可:

var navigator = {};
var window = global;

這里擴展一下姥宝,在瀏覽器里面 window 其實就是 global翅萤,在 nodejs 里沒有 window,但是有個 global腊满,與瀏覽器的 window 對象類型相似套么,是全局可訪問的對象,因此在 nodejs 環(huán)境中可以將 window 定義為 global碳蛋,如果定義為空胚泌,可能會引起其他錯誤。

完整代碼

GitHub 關(guān)注 K 哥爬蟲肃弟,持續(xù)分享爬蟲相關(guān)代碼玷室!歡迎 star !https://github.com/kgepachong/

以下只演示部分關(guān)鍵代碼笤受,不能直接運行穷缤!完整代碼倉庫地址:https://github.com/kgepachong/crawler/

JavaScript 加密關(guān)鍵代碼架構(gòu)

方法一:webpack 改寫源碼實現(xiàn) RSA 加密:

var navigator = {};
var window = global;
var eFunc;

!function (t) {
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
            n.loaded = !0,
            n.exports
    }

    var i = {};
    eFunc = e;
}(
    {
        4: function (t, e, i) {},
        3: function (t, e, i) {}
    }
)

function getEncryptedPassword(password) {
    var timestamp = (new Date).getTime();
    var encryptFunc = eFunc("3");
    var encrypt = new encryptFunc;
    return encrypt.encode(password, timestamp)
}

// 測試樣例
// console.log(getEncryptedPassword("12345678"))

方法二:直接使用 JSEncrypt 模塊實現(xiàn) RSA 加密:

/*
引用 jsencrypt 加密模塊,此腳適合在 nodejs 環(huán)境下運行箩兽。
1津肛、使用 require 語句引用,前提是使用 npm 安裝過汗贫;
2身坐、將 jsencrypt.js 直接粘貼到此腳本中使用秸脱,同時要將結(jié)尾 exports.JSEncrypt = JSEncrypt; 改為 je = JSEncrypt 導(dǎo)出方法。
PS:需要定義 var navigator = {}; var window = global;掀亥,否則提示未定義撞反。
*/

// ========================= 1妥色、require 方式引用 =========================
// var je = require("jsencrypt")

// =================== 2搪花、直接將 jsencrypt.js 復(fù)制過來 ===================
/*! JSEncrypt v2.3.1 | https://npmcdn.com/jsencrypt@2.3.1/LICENSE.txt */
var navigator = {};
var window = global;

// 這里是 jsencrypt.js 代碼

function getEncryptedPassword(t) {
    var jsEncrypt = new je();
    jsEncrypt.setPublicKey('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB');
    var e = (new Date).getTime();
    var i = e ? e + "|" + t : t;
    return encodeURIComponent(jsEncrypt.encrypt(i));
}

// 測試樣例
// console.log(getEncryptedPassword("12345678"));

Python 登錄關(guān)鍵代碼

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


import re
import json
import time
import random
import base64
from urllib import parse

import execjs
import requests
from PIL import Image
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_v1_5

login_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'
verify_image_url = '脫敏處理嘹害,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'
check_code_url = '脫敏處理撮竿,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
session = requests.session()


def get_jquery():
    jsonp = ''
    for _ in range(21):
        jsonp += str(random.randint(0, 9))
    jquery = 'jQuery' + jsonp + '_'
    return jquery


def get_dict_from_jquery(text):
    result = re.findall(r'\((.*?)\)', text)[0]
    return json.loads(result)


def get_encrypted_password_by_javascript(password):
    # 兩個 JavaScript 腳本,兩種方法均可
    with open('gm99_encrypt.js', 'r', encoding='utf-8') as f:
    # with open('gm99_encrypt_2.js', 'r', encoding='utf-8') as f:
        exec_js = f.read()
    encrypted_password = execjs.compile(exec_js).call('getEncryptedPassword', password)
    return encrypted_password


def get_encrypted_password_by_python(password):
    timestamp = str(int(time.time() * 1000))
    encrypted_object = timestamp + "|" + password
    public_key = "脫敏處理笔呀,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler"
    rsa_key = RSA.import_key(base64.b64decode(public_key))  # 導(dǎo)入讀取到的公鑰
    cipher = PKCS1_v1_5.new(rsa_key)                        # 生成對象
    encrypted_password = base64.b64encode(cipher.encrypt(encrypted_object.encode(encoding="utf-8")))
    encrypted_password = parse.quote(encrypted_password)
    return encrypted_password


def get_verify_code():
    response = session.get(url=verify_image_url, headers=headers)
    with open('code.png', 'wb') as f:
        f.write(response.content)
    image = Image.open('code.png')
    image.show()
    code = input('請輸入圖片驗證碼: ')
    return code


def check_code(code):
    timestamp = str(int(time.time() * 1000))
    params = {
        'callback': get_jquery() + timestamp,
        'ckcode': code,
        '_': timestamp,
    }
    response = session.get(url=check_code_url, params=params, headers=headers)
    result = get_dict_from_jquery(response.text)
    if result['result'] == 1:
        pass
    else:
        raise Exception('驗證碼輸入錯誤幢踏!')


def login(username, encrypted_password, code):
    timestamp = str(int(time.time() * 1000))
    params = {
        'callback': get_jquery() + timestamp,
        'encrypt': 1,
        'uname': username,
        'password': encrypted_password,
        'remember': 'checked',
        'ckcode': code,
        '_': timestamp
    }
    response = session.get(url=login_url, params=params, headers=headers)
    result = get_dict_from_jquery(response.text)
    print(result)


def main():
    # 測試賬號:15434947408,密碼:iXqC@aJt8fi@VwV
    username = input('請輸入登錄賬號: ')
    password = input('請輸入登錄密碼: ')

    # 獲取加密后的密碼许师,使用 Python 或者 JavaScript 實現(xiàn)均可
    encrypted_password = get_encrypted_password_by_javascript(password)
    # encrypted_password = get_encrypted_password_by_python(password)

    # 獲取驗證碼
    code = get_verify_code()

    # 校驗驗證碼
    check_code(code)

    # 登錄
    login(username, encrypted_password, code)


if __name__ == '__main__':
    main()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末房蝉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子微渠,更是在濱河造成了極大的恐慌搭幻,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逞盆,死亡現(xiàn)場離奇詭異檀蹋,居然都是意外死亡,警方通過查閱死者的電腦和手機云芦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門俯逾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人舅逸,你說我怎么就攤上這事桌肴。” “怎么了琉历?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵坠七,是天一觀的道長。 經(jīng)常有香客問我善已,道長灼捂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任换团,我火速辦了婚禮悉稠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘艘包。我一直安慰自己的猛,他們只是感情好耀盗,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卦尊,像睡著了一般叛拷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上岂却,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天忿薇,我揣著相機與錄音,去河邊找鬼躏哩。 笑死署浩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扫尺。 我是一名探鬼主播筋栋,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼正驻!你這毒婦竟也來了弊攘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤姑曙,失蹤者是張志新(化名)和其女友劉穎襟交,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渣磷,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡婿着,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了醋界。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竟宋。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖形纺,靈堂內(nèi)的尸體忽然破棺而出丘侠,到底是詐尸還是另有隱情,我是刑警寧澤逐样,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布蜗字,位于F島的核電站,受9級特大地震影響脂新,放射性物質(zhì)發(fā)生泄漏挪捕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一争便、第九天 我趴在偏房一處隱蔽的房頂上張望级零。 院中可真熱鬧,春花似錦滞乙、人聲如沸奏纪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽序调。三九已至醉锅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間发绢,已是汗流浹背硬耍。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留朴摊,地道東北人默垄。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓此虑,卻偏偏與公主長得像甚纲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子朦前,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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