JS逆向-Bitcoin浏览器交易x-apikey参数加密逆向

本文仅作学习交流,敏感信息已做加密处理。

实战网址:aHR0cHM6Ly93d3cub2tsaW5rLmNvbS96aC1oYW5zL2J0Yy90eC1saXN0

分析过程

刷新页面,会看到具体get请求中会有一个加密协议头x-apikey,这个就是需要逆向的加密字段

  1. 首先源代码里搜索 apikey
    bit逆向apikey-orxo.png
    可以看到这里有一个encryptApiKey的定义,点进去,应该就是这里,直接把这一串复制下来
            {
                key: "encryptApiKey",
                value: function() {
                    var e = this.API_KEY
                      , t = e.split("")
                      , n = t.splice(0, 8);
                    return e = t.concat(n).join("")
                }
            }, {
                key: "encryptTime",
                value: function(e) {
                    var t = (1 * e + c).toString().split("")
                      , n = parseInt(10 * i.o.mathRandom(), 10)
                      , r = parseInt(10 * i.o.mathRandom(), 10)
                      , o = parseInt(10 * i.o.mathRandom(), 10);
                    return t.concat([n, r, o]).join("")
                }
            }, {
                key: "comb",
                value: function(e, t) {
                    var n = "".concat(e, "|").concat(t);
                    return a.A.btoa(n)
                }
            }, {
                key: "getApiKey",
                value: function() {
                    var e = (new Date).getTime()
                      , t = this.encryptApiKey();
                    return e = this.encryptTime(e),
                    this.comb(t, e)
                }
            }
  1. 刷新页面,下断点
    bit逆向apikey下断点.jpg
    可以看到,代码执行到这里停住了,就说明我们找对地方了,进一步查看堆栈调用,发现上一步调用地方在下面的getApiKey定义里,那基本可以确定getApiKey就是生成x-apiKey的地方,接下来再来分析具体加密方法逻辑
  2. 查看getApiKey方法,分析加密逻辑
                key: "getApiKey",
                value: function() {
                    var e = (new Date).getTime()
                      , t = this.encryptApiKey();
                    return e = this.encryptTime(e),
                    this.comb(t, e)
                }

首先 var e ,这就是获取一个时间戳,不需要说明什么,直接看t,t调用了上面的encryptApiKey方法,直接具体看这个方法

                    var e = this.API_KEY
                      , t = e.split("")
                      , n = t.splice(0, 8);
                    return e = t.concat(n).join("")

e 这里就是一个固定值,可以在上面看到,this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
t = e.split("") 就是把 API_KEY 拆分成字符数组 ["a","2","c","9"...] 这种
n = t.splice(0,8) 就是删除t的前八位并返回 也就是返回 a2c903cc
最后return返回 就是t和n组合成新的字符数组,n添加在t后面,因为t在前面转换成了字符数组,所以需要join连接成字符串 也就是 -b31e-4547-9299-b6d07b7631aba2c903cc

接下来看 encryptTime(e)

                key: "encryptTime",
                value: function(e) {
                    var t = (1 * e + c).toString().split("")
                      , n = parseInt(10 * i.o.mathRandom(), 10)
                      , r = parseInt(10 * i.o.mathRandom(), 10)
                      , o = parseInt(10 * i.o.mathRandom(), 10);
                    return t.concat([n, r, o]).join("")
                }

t 把 1* e +c 的结果转字符串,e是我们传入的时间戳,然后再转字符数组,c在前面有定义,是个常量,直接拿下来,c = 1111111111111
n,r,o这里,都是获取一个0-9的随机数
return返回也类似,t和n,r,o组成新的字符数组,然后再连接成字符串

再看this.comb(t, e)

                key: "comb",
                value: function(e, t) {
                    var n = "".concat(e, "|").concat(t);
                    return a.A.btoa(n)
                }

e 和 t 是我们传入的就是 encryptApiKey()encryptTime()返回的数据
"".concat(e, "|"):这里的 "" 是一个空字符串,concat 方法用于将多个字符串拼接在一起。e 是第一个字符串,"|" 是第二个字符串,所以这部分代码的结果是将 e 和 | 拼接在一起
最后再通过btoa函数进行base64编码即可。 btoa(n) 是 JavaScript 中的一个函数,用于将字符串 n 进行 Base64 编码。

最终Py代码

import requests
import random
import time
import base64

def getAPiKey():
    api_key = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
    t = list(api_key)
    n = t[:8]
    t = t[8:]
    t.extend(n)
    return "".join(t)

def encryptTime(e):
    c = 1111111111111
    t = list(str(1 * e + c))  # 将e和c的和转换为字符串,然后拆分为字符列表
    n = int(10 * random.random())  # 生成0到9之间的随机整数
    r = int(10 * random.random())  
    o = int(10 * random.random()) 
    return ''.join(t + [str(n), str(r), str(o)])  # 将t和随机数列表连接起来,然后转换为字符串

def comb(e,t):
    n = "".join([e, "|", t])
    # Python的base64编码函数需要字节,所以我们先编码为字节
    n_bytes = n.encode('utf-8')
    # 使用base64.b64encode进行编码
    return base64.b64encode(n_bytes).decode('utf-8')

def getUrl():
    timestamp = int(round(time.time() * 1000))
    t = getAPiKey()
    e = encryptTime(timestamp)
    resut = comb(t, e)
    page = input("请输入要查看的页数:")
    offset = 20*int(page)
    url = 'https://www.oklink.com/api/explorer/v1/btc/transactionsNoRestrict?offset={}&limit=20&t={}'.format(offset, timestamp)
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
        "x-apiKey":resut
    }
    response = requests.get(url, headers=headers)
    response_data = response.json()  # 解析 JSON 数据
    print(response_data)

if __name__ == '__main__':
    getUrl()

运行结果

bit逆向apikey运行结果.jpg