1.nvm安装与使用 node软件版本管理
2.Js逆向基础相关知识
常见非指纹built-in函数
unescape
unescape('abc123'); // "abc123"
unescape('%E4%F6%FC'); // "äöü"
unescape('%u0107'); // "ć"
//法计算生成一个新的字符串,其中的十六进制转义序列将被其表示的字符替换
Function
//构造函数创建一个新的 Function 对象
// 可以直接在 JavaScript 控制台中运行
// 创建了一个能返回两个参数和的函数
const adder = new Function("a", "b", "return a + b");
// 调用函数
adder(2, 6);
// > 8
unescape
Function
eval
Array
Object
Date
RegExp
indexOf
hasOwnProperty
decodeURIComponent encodeURI encodeURIComponent
Math 、round 、 random、parseInt 等强制转换
shift、pop、push、unshift
slice、splice、split、substring、substr、concat
String 、 fromCharCode、 charCodeAt
atob 、btoa、Uint8Array、 ArrayBuffer、 Int32Array、 Int16Array
setTimeout 、setInterval、 clearTimeout
调试干扰
一.debugger实现方案
1.不可混淆
debugger;
2.可混淆
eval(debugger);
3.可重度混淆
//借助于Function 来实现debugger方案
//实例1 生成一个debugger的匿名函数 并且执行
Function("debugger").call()/apply() 或赋值 bind()
//生成一个debugger的匿名函数 并且执行
(function anonymous(
) {
debugger;
})
//实例2
XXX.constructor("debugger").call("action")
function a(){}
a.constructor === Function()
a.constructor("debugger").call()
//实例3
Function.constructor("debugger").call("action")
Function.constructor === Function()
//实例4 使用匿名函数
(function() {return !![];}["constructor"]("debugger")["call"]("action"))
(function(){}).constructor("debugger").call()
(function(){}.constructor("debugger").call())
二.无限debugger
//贯穿全局的
//死循环debug 会把页面卡死
while(1){debugger;};
//定时器debug 不影响业务逻辑和代码
function a (){
debugger;
};
setInterval(a,500);
三.如何处理无限debug
1.无限debugger贯穿全局
//干掉定时器等全局事件(置空或重写)
//解决方案 需要在代码执行之前进行声明
//重写 setInterval
setInterval_back = setInterval
setInterval =function (a,b) {
//如果传入的参数 a 中没有debugger 这段字符
if(a.toString().indexOf("debugger") == -1){
//重写返回原来 有的话啥都不执行
return setInterval_back(a,b);
}
}
//如果 setInterval 不是很重要的执行逻辑 可以直接置空
setInterval = function(){}
2.无限debugger在加密逻辑之前
这就证明,想要调试到函数入口,必须越过这个无限debugger
针对静态文件/伪动态文件(大部分都是这个情况)
用 fiddler Autoresponse 删掉 debugger
可以右键 never
针对真动态文件或Autoresponse失效或删掉debugger逻辑很繁琐的情况下
1. 如果是 Function 原理的 debugger,可以重写 函数构造器
Function.prototype.constructor = function(){}
Function.prototype.constructor_bc = Function.prototype.constructor
Function.prototype.constructor = function(){
if(arguments[0] === "debugger"){}
else{
return Function.prototype.constructor_bc.apply(this,arugments)
}
}
2. 如果是eval型的构造器,可以重构 eval函数
eval_bc = eval
eval = function(a){
if(a==="debugger" || a==="asfsdfaf..."){
}else{
return eval_bc(a)
}
}
3. 如果是定时器,并且 2失效了,可以重构定时器
4. 在以上方式都失效时,向上找堆栈,在进入无限debugger之前打上断点将触发无限debugger的函数置空(最麻烦,但是适用性最广)
用 fiddler Autoresponse 删掉 debugger 要注意提前把缓存删掉
3.常用的过debugger方法函数
//过createElement
_createElement=document.createElement
document.createElement=function(){
if(arguments[0].indexOf('script') != -1){
return _createElement("")
}
return _createElement(arguments[0])
}
//过eval
_eval = eval;
eval = function(){
if(arguments[0].indexOf('debugger'))
return _eval(arguments[0])
}
//过appendChild
_appendChild = Node.prototype.appendChild
Node.prototype.appendChild = function(){
if (arguments[0].innerHTML && arguments[0].innerHTML.indexOf('debugger') != -1){
arguments[0].innerHTML = ''
}
return _appendChild.apply(this, arguments)
}
四.调试检测
首先,控制台检测一定是通过JS实现。
1. 禁止F12 右键的解决方案:直接手动开启控制台
2. 呼出控制台弹窗或者跳转的解决方案:script断点,并且先尝试进行关键词搜索找线索。随机打上断点,不断缩小检测范围,直到找到。若是静态js/假动态直接可以Autoresponse干掉,若是真动态则在执行控制台检测逻辑附近的时候重置函数(这个可以参考无限debugger处理方案,重写函数,hook关键位置等)
非常重要的细节,先定义,后重写
函数定义之后,函数
调用之前
调用控制台检测原理
<script>
//部分浏览器不支持改方法 火狐
var x = document.createElement("div");
Object.defineProperty(x,'id',{
get:function (){
alert('111')
}
});
function use(){
console.log(x);
console.clear();
}
setInterval(use,200);
</script>
五.内存爆破原理
内存爆破,指js通过死循环/频繁操作数据库(包括cookie)/频繁调取history等方式,使浏览器崩溃的一种反调试手段。关键词:频繁
还有一种特性情况:js文件很大,电脑内存不足(这种情况在调试层面几乎无解)
特点:1. 正常运行时,一切正常
2. 调试时利用时间差,调试特点等讲控制流推入循环
3. 利用正则/toString() 判断代码是否进行格式化
4. 利用浏览器指纹判断是否为浏览器环境
python与node.js的代码交互
py-mini-racer
安装
pip install py-mini-racer
示例
js_code = """
// console.log(__dirname)
var a = 1;
var f = 1;
function b(){
return arguments[0] + 100
}
"""
from py_mini_racer import MiniRacer
ctx = MiniRacer()
ctx.eval(js_code)
result = ctx.call('b', 100)
print(result)
Pyexecjs
安装
pip install Pyexecjs
不能异步
示例
js_code = """
// console.log(__dirname)
var a = 1;
var f = 1;
function b(){
return arguments[0] + 100
}
"""
import execjs
ctx = execjs.compile(js_code)
result = ctx.call('b', 200)
print(result)
os.popen
跟上两个比:
坏处:不能调函数,不能传参
好处:能收到异步内容,只要控制台有console.log,通道就能接受到
js_code = """
// console.log(__dirname)
var a = 1;
var f = 1;
function b(){
return arguments[0] + 100
}
"""
import os
js_code = js_code.replace('// ', '')
print(js_code)
with os.popen('node -e console.log(global)') as p:
print(p._stream.buffer.read().decode('utf-8'))
直接用node.js调
subprocess.check_output(['node', '-e', js_code])
subprocess.check_output 手感更好,出异常概率更小
示例
import subprocess
result = subprocess.check_output(['node', '-e', js_code])
print(result)
调用参数的操作
js_code = """
// console.log(__dirname)
var a = 1;
var f = 1;
function b(){
return arguments[0] + 100
}
"""
#使用replace替换
import subprocess
result = subprocess.check_output(['node', '-e', js_code.replace('//', '')])
print(result)
异步并发方案
1.js代码
function decode(){
console.log((new Date()).getTime())
process.exit()
}
(new Promise((f)=>{f()})).then(()=>{
setTimeout(decode, 3000)
}
)
示例
import subprocess
result = subprocess.check_output(['node', '1.js'])
print(result)
import threading
def parallel():
result = subprocess.check_output(['node', '1.js'])
print(result)
for i in range(10):
th = threading.Thread(target=parallel, args=())
th.start()
如果要传参怎么办?
with open('1.js') as f:
js_code = f.read().replace('getTime()', 'getTime() + 900000000000000000')
import threading
import subprocess
def parallel(js_code):
result = subprocess.check_output(['node', '-e', js_code])
print(result)
for i in range(10):
th = threading.Thread(target=parallel, args=(js_code,))
th.start()
js_code 非常大 ,传进去会报错,可以借助借助硬盘io
import time
import threading
import os
import random
import subprocess
def parallel():
with open('1.js', 'r') as f:
js_code = f.read().replace('getTime()', 'getTime() + 1900000000000000000')
file_name = 'result{}.js'.format(time.time() + random.random())
with open(file_name, 'w') as f:
f.write(js_code)
result = subprocess.check_output(['node', file_name])
print(result)
os.remove(file_name) # 删除缓存文件
for i in range(10):
th = threading.Thread(target=parallel, args=())
th.start()
js逆向
事件监听断点
非常频繁使用的事件监听断点:script、XHR
一般频繁使用的:Dom断点、Control、timer
不太常用但是偶尔会用到的:Mouse
HOOK
HOOK定义
Hook 技术又叫做钩子函数,在系统没有调用该函数之前,钩子程序就先捕获该消息,钩子函数先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,还可以强制结束消息的传递。简单来说,就是把系统的程序拉出来变成我们自己执行代码片段。
在js中,系统程序可以指浏览器API,也可以指代码中实现的一些方法等
分类:手动hook,自动hook
Hook步骤
//寻找hook点
//编写hook逻辑
//调试
//函数Hook公式:
old_func = funcfunc = function(argument){
my task;
return old_func .apply(argument)
}
func.prototype..... = .......
func :要hook的函数
//对象中属性Hook公式:
old_attr = obj.attr
Object.defineProperty(obj, 'attr', {
get: function() {
console.log(cookie_cache);
return old_attr
},
set: function(val) {
return ......
}
Hook的弊端和缺陷
函数hook一般情况下不会出现hook失败的情况,只有可能是 __proto__ 模拟的不好导致被检测到了。
属性hook 当所有网站的逻辑都采用Object.defineProperty绑定后,属性hook就会失效。暂时没有发现好的解决方案。
这里还有一种我没讲的hook,叫局部hook,原理是一样的,只不过需要在进入作用域的那一刻进行hook。
Hook插件 油猴脚本
@name :脚本名,你爱叫什么叫什么。
@namespace :脚本的命名空间。(一般就是写个url,告诉自己用在哪里)。
@version:版本,你爱写多少写多少。
@author:作者,你爱写谁写谁。
@description:描述,你爱怎么描述怎么描述。反正别人也看不懂。
@homepage, @homepageURL, @website and @source: 一般正常人都不写这几个参数。从脚本 名称链接到给定页面的作者主页。
@icon, @iconURL and @defaulticon:一般正常人都不写这几个参数,低分辨率脚本图标。
@icon64 and @icon64URL:一般正常人都不写这几个参数,高分辨率脚本图标。
@updateURL: 更新检查的url,@version参数开启,会向url检查更新。
@downloadURL:定时监测到更新会自动下载url内容,若为 none则不检查
@include @match @exclude:匹配规则相关。支持精确匹配与正则匹配。@exclude是排除, 不写相当于脚本白写
@require @resource :导包,支持url引入。比如引入 jquery,可以使用$
@connect:标记定义域,感觉很有用,但是我菜,所以很少用。
@grant:白名单函数:比如:@grant window.close 。很强大,如果默认不写则会对一些原生 函数如:eval等进行保护,显然这不是我们所期待的,所以就直接 @grant none了
//演示
// ==UserScript==
// @name 万能hook eval函数
// @namespace http://tampermonkey.net/
// @version 0.1
// @description eval-everything
// @author An-lan
// @include *
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
alert('hook success');
var eval_bk = eval;
eval = function(val){
console.log(val)
return eval_bk(val);
};
eval.toString = function(){
return "function eval() { [native code] }"
};
eval.length = 1;
})();
局部hook
//局部hook
function a(){
function b(a){
return a
}
}
function a(){
function b(a){
return a
}
b_bk = b;
b = function(val){
if(val === 5){
debugger;
}
return b_bk;
}
b(1);
b(2);
eval('b('+5+')')
}
a()
全局变量的hook
//全局变量的hook
Object.defineProperty(document,'hook',{
set:function(val){
if(val === 5){
debugger
}
return val
}
})
一些常用的hook逻辑
hook eval 、hook Function 、hook JSON.stringify、JSON.parse 、hook cookie、hook window对象等
补环境
_$ob('0x36') eval("_$ob('0x36')") replace
node跟浏览器差异
//浏览器 无法删除这些变量 而node里面可以删除
window
document
投毒
try 分支 浏览器报错 node不报错
if else 导致分支
|| && 类似实现分支的功能
node中 window=global 和window=this 的区别
global是全局变量,相当于浏览器中的window,具有一小部分window的功能
this在浏览器中指向window,而在node里面指向的 module.exports [是个空对象]
所以 window=this之后,window.a=100,console.log(a)是报错
而window=global之后,就不会报错 ,建议不要使用window=this
ATS抽象语法树
网址
https://www.babeljs.cn/docs/configuration 中文
https://www.babeljs.cn/docs/babel-parser
https://astexplorer.net ast查看网址
基础入门工具
generatior : 将 ast转化为js代码
parse:将js代码转化为ast
traverse:节点遍历操作的方便功能
types:提供一个与格式相关的对象合集
常用加密
AES
function b(a, b) {
// CryptoJS 没有..
// js里面看到以下内容. 或者类似以下内容
// 可以去这里找. https://www.npmjs.com/
// CryptoJS => 安装方式. npm i crypto-js 相对路径安装
// JSEncrypt
// 这俩玩意是前端js的两个加密库.
var c = CryptoJS.enc.Utf8.parse(b)
, d = CryptoJS.enc.Utf8.parse("0102030405060708")
, e = CryptoJS.enc.Utf8.parse(a)
, f = CryptoJS.AES.encrypt(e, c, {
iv: d,
mode: CryptoJS.mode.CBC
});
return f.toString()
}
PYexecJS模块
注意事项
windows中如果出现编码错误. 在引入execjs之前. 插入以下代码即可
# 在python中连接CMD的那个东西是subprocess里面的Popen
# 解决execjs的乱码问题.
# 在引入execjs之前. 加上以下代码
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')
import execjs
简单使用
import execjs
print(execjs.get().name)
# execjs.eval 可以直接运行js代码并得到结果
js = """
"鲁班_王昭君_猴子_亚瑟_蔡文姬".split("_")
"""
res = execjs.eval(js)
print(res)
# execjs.compile(), call()
# execjs.compile() 事先加载好一段js代码,
jj = execjs.compile("""
function an(a, b){
return a + b
}
""")
# call() 运行代码中的xxx函数. 后续的参数是xxx的参数
ret = jj.call("an", 10, 20)
print(ret)
安装
pip install pyexecjs
测试
import execjs
print(execjs.get().name) # 需要重启pycharm或者重启电脑 Node.js (V8)
加密数据
ajax 寻找success
寻找拦截器 搜 interceptors
adb命令
adb --version 查看版本
fastboot --version
adb devices 查看是否链接
adb install 路径 安装
adb push 本地路径 手机路径 移动文件
adb push D:\..\.. /sdcard/Download/
adb pull 手机文件路径 本地文件路径 将电脑文件拉到手机上
>>>adb reboot bootloader 进入bootloader
>>>fastboot flash boot 修复的boot文件 刷入boot
>>>fastboot reboot 重启手机
adb connect 127.0.0.1:7555 链接木木模拟器
重启服务
adb kill-server
adb start-server
查看手机架构
>>>adb shell getprop ro.product.cpu.abi
>>>arm64-v8a 【1000+】
>>>arm-v7a 【便宜手机】
>>>x86
>>>x86_64 [mumu模拟器]
adb root;adb remount
adb shell mount -o rw,remount /system
shell进入相应的目录
adb shell
su
cd data/local/tmp
逆向流程
- 抓包
- 分析登录请求的包,找到需逆向的包
- 利用jadx反编译apk,得到java代码
- 寻找关键字 + Hook验证
- 还原算法
curl转代码
curlconverter example.com
echo 'curl example.com' | curlconverter -
项目地址
https://github.com/curlconverter/curlconverter
Java关键词
SharedPreferences //写入xml文件
js调试插件
// 我们可以在node环境中安装一个node-inspect插件. 就可以把你当前的环境丢到浏览器上去跑. 看结果.
// 这是你当前的环境, 不是浏览器环境.
安装
npm install -g node-inspect
使用
node-inspect 文件名
扣代码过程
查看类里面的代码 用new
new ce('123456')['$_EAz']
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探