JS逆向系统性认知

cooolr 于 2021-07-07 发布

分享会目标

对JS逆向有个系统性的认知,通过实战对JS逆向有个整体的感官。当然这里还有许多内容没有囊括,需要感兴趣的同学继续探索。

温馨提示:技术无罪,切勿犯罪。

JS逆向目标

模拟正常的请求。即绕过目标网站的反爬措施,欺骗目标网站为正常用户请求,获取到正常的数据返回。

从具体操作来说,就是绕过检测,找到加密位置,拿到加密过程,并在本地运行起来,正常请求得到返回数据。

JS基础之JS组成

JavaScript组成中最值得我们注意的是三个部分:DOM、BOM、ECMAScript。每个浏览器的实现都会包含这三个部分,而本地的开发环境只有JS引擎,会产生什么后果呢?

DOM

DOM(Document Object Model)就是文档对象模型,描述的是处理网页内容的方法和接口,如对某个dom树节点的增删,监听某个按钮点击事件等等。对应的是document对象。document根节点包含子节点:forms、embeds、anchors、images、links。

BOM

BOM(Browser Object Model)就是浏览器对象模型,描述的是浏览器行为控制的方法和接口,如网页前进后退等。核心表现是window对象。而window对象还有另一重身份,是一个全局对象,在网页中定义的任意对象都以window作为其global对象。

ECMAScript

JS核心模型,描述了JS的语法和基本对象,每个JS引擎都会实现。

常见加密方式

了解常见的加密方式及其特征有助于逆向时快速判断和破解。你能总结各加密方式多少个特征呢?

BASE64

base64不是加密方法,而是一个编码格式,但把AES等加密方法的结果再进行一次base64转换是很常见的方式,值得各位逆向好手注意。

MD系列

成员有md2、md4、md5等。严格意义上不能算是一种加密方式,而是一个取盐校验的方法,取出摘要信息进行校验,无法还原全部信息,作用不可逆。

SHA系列

成员有sha1、sha256、sha512。同MD系列。

对称加密

加密和解密共用一个密钥。成员有AES、DES、3DES。

非对称加密

有一对密钥,公钥和私钥。同一个明文可以通过公钥加密成多个密文,多个密文也可以通过私钥解密成同一个明文。公钥是公之于众的,私钥只掌握在发布者手中。常见是RSA。

反调试

反调试就是阻止调试的行为。作为网络攻防的防守端,网站服务器会在敏感的数据接口请求前做相应的检测,并做出相应的对抗行为。反调试手段分为显性和隐性。

检测点举例

显性反调试

隐性(暗桩)

JS逆向之加密定位

作为网络攻防中的攻击方,第一步是找到目标网站的加密位置。

正常网页加载运行流程

加载html -> 加载js -> 运行js初始化 -> 用户触发某个事件,调用了某段js -> 一系列js运行,对明文操作 -> 加密函数加密 -> 一系列js运行,组装请求,给服务器发送请求(XHR send) -> 接收服务器数据 -> 解密函数解密 -> 刷新网页渲染

全局搜索。定位位置比较贴近加密函数,但搜索到结果比较多要筛选,若变量名混淆了则没办法搜索到了。容易定位到拼装封包的步骤。

xhr

定位的位置在发包函数,可以方便的跟调用栈。只能用于xhr的包。

Initiator

通过调试器的Initiator,也就是堆栈跟踪,定位加密位置。

dom事件

定位的位置比较靠前,容易定位到用户输入明文的位置。没办法太好的使用调用栈。

hook

hook就是替换原方法,加入自己的处理逻辑。要注意代码注入的时机问题。一般可以有两种方式:

(function() {
    'use strict';
	var cookieTemp = "";
    Object.defineProperty(document, 'cookie', {
			set: function(val) {
				console.log('Hook捕获到cookie设置->', val);
				cookieTemp = val;
				return val;
			},
			get: function()
			{
				return cookieTemp;
			}
    });
})();

JS逆向之加密破解

找到目标网站的加密位置后,第二步就是要确定破解的方式了。一般有两种处理方式,手动构造或扣代码。

手动构造加密函数

顾名思义,就是自己写代码。一些简单的网站用的是常规的加密方法如base64,可以直接自己写代码替代。

扣代码

目的就是把加密过程中会使用到的JS代码扒下来,在本地成功运行。最值得注意的两件事:是否扣全、性能如何?

导出方法

多数目标方法都会使用到上下文中定义加载好的变量和函数等,直接扣取方法出来是无法运行的。更稳妥的方式是在整个相关的结构加载好后,再进行方法导出来使用。

// 假设存在目标函数B
function A(){
	var B = function(){
		console.log("这是一个加密函数")
	}
}

// 方式一:使用全局变量导出目标函数
// 此时C()执行失败,但先执行A()后执行C()可运行
var C;
function A(){
	var B = function(){
		console.log("这是一个加密函数");
	}
	C = B;
}

// 方式二:改写成自执行函数
var C;
!(function A(){
	var B = function(){
		console.log("这是一个加密函数");
	}
	C = B;
})()

目标网站一

 [学生空间](https://sk.open.com.cn/stuspace-auth/#/login)

目标参数

登录密码:password

定位

你能想到的最快找到加密方式的方法是什么?

目标网站二

 [G妹游戏](https://www.gm99.com/)

目标参数

登录密码:password

定位

目标网站三

bilibili

目标参数

登录密码:password

扣代码

要如何把目标服务器的代码本地运行起来呢?

课后练习

土巴兔: 请用尽可能多的方式定位password,并实现在本地加密。