吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 13195|回复: 41
收起左侧

[Web逆向] 某高考志愿信息网站爬虫分析

  [复制链接]
AnonymousQsh 发表于 2020-2-5 15:11

近日, 对于某高考志愿信息网站写了一个爬虫, 遇到了一些问题, 在这里记录一下, 顺便学到了一些反爬虫的技巧.

获取每个学校的分数线情况, 首先在浏览器查看所有请求, 找到获取数据的请求, 但是可以发现他这个请求回来的某些数据应该是经过加密的.

CleanShot 2020-02-05 at 07.24.06.png

这个解密代码一定在客户端, 因此我们找找, 看看能不能找到解密的代码. 首先我们添加请求断点, 看看能有什么突破.

CleanShot 2020-02-05 at 07.41.08.png

接下来触发请求, 我们来看一下Call Stack中的信息, 经过排查, 我们可以发现如下重要的函数:

CleanShot 2020-02-05 at 07.44.41.png

通过查找源码, 我们找到上面的那个函数的源码, 这里代码没经过压缩和混淆, 因此可读性是真的好, 太良心了. 我们可以发现其中的两个关键的函数showNumbercnDeCrypt, 猜测应该是这两个函数完成的对于参数的解密

CleanShot 2020-02-05 at 07.48.44.png

直接在这些函数下断点, 来看看具体的调用, 我们可以发现showNumber的代码非常简单, 这里就不解释了.

CleanShot 2020-02-05 at 07.54.34.png

接下来是cnDeCrypt, 这个函数看起来比较复杂, 实际上, 可以直接复制代码到控制台, 这个是可以直接执行的, 简单分析一下可以知道他调用了split()forEach两个函数
CleanShot 2020-02-05 at 07.56.49.png
CleanShot 2020-02-05 at 08.00.02.png
CleanShot 2020-02-05 at 08.04.54.png

在这里, 简单翻译一下这段代码吧, 到这里, 这个函数的作用就十分明显了.

var _cnDeCrypt = function (zlVjhiyMm1) {
    var YB2 = "";
    zlVjhiyMm1.split("|").forEach(function ($lvd3) {
        if ($lvd3.search(/【(.*?)】/) !== -1) {
            YB2 += $lvd3.replace('【', '').replace('】', '');
        } else {
            $lvd3 = $lvd3.replace(/[g-t]/ig, "");
            YB2 += "\x26\x23\x78" + $lvd3 + "\x3b"
        }
    });
    return YB2
}

最后我们可以发现, 最终返回的是html编码, 但是这个和数据好像并不一样, 我们审查元素来看看, 发现其内容是看不懂的内容, 这里感觉应该是采用了字体加密

CleanShot 2020-02-05 at 08.07.20.png

我们通过请求搜索一下字体文件, 我们可以发现如下的可疑文件, 利用FontEditor, 来查看一下.

CleanShot 2020-02-05 at 08.24.02.png

首先打开数字来看看, 字符串和数字差不多, 在这里就不截图展示了.

CleanShot 2020-02-05 at 08.26.53.png

这个手动写一个字典吧, 我没找到好的解决方案, 反正这个也不多, 有大佬有好的方案可以告诉我, 我是截图然后识别的.

from fontTools.ttLib import TTFont

def get_number_dict():
    font = TTFont('./number_a.woff')
    keys = font['glyf'].keys()
    values = list("    6920714538")
    return dict((k, v) for k, v in zip(keys, values))

def get_string_dict():
    font = TTFont('./cn_5.woff')
    keys = font['glyf'].keys()
    values = list(
        "    像艺包据印探及营命历曲服机境械磁飞食备植空武设水居油洋测纽统件软轻美丁下与世业丝中主义乌书事互交产人仪价休会伤伦估体作供侦俄保信修健儿光克党全公共关兵其军农准减出分划则别制刷力功加务动助劳化医华卫发古史司合告品商回国土地型培声大天女媒子学安定宝实审室家宾密小少尔展属嵌工市师广应康建开录形影律微德心情想感成战房技投护报拉控推播收放政教数文料斯无日时景智术材村来查正民气污河治法泰海源灾炸然照爆版物环班理生用画界疗监知石研种科秘移程税立筑算管类精纺组织经网职育能自航船英草葡萄行表装观规视计论评识译试语财质资路车轨轮运通造采量金鉴间非韩项预饰馆验高麻()0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
    return dict((k, v) for k, v in zip(keys, values))

直接下载字体文件, 然后生成对应的字典. 对于数字和字符串解密的函数, 这里有两种方案:

  1. 利用Python重写js代码, 这个代码逻辑也不复杂, 不难实现

  2. 直接利用Python解析JS代码, 因为我比较懒, 所以采用的第二种方案.

def show_number(string="o6onqsf732|oipr72hef1|g6htsfn732"):
    code = """var showNumber = function(myNumbers) {
        var ns = [];
        myNumbers.split("|").forEach(function(value) {
            value = value.replace(/[g-t]/ig, "");
            ns.push(value);
        });
        return ns
    }
    """
    ctx = execjs.compile(code)
    return ctx.call('showNumber', string)

def cn_decrypt(string="gmcl6ak5|gsc6gl74|c6nktgda"):
    code = """
    var _cnDeCrypt = function (zlVjhiyMm1) {
        var YB2 = "";
        var string_list = [];
        zlVjhiyMm1['\x73\x70\x6c\x69\x74']("\x7c")['\x66\x6f\x72\x45\x61\x63\x68'](function ($lvd3) {
            if ($lvd3['\x73\x65\x61\x72\x63\x68'](/【(.*?)】/) != -1) {
                YB2 += $lvd3['\x72\x65\x70\x6c\x61\x63\x65']("\u3010", "")['\x72\x65\x70\x6c\x61\x63\x65']("\u3011", "")
                string_list.push($lvd3['\x72\x65\x70\x6c\x61\x63\x65']("\u3010", "")['\x72\x65\x70\x6c\x61\x63\x65']("\u3011", ""));
            } else {
                $lvd3 = $lvd3['\x72\x65\x70\x6c\x61\x63\x65'](/[g-t]/ig, "");
                YB2 += "\x26\x23\x78" + $lvd3 + "\x3b"
                string_list.push("\x26\x23\x78" + $lvd3 + "\x3b")
            }
        });
        return string_list
    }
    """
    ctx = js2py.eval_js(code)
    string_list = ctx.call('_cnDeCrypt', string)
    ret = ''
    string_dict = get_string_dict()
    for string in string_list:
        if string.startswith('&#x'):
            ret += string_dict['uni' + string.replace('&#x', '').replace(';', '').upper()]
        else:
            ret += string
    return ret

在这里, 我修改了部分js的代码, 便于python解析, 网站本身的代码我就不完整的贴上来了, 前面的截图都有. 在这里有一个坑, 如果用execjs遇到转义字符会有问题, 当然这个代可以手动吧转义代码去掉, 或者用另一个库js2py.

到这里, 返回数据的解密就完成了, 下面我们来看一看请求的参数是如何加密的.

采用之前的方案, 在url处下断点, 查看找到关键函数, 我们可以发现这里调用是youzyEpt这个函数进行的加密

CleanShot 2020-02-05 at 11.21.07.png

从源码中找到这个函数, 先来看看.

CleanShot 2020-02-05 at 11.28.34.png

显然这里采用的AES进行的加密, 这么明显, 不过多解释了, 我们来看一下他的密钥是怎么得到的, 查看源码, 发现3个关键文件

CleanShot 2020-02-05 at 11.43.19.png

读一下代码, 不难发现密钥是: [11, 23, 32, 43, 45, 46, 67, 8, 9, 10, 11, 12, 13, 14, 15, 16], 下面我们直接用Python写加密算法吧, 因为我不想引入js的aes加密算法了, 调用js还麻烦.

from Crypto.Cipher import AES

def params_encrypt(data):
    key = bytes([11, 23, 32, 43, 45, 46, 67, 8, 9, 10, 11, 12, 13, 14, 15, 16])
    txt = str(json.dumps(data)).encode(encoding='utf-8')
    ctr = Counter.new(128, initial_value=5)
    cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
    data = cipher.decrypt(txt)
    return b2a_hex(data).decode(encoding='utf-8'

写完之后, 让我们下断点测试一下代码是否正确.

CleanShot 2020-02-05 at 14.32.50.png

CleanShot 2020-02-05 at 14.36.47.png

对于密钥的获取, 如果不想读代码的话, 可以直接通过断点解决.

CleanShot 2020-02-05 at 14.39.14.png

这样就完成了对于请求的加密和解密.

在这里讲一个小技巧, 如果请求的js文件后面有类似于v=timestamps等代码, 在source下断点之后, 刷新页面断点会消失.

CleanShot 2020-02-05 at 14.46.18.png

可以采用代{过}{滤}理软件将其代{过}{滤}理到本地, 然后硬编码debugger这样就可以刷新也可以保持断点了. 在这里我用的Charles, 找到对应的url, 右键map local, 然后配置一下就可以了.

CleanShot 2020-02-05 at 14.48.29.png

总结

对于这个网站, 代码几乎没有混淆和压缩, 因此读起来还是十分愉悦的, 对于调试, 如果在请求js的后面添加v=timestamps等类似的东西的话, 下完断点之后, 重新请求会消失, 可以采用代{过}{滤}理软件, 把这些东西代{过}{滤}理到本地, 添加debugger下断点来进行调试.

本教程仅可作为研究学习为目的, 请勿用作其他用途.

CleanShot 2020-02-05 at 07.42.00.png

免费评分

参与人数 13威望 +1 吾爱币 +31 热心值 +12 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
杀猪用牛刀 + 1 + 1 精彩
xzl2021 + 1 + 1 用心讨论,共获提升!
DarkTourist + 1 + 1 热心回复!
K14965 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
sunnylds7 + 1 + 1 热心回复!
Fuung + 1 + 1 用心讨论,共获提升!
撸冰花 + 1 + 1 热心回复!
rhinorhino + 1 + 1 谢谢@Thanks!
这是追求不是梦 + 1 + 1 热心回复!
hh_z_l + 1 + 1 热心回复!
处女-大龙猫 + 1 谢谢@Thanks!
lookerJ + 1 + 1 用心讨论,共获提升!

查看全部评分

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

hackbase 发表于 2020-2-5 15:51
关乎无数考生的命运,慎重慎重~~希望楼主能主动帮助某网站完成加密升级!
天天涨停天天盈 发表于 2020-2-5 15:20
求个成品  或者 分享下数据噢~     谢谢                     
hnwang 发表于 2020-2-5 15:47
q510 发表于 2020-2-5 16:02
谢谢LZ分享
威风的黑龙 发表于 2020-2-5 16:03
有了这个报名就更加科学了,不会说人多得挤一个名额
hicodecn 发表于 2020-2-5 16:15
消息楼主分享
HighBox 发表于 2020-2-5 17:21
某网站指的是?
yhlz 发表于 2020-2-5 17:42
谢谢分享  牛逼
0neS1e 发表于 2020-2-5 17:46
没看懂到底要爬什么   之前的分数线也没啥用
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-4-23 16:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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