吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5042|回复: 13
收起左侧

[Python 转载] 【js逆向】Qfang网的解析与爬取

[复制链接]
helian147 发表于 2021-5-24 16:25
本帖最后由 helian147 于 2021-5-24 17:13 编辑

一、链接的请求逻辑

先用F12进入浏览器控制台看看,直接被debugger糊一脸。还是Fiddler来试试,不能这也不行吧。

看前几个请求,在第三个请求发现了返回的网页数据,往上回溯:

第一个get请求的response返回set-cookie、且返回一个js文件;
第二个get请求为302重定向,URL带参数,response返回新的set-cookie;
第三个get请求,返回HTML内容。

显然,解析js文件,获得第二个请求的URL参数是关键。
各个请求的headers, cookie可以通过requests.Session来保持、传递。
get2.png

get1.png
get3.png




二、js逆向
分析js文件的目的就是获得第二个get请求的URL参数生成逻辑。
【'jsjiami.com.v6'   这是js文件直接提示的加密版本号】

从前面第一步获得js文件保存,格式化,是ob混淆后的一堆s山,要分析出参数生成逻辑不得头秃?
1、先清除浏览器cookie、缓存等数据,进浏览器控制台,有无限debugger挡着,Deactivate Breakpoints先统统禁止掉,此时页面已加载完毕。
debugger被禁止了,自己也没法用插件下debugger了,只能手撕了:

二分法,将各个明显的function都打下断点,然后逐步迫近。首先得下断点在无限debugger之前,多打几个断点,不要钱的。
重新加载页面,被第一个断点断下。
之后,被断下,跳转到_0x305110,执行完,返回;
再次进入_0x305110,执行其内的_x7fc51d(0x0),再次返回;
再次进入_0x305110,执行其内的_x7fc51d(),然后就是无限debugger。

查看884行附近if-else语句,不仅有_x7fc51d(0x0),还有一句_x7fc51d(‘0’)语句未被执行到,这可能是正常运行时的语句。
这个‘0’是哪里赋值的,只要向_x7fc51d输入参数‘0’,就可让其去想去的地方,而不是无限debugger卡着。
_0x459edd,很明显,而_0x459edd就在if语句上头呢: _0x459edd = f _0x7fc51d(_0x3cff02)
验证一下:
console控制台直接输入 _0x3cff02,获得其值正是整数0
console控制台将其值修改为‘0’字符,输入 _0x3cff02 = ‘0’
然后让断点下一步,来到新地方,接着直接跳出第二个get请求。



01.png

02.png

03.png


04.png

2、很明显了,重新来过:
先在上一步跳转的附近多下几个断点;
清除浏览器cookie、缓存,重新加载页面;
为避免反复被debugger,在try语句附近查看_0x3cff02值,为整数0,直接修改赋值为字符‘0’
1023行附近,_0x21f02d变量生成了URL参数,目的达到。


05.png



3、回溯_0x21f02d变量的生成过程
直接往上回溯即可,有两个坑:

var  _0x14e579 , var _0x351708   这个2个变量,每次get获得js文件中的值都不同;
06.png

var _0x4ce3 变量存储了大量变量和函数,一般js逆向时,找到参数的生成过程后,直接扒拉下来相关的js代码,运行即可,包括node,浏览器等都可以运行js代码,这个_0x4ce3扒下来后运行直接是node崩溃、浏览器控制台崩溃,吐血......  替换掉_0x4ce3[]对应的值。

[JavaScript] 纯文本查看 复制代码
function _0xcff1b8(_0x358fd9) {
    var _0x179d92 = {
        'TXsUM': function (_0x2383e2, _0x1de425) {
            return _0x2383e2(_0x1de425);
        },
        'HQeHK': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
        'ZUcpH': function (_0x248b52, _0x5ed497) {
            return _0x248b52 < _0x5ed497;
        },
        'FbBTx': function (_0x36946b, _0x3a2f11) {
            return _0x36946b & _0x3a2f11;
        },
        'jhkwT': function (_0x4e9119, _0xa070d6) {
            return _0x4e9119 == _0xa070d6;
        },
        'WJmPx': function (_0x51583c, _0x5367ea) {
            return _0x51583c !== _0x5367ea;
        },
        'NiLhy': "BVUeB",
        'FjkCX': function (_0x3ddcc5, _0x2b6867) {
            return _0x3ddcc5 >> _0x2b6867;
        },
        'mBHDt': function (_0x2a91d8, _0x228d4f) {
            return _0x2a91d8 << _0x228d4f;
        },
        'aCQPW': function (_0x1306f3, _0x598fc9) {
            return _0x1306f3 & _0x598fc9;
        },
        'Walbv': function (_0x793957, _0x39b61b) {
            return _0x793957 >> _0x39b61b;
        },
        'NWBHv': function (_0x4586db, _0x3a8868) {
            return _0x4586db | _0x3a8868;
        },
        'fBZaG': function (_0x68d10e, _0x3db0c3) {
            return _0x68d10e >> _0x3db0c3;
        },
        'pOsdD': function (_0x1d641f, _0x4f2573) {
            return _0x1d641f & _0x4f2573;
        },
        'atQDi': function (_0x1b239c, _0x21e5f5) {
            return _0x1b239c | _0x21e5f5;
        },
        'WtLrH': function (_0x31fc35, _0x3b7945) {
            return _0x31fc35 << _0x3b7945;
        },
        'pyPRI': function (_0x328d78, _0x36b47f) {
            return _0x328d78 >> _0x36b47f;
        },
        'LVufl': function (_0x1bdb11, _0x337636) {
            return _0x1bdb11 << _0x337636;
        },
        'NNOIu': function (_0x4d3d01, _0x17a933) {
            return _0x4d3d01 & _0x17a933;
        },
        'OIfGa': function (_0xf3dd18, _0x7f485e) {
            return _0xf3dd18 & _0x7f485e;
        }
    };
    var _0xfed051 = _0x179d92['HQeHK']; 
    var _0x2139d5 = _0x358fd9["length"]; // _0x4ce3
    var _0x10071f = '';
    for (var _0x23e584 = 0x0; _0x179d92['ZUcpH'](_0x23e584, _0x2139d5); ) {
        var _0x2fa93b = _0x179d92['FbBTx'](_0x358fd9["charCodeAt"](_0x23e584++), 0xff);
        if (_0x179d92["jhkwT"](_0x23e584, _0x2139d5)) {
            if (_0x179d92["WJmPx"](_0x179d92["NiLhy"], _0x179d92["NiLhy"])) {
                _0x179d92["TXsUM"](result, '0');
            } else {
                _0x10071f += _0xfed051["charAt"](_0x179d92["FjkCX"](_0x2fa93b, 0x2));
                _0x10071f += _0xfed051["charAt"](_0x179d92["mBHDt"](_0x179d92["aCQPW"](_0x2fa93b, 0x3), 0x4));
                _0x10071f += '==';
                break;
            }
        }
        var _0x3a4809 = _0x358fd9["charCodeAt"](_0x23e584++);       
        if (_0x179d92["jhkwT"](_0x23e584, _0x2139d5)) {           
            _0x10071f += _0xfed051["charAt"](_0x179d92["Walbv"](_0x2fa93b, 0x2));             
            _0x10071f += _0xfed051["charAt"](_0x179d92["NWBHv"](_0x179d92["mBHDt"](_0x179d92["aCQPW"](_0x2fa93b, 0x3), 0x4), _0x179d92["fBZaG"](_0x179d92["aCQPW"](_0x3a4809, 0xf0), 0x4)));            
            _0x10071f += _0xfed051["charAt"](_0x179d92["mBHDt"](_0x179d92["pOsdD"](_0x3a4809, 0xf), 0x2));            
            _0x10071f += '=';
            break;
        }
        var _0x3e2d13 = _0x358fd9["charCodeAt"](_0x23e584++);
        _0x10071f += _0xfed051["charAt"](_0x179d92["fBZaG"](_0x2fa93b, 0x2));
        _0x10071f += _0xfed051["charAt"](_0x179d92["atQDi"](_0x179d92["WtLrH"](_0x179d92["pOsdD"](_0x2fa93b, 0x3), 0x4), _0x179d92["pyPRI"](_0x179d92["pOsdD"](_0x3a4809, 0xf0), 0x4)));
        _0x10071f += _0xfed051["charAt"](_0x179d92["atQDi"](_0x179d92["LVufl"](_0x179d92["NNOIu"](_0x3a4809, 0xf), 0x2), _0x179d92["pyPRI"](_0x179d92["NNOIu"](_0x3e2d13, 0xc0), 0x6)));
        _0x10071f += _0xfed051["charAt"](_0x179d92["OIfGa"](_0x3e2d13, 0x3f));
    }
    return _0x10071f;
}


var args = process.argv.splice(2);
console.log(_0xcff1b8(args[0]));



三、python爬取数据
解析后,python代码就好办了。
[Python] 纯文本查看 复制代码
import requests
from lxml import etree
import time
import re 
from subprocess import check_output

headers = { 
    "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36',
    'Host':'shenzhen.qfang.com',
    'Connection': 'keep-alive'
    }


def c_0x25d6be(a, b):
    j = 0
    for i in range(0, len(a)):
        j += ord(a[i])
    j *= int(b)
    j += 0x1b207
    str_wzws = "WZWS_CONFIRM_PREFIX_LABEL" + str(j)
    print(str_wzws)
    return str_wzws


# 由于有302重定向,以Session保持、传递response的set-cookie
s = requests.Session()

# 第一次get请求:js文件中的2个变量值提取、计算得出第二次get的url参数
url = 'https://shenzhen.qfang.com/sale'
rsp_1 = s.get(url=url, headers=headers)

rsp_1_0x14e579 = re.findall(r"_0x14e579='(.*?)';" ,rsp_1.text)[0]
rps_1_0x351708 = re.findall(r"_0x351708='(.*?)';" ,rsp_1.text)[0]
str_wzws = c_0x25d6be(rsp_1_0x14e579, rps_1_0x351708)

# process模块的check_output, 以命令行运行node
js_open = check_output(['node', r'd:\new-3.js', str_wzws], timeout=100)
url_path = js_open.decode('utf8').strip()
print(url_path)
time.sleep(1)


# 第二次get请求:
headers.update({'Referer':'https://shenzhen.qfang.com/sale'})

url_2 = 'https://shenzhen.qfang.com/WZWSREL3NhbGU=?wzwschallenge={0}'.format(url_path)
rsp_2 = s.get(url=url_2, headers=headers)
time.sleep(1)


# 第三次get请求:解析response获得数据
rsp_3 = s.get(url=url, headers=headers)
selector = etree.HTML(rsp_3.text)
x = selector.xpath('/html/body/div[4]/div/div[1]/div[4]/ul/li[1]/div[2]/div[1]/a/text()')
print(x)

get-final.png

免费评分

参与人数 4吾爱币 +8 热心值 +4 收起 理由
jenson1 + 1 + 1 &amp;lt;font style=&amp;quot;vertical-align: inherit;&amp;quot;&amp;gt;&amp;lt;font style=
肌肉书生 + 1 + 1 我很赞同!
wushaominkk + 5 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
ricohrh + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

⊙⌒⊙ 发表于 2021-5-25 10:05
get 换成了post,立即就出来了,这是为什么呀???为什么呀???求解原理!
涛之雨 发表于 2021-5-24 21:09
[JavaScript] 纯文本查看 复制代码
var _0x500dd8 = '/WZWSREL3NhbGU=';
var _0x14e579 = '#IPP)&93(;Q]V!Yaz';
var _0x351708 = '4231';
var _0x41f35b = 'WZWS_METHOD';
var _0x349042 = 'WZWS_PARAMS';

function _0xcff1b8(_0x358fd9) {
  var _0xfed051 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  var _0x2139d5 = _0x358fd9.length;
  var _0x10071f = '';

  for (var _0x23e584 = 0; _0x23e584 < _0x2139d5;) {
    var _0x2fa93b = _0x358fd9.charCodeAt(_0x23e584++) & 255;

    if (_0x23e584 == _0x2139d5) {
      _0x10071f += _0xfed051.charAt(_0x2fa93b >> 2);
      _0x10071f += _0xfed051.charAt((_0x2fa93b & 3) << 4);
      _0x10071f += '==';
      break;
    }

    var _0x3a4809 = _0x358fd9.charCodeAt(_0x23e584++);

    if (_0x23e584 == _0x2139d5) {
      _0x10071f += _0xfed051.charAt(_0x2fa93b >> 2);
      _0x10071f += _0xfed051.charAt((_0x2fa93b & 3) << 4 | (_0x3a4809 & 240) >> 4);
      _0x10071f += _0xfed051.charAt((_0x3a4809 & 15) << 2);
      _0x10071f += '=';
      break;
    }

    var _0x3e2d13 = _0x358fd9.charCodeAt(_0x23e584++);

    _0x10071f += _0xfed051.charAt(_0x2fa93b >> 2);
    _0x10071f += _0xfed051.charAt((_0x2fa93b & 3) << 4 | (_0x3a4809 & 240) >> 4);
    _0x10071f += _0xfed051.charAt((_0x3a4809 & 15) << 2 | (_0x3e2d13 & 192) >> 6);
    _0x10071f += _0xfed051.charAt(_0x3e2d13 & 63);
  }

  return _0x10071f;
}

function _0x2a8db4(_0x589677) {
  var _0x98cb2b = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);

  var _0x5cf96d = _0x589677.length;
  var _0xc6e80d = '';

  for (var _0x145031 = 0; _0x145031 < _0x5cf96d;) {
    var _0x3f81b5, _0x1ac542, _0x3f8231, _0x3661aa;

    do {
      _0x3f81b5 = _0x98cb2b[_0x589677.charCodeAt(_0x145031++) & 255];
    } while (_0x145031 < _0x5cf96d && _0x3f81b5 == -1);

    if (_0x3f81b5 == -1) break;

    do {
      _0x1ac542 = _0x98cb2b[_0x589677.charCodeAt(_0x145031++) & 255];
    } while (_0x145031 < _0x5cf96d && _0x1ac542 == -1);

    if (_0x1ac542 == -1) break;
    _0xc6e80d += String.fromCharCode(_0x3f81b5 << 2 | (_0x1ac542 & 48) >> 4);

    do {
      _0x3f8231 = _0x589677.charCodeAt(_0x145031++) & 255;
      if (_0x3f8231 == 61) return _0xc6e80d;
      _0x3f8231 = _0x98cb2b[_0x3f8231];
    } while (_0x145031 < _0x5cf96d && _0x3f8231 == -1);

    if (_0x3f8231 == -1) break;
    _0xc6e80d += String.fromCharCode((_0x1ac542 & 15) << 4 | (_0x3f8231 & 60) >> 2);

    do {
      _0x3661aa = _0x589677.charCodeAt(_0x145031++) & 255;
      if (_0x3661aa == 61) return _0xc6e80d;
      _0x3661aa = _0x98cb2b[_0x3661aa];
    } while (_0x145031 < _0x5cf96d && _0x3661aa == -1);

    if (_0x3661aa == -1) break;
    _0xc6e80d += String.fromCharCode((_0x3f8231 & 3) << 6 | _0x3661aa);
  }

  return _0xc6e80d;
}

function _0x13698a() {
  var _0x338d15 = 0;
  var _0xbe152f = 0;

  for (_0xbe152f = 0; _0xbe152f < _0x14e579.length; _0xbe152f++) {
    _0x338d15 += _0x14e579.charCodeAt(_0xbe152f);
  }

  _0x338d15 *= _0x351708;
  _0x338d15 += 111111;
  return "WZWS_CONFIRM_PREFIX_LABEL" + _0x338d15;
}

function _0x1eb786(_0x180717, _0x349042) {
  var _0x49b27c = document.createElement("form");

  _0x49b27c.action = _0x180717;
  _0x49b27c.method = "post";
  _0x49b27c.style.display = "none";

  var _0x48c71a = _0x2a8db4(_0x349042);

  if (_0x48c71a.search('=') != -1) {
    var _0xce49ba = _0x48c71a.split('&');

    for (var _0x125e40 = 0; _0x125e40 < _0xce49ba.length; _0x125e40++) {
      var _0x45f660 = document.createElement("textarea");

      var _0x2409cd = _0xce49ba[_0x125e40];

      var _0x25642e = _0x2409cd.split('=');

      _0x45f660.name = _0x25642e[0];
      _0x45f660.value = _0x25642e[1];

      _0x49b27c.appendChild(_0x45f660);
    }
  }

  document.body.appendChild(_0x49b27c);

  _0x49b27c.submit();

  return _0x49b27c;
}

!function submit_answer() {
  var _0x59fc72 = _0x13698a();

  var _0x25d6be = _0xcff1b8(_0x59fc72.toString());

  var _0x21f02d = _0x500dd8 + "?wzwschallenge=" + _0x25d6be;

  if (_0x41f35b == "post") {
    _0x1eb786(_0x21f02d, _0x349042);
  } else {
    window.location = _0x21f02d;
  }
}();


源码大概是这样,可以对照看一下
986244073 发表于 2021-5-24 21:08
Nemoris丶 发表于 2021-5-24 21:36
针对这个解迷,你其实可以试试用post请求看看,你会发现新天地。好像这种加密的,跟换了post请求后全部都失效了

免费评分

参与人数 3吾爱币 +3 热心值 +2 收起 理由
大侠在路上 + 1 我很赞同!
liu101816 + 1 + 1 我很赞同!
helian147 + 1 + 1 谢谢@Thanks!

查看全部评分

 楼主| helian147 发表于 2021-5-24 21:44
感谢大佬!

这种以代码生成的无限debuger,能有比较简单方便的方法绕过吗?
如能过了这个debuger,利用CC11001100的下断点来追踪URL参数,就会很快定位参数的生成位置了吧
【https://github.com/CC11001100/crawler-js-hook-framework-public】

 楼主| helian147 发表于 2021-5-24 21:52
本帖最后由 helian147 于 2021-5-24 21:54 编辑
Nemoris丶 发表于 2021-5-24 21:36
针对这个解迷,你其实可以试试用post请求看看,你会发现新天地。好像这种加密的,跟换了post请求 ...

我......发现了什么???

[Python] 纯文本查看 复制代码
import requests
from lxml import etree

headers = { 
    "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36',
    'Host':'shenzhen.qfang.com',
    'Connection': 'keep-alive'
    }

url = 'https://shenzhen.qfang.com/sale'
rsp_3 = requests.post(url=url, headers=headers)
selector = etree.HTML(rsp_3.text)
x = selector.xpath('/html/body/div[4]/div/div[1]/div[4]/ul/li[1]/div[2]/div[1]/a/text()')
print(x)


post-jiemi.png

太神奇了,服务器那边肿了么? 感谢感谢,哈哈哈
8814202 发表于 2021-5-25 00:10
Q房网员工路过
xixicoco 发表于 2021-5-25 01:43
呵呵,感谢各位大佬出手干饭
鸭子咯咯哒~ 发表于 2021-5-25 06:11
helian147 发表于 2021-5-24 21:52
我......发现了什么???

[mw_shl_code=python,true]import requests

请求头什么参数都能设置吗
 楼主| helian147 发表于 2021-5-25 08:02
鸭子咯咯哒~ 发表于 2021-5-25 06:11
请求头什么参数都能设置吗

URL参数, 请求头里的参数, POST请求的data表单参数,代{过}{滤}理设置proxyies,证书验证verify,这些都有自己的设置。

请求头headers,服务器需要验证request的哪些参数,就在headers里面设置哪些参数,具体会有哪些参数,可以用浏览器的控制台、postman、fiddler等工具查看、验证。

所以你的疑问太笼统。
如果为了让服务器返回我们需要的response数据,那要按服务器的request要求设置。
如果是试探服务器漏洞,那随便设置,只要请求数据能发出去。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 16:00

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表