灵寒谷
Couponbirds插件接口破解

Couponbirds插件接口破解

Couponbirds插件采集,逆向破解

灵谷2026-03-102268Markdown 发布

采集内容

  • 插件端返回的code信息,如图所示

image

找接口

image

  • 通过测试可以发现,该请求有两个必要参数
    • access-token

    • cb-user-id

参数破解

Access-toke

  • 通过分析插件源码,该源码由webpack打包而成

  • 通过debugger, 找到函数入口点,找到对应使用的加密模块即可完成破解

  • 函数入口点找寻如下:

  1. 全局搜索 access-token,下断点

image

  1. 通过断点,可以发现, token生成主逻辑为:S((new Date).toISOString().substr(0, 16) + e).toString()

image

  1. 往下单步调试可以发现,S方法为调用的加密方法 _createHelper, 该方法其实为魔改后的md5方法

image image

  1. 往上找S方法的初始定义位置

image

  1. 可以发现是典型的webpack打包后的调用方式,跟进 n 找webpack加载器

image

  1. 找到加载器后,将加载器取出,在本地运行补全相应的模块就好了,补全代码如下:
!function (e) {
    t = {};

    function n(o) {
        var r = t[o];
        if (void 0 !== r)
            return r.exports;
        var i = t[o] = {
            exports: {}
        };
        return e[o].call(i.exports, i, i.exports, n),
            i.exports
    };
    n(8214);

}({
    2480: ()=>{},
    8214: function (e, t, n) {
        var o;
        e.exports = (o = n(8249),
            function (e) {
                var t = o
                    , n = t.lib
                    , r = n.WordArray
                    , i = n.Hasher
                    , a = t.algo
                    , l = [];
                !function () {
                    for (var t = 0; t < 64; t++)
                        l[t] = 4294967296 * e.abs(e.sin(t + 1)) | 0
                }();
                var s = a.MD5 = i.extend({
                    _doReset: function () {
                        this._hash = new r.init([1732584193, 4023233417, 2562383102, 271733878])
                    },
                    _doProcessBlock: function (e, t) {
                        for (var n = 0; n < 16; n++) {
                            var o = t + n
                                , r = e[o];
                            e[o] = 16711935 & (r << 8 | r >>> 24) | 4278255360 & (r << 24 | r >>> 8)
                        }
                        var i = this._hash.words
                            , a = e[t + 0]
                            , s = e[t + 1]
                            , f = e[t + 2]
                            , m = e[t + 3]
                            , h = e[t + 4]
                            , w = e[t + 5]
                            , g = e[t + 6]
                            , v = e[t + 7]
                            , y = e[t + 8]
                            , C = e[t + 9]
                            , A = e[t + 10]
                            , b = e[t + 11]
                            , E = e[t + 12]
                            , H = e[t + 13]
                            , S = e[t + 14]
                            , x = e[t + 15]
                            , P = i[0]
                            , I = i[1]
                            , T = i[2]
                            , k = i[3];
                        P = c(P, I, T, k, a, 7, l[0]),
                            k = c(k, P, I, T, s, 12, l[1]),
                            T = c(T, k, P, I, f, 17, l[2]),
                            I = c(I, T, k, P, m, 22, l[3]),
                            P = c(P, I, T, k, h, 7, l[4]),
                            k = c(k, P, I, T, w, 12, l[5]),
                            T = c(T, k, P, I, g, 17, l[6]),
                            I = c(I, T, k, P, v, 22, l[7]),
                            P = c(P, I, T, k, y, 7, l[8]),
                            k = c(k, P, I, T, C, 12, l[9]),
                            T = c(T, k, P, I, A, 17, l[10]),
                            I = c(I, T, k, P, b, 22, l[11]),
                            P = c(P, I, T, k, E, 7, l[12]),
                            k = c(k, P, I, T, H, 12, l[13]),
                            T = c(T, k, P, I, S, 17, l[14]),
                            P = u(P, I = c(I, T, k, P, x, 22, l[15]), T, k, s, 5, l[16]),
                            k = u(k, P, I, T, g, 9, l[17]),
                            T = u(T, k, P, I, b, 14, l[18]),
                            I = u(I, T, k, P, a, 20, l[19]),
                            P = u(P, I, T, k, w, 5, l[20]),
                            k = u(k, P, I, T, A, 9, l[21]),
                            T = u(T, k, P, I, x, 14, l[22]),
                            I = u(I, T, k, P, h, 20, l[23]),
                            P = u(P, I, T, k, C, 5, l[24]),
                            k = u(k, P, I, T, S, 9, l[25]),
                            T = u(T, k, P, I, m, 14, l[26]),
                            I = u(I, T, k, P, y, 20, l[27]),
                            P = u(P, I, T, k, H, 5, l[28]),
                            k = u(k, P, I, T, f, 9, l[29]),
                            T = u(T, k, P, I, v, 14, l[30]),
                            P = p(P, I = u(I, T, k, P, E, 20, l[31]), T, k, w, 4, l[32]),
                            k = p(k, P, I, T, y, 11, l[33]),
                            T = p(T, k, P, I, b, 16, l[34]),
                            I = p(I, T, k, P, S, 23, l[35]),
                            P = p(P, I, T, k, s, 4, l[36]),
                            k = p(k, P, I, T, h, 11, l[37]),
                            T = p(T, k, P, I, v, 16, l[38]),
                            I = p(I, T, k, P, A, 23, l[39]),
                            P = p(P, I, T, k, H, 4, l[40]),
                            k = p(k, P, I, T, a, 11, l[41]),
                            T = p(T, k, P, I, m, 16, l[42]),
                            I = p(I, T, k, P, g, 23, l[43]),
                            P = p(P, I, T, k, C, 4, l[44]),
                            k = p(k, P, I, T, E, 11, l[45]),
                            T = p(T, k, P, I, x, 16, l[46]),
                            P = d(P, I = p(I, T, k, P, f, 23, l[47]), T, k, a, 6, l[48]),
                            k = d(k, P, I, T, v, 10, l[49]),
                            T = d(T, k, P, I, S, 15, l[50]),
                            I = d(I, T, k, P, w, 21, l[51]),
                            P = d(P, I, T, k, E, 6, l[52]),
                            k = d(k, P, I, T, m, 10, l[53]),
                            T = d(T, k, P, I, A, 15, l[54]),
                            I = d(I, T, k, P, s, 21, l[55]),
                            P = d(P, I, T, k, y, 6, l[56]),
                            k = d(k, P, I, T, x, 10, l[57]),
                            T = d(T, k, P, I, g, 15, l[58]),
                            I = d(I, T, k, P, H, 21, l[59]),
                            P = d(P, I, T, k, h, 6, l[60]),
                            k = d(k, P, I, T, b, 10, l[61]),
                            T = d(T, k, P, I, f, 15, l[62]),
                            I = d(I, T, k, P, C, 21, l[63]),
                            i[0] = i[0] + P | 0,
                            i[1] = i[1] + I | 0,
                            i[2] = i[2] + T | 0,
                            i[3] = i[3] + k | 0
                    },
                    _doFinalize: function () {
                        var t = this._data
                            , n = t.words
                            , o = 8 * this._nDataBytes
                            , r = 8 * t.sigBytes;
                        n[r >>> 5] |= 128 << 24 - r % 32;
                        var i = e.floor(o / 4294967296)
                            , a = o;
                        n[15 + (r + 64 >>> 9 << 4)] = 16711935 & (i << 8 | i >>> 24) | 4278255360 & (i << 24 | i >>> 8),
                            n[14 + (r + 64 >>> 9 << 4)] = 16711935 & (a << 8 | a >>> 24) | 4278255360 & (a << 24 | a >>> 8),
                            t.sigBytes = 4 * (n.length + 1),
                            this._process();
                        for (var l = this._hash, s = l.words, c = 0; c < 4; c++) {
                            var u = s[c];
                            s[c] = 16711935 & (u << 8 | u >>> 24) | 4278255360 & (u << 24 | u >>> 8)
                        }
                        return l
                    },
                    clone: function () {
                        var e = i.clone.call(this);
                        return e._hash = this._hash.clone(),
                            e
                    }
                });

                function c(e, t, n, o, r, i, a) {
                    var l = e + (t & n | ~t & o) + r + a;
                    return (l << i | l >>> 32 - i) + t
                }

                function u(e, t, n, o, r, i, a) {
                    var l = e + (t & o | n & ~o) + r + a;
                    return (l << i | l >>> 32 - i) + t
                }

                function p(e, t, n, o, r, i, a) {
                    var l = e + (t ^ n ^ o) + r + a;
                    return (l << i | l >>> 32 - i) + t
                }

                function d(e, t, n, o, r, i, a) {
                    var l = e + (n ^ (t | ~o)) + r + a;
                    return (l << i | l >>> 32 - i) + t
                }

                t.MD5 = i._createHelper(s),
                    t.HmacMD5 = i._createHmacHelper(s),
                    global.generate_token = i._createHelper(s)

            }(Math),
            o.MD5)
    },
    8249: function (e, t, n) {
        var o;
        e.exports = (o = o || function (e, t) {
            var o;
            if ("undefined" != typeof window && window.crypto && (o = window.crypto),
            "undefined" != typeof self && self.crypto && (o = self.crypto),
            "undefined" != typeof globalThis && globalThis.crypto && (o = globalThis.crypto),
            !o && "undefined" != typeof window && window.msCrypto && (o = window.msCrypto),
            !o && void 0 !== n.g && n.g.crypto && (o = n.g.crypto),
                !o)
                try {
                    o = n(2480)
                } catch (e) {
                }
            var r = function () {
                if (o) {
                    if ("function" == typeof o.getRandomValues)
                        try {
                            return o.getRandomValues(new Uint32Array(1))[0]
                        } catch (e) {
                        }
                    if ("function" == typeof o.randomBytes)
                        try {
                            return o.randomBytes(4).readInt32LE()
                        } catch (e) {
                        }
                }
                throw new Error("Native crypto module could not be used to get secure random number.")
            }
                , i = Object.create || function () {
                function e() {
                }

                return function (t) {
                    var n;
                    return e.prototype = t,
                        n = new e,
                        e.prototype = null,
                        n
                }
            }()
                , a = {}
                , l = a.lib = {}
                , s = l.Base = {
                extend: function (e) {
                    var t = i(this);
                    return e && t.mixIn(e),
                    t.hasOwnProperty("init") && this.init !== t.init || (t.init = function () {
                            t.$super.init.apply(this, arguments)
                        }
                    ),
                        t.init.prototype = t,
                        t.$super = this,
                        t
                },
                create: function () {
                    var e = this.extend();
                    return e.init.apply(e, arguments),
                        e
                },
                init: function () {
                },
                mixIn: function (e) {
                    for (var t in e)
                        e.hasOwnProperty(t) && (this[t] = e[t]);
                    e.hasOwnProperty("toString") && (this.toString = e.toString)
                },
                clone: function () {
                    return this.init.prototype.extend(this)
                }
            }
                , c = l.WordArray = s.extend({
                init: function (e, t) {
                    e = this.words = e || [],
                        this.sigBytes = null != t ? t : 4 * e.length
                },
                toString: function (e) {
                    return (e || p).stringify(this)
                },
                concat: function (e) {
                    var t = this.words
                        , n = e.words
                        , o = this.sigBytes
                        , r = e.sigBytes;
                    if (this.clamp(),
                    o % 4)
                        for (var i = 0; i < r; i++) {
                            var a = n[i >>> 2] >>> 24 - i % 4 * 8 & 255;
                            t[o + i >>> 2] |= a << 24 - (o + i) % 4 * 8
                        }
                    else
                        for (var l = 0; l < r; l += 4)
                            t[o + l >>> 2] = n[l >>> 2];
                    return this.sigBytes += r,
                        this
                },
                clamp: function () {
                    var t = this.words
                        , n = this.sigBytes;
                    t[n >>> 2] &= 4294967295 << 32 - n % 4 * 8,
                        t.length = e.ceil(n / 4)
                },
                clone: function () {
                    var e = s.clone.call(this);
                    return e.words = this.words.slice(0),
                        e
                },
                random: function (e) {
                    for (var t = [], n = 0; n < e; n += 4)
                        t.push(r());
                    return new c.init(t, e)
                }
            })
                , u = a.enc = {}
                , p = u.Hex = {
                stringify: function (e) {
                    for (var t = e.words, n = e.sigBytes, o = [], r = 0; r < n; r++) {
                        var i = t[r >>> 2] >>> 24 - r % 4 * 8 & 255;
                        o.push((i >>> 4).toString(16)),
                            o.push((15 & i).toString(16))
                    }
                    return o.join("")
                },
                parse: function (e) {
                    for (var t = e.length, n = [], o = 0; o < t; o += 2)
                        n[o >>> 3] |= parseInt(e.substr(o, 2), 16) << 24 - o % 8 * 4;
                    return new c.init(n, t / 2)
                }
            }
                , d = u.Latin1 = {
                stringify: function (e) {
                    for (var t = e.words, n = e.sigBytes, o = [], r = 0; r < n; r++) {
                        var i = t[r >>> 2] >>> 24 - r % 4 * 8 & 255;
                        o.push(String.fromCharCode(i))
                    }
                    return o.join("")
                },
                parse: function (e) {
                    for (var t = e.length, n = [], o = 0; o < t; o++)
                        n[o >>> 2] |= (255 & e.charCodeAt(o)) << 24 - o % 4 * 8;
                    return new c.init(n, t)
                }
            }
                , f = u.Utf8 = {
                stringify: function (e) {
                    try {
                        return decodeURIComponent(escape(d.stringify(e)))
                    } catch (e) {
                        throw new Error("Malformed UTF-8 data")
                    }
                },
                parse: function (e) {
                    return d.parse(unescape(encodeURIComponent(e)))
                }
            }
                , m = l.BufferedBlockAlgorithm = s.extend({
                reset: function () {
                    this._data = new c.init,
                        this._nDataBytes = 0
                },
                _append: function (e) {
                    "string" == typeof e && (e = f.parse(e)),
                        this._data.concat(e),
                        this._nDataBytes += e.sigBytes
                },
                _process: function (t) {
                    var n, o = this._data, r = o.words, i = o.sigBytes, a = this.blockSize, l = i / (4 * a),
                        s = (l = t ? e.ceil(l) : e.max((0 | l) - this._minBufferSize, 0)) * a, u = e.min(4 * s, i);
                    if (s) {
                        for (var p = 0; p < s; p += a)
                            this._doProcessBlock(r, p);
                        n = r.splice(0, s),
                            o.sigBytes -= u
                    }
                    return new c.init(n, u)
                },
                clone: function () {
                    var e = s.clone.call(this);
                    return e._data = this._data.clone(),
                        e
                },
                _minBufferSize: 0
            })
                , h = (l.Hasher = m.extend({
                cfg: s.extend(),
                init: function (e) {
                    this.cfg = this.cfg.extend(e),
                        this.reset()
                },
                reset: function () {
                    m.reset.call(this),
                        this._doReset()
                },
                update: function (e) {
                    return this._append(e),
                        this._process(),
                        this
                },
                finalize: function (e) {
                    return e && this._append(e),
                        this._doFinalize()
                },
                blockSize: 16,
                _createHelper: function (e) {
                    return function (t, n) {
                        return new e.init(n).finalize(t)
                    }
                },
                _createHmacHelper: function (e) {
                    return function (t, n) {
                        return new h.HMAC.init(e, n).finalize(t)
                    }
                }

            }),
                a.algo = {});
            return a
        }(Math),
            o)
    }
})

function I(e) {
    if (typeof e === "string" && e.length <= 64) {
        console.log((new Date()).toISOString().substr(0, 16) + e)
        return global.generate_token((new Date()).toISOString().substr(0, 16) + e).toString();
    } else {
        return "";
    }
}
```7.
传入参数,即可得到加密后的结果
    

![image](/api/uploads/posts/87CvNw6E_Bpa.webp)

8.  传入的参数为 cb-user-id
    

## Cb-user-id

-   该参数由服务器端返回,需要结合ip信息,浏览器请求头,时区偏移量进行请求即可获得
    
-   该参数在插件装到浏览器上后会自动发起请求进行获取,抓包即可获得
    
-   接口信息记录如下, 该请求无需带参数和cookie:
    

```Plain
GET https://smart.couponbirds.com/v1/commonLog/uniqueId HTTP/1.1
Host: smart.couponbirds.com
Connection: keep-alive
cb-type: default
cb-app-version-num: 40120
cb-user-id: null
cb-default-user-id: null
cb-ads-default-visitor-id: null
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
cb-app-type: chrome
cb-default-visitor-id: null
cb-app-version: 4.1.20
cb-baseBrowserInfo: {"browserOs":"Win32","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36","browserVersion":"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36","hardwareConcurrency":8,"language":"en-US","screenResolution":null,"screenColorDepth":null,"timezone":0}
Accept: */*
Sec-Fetch-Site: none
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9
```-
请求结果如下:
    

![image](/api/uploads/posts/4eegKXxfjKkD.webp)

# 风控检测

1.  couponbirds 单个代理只能生成3-4个用户id,请求多了会返回429
    
2.  采集时可以用一个用户id, 多个代理切换采集
    
3.  couponbirds 对代理质量要求较高,生成用户的接口有cf防护,该处猜测会过滤大量ip
    
4.  时区偏移量,最好和ip地区一致,该参数偶尔会出现影响,还需校验测试
    
5.  单个用户可采集量为:200-300个,到达限制后,不封账号,但是会返回空数据,第二天可解除限制

留言互动

共 0 条