st779779

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

常见非指纹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 要注意提前把缓存删掉

image-20230214220103467

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

image-20230429221659492

寻找拦截器 搜 interceptors

image-20230429221901859

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']
posted on 2023-10-13 21:08  xirang熙攘  阅读(108)  评论(0编辑  收藏  举报