98js逆向笔记

1、工具

JS加解密

https://www.bejson.com/enc/eval_package/

Ob混淆

https://github.com/Tsaiboss/decodeObfuscator

AST 混淆还原框架

https://github.com/sml2h3/ast_tools

Chrome 插件

https://github.com/cilame/v_jstools

jsjiami v6 专用解密工具

https://github.com/NXY666/JsjiamiV6-Decryptor

谷歌验证码绕过插件

Noptcha

2、JS逆向基础

JS基础

# JS对象--------------------------------------------------
function Person(name, age) {
  this.name = name;
  this.age = age;
}

let obj = new Person("zs", 18);

console.log(obj.name);
console.log(obj.age);


# 函数参数------------------------------------------------
function add(a, b){
  
  console.log(arguments[0]);
  console.log(arguments[1]);
  return a + b;
  
}

let res = add(1, 5);
console.log(res);


# 函数作用域---------------------------------------------------
let a = 1;

function test(){
	a = 5;
	console.log(a);
}

test();
console.log(a);


# 字符串-----------------------------------------------------
let name = "zs";

console.log(name);
console.log(\u006e\u0061\u006d\u0065);
            

            
# base64------------------------------------------------

// str -> base64

let buffer = Buffer.from("i love you china");
let base64Str = buffer.toString("base64");
console.log(base64Str);  // aSBsb3ZlIHlvdSBjaGluYQ==


// base64 -> str
let str = Buffer.from("aSBsb3ZlIHlvdSBjaGluYQ==", "base64").toString();
console.log(str);

JS面向对象编程

js中一切皆对象

构造函数对象都有一个属性prototypejs中, 只要是对象, 都有一个属性__proto_

# JS面向对象--------------------------------------------------

function Person(name, age){
	this.name=name;
	this.age=age;
	/*this.show=function(){
		console.log("p实例:my name is " + this.name);
	}*/
}

Person.prototype.show = function(){
	console.log("原型对象:my name is " + this.name);
}

let p =new Person("zs", 18);
p.show();


# 继承链------------------------------------------------------------
function Person(name, age) {
	this.name=name;
	this.age=age;
	/*this.say=function(){
		console.log("实例my name is " + this.name);
	}*/
}

/*Person.prototype.say=function () {
	console.log("my name is " + this.name);
}
*/

Object.prototype.say=function () {
	console.log("my name is " + this.name);
}

let p = new Person("zs", 18);
p.say();

数据劫持

# 数据代理
let o1 = {
    num: 1
}

let o2 = {}

Object.defineProperty(o2, 'num', {
    get(){
        return o1.num
    },
    set(val){
        o1.num = val
    }
})

ES6语法

# 模块的导入和导出
module.exports = {
    
}

// 导入
const m = require("moduleName");

let与var变量的区别

let变量不可重复声明

let变量有块级作用域,var没有

var会变量提升,let不存在变量提升

模板字符串

str = my name is ${p.name}

箭头函数

f = () ->{
    
}

可变形参

function f(...params) {
    console.log(params.length)
}

3、常见加解密算法

Base64编解码

# 浏览器-----------------------------------------
// 编码
window.btoa("gmbjzg")  // "Z21ianpn"
// 解码
window.atob("Z21ianpn")  // "gmbjzg"

哈希散列MD5

工具:https://www.cmd5.com/

# Node-----------------------------------------
// 导库
const crypto = require('crypto');

// md5加密算法
var obj = crypto.createHash('md5');
obj.update('123456');
var str = obj.digest('hex');
console.log(str);

对称加密算法AES/DES

什么叫对称加密算法呢?对称加密算法就是使用密钥对明文进行加密,使用加密的密钥对密文进行解密。对称加密算法是可逆的。也就是说,如果我们得到一段密文数据,如果能够获取到加密的密钥,那么我们就能对密文数据进行解密。

# AES-ECB---------------------------------------
 const CryptoJs = require('crypto-js');

// AES加密

let password = "123456";

let key = "1234567890abcdef"

cfg = {
 mode: CryptoJs.mode.ECB,
 padding: CryptoJs.pad.Pkcs7
}

let encPwd = CryptoJs.AES.encrypt(password, key, cfg).toString()

console.log(encPwd)  // U2FsdGVkX1+meKI+IXd44qgc50bKb2rDbN91OutwBWs=


// AES解密
encPwd = "U2FsdGVkX1+meKI+IXd44qgc50bKb2rDbN91OutwBWs="

decPwd = CryptoJs.AES.decrypt(encPwd, key, cfg).toString(CryptoJs.enc.Utf8) // 指定解码方式

console.log(decPwd)  // 123456

一共需要传递三个参数,分别是password | key 以及 cfg配置模式

mode模式常用的有 CBC | ECB两种

这两种模式的区别在于是否需要配置iv向量

使用CBC模式进行加密示例代码如下:

# AES-CBC-----------------------------------------------------
const CryptoJs = require('crypto-js');

let password = CryptoJs.enc.Utf8.parse("123456")  // 指定以什么编码方式解析明文

let key = CryptoJs.enc.Utf8.parse("1234567890abcdef")

let iv = CryptoJs.enc.Utf8.parse("123456")  // 需指定初始向量

cfg = {
 mode: CryptoJs.mode.CBC,
 padding: CryptoJs.pad.Pkcs7,
 iv: iv
}

let encPwd = CryptoJs.AES.encrypt(password, key, cfg).toString(CryptoJs.enc.Utf8)

console.log(encPwd)

非对称加密算法RSA

公钥和私钥需要生成,这里我们使用在线生成方式

加解密网址:http://web.chacuo.net/netrsakeypair/

非对称加密算法有公钥和私钥,公钥加密,私钥解密

RSA--------------------------------------
const JSEncrypt = require("jsencrypt");

window = global

publickey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnX3j/luQG7JnPFIFJKEvPC/tFtv14XIzT7FQXYpKsOt2t4uLh6hZa5H5WcEinF46nc91UbrS5UA9Fnnm+Ev20pwUEPVu4On47am6vJOsq8oqQoZDsMu6VGZIzKIm8vDylO6I2xrTaXY2G3hdiRKF7988tA4oYsFOTZ/yG/BOlNwIDAQAB'

// 加密
let jse = new JSEncrypt()
jse.setPublicKey(publickey)
var encStr = jse.encrypt('123456')
console.log("加密数据: " + encStr)

// 解密
privatekey = 'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKdfeP+W5Absmc8UgUkoS88L+0W2/XhcjNPsVBdikqw63a3i4uHqFlrkflZwSKcXjqdz3VRutLlQD0Weeb4S/bSnBQQ9W7g6fjtqbq8k6yryipChkOwy7pUZkjMoiby8PKU7ojbGtNpdjYbeF2JEoXv3zy0DihiwU5Nn/Ib8E6U3AgMBAAECgYA6KW0stEytM08HrQJ4X65oVquMwFg4mUC+7CMUtUZu303lfTCGfQgjsb9NXluA5SjHe/Xvv0DCHNYRxU5dBNBwhIXaRLy6zLKKKp/0gOn1C3dFY/MQOVoEpJ8uxUQh9Kf37F5J9gT64JNooKTTNydqTcmfIhG/u3WFiTVjfW5sEQJBANmvAgUneA6eEC6LwhX9gxdp0T2S+hop19zAm4ErHQld47TlSAxVgwArQG4oJ5J2OWlIT4vzuO1OJOaCj4wZYXMCQQDE1W0uZA1YtjVK7OUuD3f/rgNzolpc0XEEZDPxKsoirEFgW/cFNCTJKIdGK2RgnthLWiN01a9bL6+sF2vLO2wtAkAd0h3Cuv91cS3iUn8KKCqXQIXLm6DriKPrt+8VqORXbidNlsNh/SzvDv3KmXGiXNPMmn1bPM4upC/l7CjiFnAFAkBnmu+dO4zK5R2oEomPdRT0v+OROiPWN2gFp7iveJZtKb4/uiiL1KaIO4z4ol5zfSjcgNWo6dEjbjZJnwpeLykBAkAY/tYLGyrHe0isoZL2xXPlrvde2tbKcbzMrheH1wuqEMX0o0+uHCyFgn2rAzMcfUlntb9iZLLJDkJ+bFET1j3l'
jse.setPrivateKey(privatekey)
var Str = jse.decrypt(encStr)
console.log("解密数据: " + Str)

4、python执行js代码

# 安装第三方库
pip install PyExecJS2


# 编译调用执行
ctx = execjs.compile(open("./xxx.js", "r", encoding="utf-8").read())
datas = ctx.call("mainc", response.text)   # 参数一:调用的函数  参数二:实参

5、Js逆向专题

运行js代码的三种 node v8引擎 浏览器

浏览器调试

打开调试面板的几种方式

  • F12
  • 快捷键 Ctrl+Shift+I
  • 鼠标右键检查
  • 浏览器右上角三个小点点 => 更多工具 => 开发者工具
  • 新打开标签页 => 输入网址 => 回车

无限Debugger

  • 断点处添加条件 Add conditional breakpoint / Never pause Here

  • ReRes/Chrome的Overrides,替换js文件

  • 代码注入

# HOOK代码------------------------------------------
Function.prototype.constructor_ = Function.prototype.constructor;
Function.prototype.constructor = function (arg) {
    if(arg == "debugger") {
        return function (){};
    }
    return Function.prototype.constructor_(arg);
}

浏览器插件编写

示例

# manifest.json---------------------------------------------
{
    "name": "shijia",          // 插件名称
    "version": "1.0",               // 插件版本
    "description": "无限debugger",   
    "manifest_version": 3,          
    "content_scripts": [{
        "matches": ["<all_urls>"],  // 匹配url地址
        "js": ["debugger.js"],   
        "all_frames": true,         
        "permissions": ["tabs"],    
        "run_at": "document_start"  // 代码注入的时间
    }]
}

# debugger.js---------------------------------------------------
console.log("注入js文件")

代理

obj = new Proxy(global, {
    set(obj, prop, value) {
        console.log(obj, prop, value);
        return Reflect.set(...arguments);
    },
    get: function (target, property, receiver) {
        console.log(target, property, receiver);
        return target[property];
    }
});

6、JS混淆原理

异或运算

// 原理: a ^ b = c => c ^ b = a

let a = 1

let b = 1

let c = a ^ b

console.log(c)  // 0 
console.log(c ^ b)  // 1

对象属性访问

arr = ["getFullYear"]

year = new Date()[arr[0]]()
console.log(year)

乱序数组

// 没有乱序的数组
arr = ["getFullYear", "getMonth", "getDay"]

// 打乱数组
function upset(arr, num){

	for(let i=0; i<num; i++){
		arr.unshift(arr.pop())
	}

	console.log(arr)
}
// 还原数组
function  recover(arr, num){

	for(let i=0; i<num; i++){
		arr.push(arr.shift())
	}

	console.log(arr)
}

垃圾代码

// 垃圾代码
function add1(n1,  n2){
	return add2(n1, n2);
}

function add2(n1, n2){
	return add3(n1, n2)
}

function add3(n1, n2){
	return n1 + n2;
}

let a  = 1;
let b = 2;

let c = add1(a, b)

console.log(c);

逗号表达式

// 原来代码
function sum(n1){
	a = n1 + 1;
	b = a + 2;
	c = b + 3;
	d = c + 4;
	e = d + 5;
	return e;
}

// 混淆后的代码
function sum(n1){
	return a = n1 + 1,
	b = a + 2,
	c = b + 3,
	d = c + 4,
	e = d + 5
}

console.log(sum(0))

7、JS常见混淆

AAEncode & JJEncode

混淆网址:https://www.sojson.com/

解决思路:复制混淆后的代码在sublime编辑器中打开,删除最后一个括号里的内容以及括号

JSFuck

混淆网址:http://www.jsfuck.com/

解决思路:复制混淆后的代码在Sublime编辑器打开,匹配最后一个括号)内的代码,复制括号中的代码在浏览器中输出

8、补浏览器环境

JS三种执行环境
浏览器
V8
Node
沙箱环境
https://github.com/patriksimek/vm2

V8
示例代码

var fs = require('fs');
const {VM} = require('vm2');
const vm = new VM();
var data = fs.readFileSync('./src/code.js', 'utf8')
vm.run(data)

调试代码

const {VM, VMScript} = require('vm2');
const fs = require('fs');
// 运行的code代码
const file = `${__dirname}/code.js`;

// 需要补的window环境
const windowfile = `${__dirname}/window.js`;
const vm = new VM();
const script = new VMScript(fs.readFileSync(windowfile)+fs.readFileSync(file), "我正在调试的代码");
vm.run(script);

Node

navigator = {
    userAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"
};

const descriptor1 = Object.getOwnPropertyDescriptor(navigator, 'userAgent');
console.log(descriptor1);

9、JS逆向经验

分析步骤

(1)抓包分析

(2)定位加密位置

(3)扣取JS代码

(4)浏览器还原

(5)Node还原

搜索关键字

笔记参考视频https://space.bilibili.com/409871996

posted @ 2023-03-11 00:09  __username  阅读(2338)  评论(0编辑  收藏  举报

本文作者:DIVMonster

本文链接:https://www.cnblogs.com/guangzan/p/12886111.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。