文章目录
- 前言
- 一、接口加密参数怎么生成?
- 二、JS代码
- 三、 环境
前言
最近看了下某网站的接口数据,发现和以前不一样了,于是花了会时间看了下
一、接口加密参数怎么生成?
看了下接口 会发现有个testab参数 (以前叫eleven)
那么这参数怎么生成的呢?
既然这个参数名字叫testab
不妨试着搜索一下这个参数
如图
然后直接点击进入代码查看
可以发现这里就是这个接口的地址然后断点
进入调试
然后发现这个参数就是这个e的值 通过 e=e()这个函数返回的
那么这个参数怎么生成的呢找下调用栈
在这里 我直接在控制台运行了这一行代码 发现返回undefined
然后试着看看里面的参数 去掉外面的函数_bot_098b后 运行了下里面这个函数
发现这个就是ajax请求的接口地址至于为什么会有两个一样的testdb参数 是因为我第一行代码也执行了一次函数,把地址拼接起来了
如下图
我再运行的话 会发现又多了一个testab参数
所以得出结论func.apply(typeof ref._bot_6d390 == "undefined" ? _bot_523b7 : ref._bot_6d390, args)
这个函数执行后的作用就是往接口url拼接一个&testab=xxxx
到这里
既然我们已经知道这个函数的作用 那么不妨看看它的参数
发现这个ref是个对象
再看看这个args
是一个array
里面的元素是window
对象和一个函数
接着我们试着运行下这个args里面的函数
二、JS代码
既然已经找到了生成testab的函数,
跟下调用栈
到这里发现 这段js代码是自调用函数 传了一个window,和一个对象{"b":"xxx", "d":"xxx"}
其实这个b,d两个参数就是和生成testab挂钩的 ,每次请求根据b,d的值来生成不同testab值那么问题来了 现在我们还没有找到这段JS代码是从哪来的
继续
到这里 发现这是一个用eval
函数运行的代码 挂载在window里面
经过一番调试 找到了js代码的位置
是一个post请求
callback
参数生成的方法
function r(){
for (var e = "qwertyuiopasdfg$hjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM",t = "", n = 0; n<10; n++)
t += e.charAt(~~(Math.random() * e.length));
return t
};
没错正是这段js 代码
接下来就是重点了 检测点很多 很多
三、 环境
新开一个窗口 把代码扔到控制台
先在浏览器环境拿到这个正确的值,然后再一步一步来
'519398dc3f8944c29bb52f95e109b4e911caae7f40142f11c7276006fe2ac74c'
观察下这个加密值 64位 并且仅通过 a-f 0-9的数字组成的 (有点类似md5构成,但这里显然不是md5了)
如果 生成的加密值 出现了大写字母 或者符号 或者乱码的话
那么就可以肯定判断出 被检测到了 生成的是错误的值
首先 我不推荐使用nodejs 去执行补环境 这段代码 因为 他检测了nodejs的一些地方 代码并不好绕过
直接使用 vm2模块 使用v8环境去补
首先是window
补上 报错
这里用了window.self
那么补上吧
window.self = window;
后续相关对window的操作都是用window.self操作的
之后运行也会报错
挂上代理看看
会发现很多都是undefined
之后会发现 navigator.userAgent appCodeName appCode等等、document.createElement appendChild remove getAttribute
等等都是要补的
补上这些之后
我们在关键点插桩看看
var _bot_25721 = function(_bot_8536a) {
if (typeof _bot_8536a._bot_05141 == 'object' || typeof _bot_8536a._bot_05141 == 'function'){
console.log(_bot_8536a._bot_05141)}
return _bot_8536a._bot_39d1c ? _bot_8536a._bot_6cb58[_bot_8536a._bot_aaa5b] : _bot_8536a._bot_05141;
在本地node vm2环境下跑下
计算的值: 519398Q^Qf894?{<9bb5TrbJe109b]yR11caaeGr40142f17c7276006fe2ac74c
正确的值: 519398dc3f8944c29bb52f95e109b4e911caae7f40142f11c7276006fe2ac74c
保存好浏览器上 和vm2 输出的日志 分析看看
由于补充的东西太多 只说下关键点
按照日志输出顺序来
appendChild
方法的检测
这里发现被检测到了
从日志分析 发现 连续调用了两次document.createElement("div")方法和 appendChild()方法
这里我们就要注意
往div标签里面添加element时,实际上我们是伪造的,所以我们直接往其children属性里面push一个元素就行了(如果你要完全还原实现appendChild方法的话 也不是不可以,,但太复杂了,这里主要是为了绕过这个检测)
改一下appendChild方法 (注意!!!!!!!!这里有个大坑)
Node.prototype.appendChild = function appendChild(x){
debugger;
this['children'].push("div");
};
等你补上这个之后 发现计算的值还是没变化
具体什么情况呢 我们分析分析
我们知道它对appenChild
调用了两次
我们进到断点里面分析下 appendChild
的具体流程
这里相当于 以下这种方式添加 是没问题的
d1 = document.createElement('div');
d2 = document.createElement('div');
d1.appendChild(d2);
<div>
<div></div>
</div>
接下来看看第二次调用appendChild
d2.appendChild(d1)
类似于我往d2标签里面添加一个子标签,但是这个子标签里面又包含了自己
在浏览器上就会出错 而如果我们是自写的appendChild
方法添加对象 是不会报错的
浏览器出错逻辑如下图;
所以我们的appendChild
方法也要抛异常
改好之后 看看
之前日志输出的true
也变成false
了
计算的值: 519398dcQf8944c59bb52fC<e109bQnG11caae@q40142f19c7276006fe2ac74c
正确的值: 519398dc3f8944c29bb52f95e109b4e911caae7f40142f11c7276006fe2ac74c
发现之前出错的第7/8位字符都正确了 但是其他位置还是不对
继续 offsetHeight
浏览器上是false
vm2 是ture
offsetHeight 是在HTMLElement原型下的属性
补上之后
计算的值: 519398dcQf8944c59bb52fC<e109bQnG11caae@q40142f19c7276006fe2ac74c
正确的值: 519398dc3f8944c29bb52f95e109b4e911caae7f40142f11c7276006fe2ac74c
发现还是不对 我们去看看浏览器上的这个属性
HTMLElement.prototype.offsetHeight
VM14136:1 Uncaught TypeError: Illegal invocation
at <anonymous>:1:23
浏览器上这个属性是不可获取的
所以要改一下get 方法 让他抛出异常
HTMLElement.prototype.__defineGetter__("offsetHeight",function(){
throw TypeError("Illegal invocation")
})
可以发现补上之后 true就变成false了
Object.keys
方法获取属性检测
hook Object.keys
函数
Object.getOwnPropertyDescriptor
检测
浏览器上:
本地:
所以 我们需要hook这个函数toString
检测
补上!
一、原型属性检测
Object.getOwnPropertyNames
检测
这里取了navigator
的属性 如果你是通过navigator = {xxx: xxx}
这种定义的 那么肯定会被检测到 拿出来不是空数组
解决方案1:定义其原型 并且在原型上补
Navigator.prototype.plugins = [];
Navigator.prototype.appCodeName = "Mozilla";
Navigator.prototype.appName = "Netscape";
Navigator.prototype.platform = "Win32";
Navigator.prototype.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36";
Navigator.prototype.languages = ["zh-CN"];
Navigator.prototype.webdriver = false;
解决方案2:hook
var obj_name = Object.getOwnPropertyNames;
Object.getOwnPropertyNames = function getOwnPropertyNames(obj){
let temp = obj_name.apply(this, arguments)
if ( obj== navigator){
return []
}
// ...其他的需自己补
return temp
}
ps:实测代码运行过程中 只对navigator的原型进行了输出,所以navigator的原型是必须补的。
之后是document的属性
也用类似navigator
的操作就行了这里要补下document.documentElement.getAttribute函数 返回null就行了
这里发现 拿了Document
的原型属性
然后把之前的['location', '__sn']
添加到数组的前面
这里又拿了Node
的属性 放到数组的后面 232 + 47 = 279
这里又拿了EventTarget
的属性 加到数组后面
这里发现取了Image
的原型属性
Object.getOwnPropertyNames(Image.prototype)
(28) ['alt', 'src', 'srcset', 'sizes', 'crossOrigin', 'useMap', 'isMap', 'width', 'height', 'naturalWidth', 'naturalHeight', 'complete', 'currentSrc', 'referrerPolicy', 'decoding', 'name', 'lowsrc', 'align', 'hspace', 'vspace', 'longDesc', 'border', 'x', 'y', 'decode', 'fetchPriority', 'loading', 'constructor']
二、node 环境检测
如果你用的是nodejs的话 那么这里就会被检测到了, 浏览器上是没有这个process的
这里就需要 delete process;
当然这只是一小部分 肯定还有其他检测的地方
比如require
等等
所以不推荐使用node
三、加密参数的数组
在代码运行过程中 有一个数组 逐渐在往里面添加数字
直到数组到64位时 这个值就生成了
五、不可改变的对象
挂上代理之后 能发现 对navigator
的userAgent,appCodeName,platform
进行赋值操作
set Navigator {plugins: Proxy, appCodeName: 'Mozilla', appName: 'Netscape', platform: 'Win32', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', …} appCodeName string ctrip.com
set Navigator {plugins: Proxy, appCodeName: 'Mozilla', appName: 'Netscape', platform: 'Win32', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', …} appCodeName string Mozilla
set Navigator {plugins: Proxy, appCodeName: 'Mozilla', appName: 'Netscape', platform: 'Win32', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', …} platform string ctrip.com
set Navigator {plugins: Proxy, appCodeName: 'Mozilla', appName: 'Netscape', platform: 'Win32', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', …} platform string Win32
set Navigator {plugins: Proxy, appCodeName: 'Mozilla', appName: 'Netscape', platform: 'Win32', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', …} userAgent string ctrip.com
set Navigator {plugins: Proxy, appCodeName: 'Mozilla', appName: 'Netscape', platform: 'Win32', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb…KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', …} userAgent string Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36
这里就要注意了
运行过程中 会给document.cookie
赋值
在浏览器上 类似window document navigator
这种 是不可被赋值的
所以我们在补完环境之后 最后加上这些代码 需要冻结这些对象
Object.freeze(navigator);
Object.freeze(document);
Object.freeze(location);
VM143 VM222:9 get Window fbejkbakrbadskfe undefined undefined
这里取了window.fbejkbakrbadskfe
在其网站上这个值也是undefined
暂时不用管
总结:
主要是对原型函数 原型链的检测 dom操作的检测 node环境 检测 自动化工具检测
补的时候必须要细
文章的顺序可能有点乱 但是需要补的关键点都已经全部写出来,剩下的就需要自己踩坑了
附上生成参数结果:
如有违规侵权 请联系我删除!!!!!!!
如有违规侵权 请联系我删除!!!!!!!
如有违规侵权 请联系我删除!!!!!!!