无线debugger解决方法
- 浏览器debugger的原理和常见方法
(function() {var a = new Date(); debugger; return new Date() - a > 100;}())
- 解决方法
- 禁用所有断点:==\>>,不能调试,适合静态分析网络请求。
- 禁用某处断点:nerver pause none
- 使用条件断点:false,使条件永不生效
- 中间人工具替换特征字符串:使用fiddler、mitmproxy,修改函数
- reres 替换本地修改过的文件:谷歌插件 reres ,在线替换js脚本
- 重写关键函数:
在函数声明之后,在console中重写关键函数
或者根据堆栈找到入口函数,重写入口函数。与之相关的setInterval
重写关键函数时,需要注意,是否需要在函数生效之前下断点,然后重写函数
Function.prototype.constructor = function(){}
//只有当下面这条语句为 true 时,在console写入上面这条语句才生效
(function(){}).constructor === Function
快速定位
开发者工具全局搜索
可以通过搜索特征参数名,或者请求url中的部分路径名。存在搜索不到的情况,当对方对js进行变量混淆,我们就搜索不到想要的结果。全局搜索不到怎么办?可以尝试查看发起者,或者下合适的断点,或尝试一些特殊hook-
断点调试
- xhr断点:当某个请求含有设定的参数,就会停在该请求发起位置
- dom断点:打上断点后,当该断点的元素属性发生变化,就会触发该断点
- 事件监听器event:在elements页面右边有一个 event listeners,在source页面右下角也有一个event listeners面板,当发生某个特定事件,就会触发该事件断点。
hook技术
当我们不知道从哪里下手时,或者大概猜测出加密方法时,可以使用hook技术对特定的属性和方法进行hook
使用execjs执行js
import execjs
with open('test.js','r') as f:
content = f.read()
ctx = execjs.compile(content)
# call 方法可以传入两个参数 函数名,参数
res = ctx.call('get_data')
print(res)
使用selenium执行js
由于execjs脱离浏览器环境,当执行的js脚本需要浏览器参数,需要手动替换。除此之外还可以直接使用selenium执行js脚本
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument('--ignore-certificate-errors')
browser = webdriver.Chrome(chrome_options=options)
wait = WebDriverWait(browser,10)
# 启动浏览器 获取网页源代码
mainUrl = ''
browser.get(mainUrl)
result = browser.execute_script('javascript 代码')
使用node开发api接口
- 通过nodejs写一个RPC(远程调用)服务,然后调用js。
- express基本使用方法
使用express开发一个api接口,供爬虫调用。扣好的js为单独的一个脚本,在该脚本最后添加
// 导出该方法,供其他模块使用
module.exports = {
// 需要调用的方法
encode
};
再新建一个关于express脚本,搭建服务
var express = require('express');
var app = express();
// 定义一个变量接收js模块导出的函数
var getData = require('./22.js');
app.get('/music', function(req, res) {
// 接收所有参数
// let text = JSON.stringify(req.query);
let keyword = req.param('keyword');
let text = 'text='+keyword+'&page=1&type=migu'
// 调用加密函数
data = getData.encode(text);
res.send(data);
});
app.listen(3000);
使用pyppeteer执行js
from pyppeteer import launch
import asyncio
async def run():
browser = await launch({"headless":True})
page = await browser.newPage()
await page.goto('http://www.dianping.com/shop/113089020')
script = """
const run=function(){
return _token
}
run()
"""
text = await page.evaluate(script)
print(text)
return text
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
# 在页面加载前执行js,通常用于修改浏览器属性,如navigator属性
# 采集页面时的用法
result = awit page.evaluateOnNewDocument(js,*data)
颜文字混淆
- 复制颜文字代码,在console中运行。如果报错,直接点击vm(由eval或者Function计算产生)。如果不出错,将最后一个表情删除,然后运行。或者替换为 toString。
- 根据堆栈查看 颜文字请求 上一个请求
([,],(,),!,+)混淆
- 代码最后如果存在(),直接运行,或者删除()
- 代码最后不存在(),将最后一个()里的代码拿出来单独运行,很可能使用eval函数包裹该代码块
eval
eval函数的参数是一段js代码字符串,这段字符串可能经过packer打包处理,解决方法,使用console.log输出eval括号内的代码,即可得到原函数。
chrome浏览器工具
toggle javascript:开关浏览器js渲染
tampermonkey:js函数注入工具,hook
editthiscookie:编辑页面cookie
-
reres :该插件可以替换js文件
使用方法:https://github.com/annnhan/ReResIf URL match栏,可以使用正则匹配,或者直接填写js文件地址
Response栏,填写的是映射的响应地址。使用本地地址的方式是file:///E:/index.js,使用线上地址的方式是http://localhost:3000/xxx/index.js
aes对称加密
- 秘钥:支持三种长度的秘钥 128位,192位,256位,长度越长性能越差安全性越高
- 填充:为什么要填充?由于aes加密是分组加密,如果每组128bit,最后一组不足128bit,那么就需要对该组明文块进行填充,下面是常见填充方式
- nopadding:不做填充,它要求明文的长度是128的整数倍
- zeropadding:用0进行填充,但不推荐,如果明文最后一个也是0,就会解密出错
- pkcs7padding:推荐使用。用缺少字节数作为数值,对明文进行填充
- 工作模式
- ECB模式:是最简单的模式,该模式下,每一个明文块的加密都是完全独立,互不干涉。
优点,可以进行并行计算,性能高。
缺点,相同的明文加密后会得到相同的密文 - CBC模式:初始向量IV。每一个明文块都要和前一个密文块进行异或操作,得到该明文块的密文块,第一个明文块就和初始向量IV进行异或
安全性提高,但是性能下降
- ECB模式:是最简单的模式,该模式下,每一个明文块的加密都是完全独立,互不干涉。
- 使用node实现
var CryptoJS = require('crypto-js');
function get_aes_decrypt(pwd,key){
// 秘钥 json格式化
var pwd = JSON.stringify(pwd);
// 加密的数据转化成 128位
var _key = CryptoJS.enc.Utf8.parse(key);
var encryptedData = CryptoJS.AES.encrypt(pwd,_key,{
mode:CryptoJS.mode.ECB,
padding:CryptoJS.pad.Pkcs7
});
return encryptedData.ciphertext.toString();
}
var data = get_aes_decrypt({"o00o0o00o0o0o0":"eval0514undefined"},'e03163e36a107c9b');
console.log(data);
- 用python实现aes加密解密
js调试遇到的错误
- JavaScript heap out of memory
有可能是代码反格式化,当我们格式化代码后运行,就会出现堆栈溢出或者内存不足
// this['zIYQbj'] = function() {
// return 'newState'
// };
//FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
this['zIYQbj'] = function() {return 'newState'};
node导入MD5
var cryptoJs = require('crypto-js');
var md5 = function(a){
return cryptoJs.MD5(a).toString();
}