爬虫笔记41之反爬系列四:字体反爬、JS反爬

一、字体反爬
1、什么是字体反爬?
开发者创作了一种字体(字体代号);网页中显示的就是这种字体代号。
字体反爬也叫CSS反爬,就是因为这个字体是隐藏在我们css文件当中的一个.ttf文件。
​2、如何解决字体反爬?(思路:先获取这些文本内容,然后在解决字体的问题)
(1)先找到.ttf文件,需并把它转换成xml文件;
(2)分析xml文件 + FontCreator(360应用市场搜索下载即可);
(3) 找出字体对应的映射关系,和真实的字体做替换。

3、案例
需求:爬取文字字体内容
思路:我们先获取这些文本内容,然后在解决字体的问题。

​目标url https://club.autohome.com.cn/bbs/thread/665330b6c7146767/80787515-1.html
第一步 页面分析
​(1)爬取要素是否在网页源码中:
在这里插入图片描述
(2)文本内容://div[@class=“tz-paragraph”]
在这里插入图片描述
第二步 实现步骤
(1)获取文本内容:
在这里插入图片描述
我们猜测:\uedb8 → 大 ;\ueca3 → 了
(2)解决字体问题:
右键查看网页源码,ctrl+f,搜索ttf,得到一个url连接(//k3.autoimg.cn/g1/M02/D0/99/wKgHFVsUz1eAH_VRAABj9PS-ubk57…ttf)
在这里插入图片描述
我们打开这个连接,下载得到ttf文件:
在这里插入图片描述
我们可以在FontCreator中打开这个ttf文件,如下图:(后面构建字体列表的顺序就是由此而来)
在这里插入图片描述

接着我们通过fontTools模块将ttf文件保存为xml文件,在这里插入图片描述
并在sublime中打开查看该文件:
在这里插入图片描述
我们接下来:

  • 构建编码列表
  • 构建字体列表
  • 编码与字体一一对应做替换
    在这里插入图片描述
    补充:
    python内置函数:eval()
    eval() 函数用来执行一个字符串表达式,并返回表达式的计算结果。
    语法:eval(expression[, globals[, locals]])
    参数
    expression – 表达式。
    globals – 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
    locals – 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。

完整代码:

import requests
from lxml import etree
from fontTools.ttLib import TTFont # pip install fontTools

url = 'https://club.autohome.com.cn/bbs/thread/665330b6c7146767/80787515-1.html'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36'
}

res = requests.get(url,headers=headers)
res_html = res.text

html = etree.HTML(res_html)
content_list = html.xpath('//div[@class="tz-paragraph"]//text()')
content_str = ''.join(content_list)
# print(content_list)

# 打开.ttf文件 
font = TTFont('wKgHFVsUz1eAH_VRAABj9PS-ubk57..ttf')
# 保存为.xml文件
# font.saveXML('fonts.xml')

# 构建编码列表 
uniList = font.getGlyphOrder()	#在font文件当中找到name所对应的值
uni_lst = []	# uniEDB8 -- > \uedb8
for i in uniList[1:]:
    r = eval(r"'\u" + i[3:] + "'")
    uni_lst.append(r)

#构建字体列表
word_list = ['很', '五', '多', '远', '大', '十', '更', '了', '的', '矮', '不', '少', '九', '三', '八', '一', '右', '坏', '近', '着', '呢', '左', '是', '长', '六', '上', '短', '七', '高', '二', '得', '好', '下', '和', '四', '地', '小', '低']

# 替换
for i in range(len(word_list)):
    content_str = content_str.replace(uni_lst[i],word_list[i])
print(content_str)

二、JS反爬
js反爬,它的分析流程和处理流程都是非常复杂和漫长

如何学习js反爬?
(1) 精通JS语言(你能够熟知js这门语言的基本语法)
(2)精通JS中常见的加密算法(并不一定都是算法)
(3)套路经验(调试JS代码)

1、 环境搭建
(1)node.js开发环境(在https://nodejs.org/en/download/下载)
(2) 准备js调试工具 (发条js调试工具)
(3)安装一个PyeXECjs模块: pip install PyeXECjs

2、 JS中常见的算法(自己拓展)
(1)md5加密算法 线性散列算法 可以产出一个128位的散列值 用于确保信息传输完整的一致性
经过md5加密后产生的是一个固定长度的数据(32位、16位)

(2) DES/AES加密
统称为 对称加密 : 加密运算和解密运算使用的是同样的密钥
密钥:一组随机的字符串
对称的意思可以理解成:锁门和开门的都是同一把钥匙

AES/DES的区别

  • 加密后的密文长度不同
    DES加密后的密文长度是8的整数倍
    AES加密后端密文长度是16的整数倍
  • 应用场景不同
    一般的企业用DES足够
    需求更高可以使用AES
    留意字眼:encrypt() 加密、 decrypt()解密

    (3)RSA加密
    非对称加密:有2个密钥
  • 公开密钥(publickey 公钥)
  • 私有密钥(privatekey 私钥)
    公钥和私钥是一对 ,如果用对应的公钥进行加密只有用对应的私钥才可以进行解密

    留意字眼:setPublickey() 、setPrivateKey()



第三个 案例
微信公众平台js算法逆向
问题描述:
在这里插入图片描述
实际我们输入的是123456,而pwd却是一串由字母和数字组成的32位‘密文’
在这里插入图片描述
那么,我们要怎样逆向的把这串密文解析得到123456呢?也就是如何解决: 密码js逆向的问题。
答案是:我们要结合断点,来进行一些相关的测试以及调试

步骤:
(1)经过分析我们要找的关键字是pwd (不要全局搜索,因为全局搜索不可以打断点)
在这里插入图片描述
通过点击 search选项 搜索关键字pwd 我们发现了一个loginpagexxx.js数据
(2)点击上图蓝色数据,并点击{}进行格式化
在这里插入图片描述
然后ctrl+f继续搜索关键字pwd,得到有20个这样的字段:
在这里插入图片描述
(3)打断点
我们浏览上述20个字段,有可疑的我们就打断点(即点击该行)
在这里插入图片描述
备注:记住,js逆向中看到get/set,什么作用都没有,不需要在这里打断点。
(4)再次点击登录,发现断点停留在1269行,如下图:
在这里插入图片描述
所以,该行的u函数,就是实现密码加密的。
(5)点击进入到u函数,如下图,直接就跳转到了黄色部分,
在这里插入图片描述
我们又看到一个函数function(t,e,n),其返回的就是我们的密文。
也就是说,我们执行函数function就能得到对应的密文。

(6)复制整个function函数,标志是花括号{}(js中对函数的定义的标志是花括号)
在这里插入图片描述
(7)点击上图左下角的加载代码,发现报错:n未定义
在这里插入图片描述
也就相当于没有定义变量,为此,我们在调试工具的首行加上一句代码: var n = {}
再加载代码。

(8)在调试工具中修改代码,并调用得到结果:

补充:
(9)如何在python中实现js逆向的逻辑,即execjs模块的使用:
①首先将调试工具中的代码完整的复制粘贴到js文件中(也就是保存文件时,后缀是.js),如下图:
在这里插入图片描述
②和上述js文件同目录下新建一个py文件,具体内容如下:
在这里插入图片描述
(10)eval() 函数的作用:
在这里插入图片描述

总结:
1 经过分析我们要找的关键字是pwd (不要全局搜索,因为全局搜索不可以打断点)
逐个js文件分析,关注 login字眼

2 分析调试Js代码
可以把怀疑的代码打断点 进行测试
通过断点测试 定位出相应的可能做了Js加密的逻辑

3 点击看一下它的内部实现
经过分析 测试我们需要哪些 Js逻辑代码

4 通过Js代码调试工具 不断的尝试 保证js语法没有错误

附:

import execjs

node = execjs.get()
ctx = node.compile(open('wechat.js',encoding='utf-8').read())

funcName = 'getPwd("123456")'
pwd = ctx.eval(funcName)
print(pwd)

var n = {}
function l(t, e) {
var n = (65535 & t) + (65535 & e);
return (t >> 16) + (e >> 16) + (n >> 16) << 16 | 65535 & n
}
function a(t, e, n, o, r, i) {
return l((s = l(l(e, t), l(o, i))) << (a = r) | s >>> 32 - a, n);
var s, a
}
function f(t, e, n, o, r, i, s) {
return a(e & n | ~e & o, t, e, r, i, s)
}
function d(t, e, n, o, r, i, s) {
return a(e & o | n & ~o, t, e, r, i, s)
}
function h(t, e, n, o, r, i, s) {
return a(e ^ n ^ o, t, e, r, i, s)
}
function m(t, e, n, o, r, i, s) {
return a(n ^ (e | ~o), t, e, r, i, s)
}
function c(t, e) {
t[e >> 5] |= 128 << e % 32,
t[14 + (e + 64 >>> 9 << 4)] = e;
var n, o, r, i, s, a = 1732584193,
c = -271733879,
u = -1732584194,
p = 271733878;
for (n = 0; n < t.length; n += 16) a = f(o = a, r = c, i = u, s = p, t[n], 7, -680876936),
p = f(p, a, c, u, t[n + 1], 12, -389564586),
u = f(u, p, a, c, t[n + 2], 17, 606105819),
c = f(c, u, p, a, t[n + 3], 22, -1044525330),
a = f(a, c, u, p, t[n + 4], 7, -176418897),
p = f(p, a, c, u, t[n + 5], 12, 1200080426),
u = f(u, p, a, c, t[n + 6], 17, -1473231341),
c = f(c, u, p, a, t[n + 7], 22, -45705983),
a = f(a, c, u, p, t[n + 8], 7, 1770035416),
p = f(p, a, c, u, t[n + 9], 12, -1958414417),
u = f(u, p, a, c, t[n + 10], 17, -42063),
c = f(c, u, p, a, t[n + 11], 22, -1990404162),
a = f(a, c, u, p, t[n + 12], 7, 1804603682),
p = f(p, a, c, u, t[n + 13], 12, -40341101),
u = f(u, p, a, c, t[n + 14], 17, -1502002290),
a = d(a, c = f(c, u, p, a, t[n + 15], 22, 1236535329), u, p, t[n + 1], 5, -165796510),
p = d(p, a, c, u, t[n + 6], 9, -1069501632),
u = d(u, p, a, c, t[n + 11], 14, 643717713),
c = d(c, u, p, a, t[n], 20, -373897302),
a = d(a, c, u, p, t[n + 5], 5, -701558691),
p = d(p, a, c, u, t[n + 10], 9, 38016083),
u = d(u, p, a, c, t[n + 15], 14, -660478335),
c = d(c, u, p, a, t[n + 4], 20, -405537848),
a = d(a, c, u, p, t[n + 9], 5, 568446438),
p = d(p, a, c, u, t[n + 14], 9, -1019803690),
u = d(u, p, a, c, t[n + 3], 14, -187363961),
c = d(c, u, p, a, t[n + 8], 20, 1163531501),
a = d(a, c, u, p, t[n + 13], 5, -1444681467),
p = d(p, a, c, u, t[n + 2], 9, -51403784),
u = d(u, p, a, c, t[n + 7], 14, 1735328473),
a = h(a, c = d(c, u, p, a, t[n + 12], 20, -1926607734), u, p, t[n + 5], 4, -378558),
p = h(p, a, c, u, t[n + 8], 11, -2022574463),
u = h(u, p, a, c, t[n + 11], 16, 1839030562),
c = h(c, u, p, a, t[n + 14], 23, -35309556),
a = h(a, c, u, p, t[n + 1], 4, -1530992060),
p = h(p, a, c, u, t[n + 4], 11, 1272893353),
u = h(u, p, a, c, t[n + 7], 16, -155497632),
c = h(c, u, p, a, t[n + 10], 23, -1094730640),
a = h(a, c, u, p, t[n + 13], 4, 681279174),
p = h(p, a, c, u, t[n], 11, -358537222),
u = h(u, p, a, c, t[n + 3], 16, -722521979),
c = h(c, u, p, a, t[n + 6], 23, 76029189),
a = h(a, c, u, p, t[n + 9], 4, -640364487),
p = h(p, a, c, u, t[n + 12], 11, -421815835),
u = h(u, p, a, c, t[n + 15], 16, 530742520),
a = m(a, c = h(c, u, p, a, t[n + 2], 23, -995338651), u, p, t[n], 6, -198630844),
p = m(p, a, c, u, t[n + 7], 10, 1126891415),
u = m(u, p, a, c, t[n + 14], 15, -1416354905),
c = m(c, u, p, a, t[n + 5], 21, -57434055),
a = m(a, c, u, p, t[n + 12], 6, 1700485571),
p = m(p, a, c, u, t[n + 3], 10, -1894986606),
u = m(u, p, a, c, t[n + 10], 15, -1051523),
c = m(c, u, p, a, t[n + 1], 21, -2054922799),
a = m(a, c, u, p, t[n + 8], 6, 1873313359),
p = m(p, a, c, u, t[n + 15], 10, -30611744),
u = m(u, p, a, c, t[n + 6], 15, -1560198380),
c = m(c, u, p, a, t[n + 13], 21, 1309151649),
a = m(a, c, u, p, t[n + 4], 6, -145523070),
p = m(p, a, c, u, t[n + 11], 10, -1120210379),
u = m(u, p, a, c, t[n + 2], 15, 718787259),
c = m(c, u, p, a, t[n + 9], 21, -343485551),
a = l(a, o),
c = l(c, r),
u = l(u, i),
p = l(p, s);
return [a, c, u, p]
}
function u(t) {
var e, n = "";
for (e = 0; e < 32 * t.length; e += 8) n += String.fromCharCode(t[e >> 5] >>> e % 32 & 255);
return n
}
function p(t) {
var e, n = [];
for (n[(t.length >> 2) - 1] = void 0, e = 0; e < n.length; e += 1) n[e] = 0;
for (e = 0; e < 8 * t.length; e += 8) n[e >> 5] |= (255 & t.charCodeAt(e / 8)) << e % 32;
return n
}
function o(t) {
var e, n, o = "0123456789abcdef",
r = "";
for (n = 0; n < t.length; n += 1) e = t.charCodeAt(n),
r += o.charAt(e >>> 4 & 15) + o.charAt(15 & e);
return r
}
function r(t) {
return unescape(encodeURIComponent(t))
}
function i(t) {
return u(c(p(e = r(t)), 8 * e.length));
var e
}
function s(t, e) {
return function(t, e) {
    var n, o, r = p(t),
    i = [],
    s = [];
    for (i[15] = s[15] = void 0, 16 < r.length && (r = c(r, 8 * t.length)), n = 0; n < 16; n += 1) i[n] = 909522486 ^ r[n],
    s[n] = 1549556828 ^ r[n];
    return o = c(i.concat(p(e)), 512 + 8 * e.length),
    u(c(s.concat(o), 640))
} (r(t), r(e))
}
function getPwd(t, e, n) {
return e ? n ? s(e, t) : o(s(e, t)) : n ? i(t) : o(i(t))
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值