麻豆黑色丝袜jk制服福利网站-麻豆精品传媒视频观看-麻豆精品传媒一二三区在线视频-麻豆精选传媒4区2021-在线视频99-在线视频a

千鋒教育-做有情懷、有良心、有品質的職業教育機構

手機站
千鋒教育

千鋒學習站 | 隨時隨地免費學

千鋒教育

掃一掃進入千鋒手機站

領取全套視頻
千鋒教育

關注千鋒學習站小程序
隨時隨地免費學習課程

當前位置:首頁  >  技術干貨  > 爬蟲之js逆向解析(滑塊驗證碼)

爬蟲之js逆向解析(滑塊驗證碼)

來源:千鋒教育
發布人:qyf
時間: 2022-09-19 17:44:53 1663580693

  為什么要做逆向

  動態網頁爬蟲一般可分為兩種:Selenium爬取和接口爬取。兩種方式各有優缺點:前者我們己經介紹了selenium的使用和驗證碼、滑塊的使用,其雖然可以很好地處理網頁異步加載問題,但面對大型爬蟲任務時,效率還是比較低的;后者雖然爬取速度較快,但請求參數很可能是動態變化的,這時就需要利用一些前端的知識,重新構造參數,整個過程通常稱為JS逆向。先來看一下簡單的請求:

Picture

  但是往往在我們編寫爬蟲時,可能會碰到以下兩種問題:

  • 所需要爬取的數據在網頁源代碼中并不存在;

  • 點擊下一頁跳轉頁面時,網頁的URL 并沒與發生變化;

  造成這種問題原因是,你所正在爬取的頁面采取了動態加載的方式

  動態加載網頁其顯示的頁面則是經過Javascript處理數據后生成的結果,可以發生改變。

  JavaScript是一種運行在瀏覽器中的解釋型編程語言,JavaScript非常值得學習,它既適合作為學習編程的入門語言,也適合當作日常開發的工作語言。JavaScript可以收集用戶的跟蹤數據,不需要重載頁面即可直接提交表單,可在頁面中嵌入多媒體文件,甚至可以運行網頁游戲等。在很多看起來非常簡單的頁面背后通常使用了許多JavaScript文件。比如:

Picture(1)

  這些數據的來源有多種,可能是經過Javascript計算生成的,也可能是通過Ajax加載的。Ajax = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML),其最大的優點是在不重新加載整個頁面的情況下,可以與服務器交換數據并更新部分網頁的內容。

  逆向工程

  對于動態加載的網頁,我們想要獲取其網頁數據,需要了解網頁是如何加載數據的,該過程就被成為逆向工程。

  對于使用了Ajax 請求技術的網頁,我們可以找到Ajax請求的具體鏈接,直接得到Ajax請求得到的數據。

  需要注意的是,構造Ajax請求有兩種方式:

  • 原生的Ajax請求,會直接創建一個XMLHTTPRequest對象。

  • 調用jQuery的ajax()方法。一般情況下,$.ajax()會返回其創建的XMLHTTPRequest對象;但是,如果$.ajax()的dataType參數指定了為script或jsonp類型,$.ajax()不再返回其創建的XMLHTTPRequest對象。

  JQuery補充:

  在大型互聯網公司的不斷推廣下,JavaScript生態圈也在不斷的完善,各種類庫、API接口層出不窮。

  jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之后又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“Write Less, Do More”,即倡導寫更少的代碼,做更多的事情。

  對于這兩種方式,只要創建返回了XMLHTTPRequest對象,就可以通過Chrome瀏覽器的調試工具在NetWork窗口通過設置XHR過濾條件,直接篩選出Ajax請求的鏈接;如果是$.ajax()并且dataType指定了為script或jsonp,則無法通過這種方式篩選出來。

  案例分析

  這次搞得還是滑塊哦???,話不多說直接開搞數美滑塊,因為小紅書、蘑菇街、脈脈、斗魚等很多都用了數美的驗證碼。整體難度還可以就是動態參數有點東西的呢!

  數美驗證碼官網:https://www.ishumei.com/trial/captcha.html

Picture(2)

  數美滑塊的驗證碼主要的難點有以下幾點:

  request的請求參數,是動態變化的。名稱是動態變化,加密的密鑰也是動態變化的,這就有點難搞了

  每天小版本更新的頻率1-2次,必須得能夠實現完全自動化,否則人工很難及時的調整驗證碼的參數,來不及。

  js里的混淆的變量也是動態變化的

  驗證碼注冊

Picture(3)

  先看一下register

Picture(4)

  下圖是響應結果:bg和fg是驗證碼圖片地址 https://castatic.fengkongcloud.com/bg

Picture(5)

  計算滑塊位置

  根據上一步可以得到驗證圖片的地址。

  驗證碼圖片:https://castatic.fengkongcloud.com/crb/set-000006/v2/07ee613eeb1b43bed7daa24c7b288ea0bg.jpg

  滑塊圖片:https://castatic.fengkongcloud.com/crb/set-000006/v2/07ee613eeb1b43bed7daa24c7b288ea0fg.png

  使用opencv查找并匹配圖像模板中的滑塊。

  需要注意的是,這里是以原圖計算的,而頁面上的圖片大小只有(300,150),(應用不同的產品可能大小也不同)

  所以需要按比例進行縮小或者放大。

  驗證

  對應的api地址是:https://captcha.fengkongcloud.com/ca/v2/fverify?...

Picture(6)

  查詢字符串參數:

Picture(7)

  params參數里的 dv,qe,ou,cf等等,都經過了DES加密,

  破解方式分析

  打開控制臺多看幾遍請求過程,我們基本就明白請求步驟了。具體的分析過程就不再贅述。

  所攜帶的請求參數如下:

  該接口返回的js參數,是下一步需要請求的目標。

  提取js參數

  js地址:https://castatic.fengkongcloud.com/pr/auto-build/v1.0.3-144/captcha-sdk.min.js

  需要提取該js中的參數名,會在最后驗證的時候使用(注:一般情況下參數名不會變),但是這些請求參數都是變化的。

  獲取js的response,搜索上面的參數我們沒有找到,但是發現了倒序的名字

  通過查看調用棧,打斷點,一層層分析,發現js做了ob混淆。

  JS混淆有很多種,這里舉幾個:UglifyJS,JScrambler,jsbeautifier.org,JSDetox,obfuscator.io 等,像下面的代碼就是ob混淆。

  開頭定義了一個大數組,然后對這個大數組里的內容進行位移,再定義一個解密函數。后面大部分的值都調用了這個解密函數,以達到混淆的效果。如果想還原可以使用ob混淆還原工具:https://github.com/DingZaiHub/ob-decrypt

  當然不進行混淆還原也可以通過斷點很快的定位到具體的函數加密的位置

  再次請求走到這里,而這里是一部分的參數的加密,先進去看下它是怎么加密的

  進來了走到這可以看到是DES加密,參數分別是加密的密碼,要加密的參數,后面兩個是數字呢就是模式選擇了,1,0是加密,0,0是解密,在這里是加密。

  我們輸出在console中輸出一下,這四個參數看一下

  那么問題來了,這個密碼"b64ccadf"哪來的呢,別急,我們重新再來一遍!很快我們又進來走到這,_0x1c2865是什么怎么是亂碼的呢?

  console輸出一下看看

Picture(8)

  密碼搞到了,加密方式也曉得了,然后參數一個一個整過去就Ok了。

  返回結果response:

Picture(9)

  message = success,riskLevel=PASS 說明驗證通過

  完整代碼

  """

  數美滑塊驗證碼破解驗證

  """

  import base64

  import json

  import random

  import re

  import time

  from io import BytesIO

  import cv2

  import numpy as np

  import requests

  from pyDes import des, ECB

  CAPTCHA_DISPLAY_WIDTH = 310

  CAPTCHA_DISPLAY_HEIGHT = 155

  p = {}

  def pad(b):

  """

  塊填充

  """

  block_size = 8

  while len(b) % block_size:

  b += b'\0'

  return b

  def split_args(s):

  """

  分割js參數

  """

  r = []

  a = ''

  i = 0

  while i < len(s):

  c = s[i]

  if c == ',' and (a[0] != '\'' or len(a) >= 2 and a[-1] == '\''):

  r.append(a)

  a = ''

  elif c:

  a += c

  i += 1

  r.append(a)

  return r

  def find_arg_names(script):

  """

  通過js解析出參數名

  """

  names = {}

  a = []

  for r in re.findall(r'function\((.*?)\)', script):

  if len(r.split(',')) > 100:

  a = split_args(r)

  break

  r = re.search(r';\)(.*?)\(}', script[::-1]).group(1)

  v = split_args(r[::-1])

  d = r'{%s}' % ''.join([((',' if i else '') + '\'k{}\':([_x0-9a-z]*)'.format(i + 1)) for i in range(15)])

  k = []

  r = re.search(d, script)

  for i in range(15):

  k.append(r.group(i + 1))

  n = int(v[a.index(re.search(r'arguments;.*?,(.*?)\);', script).group(1))], base=16)

  for i in range(n // 2):

  v[i], v[n - 1 - i] = v[n - 1 - i], v[i]

  for i, b in enumerate(k):

  t = v[a.index(b)].strip('\'')

  names['k{}'.format(i + 1)] = t if len(t) > 2 else t[::-1]

  return names

  def get_encrypt_content(message, key, flag):

  """

  接口參數的加密、解密

  """

  des_obj = des(key.encode(), mode=ECB)

  if flag:

  content = pad(str(message).replace(' ', '').encode())

  return base64.b64encode(des_obj.encrypt(content)).decode('utf-8')

  else:

  return des_obj.decrypt(base64.b64decode(message)).decode('utf-8')

  def get_random_ge(distance):

  """

  生成隨機的軌跡

  """

  ge = []

  y = 0

  v = 0

  t = 1

  current = 0

  mid = distance * 3 / 4

  exceed = 20

  z = t

  ge.append([0, 0, 1])

  while current < (distance + exceed):

  if current < mid / 2:

  a = 15

  elif current < mid:

  a = 20

  else:

  a = -30

  a /= 2

  v0 = v

  s = v0 * t + 0.5 * a * (t * t)

  current += int(s)

  v = v0 + a * t

  y += random.randint(-5, 5)

  z += 100 + random.randint(0, 10)

  ge.append([min(current, (distance + exceed)), y, z])

  while exceed > 0:

  exceed -= random.randint(0, 5)

  y += random.randint(-5, 5)

  z += 100 + random.randint(0, 10)

  ge.append([min(current, (distance + exceed)), y, z])

  return ge

  def make_mouse_action_args(distance):

  """

  生成鼠標行為相關的參數

  """

  ge = get_random_ge(distance)

  args = {

  p['k']['k5']: round(distance / CAPTCHA_DISPLAY_WIDTH, 2),

  p['k']['k6']: get_random_ge(distance),

  p['k']['k7']: ge[-1][-1] + random.randint(0, 100),

  p['k']['k8']: CAPTCHA_DISPLAY_WIDTH,

  p['k']['k9']: CAPTCHA_DISPLAY_HEIGHT,

  p['k']['k11']: 1,

  p['k']['k12']: 0,

  p['k']['k13']: -1,

  'act.os': 'android'

  }

  return args

  def get_distance(fg, bg):

  """

  計算滑動距離

  """

  target = cv2.imdecode(np.asarray(bytearray(fg.read()), dtype=np.uint8), 0)

  template = cv2.imdecode(np.asarray(bytearray(bg.read()), dtype=np.uint8), 0)

  result = cv2.matchTemplate(target, template, cv2.TM_CCORR_NORMED)

  _, distance = np.unravel_index(result.argmax(), result.shape)

  return distance

  def update_protocol(protocol_num, js_uri):

  """

  更新協議

  """

  global p

  r = requests.get(js_uri, verify=False)

  names = find_arg_names(r.text)

  p = {

  'i': protocol_num,

  'k': names

  }

  def conf_captcha(organization):

  """

  獲取驗證碼設置

  """

  url = 'https://captcha.fengkongcloud.com/ca/v1/conf'

  args = {

  'organization': organization,

  'model': 'slide',

  'sdkver': '1.1.3',

  'rversion': '1.0.3',

  'appId': 'default',

  'lang': 'zh-cn',

  'channel': 'YingYongBao',

  'callback': 'sm_{}'.format(int(time.time() * 1000))

  }

  r = requests.get(url, params=args, verify=False)

  resp = json.loads(re.search(r'{}\((.*)\)'.format(args['callback']), r.text).group(1))

  return resp

  def register_captcha(organization):

  """

  注冊驗證碼

  """

  url = 'https://captcha.fengkongcloud.com/ca/v1/register'

  args = {

  'organization': organization,

  'channel': 'DEFAULT',

  'lang': 'zh-cn',

  'model': 'slide',

  'appId': 'default',

  'sdkver': '1.1.3',

  'data': '{}',

  'rversion': '1.0.3',

  'callback': 'sm_{}'.format(int(time.time() * 1000))

  }

  r = requests.get(url, params=args, verify=False)

  resp = json.loads(re.search(r'{}\((.*)\)'.format(args['callback']), r.text).group(1))

  return resp

  def verify_captcha(organization, rid, key, distance):

  """

  提交驗證

  """

  url = 'https://captcha.fengkongcloud.com/ca/v2/fverify'

  args = {

  'organization': organization,

  p['k']['k1']: 'default',

  p['k']['k2']: 'YingYongBao',

  p['k']['k3']: 'zh-cn',

  'rid': rid,

  'rversion': '1.0.3',

  'sdkver': '1.1.3',

  'protocol': p['i'],

  'ostype': 'web',

  'callback': 'sm_{}'.format(int(time.time() * 1000))

  }

  args.update(make_mouse_action_args(distance))

  key = get_encrypt_content(key, 'sshummei', 0)

  for k, v in args.items():

  if len(k) == 2:

  args[k] = get_encrypt_content(v, key, 1)

  print(args)

  r = requests.get(url, params=args, verify=False)

  resp = json.loads(re.search(r'{}\((.*)\)'.format(args['callback']), r.text).group(1))

  return resp

  def get_verify(organization):

  """

  進行驗證

  """

  resp = conf_captcha(organization)

  protocol_num = re.search(r'build/v1.0.3-(.*?)/captcha-sdk.min.js', resp['detail']['js']).group(1)

  if not p.get('id') or protocol_num != p['i']:

  update_protocol(protocol_num, ''.join(['https://', resp['detail']['domains'][0], resp['detail']['js']]))

  resp = register_captcha(organization)

  rid = resp['detail']['rid']

  key = resp['detail']['k']

  domain = resp['detail']['domains'][0]

  fg_uri = resp['detail']['fg']

  bg_uri = resp['detail']['bg']

  fg_url = ''.join(['http://', domain, fg_uri])

  bg_url = ''.join(['http://', domain, bg_uri])

  r = requests.get(fg_url, verify=False)

  fg = BytesIO(r.content)

  r = requests.get(bg_url, verify=False)

  bg = BytesIO(r.content)

  distance = get_distance(fg, bg)

  print(distance)

  r = verify_captcha(organization, rid, key, int(distance / 600 * 310))

  return rid, r

  def test():

  organization = 'RlokQwRlVjUrTUlkIqOg'

  # rid是驗證過程中響應的標示,r是最后提交驗證返回的響應

  rid, r = get_verify(organization)

  print(rid, r)

  # riskLevel為PASS說明驗證通過

  if r['riskLevel'] == 'PASS':

  # 具體可抓包查看,接口:/api/sns/v1/system_service/slide_captcha_check

  pass

  if __name__ == '__main__':

  test()

  大家用同樣的方法趕快試一試小紅書,蘑菇街等網站登陸吧!

tags:
聲明:本站稿件版權均屬千鋒教育所有,未經許可不得擅自轉載。
10年以上業內強師集結,手把手帶你蛻變精英
請您保持通訊暢通,專屬學習老師24小時內將與您1V1溝通
免費領取
今日已有369人領取成功
劉同學 138****2860 剛剛成功領取
王同學 131****2015 剛剛成功領取
張同學 133****4652 剛剛成功領取
李同學 135****8607 剛剛成功領取
楊同學 132****5667 剛剛成功領取
岳同學 134****6652 剛剛成功領取
梁同學 157****2950 剛剛成功領取
劉同學 189****1015 剛剛成功領取
張同學 155****4678 剛剛成功領取
鄒同學 139****2907 剛剛成功領取
董同學 138****2867 剛剛成功領取
周同學 136****3602 剛剛成功領取
相關推薦HOT
主站蜘蛛池模板: 国产精品99| 伊人a.v在线| 80s国产成年女人毛片| 天天夜天干天天爽| 西西人体高清444rt·wang| 九九九精品视频免费| 天堂mv在线免费看| 久久综合九色欧美综合狠狠| 小婷又紧又深又滑又湿好爽| 欧洲成人r片在线观看| 黄色三级电影免费| 欧美三级黄视频| 欧美va在线观看| 日本欧美日韩| 国产精品jvid在线观看| 538精品在线视频| 一边摸一边叫床一边爽| 日本夫妇交换| 成人午夜电影在线| 91精品国产综合久久青草| 日本中文字幕一区二区高清在线 | 污污免费在线观看| 一个色综合高清在线观看| 稚嫩娇小哭叫粗大撑破h| 2015天堂网| 亚洲欧美综合另类| 又大又硬又爽免费视频| 中国美团外卖男男china| 岳一夜要我六次| 中文字幕在线视频免费观看| 538在线精品| 东京久久| 久久精品国产色蜜蜜麻豆| 国产99久久亚洲综合精品| 国产大片在线观看| 亚洲欧美成人日韩| 久久精品日日躁夜夜躁欧美| 一级特黄aaa大片在| 扒开双腿猛进入免费观看美女| 欧美精品国产综合久久| 国产无套护士丝袜在线观看|