确定逆向目标参数

拿取地址、请求body参数,请求头(如果需要)、cookies(如果需要)

分析参数来源,是固定的,还是变动的

e.g:X盾|获取验证码背景图的接口逆向分析

通过分析,发现需要逆向的有fp和cb参数

获取验证码背景图片 - 图1

分析发现,fp和cb参数所在的js文件是动态的,需要使用动态JS文件处理一下:

获取验证码背景图片 - 图2

然后使用代理替换解决之。

定位参数

定位到如下直接赋值关键代码:

  1. 'fp':wh, #发现需要继续向上。
  2. 'cb':w1, #简单返回的那种

处理cb

拷贝整个JS文件,命名为v1.js

补环境后,写嫁接代码:

获取验证码背景图片 - 图3

调试看看行不行:

获取验证码背景图片 - 图4

处理fp

定位:

‘fp’:wh,

wh = wJ[‘fingerprint’]

wJ = wN[‘state’]

wN[‘state]=this[‘state’]

一旦涉及到this,就需要看真个对象了

发现对象里有个 initialize

在 initialize 里继续逆向回去

定位到 ‘fingerprint’ : wW

var wW = window[‘gdxidpyhxde’];

然后逆向赋值调试,得知

window[‘gdxidpyhxde’] = wv

发现这个赋值和cb在同一个js文件了,猜测这个js只要执行,就可以自动给window赋值,做个尝试,发现真的可以得到值:

获取验证码背景图片 - 图5

代码整合

结合node.js+py的思路

  1. import json
  2. import random
  3. import subprocess
  4. import requests
  5. import string
  6. def cb_fp():
  7. res = subprocess.check_output("node sdk.js")
  8. char_string = res.decode('utf-8').strip()
  9. cb, fp = char_string.strip().split()
  10. return cb, fp
  11. def get_conf():
  12. callback_string = f"__JSONP_{''.join(random.sample(string.ascii_letters, 7)).lower()}_1"
  13. res = requests.get(
  14. url="https://c.dun.163.com/api/v2/getconf",
  15. params={
  16. "referer": "https%3A%2F%2Fdun.163.com%2Ftrial%2Fjigsaw",
  17. "zoneId": "",
  18. "id": "07e2387ab53a4d6f930b8d9a9be71bdf",
  19. "ipv6": "false",
  20. "runEnv": "10",
  21. "iv": "3",
  22. "type": "2",
  23. "loadVersion": "2.4.0",
  24. "callback": callback_string
  25. },
  26. headers={
  27. "Referer": "https://dun.163.com/",
  28. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
  29. },
  30. )
  31. res.close()
  32. res_string = res.text.strip(f"{callback_string}(").strip(");")
  33. res_dict = json.loads(res_string)
  34. dt = res_dict['data']['dt']
  35. ac_bid = res_dict['data']['ac']['bid']
  36. ac_token = res_dict['data']['ac']['token']
  37. return dt, ac_bid, ac_token
  38. def get(dt, ac_bid, ac_token, cb, fp):
  39. callback_string = f"__JSONP_{''.join(random.sample(string.ascii_letters, 7)).lower()}_1"
  40. res = requests.get(
  41. url="https://c.dun.163.com/api/v3/get",
  42. params={
  43. "referer": "https%3A%2F%2Fdun.163.com%2Ftrial%2Fjigsaw",
  44. "zoneId": "CN31",
  45. "dt": dt,
  46. "acToken": ac_token,
  47. "id": ac_bid,
  48. "fp": fp,
  49. "https": "true",
  50. "type": "2",
  51. "version": "2.25.0",
  52. "dpr": "2",
  53. "dev": "1",
  54. "cb": cb,
  55. "ipv6": "false",
  56. "runEnv": "10",
  57. "group": "",
  58. "scene": "",
  59. "lang": "zh-CN",
  60. "sdkVersion": "undefined",
  61. "iv": "3",
  62. "width": "320",
  63. "audio": "false",
  64. "sizeType": "10",
  65. "smsVersion": "v3",
  66. "token": "",
  67. "callback": callback_string
  68. },
  69. headers={
  70. # "Accept-Language": "zh-CN,zh;q=0.9",
  71. "Referer": "https://dun.163.com/",
  72. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
  73. },
  74. )
  75. res.close()
  76. res_string = res.text.strip(f"{callback_string}(").strip(");")
  77. res_dict = json.loads(res_string)
  78. print(res_dict)
  79. def run():
  80. # get_conf请求
  81. dt, ac_bid, ac_token = get_conf()
  82. # get请求
  83. cb, fp = cb_fp()
  84. get(dt, ac_bid, ac_token, cb, fp)
  85. if __name__ == '__main__':
  86. run()