逆向爬虫28 webpack扣代码

本文详细介绍了如何分析和扣取webpack打包后的JavaScript代码,特别是涉及加密解密算法的部分。通过理解webpack代码的特征,找到并导出函数加载器,以及定位到实际使用的加密函数,最终在Python环境中使用execjs模块运行扣取的js代码实现加密解密。文章还提供了一个实际的扣取和重构js加密函数的案例,并展示了如何在Python中调用该模块进行密码加密。
摘要由CSDN通过智能技术生成

逆向爬虫28 webpack扣取码

目标:

  1. 了解 js 模块化打包webpack代码的特点。
  2. 掌握扣取 webpack 代码的方法。

一. 模块化 webpack 代码特点

有的时候, 我们发现一些网站的 js 代码的函数不是以全部并列顶格书写的。

function a(){}
function b(){}
function c(){}
// ... 一系列函数
function z(){}

而是以下面形式书写

// 自执行函数, 参数是一个数组, 数组里打包了一堆函数
!function(arr){
    
}([
    function a(){},
    function b(){},
    function c(){},
    // ... 一系列函数
    function z(){}
])

亦或是

// 自执行函数, 参数是一个对象, 对象里打包了一堆函数
!function(obj){
    
}({
    a: function(){},
    b: function(){},
    c: function(){},
    // ... 一系列函数
    z: function(){}
})

遇到上述型类型情况网页的代码, 我们应该怎么扣取相应的加密函数, 放进 execjs 模块中运行呢?其实这是前端 webpack 技术模块化打包后呈现的代码, 这类代码的完整特征呈下述形状

// 自执行函数
!function (allModule) {
    // 函数加载器
    function useModule(whichModule) {
        // 利用 call 或 apply 调用函数
        allModule[whichModule].call(null, "hello world!");
    }
    // 加载并运行了下面数组中的第1个函数
    useModule(0)
}([
    // 用数组打包起来的函数列表
    function module0(param) {console.log("module0: " + param)},
    function module1(param) {console.log("module1: " + param)},
    function module2(param) {console.log("module2: " + param)},
]);

它有以下四个特征:

自执行函数!function(){}()

自执行函数参数[function a(){}, function b(){}, ...]{a: function(){}, b: function(){}, ...}

函数加载器function useModule(){}

函数加载器中有callapply 函数

更多webpack基础内容可以参考下面这个链接:

爬虫逆向基础,理解 JavaScript 模块化编程 webpack

二. 扣取 webpack 方法

因为这是第一次在我的博文中提到扣取 js 代码, 因此就先来谈谈下面两个问题:

  1. 为什么要扣 js 代码?扣 js 代码在 js逆向中的作用。
  2. 怎么扣代码才算是最好的扣法。

首先要弄明白我们为什么要扣 js 代码, 扣代码的作用在于, 我们想复用目标网站已经写好的加密或解密算法, 因为这些代码是维护网站的程序员们写的前端代码, 在浏览器中运行, 并且一定可以与他们的后端服务器进行交互工作, 因此如果能够直接使用他们写好的 js 加密或解密算法, 可以省去我们将加密或解密算法翻译成 python 或其他语言的过程, 在 python 中, 正好有一个 execjs 模块, 可以用来执行 js 代码, 如果我们能够把目标网站中的 js 加密或解密函数从浏览器中扣取下来, 保存到本地, 并用 execjs 模块加载执行, 我们就可以相当轻松地得到和浏览器一样加解密效果。

知道了为什么要扣 js 代码之后, 我们再来讨论一下, 怎么扣才算是最好的扣法, 因为我们并不打算在读懂 js 代码后, 自己用 python 或其他语言来自己实现相同的功能, 因此我们就要做到最大程度地复用网站上现有地 js 代码, 而这个过程中, 希望能做到尽量少改动 js 代码, 原因是改的地方越多, 改错的可能性就越大, 后期的维护和扩展成本也就越高。理论上最好的扣法是, 把和你需要的加密和解密相关的函数扣取出来, 并把它们封装成自定义的加密和解密函数, 这部分代码工作时, 由外部的 python execjs 模块调用自定义的加解密函数来完成加解密的工作。

基于上述两个问题, 我们来给出下面这个针对 webpack 样式的代码扣取方法

找到加载器 (加载模块的方法)
找到调用的模块
构造一个自执行方法
导出加载器
编写自定义方法 按照流程加密

三. 扣取 webpack 实例

由于不能指名道姓地公开网站的逆向方案, 因此下面的案例我不会贴出网址, 只是基于一个 webpack 的 js 文件, 扣取内部的加密算法。

下图是一个网站中包含加密函数的 js文件

在这里插入图片描述

把它全选复制到本地 IDE 中

在这里插入图片描述

可以看到它满足 webpack 代码的所有特点, 因此我们可以先把 自执行函数 函数加载器 先扣下来, 自执行函数里除了 函数加载器 之外的东西可以不要

!function(t) {
    var i = {};
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
        n.loaded = !0,
        n.exports
    }
}({});

下图是我在网页输入用户名密码后, 点击登陆后找到的加密函数位置

在这里插入图片描述

这里我们找到了第一个用到的函数模块, 就是对象中的第四个函数, 因此把它扣下来即可, 为了外部自定义函数方便调用, 这里我把 key 值从 3 换成了 encrypt

!function(t) {
    var i = {};
    function e(s) {
        if (i[s])
            return i[s].exports;
        var n = i[s] = {
            exports: {},
            id: s,
            loaded: !1
        };
        return t[s].call(n.exports, n, n.exports, e),
        n.loaded = !0,
        n.exports
    }
}({
    encrypt: function(t, e, i) {
        var s;
        s = function(t, e, s) {
            function n() {
                "undefined" != typeof r && (this.jsencrypt = new r.JSEncrypt,
                this.jsencrypt.setPublicKey("-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB-----END PUBLIC KEY-----"))
            }
            var r = i(4);
            n.prototype.encode = function(t, e) {
                var i = e ? e + "|" + t : t;
                return encodeURIComponent(this.jsencrypt.encrypt(i))
            },
            s.exports = n
        }
        .call(e, i, e, t),
        !(void 0 !== s && (t.exports = s))
    }
});

接下来我们利用浏览器调试, 追到 594 行代码 this.jsencrypt.encrypt(i) 函数内部

在这里插入图片描述

在本地 IDE 中查看3340行属于哪个函数

在这里插入图片描述

扣下来的效果如下, 由于代码太长, 这里就放截图效果

在这里插入图片描述

从中我们可以看出, 原本标号为 3 的函数又加载了 标号为 4 的函数, 因此我们需要再确认一下, 标号 4 的函数是否有加载其他标号的函数, 另外 4 号函数为什么没有重命名呢?因为是内部调用的函数, 不是接口函数, 我们无需关心它的名字。

如何快速查看 4 号函数是否有再加载其他函数呢?可以使用 IDE 中的搜索功能 (ctrl + f ), 开启正则表达式匹配

在这里插入图片描述

现在前三步已经完成了

找到加载器 (加载模块的方法)		完成
找到调用的模块				   完成
构造一个自执行方法			  完成
导出加载器
编写自定义方法 按照流程加密

接下来是 导出加载器

在这里插入图片描述

加载器也导出了, 下一步就是先把这段代码复制到浏览器中运行一下, 看看有没有问题。

在这里插入图片描述

因此可以封装如下自定义加密函数

在这里插入图片描述

然后把它放进 js 调试工具中试试, 分别报了找不到 navigator 和 window 两个对象, 加上之后就运行成功了。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

最终, 扣出来并修改好的js文件长这个样子。

在这里插入图片描述

四. 用python execjs调用该模块

from time import time
import execjs

def getPwd(pwd):
    """ 密码加密 
        param:
            pwd: 密码明文
        return:
            encrypt_pwd: 密码密文
    """
    node = execjs.get()
    fp = open('encrypt.js','r',encoding='gbk')
    ctx = node.compile(fp.read())
    funcName = f"jiami('{pwd}', {int(time()*1000)})"
    print(funcName)
    encrypt_pwd = ctx.eval(funcName)
    print(encrypt_pwd)
    return encrypt_pwd

def run():
    pwd = '123456'
    encrypt_pwd = getPwd(pwd)

if __name__ == '__main__':
    run()

对了, 中间出了个编码问题, 是因为抠出来的 js 文件中存在 gbk 编码的字符, 因此我以 gbk 编码重新打开了一个新的空的 js 文件, 并将这抠出来的 js 代码复制到里面, 保存。在 python 以 gbk 方式打开它, 就可以了

webpack代码,可以采用以下技巧: 1. 首先,观察真实网站中的webpack配置,了解其组成和功能。通过观察可以发现,加载器函数中的功能更加完善,而加载器函数与执行对象在一个文件中。这种情况下,可以对这个文件进行取。 2. 其次,需要找到webpack的基本要素。在这里,不仅需要注意自执行函数,还要关注传入的实参,也就是那个对象或数组。这个对象或数组包含了webpack的配置信息和各种插件。 3. 了解webpack的配置文件结构,其中包括入口文件、输出路径、加载器、插件等。通过分析配置文件,可以获取到webpack的关键信息。 4. 使用工具或方法来webpack代码,例如使用Chrome浏览器的开发者工具来查看网页加载的资源文件,或者使用webpack的插件或工具来分析和提取代码。 5. 学习和掌握webpack的相关知识,包括模块化的原理、加载器的使用、插件的配置等。这样可以更好地理解和分析webpack代码结构。 总之,要webpack代码,需要对其配置文件和代码结构进行分析,掌握相关的技巧和工具,以便能够准确地提取所需的代码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [js逆向——webpack法](https://blog.csdn.net/sin_0119/article/details/129658679)[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: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值