146 lines
4.2 KiB
Go
146 lines
4.2 KiB
Go
// abogus_poc 验证 goja 嵌入 a_bogus 算法能否绕过抖店风控
|
||
//
|
||
// 流程:
|
||
// 1. 构造 抖店 searchlist 的 URL params(不含 a_bogus)
|
||
// 2. 用 goja 跑 a_bogus.js 算签名
|
||
// 3. 把 a_bogus 拼上去发请求,看是否返回 st=0 的真实订单数据
|
||
//
|
||
// 用法:
|
||
//
|
||
// go run cmd/abogus_poc/main.go -buyer 47074703875 -cookie '<完整 cookie>'
|
||
package main
|
||
|
||
import (
|
||
"flag"
|
||
"fmt"
|
||
"io"
|
||
"net/http"
|
||
"net/url"
|
||
"os"
|
||
"strings"
|
||
"time"
|
||
|
||
"bindbox-game/internal/service/douyin/abogus"
|
||
)
|
||
|
||
const (
|
||
defaultUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36"
|
||
defaultReferer = "https://fxg.jinritemai.com/ffa/morder/order/list"
|
||
)
|
||
|
||
func main() {
|
||
buyer := flag.String("buyer", "", "抖音 Buyer ID,必填")
|
||
cookie := flag.String("cookie", "", "抖店登录 cookie 字符串,必填")
|
||
pageSize := flag.Int("page-size", 10, "pageSize")
|
||
flag.Parse()
|
||
|
||
if *buyer == "" || *cookie == "" {
|
||
fmt.Println("用法: -buyer <id> -cookie <cookie>")
|
||
os.Exit(1)
|
||
}
|
||
|
||
gen, err := abogus.NewGenerator()
|
||
if err != nil {
|
||
exit("初始化 a_bogus 生成器失败: %v", err)
|
||
}
|
||
|
||
csrf := parseCookie(*cookie, "csrf_session_id")
|
||
msToken := parseCookie(*cookie, "msToken")
|
||
if csrf == "" {
|
||
fmt.Println("[WARN] cookie 中找不到 csrf_session_id,__token 用兜底值")
|
||
}
|
||
if msToken == "" {
|
||
msToken = "qo0QYnkK7z_SrM7MPt2AA5xdWwKSGInO7AEeALRJ_BshJqip3nSLTnGa-gFL-aSNP6m1qNnf71-kf6hUf8xbwwLhbsaa_q3BamgxUXPxm4oXIyWPwBOXeXldqOkRV3naDtcad6PJb7rbxhbOaESKQ1YHY1y__z9Wt8GduCOxF-3ks9xHqstnKccV"
|
||
fmt.Println("[WARN] cookie 中找不到 msToken,使用历史值(很可能已过期,建议从浏览器刷新一份)")
|
||
}
|
||
verifyFp := parseCookie(*cookie, "s_v_web_id")
|
||
if verifyFp == "" {
|
||
verifyFp = "verify_mmwdotm1_QYpHiLoc_99vO_49un_9xFU_0ZKfqsmF8gzh"
|
||
}
|
||
|
||
params := url.Values{}
|
||
params.Set("page", "0")
|
||
params.Set("pageSize", fmt.Sprintf("%d", *pageSize))
|
||
params.Set("compact_time[select]", "create_time_start,create_time_end")
|
||
params.Set("buyer", *buyer)
|
||
params.Set("order_by", "create_time")
|
||
params.Set("order", "desc")
|
||
params.Set("tab", "all")
|
||
params.Set("appid", "1")
|
||
if csrf != "" {
|
||
params.Set("__token", csrf)
|
||
}
|
||
params.Set("_bid", "ffa_order")
|
||
params.Set("aid", "4272")
|
||
params.Set("verifyFp", verifyFp)
|
||
params.Set("fp", verifyFp)
|
||
params.Set("msToken", msToken)
|
||
|
||
queryStr := params.Encode()
|
||
|
||
aBogus, err := gen.Sign(queryStr, defaultUA)
|
||
if err != nil {
|
||
exit("计算 a_bogus 失败: %v", err)
|
||
}
|
||
fmt.Printf("生成 a_bogus = %s (长度 %d)\n", aBogus, len(aBogus))
|
||
|
||
finalURL := "https://fxg.jinritemai.com/api/order/searchlist?" + queryStr + "&a_bogus=" + url.QueryEscape(aBogus)
|
||
|
||
body, status, err := doGet(finalURL, *cookie)
|
||
if err != nil {
|
||
exit("请求失败: %v", err)
|
||
}
|
||
fmt.Printf("HTTP %d\n响应前 1500 字节:\n%s\n", status, truncate(body, 1500))
|
||
}
|
||
|
||
func parseCookie(cookie, key string) string {
|
||
for _, part := range strings.Split(cookie, ";") {
|
||
kv := strings.TrimSpace(part)
|
||
if strings.HasPrefix(kv, key+"=") {
|
||
return strings.TrimPrefix(kv, key+"=")
|
||
}
|
||
}
|
||
return ""
|
||
}
|
||
|
||
func doGet(u, cookie string) (string, int, error) {
|
||
req, err := http.NewRequest("GET", u, nil)
|
||
if err != nil {
|
||
return "", 0, err
|
||
}
|
||
req.Header.Set("User-Agent", defaultUA)
|
||
req.Header.Set("Accept", "application/json, text/plain, */*")
|
||
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
|
||
req.Header.Set("Cookie", cookie)
|
||
req.Header.Set("Referer", defaultReferer)
|
||
req.Header.Set("priority", "u=1, i")
|
||
req.Header.Set("sec-ch-ua", `"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"`)
|
||
req.Header.Set("sec-ch-ua-mobile", "?0")
|
||
req.Header.Set("sec-ch-ua-platform", `"macOS"`)
|
||
req.Header.Set("sec-fetch-dest", "empty")
|
||
req.Header.Set("sec-fetch-mode", "cors")
|
||
req.Header.Set("sec-fetch-site", "same-origin")
|
||
req.Close = true
|
||
|
||
cli := &http.Client{Timeout: 60 * time.Second}
|
||
resp, err := cli.Do(req)
|
||
if err != nil {
|
||
return "", 0, err
|
||
}
|
||
defer resp.Body.Close()
|
||
b, err := io.ReadAll(resp.Body)
|
||
return string(b), resp.StatusCode, err
|
||
}
|
||
|
||
func truncate(s string, n int) string {
|
||
if len(s) <= n {
|
||
return s
|
||
}
|
||
return s[:n]
|
||
}
|
||
|
||
func exit(format string, a ...any) {
|
||
fmt.Fprintf(os.Stderr, format+"\n", a...)
|
||
os.Exit(1)
|
||
}
|