浅谈JS逆向

好久没发文章了,博客迁移了新地址:https://s1nja.github.io/

JS基础

变量声明

在JS中,可以通过var关键字来声明变量

var name;
或
name = "S1nJa"

在这里插入图片描述

也可以一次定义多个变量

var name = "S1nJa",age=18

函数

function add(a,b){
    c = a+b
    return c
}
add(1,1) 

在这里插入图片描述

常用函数

length

返回字符串的长度。

在这里插入图片描述

indexOf

用于查找指定字符串在另一个字符串中第一次出现的位置。

在这里插入图片描述

slice

slice(start, end)

从一个字符串中返回指定起始索引和结束索引之间的子串

在这里插入图片描述

substring

substring(start, end)

substring方法类似于slice,不同的是substring方法无法接受负数索引。

在这里插入图片描述

substr

substr(start, length)

substr的第二个形参接受的不是结束为止,而是截取长度

在这里插入图片描述

replace

用于字符串替换

在这里插入图片描述

concat

用于字符串拼接

在这里插入图片描述

push

向数组中添加元素

在这里插入图片描述

join

将所有元素合并为一个字符串

在这里插入图片描述

toUpperCase() 用于将字符串转为大写

toLowerCase() 用于将字符串转为小写

trim() 删除字符串两端的空白符,同Python中的strip()一样的功能。

charAt() 方法返回字符串中指定下标(位置)的字符串

split() 分割字符串

pop() 从数组中删除最后一个元素

push() 向数组结尾处添加新的元素

shift() 删除数组最后一个元素

unshift() 向数组开头处添加元素

sort() 对数组进行排序(按照数字大小或者字母顺序)

reverse() 反转数组中的元素。

条件运算

if (condition){
    语句
}
...................
if (condition){
	语句
}else{
	语句
}
...................
if (condition1){
    语句
}else if (condition2){
    语句
}else{
  语句
}
...................
switch(n)
{
    case 1:
        代码块 1
        break;
    case 2:
        代码块 2
        break;
    default:
        代码块3
}

在这里插入图片描述

循环语句

for (语句 1; 语句 2; 语句 3){
    语句
}

while (condition){
    语句
}

do{
    语句
}
while (condition);

在这里插入图片描述

JS调试

在JavaScript中,断点调试是一种常用的调试技术,它允许开发者在代码的特定位置暂停执行,以便检查和分析程序的状态。

当发现可疑函数时,可以通过在断点处暂停,查看和修改变量的当前值,观察每一步数值的变化。

当打下断点后,重新请求页面便会进入调试模式

在这里插入图片描述

主要分为以下功能:

①逐过程执行:常用存在多个断点,需要在多断点间进行调试使用

②逐语句执行:步过,遇到自定义函数也当成一个语句执行,而不会进入函数内部

③:与①一致

④:与②一致

⑤步入:遇到自定义函数就跟入到函数内部步出,跳出当前自定义函数

⑥步出:跳出当前自定义函数

除此外右侧部分可以查看作用域(变量的内容)和当前的调用栈等信息

加密方法定位

定位的方式有很多如提交表单时存在onClick寻找加密函数,Event Listeners定位,全局搜索等,就不一一介绍了,主要看下JS函数检测辅助工具

v_jstools

安装

下载解压后直接添加扩展即可

GitHub - cilame/v_jstools: 模仿着写一个 chrome 插件,用来快速调试前端 js 代码。

打开hook开关,根据需求进行配置即可
在这里插入图片描述

使用

这里使用的是师傅编写的JS逆向练习靶场,https://github.com/0ctDay/encrypt-decrypt-vuls/

开启后重新发送请求,控制台会提示inject start!即开启成功

在这里插入图片描述

1、此时发送请求,即可对我们设置的功能点进行hook,找到了明文请求的点并返回hook的位置

在这里插入图片描述

2、在hook点打断点调试,寻找将数据进行加密的函数

n即为原始的明文数据,当调试到t.data = l(n);,发现经过l()函数,t.data的值发生了改变,并且对应的值就是我们传入数据加密后的值,因此l()函数一定就是要找的加密函数

在这里插入图片描述

3、跟进l()函数,t为传入的明文数据,f为秘钥,h为偏移量

在这里插入图片描述

4、同时在调用l()前,发现了requestID、时间戳、签名

在这里插入图片描述

修改数据包

定位到加密函数后,就要着手修改数据包了

JS-RPC

https://github.com/jxhczhl/JsRpc

JS-RPC是一款远程调用浏览器方法的工具,通过websocket与本地python服务端相连。当python中想要执行代码时,只需要通过RPC即可调用控制台中的函数,不需要再本地还原。

使用

JsRpc/README.md at main · jxhczhl/JsRpc · GitHub

1、打开客户端,将JSRPC项目中的JsEnv.js中的代码复制到控制台中

2、输入var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=S1nJa");建立连接

在这里插入图片描述

3、经过刚才的调试我们已经知道了l()函数即为加密函数,那便可打断点记录该函数进行调用

在这里插入图片描述

4、将其注册到JSRPC

demo.regAction("enc", function (resolve, param) {
    var res = enc(String(param));
    resolve(res);
})

在这里插入图片描述

5、注册完成后即可进行本地调用了

http://127.0.0.1:12080/go?group=S1nJa&action=enc&param=test

在这里插入图片描述

6、解密函数同理,通过调试发现解密函数为d(),直接记录注册

在这里插入图片描述

JS-RPC+MITM

mitmproxy - an interactive HTTPS proxy

mitmproxy作为一款代理工具,可以通过python对请求进行拦截,篡改,从而达到hook的目的

经过前边的分析可知,我们的每次请求都包含以下参数

在这里插入图片描述

  • r:时间戳
  • n:Json格式的原始数据
  • i:requestId
  • s:签名信息
  • l:加密函数
  • d:解密函数

所以如果想要构造请求,就需要获取到以上参数,这里对明文请求进行加密,密文回显解密为例

JS-RPC

首先还是注册JS-RPC,对每个参数进行记录注册:

记录:

//时间戳
window.time = Date.parse
//requestId
window.id = p
//v函数
window.v1 = v
//签名
window.m = a.a.MD5
//加密函数
window.enc = l
//解密函数
window.dec = d

注册:

demo.regAction("req", function (resolve,param) {

    let timestamp = time(new Date());
    let requestid = id();
    let v_data = JSON.stringify(v1(param));
    let sign = m(v_data + requestid + timestamp).toString();
	
    let encstr = enc(v_data);

    let res = {
        "timestamp":timestamp,
        "requestid":requestid,
        "encstr":encstr,
        "sign":sign
    };
    resolve(res);
})

在这里插入图片描述

注册dec

demo.regAction("dec", function (resolve, param) {
    var res = dec(String(param));
    resolve(res);
})
#测试
http://127.0.0.1:12080/go?group=S1nJa&action=dec&param=wyJy7dTITM1EBaQzVmT%2Blw==

测试

在这里插入图片描述

MITM

现在通过JS-RPC已经可以获取到,时间戳、requestid、sign、加解密内容,之后就可以通过Mitmproxy对请求响应进行hook了

import json
from mitmproxy import http
import requests

def getHeader(method,body):
    data = {"group": "S1nJa", "action": method, "param": body}
    res = requests.post("http://127.0.0.1:12080/go", data=data)
    res_json = json.loads(res.text)["data"]
    return res_json

def request(flow: http.HTTPFlow) -> None:
    if flow.request.pretty_url.startswith("http://127.0.0.1:8085/api/"):
        # 获取原始请求
        original_body = flow.request.content.decode('utf-8')
        res_json = getHeader("req",original_body)
        data_json = json.loads(res_json)

        # 获取生成的请求信息
        encrypted_body = data_json["encstr"]
        request_id = data_json["requestid"]
        timestamp = data_json["timestamp"]
        sign = data_json["sign"]

        # 添加或替换数据
        flow.request.text = encrypted_body
        flow.request.headers["requestId"] = request_id
        flow.request.headers["timestamp"] = str(timestamp)
        flow.request.headers["sign"] = sign

def response(flow: http.HTTPFlow) -> None:
    content_type = flow.response.headers.get("Content-Type", "")
    if "application/json" in content_type:
        # 获取响应体
        response_body = flow.response.get_text()
        res = getHeader("dec",response_body)
        flow.response.set_text(res)

运行mitmproxy

mitmproxy -p 8083 -s mit.py

将8083端口设为burp的上游代理

在这里插入图片描述

此时明文发包,可以看到数据会经过mitm加密处理,返回包也为明文数据

在这里插入图片描述

JS-RPC+autoDecoder

GitHub - f0ng/autoDecoder: Burp插件

autoDecoder是f0ng师傅编写的一款Burp插件,同样可以与JS-RPC进行联动,达到hook的目的

插件中自带了一些常规的加密方式如aes、des、RSA、国密等

在这里插入图片描述

特殊加密方式可以通过修改项目中的flasktest.py与JS-RPC进行联动

autoDecoder

JS-RPC注册跟MITM中方式一样,加密部分由于需要替换请求头时间戳、requestid、sign还未实现,暂贴解密部分代码

from flask import Flask, Response, request
import requests
import json


def getHeader(method, body):
    data = {"group": "S1nJa", "action": method, "param": body}
    res = requests.post("http://127.0.0.1:12080/go", data=data)
    res_json = json.loads(res.text)["data"]
    return res_json


app = Flask(__name__)


@app.route('/decode', methods=["POST"])
def decrypt():
    param = request.form.get('dataBody')  # 获取 post 参数
    param_headers = request.form.get('dataHeaders')  # 获取 post 参数
    param_requestorresponse = request.form.get('requestorresponse')  # 获取 post 参数

    res = getHeader("dec", param)
    print(param)
    if param_requestorresponse == "request":
        return param_headers + "\r\n\r\n\r\n\r\n" + param
    else:
        return res


if __name__ == '__main__':
    app.debug = True  
    app.run(host="0.0.0.0", port="8888")

测试调试

在这里插入图片描述

成功后,便可抓包选择加密部分右键选择autodecoder->Decode-Autodecoder进行解密

JS-PRC+YAKIT

在前边MITM方式中,使用的是mitmproxy自带库,对原始http请求进行拦截修改,而yakit中拥有热加载功能,此功能中有两个魔方方法beforeRequestafterRequest,他们分别可以在发送数据包前和对每一个请求的响应再做一次处理

而yakit的官方[poc库](poc | Yak Program Language (yaklang.com)),可以对HTTP请求进行处理,这样结合beforeRequestafterRequest便可对请求响应进行hook

JS-RPC跟前边一致

热加载加解密

热加载代码:

func getHeader(method,body){
    res,rep,err = poc.Post("http://127.0.0.1:12080/go",poc.replaceBody("group=S1nJa&action="+method+"&param="+body, false),poc.appendHeader("content-type", "application/x-www-form-urlencoded"))
    if(err){
        return(err)
    }
    res_json = json.loads(res.GetBody())["data"]
    return res_json
}


// beforeRequest 允许发送数据包前再做一次处理,定义为 func(origin []byte) []byte
beforeRequest = func(req) {
    //获取请求体
    original_body = poc.GetHTTPPacketBody(req)
    //加密
    res = getHeader("req",string(original_body))
    //获取其他的参数
    res = json.loads(res)

    //修改其他的请求头
    req = poc.ReplaceHTTPPacketHeader(req, "requestId", res["requestid"])
    req = poc.ReplaceHTTPPacketHeader(req, "timestamp", res["timestamp"])
    req = poc.ReplaceHTTPPacketHeader(req, "sign", res["sign"])

    //修改请求体
    req = poc.ReplaceHTTPPacketBody(req, res["encstr"])


    return []byte(req)
}

// afterRequest 允许对每一个请求的响应做处理,定义为 func(origin []byte) []byte
afterRequest = func(rsp) {
    hd,body = poc.Split(rsp)
    rss = getHeader("dec",codec.EncodeUrl(string(body)))
    rsp = poc.ReplaceHTTPPacketBody(rsp,rss)
    return []byte(rsp)
}

// mirrorHTTPFlow 允许对每一个请求的响应做处理,定义为 func(req []byte, rsp []byte, params map[string]any) map[string]any
// 返回值回作为下一个请求的参数,或者提取的数据,如果你需要解密响应内容,在这里操作是最合适的
mirrorHTTPFlow = func(req, rsp, params) {
    return params
}

通过热加载,成功将明文数据加密并发送请求进行fuzz,响应体通过解密返回明文数据

在这里插入图片描述

添加插件解密

先注册解密函数

window.dec = d
demo.regAction("dec", function (resolve, param) {
    var res = dec(String(param));
    resolve(res);
})

新建插件(插件—>本地—>新建插件)

在这里插入图片描述

选择Yak-codec

在这里插入图片描述

源码

handle = func(origin /*string*/) {
    group = "S1nJa";
    action = "dec";
    rsp,rep = poc.Post("http://127.0.0.1:12080/go",poc.replaceBody("group="+group+"&action="+action+"&param="+codec.EncodeUrl(origin), false),poc.appendHeader("content-type", "application/x-www-form-urlencoded"))~

    return json.loads(rsp.GetBody())["data"];
}

保存后便可通过右键菜单中的JS解密,将密文转换为明文

在这里插入图片描述

参考链接

poc | Yak Program Language (yaklang.com)

奇安信攻防社区-在渗透的"幽灵模式"中开启"透视"外挂 (butian.net)

奇安信攻防社区-死磕某小程序 (butian.net)

奇安信攻防社区-某众测前端解密学习记录 (butian.net)

保姆级教程—前端加密的对抗(附带靶场) - 先知社区 (aliyun.com)

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
app逆向js逆向是两种不同的技术方法。app逆向主要是指对安卓应用程序的逆向工程,通过反编译、分析、修改应用程序的代码和功能。在app逆向过程中,常用的工具包括jadx反编译工具、JEB反编译工具、Frida之Hook工具、IDAPro反汇编工具等。可以通过这些工具来分析应用程序的逻辑、修改参数和功能等。 而js逆向主要是指对JavaScript代码的逆向工程,通过分析和解密JavaScript代码,获取其中的关键信息。在js逆向过程中,常用的工具包括查壳工具、加密解密工具、鬼鬼js加密浏览器、Python的execjs库等。可以通过这些工具来解密加密的JavaScript代码、分析代码逻辑以及调试代码等。 所以,app逆向主要是对安卓应用程序进行逆向分析和修改,而js逆向主要是对JavaScript代码进行解密和分析。这两种逆向方法在实际应用中可以结合使用,以达到更好的逆向效果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [APP逆向工具-js调试](https://blog.csdn.net/b806071099/article/details/115553351)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [suning易购商城app api_sign参数逆向解析 最新现可用_x_req_block_加密 解密sign等参数](https://download.csdn.net/download/qq_40609990/85586243)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Android逆向基础入门](https://blog.csdn.net/weixin_43411585/article/details/122503411)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值