
webpack打包是前端js模块化压缩打包常用的手段,特征明显,比如下方的形式的代码就是webpack分发器
// 分发器
!function(x){
function xx(n){
return ..call(**.exports, ***, ***.exports, xx)
}
}()
又或者更直观的表现n["xxx"]这种,你可以大概知道了这是调用了webpack打包的js模块代码。
webpack打包后JS依赖模块代码的固定结构:
(this["webpackJsonpzsgk-pc"] = this["webpackJsonpzsgk-pc"] || []).push([[15], [function(e, t, n) {
"use strict";
e.exports = n(693)
}
// 参数固定为e, t, n
, function(e, t, n) {
e.exports = n(697)()
}
说个逆向webpack的通用方法:
先去找加密网站的加密入口。这应该是加密网站都必须要做的==> 直接根据参数名搜索参数
找到分发器的位置,或者说是加载器,n["xxx"]这种的n就是分发器,就比如下方中的exports的位置,最后执行了d函数==>一般是runtimexxx.js中(提供环境);一般以! function(e) {的形式出现

寻找分发编号、加密使用模块(用到了哪些模块就导入哪些模块)==>一般在chunk-lib.js,以(window.webpackJsonp = window.webpackJsonp || []).push([的形式出现
将函数入口的地方返回全局变量,最终返回: var sign; var window = global;!function(){... sign = d}, 赋值为分发器返回的d
使用自定义的sign代替webpack代码中的n进行加密
from: https://blog.csdn.net/weixin_41586984/article/details/116268341
打开开发者工具后,F5刷新后Ctrl + Shift + F搜索参数名,如signdata,会显示多个JS文件,选择后仔细查看(点击左下角{}美观格式化按钮)。
more: 如果文件太多,则直接通过请求的链接去找,比如user/login
Network找到新发出的xhr条目后,查看Initiator里的调用栈信息,如Login;
注: 如果加密参数名称比较简单如s,比较难定位的话,可以借助请求的其他参数来查找,比如verificationCode
时间戳: (new Date).getTime()
var a = (f1(), f2(), f3())后,f1、f2、f3函数都会执行,而a最后的结果为f3的返回值
javascript:void(0): void 是 JavaScript 中非常重要的关键字,该操作符指定要计算一个表达式但是不返回值。
TypeError: window.btoa is not a function
btoa-atob 模块没有输出一个编程接口,它只提供命令行工具。
如果你需要转换为Base64,你可以用Buffer来完成。
console.log(Buffer.from('Hello World!').toString('base64'));
相反的,假设你要解码的内容是一个base64编码过的字符串。
console.log(Buffer.from(b64Encoded, 'base64').toString());
var m = this.newEncrypt(JSON.stringify(h));
需要对this.privaKey的值细化下,传入拿到固定的str
// , p = t("NFKh") , s = t("cg2h")
l.prototype.newEncrypt = function(l) {
var n = p.enc.Utf8.parse(this.privaKey)
, t = p.enc.Utf8.parse(this.privaKey)
, e = p.enc.Utf8.parse(l)
, a = p.AES.encrypt(e, n, {
iv: t,
mode: p.mode.CBC,
padding: p.pad.Pkcs7
});
return p.enc.Base64.stringify(a.ciphertext)
}
password: this.encode(this.encrypt(this.form.password)),
c = a("3452")、n = a.n(c),看到需要依赖3452后立马Ctrl+shift+F全局搜3452,然后把整个webpack模块扒下来r = n("XBrZ");,在另一个文件中,module需要放两个
var t = encodeURIComponent(c["c"].Des.encrypt(this.form.email, this.form.pwd)),
webpack实现
c = (mycode("ac6a"), mycode("b3ae"))
自己实现:直接扒下来encrypt加密的JS内容
mycode = obj;
u = i("x4Ab")return e.encrypt_data && (e.data = Object(u.a)(e.encrypt_data)),
x4Ab模块依赖aqBw,aqBw又依赖YuTi、yLpj,因此依赖项中放"x4Ab"、"aqBw"、"YuTi"、"yLpj"函数定义
模拟解析函数
function encrypt(data){
return data && (Object(u.a)(data))
}
var navigator = {}o = (u=a(42), a.n(u)),使用到了a.n(u)即点n函数{"xxx": function()}的形式,因此直接require也没用TypeError: Cannot read property '42' of undefined,而是将依赖模块数组作为参数写入到分发器依赖函数中!function(e){}([...])即方括号中,从而才能找到42函数
t.data.reqId = n,
直接通过n(109)定位可能不那么准确(双击后定位的函数),可以试着直接在分发器位置进行断点,然后console输出e["109"]
只要分发器定义部分(其他的删了,因为只用了l=n(109)、c=n.n(l))+依赖模块中定义109函数(整个function而不是t.exports),以及观察其中还依赖什么如n(202)、n(203)就补充拿什么
// 如果不删分发器中其他部分
l = mycode(109)
c = mycode.n(l) // ==>得到l
var r = c()();
console.log(r)
// 由于只用到了n.n(l),所以可以删分发器大代码中其他部分, 在使用时直接让c=l
l = mycode(109)
c = l();
console.log(c) // 等价于 r = l(); console(r)
文章: https://blog.csdn.net/weixin_43189702/article/details/119860838
require模块内容可以放在逆向JS文件里一起,而不是一定得创建新的JS文件导入
先登录然后找到加密处加断点,这个断点会在发起登录请求时才触发;往上找分发器,加上断点,分发器位置的断点是在页面刷新时触发,因此要触发这个断点需要刷新页面
找加密函数c["c"].Des.encrypt(this.form.email, this.form.pwd)的时候,找完整的函数如c["c"].Des.encrypt,而不是直接找c
n(42), 或者n("xxx"),可以直接搜xxx,也可以在console里面输出后找到对应的FunctionLocation来快速定位
如果依赖模块是字典的形式,则分发器依赖中写字典,如!function(e){..}({ 32:function(){...}})(一般情况n(32)、n("ABCD")), 如果不是则需要传函数数组,如n(42),此处42表示的是第42个函数,见掌上高考。
var mycode;后赋值的位置直接在分发器的下方即可,不用在最后面
提示缺少window时,定义全局变量var window = global;,(JS逆向文件、依赖文件)
window表示浏览器打开的窗口,在客户端JavaScript中window对象是全局的对象,所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。但在nodejs中直接调用window是不存在的,而代替的是global,所以要用nodejs运行时,得用var window = global;
var navigator = this等价于var navigator = {},因为在NodeJS文件中运行输出this后可以发现this={},而在浏览器中this默认为window(函数或类作用域内为函数或者类实例)
心得
①所有webpack打包的的js都要先看懂打包后代码运行的顺序,找到加密处;②找到webpack对象,一般是 n(数字) 调用③确定分发器。④找依赖模块,有时候各包的依赖关系太多,可以直接把文件爬下来引入,如果各个包的依赖关系不多,就可以只把调用到的函数找出来放到依赖中。⑤最后剩下的就是找到你要的代码,慢慢复现调用加密/解密函数就好了。
相应的data.text是加密的,页面通过JS解密后渲染
确定加密位置
return null != l && null !== (a = l.data) && void 0 !== a && a.text && (l.data = (n = (e = {
iv: u.uri,
text: l.data.text,
SIGN: h
}).iv,
确定分发器位置,在html内
通过打断o = (u=a(42), a.n(u)) // 等价于 o = a(42)
确定依赖模块:给return e[a].call(c.exports, c, c.exports, r),打断点后console输出e["42"]查看a(42)位置:
function(e, t, n) {
e.exports = (e = n(21),
n(201),
n(825),
...
n(847),
e)
}
可以看到需要依赖多个,因此直接把整个文件引入
return表达式后是逗号的情况:会从左到右执行执行,并返回最后一个。注意:JS函数并不能返回多个返回值
then((function(l) {
var e, a, t, b, n;
return null != l && null !== (a = l.data) && void 0 !== a && a.text && (l.data = (n = (e = {
iv: u.uri,
text: l.data.text,
SIGN: h
}).iv,
a = e.text,
e = e.SIGN,
e = o.a.PBKDF2(e, "secret", {
keySize: 8,
iterations: 1e3,
hasher: o.a.algo.SHA256
}).toString(),
n = o.a.PBKDF2(n, "secret", {
keySize: 4,
iterations: 1e3,
hasher: o.a.algo.SHA256
}).toString(),
a = o.a.lib.CipherParams.create({
ciphertext: o.a.enc.Hex.parse(a)
}),
n = o.a.AES.decrypt(a, o.a.enc.Hex.parse(e), {
iv: o.a.enc.Hex.parse(n)
}),
// data.text解析结果
JSON.parse(n.toString(o.a.enc.Utf8)))),
v && (t = r,
b = l,
null !== (n = window.apiConfig) && void 0 !== n && null !== (n = n.filterCacheList) && void 0 !== n && n.length ? window.apiConfig.filterCacheList.forEach((function(l) {
new RegExp(l).test(t) || d.set(t, b)
})) : d.set(t, b)),
l
}
难点:
跟"xxx"模式不同的是,由于没有用字典{"xxx": function()}的形式,因此直接require也没用TypeError: Cannot read property '42' of undefined,而是将依赖模块函数数组作为参数写入到分发器依赖函数中!function(e){}([...])即方括号中,从而才能找到42函数
挑选push后第二个[]中的函数数组
(this["webpackJsonpzsgk-pc"] = this["webpackJsonpzsgk-pc"] || []).push([[15], [function(e, t, n) {
"use strict";
e.exports = n(693)
},
...
}
]]); // 第一个]
理解了a.n的含义后,可以直接把o = (u=a(42), a.n(u))转化为o=a(42)
大致流程跟data.text差不多,但是
p = c()(g)执行时,会报错Md5.prototype.update = function(e) { if (!this.finalized) { var t, n = typeof e; if ("string" != n) { if ("object" != n) throw ERROR; if (null === e)根据一步步调试之后发现,还是
c = (u=a(291),a.n(u))直接替换出的问题
Ctrl + shift + F定位参数
g = void 0,
g = (t = {
SIGN: h,
str: f.replace(/^\/|https?:\/\/\/?/, "")
}).SIGN,
t = t.str,
g = o.a.HmacSHA1(o.a.enc.Utf8.parse(t), g),
g = o.a.enc.Base64.stringify(g).toString(),
p = c()(g),
u.signsafe = p,
往上找c和o.a: o = (u = a(42),a.n(u)), c = (u = a(291),a.n(u))
找到分发器扣出==>这次不能删除分发器中多余的函数,比如r.a、r.d、r.n因为后面得用
将依赖模块跟data.text一样,放入分发器依赖模块中
扣加密函数
网页上是return后多段内容,以及g变量不断被修改,因此通过一步步调试确定入参,以及分解return抽离出真正的加密参数signsafe
h = "D23ABC@#56"
var o = {}
o.a = mycode(42)
// ▲
c = (u = mycode(291), mycode.n(u))
/**
* 对url进行加密
*/
function encrypt(f) {
g = (t = {
SIGN: h,
str: f.replace(/^\/|https?:\/\/\/?/, "")
}).SIGN,
t = t.str;
// console.log(t, g);
g = o.a.HmacSHA1(o.a.enc.Utf8.parse(t), g);
// console.log(g)
g = o.a.enc.Base64.stringify(g).toString();
// console.log(g)
p = c()(g);
return p;
}
res = encrypt("https://api.eol.cn/web/api/counter?cid=1&did=263")
console.log(res)
可以看到o.a和c的赋值是不一样的,虽然说大多数情况x = a.n(u)等价于x=u,但难免有时会有不一样,因此谨慎期间,还是还原到底最好。
import execjs
def get_signsafe_by_javascript(url):
# 两个 JavaScript 脚本,两种方法均可
with open('gk_signsafe.js', 'r', encoding='utf-8') as f:
exec_js = f.read()
signsafe = execjs.compile(exec_js).call('encrypt', url)
return signsafe
signsafe = get_encrypted_password_by_javascript("https://api.eol.cn/web/api/counter?cid=1&did=263")
print(signsafe)
注: var window=global、var navigator={}
// window.JSEncrypt is not a constructor 在抠出来的JS Encrypt代码中加上
window.JSEncrpt = ze
// 网页中位var n = new JSEncrypt ==> JSEncrypt is not defined
var n = new window.JSEncrypt;
n.setPublicKey...
var a = n.encrypt(t.data.hash + password);
console.log(a)
网易云爬评论:python通过execjs来调用JS代码,代码中用到了CryptoJS库, 需要os.environ["NODE_PATH"]="F:/..../node_modules"把库导入
JS逆向实战分析--某铁网分析:document返回类型,initiator是一条条文本(Other),因为其没有用ajax(XHR),而是通过原生的网页表单提交
loginForm.password.value = encryptByDES(loginForm.password.value), loginForm.publickey.value);
loginForm.submit();
直接require导入CryptoJS模块
or直接扣encryptByDES的加密函数==>出现cannot read property 'createEncryptor' of undefined
MD5加密:
JS: const crypto = require("CryptoJS"); crypto.MD5('待加密字符串').toString()
Python: https://blog.csdn.net/weixin_44799217/article/details/112486097
# 法一:创建md5对象
hl = hashlib.md5()
# Tips
# 此处必须声明encode,若写法为hl.update(str) 报错为: Unicode-objects must be encoded before hashing
hl.update(str.encode(encoding='utf-8'))
# 法二:
str_md5 = hashlib.md5(str.encode(encoding='utf-8')).hexdigest()
base64编码
JS: CryptoJS.enc.Base64.parse("待解密字符串").toString(CryptoJS.enc.Utf8)
Python
# 字符串
encode_str = base64.encodebytes(test_str.encode('utf8')) # b'aGVsbG8gd29ybGQh\n'
print(encode_str.decode()) # 默认以utf8解码,结果 aGVsbG8gd29ybGQh
# 图片
with open("D:\\redis.png", 'rb') as f:
encode_img = base64.b64encode(f.read())
file_ext = os.path.splitext("D:\\redis.png")[1]
print('data:image/{};base64,{}'.format(file_ext[1:], encode_img.decode()))
f.close()
urlencode是一个函数,可将字符串以URL编码,用于编码处理。
URL编码(URL encoding),也称作百分号编码(Percent-encoding), 是特定上下文的统一资源定位符 (URL)的编码机制。
最常见的用于传输8Bit字节码的编码方式之一
注:跟下面的算法区分一下,base64是编码方式,并不能算加密算法。应用场景还有传输图片:data:image/jpg;base64,/9j/4QMZRXhpZgAASUk...
消息摘要算法
注:RSA加解密中必须考虑到的密钥长度、明文长度和密文长度问题;
▲.一般会使用 JSEncrypt 库,会有 new 一个实例对象的操作;
SHA 是比 MD5 更安全一点的摘要算法,SHA 通常指 SHA 家族算法,
sha1
字母(a-f)和数字(0-9)混合
密文特征跟MD5差不多,只不过数字是40位,bit位数(160)==>4位十六进制表示一个数
Sha256
字母(a-f)和数字(0-9)混合
对于任意长度的消息,SHA256都会产生一个256位的哈希值,即64位十六进制数,称作消息摘要。
HMAC
在md5和sha1加密的基础上引入了秘钥,而秘钥又只有传输双方才知道,所以基本上是破解不了的,常用于接口签名验证
AES、DES、3DES、RC4、Rabbit 等加密算法的密文通常没有固定的长度,他们通常使用crypto-js库来实现
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现
最近在工作中,看到一些新手测试同学,对接口测试存在很多疑问,甚至包括一些从事软件测试3,5年的同学,在聊到接口时,也是一知半解;今天借着这个机会,对接口测试做个实战教学,顺便总结一下经验,分享给大家。计划拆分成4个模块跟大家做一个分享,(接口测试、接口基础知识、接口自动化、接口进阶)感兴趣的小伙伴记得关注,希望对你的日常工作和求职面试,带来一些帮助。注:文章较长有5000多字,希望小伙伴们认真看完,当然有些内容对小白同学不是太友好,如果你需要详细了解其中的一些概念或者名词,请在文章之后留言,后续我将针对大家的疑问,整理输出一些大家感兴趣的文章。随着开发模式的迭代更新,前后端分离已不是新的概念,
目录FIFO一.自定义同步FIFO1.1代码设计1.2Testbech1.3行为仿真***学习位宽计算函数$clog2()***$clog2()系统函数使用,可以不关注***分布式资源或者BLOCKBRAM二.异步FIFO2.1在FIFO判满的时候有两种方式:2.2异步FIFO为什么要使用格雷码2.2.1介绍格雷码2.2.2格雷码在异步FIFO中的应用2.2.2格雷码判满2.4二进制与格雷码之间的转换2.4.1二进制码转换为格雷码的方法2.4.2格雷码转换为二进制码的方法2.3实现框图2.5实现及仿真代码2.6仿真图验证2.7结论FIFO 这篇更多的是记录FIFO学习,参考了众多优秀的文章,
运行有问题或需要源码请点赞关注收藏后评论区留言一、利用ContentResolver读写联系人在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。首先要给AndroidMaifest.xml中添加响应的权限配置 下面是往手机通讯录添加联系人信息的例子效果如下分成三个步骤先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱代码 ContactAddActivity类packagecom.example.chapter07;importandroid
📝学技术、更要掌握学习的方法,一起学习,让进步发生👩🏻作者:一只IT攻城狮。💐学习建议:1、养成习惯,学习java的任何一个技术,都可以先去官网先看看,更准确、更专业。💐学习建议:2、然后记住每个技术最关键的特性(通常一句话或者几个字),从主线入手,由浅入深学习。❤️《SpringCloud入门实战系列》解锁SpringCloud主流组件入门应用及关键特性。带你了解SpringCloud主流组件,是如何一战解决微服务诸多难题的。项目demo:源码地址👉🏻SpringCloud入门实战系列不迷路👈🏻:SpringCloud入门实战(一)什么是SpringCloud?SpringCloud入门实战
前言程序使用一段时间后会遇到HTTPError403:Forbidden错误。因为在短时间内直接使用Get获取大量数据,会被服务器认为在对它进行攻击,所以拒绝我们的请求,自动把电脑IP封了。解决这个问题有两种方法。一是将请求加以包装,变成浏览器请求模式,而不再是“赤裸裸”的请求。但有时服务器是根据同一IP的请求频率来判断的,即使伪装成不同浏览器。由于是同一IP访问,还是会被封。所以就有了第二种方法,就是降低请求频率。具体说来也有两种方法。一种是在每次请求时暂停短暂时间,从而降低请求频率。第二种是使用不同的IP进行访问。显然第一种方法不是最佳选择。因为我们并不希望下载太慢,尤其是在请求次数很多时
这可能是也可能不是灰色地带主题,尽管我的意图肯定不是,所以我的意图不是激起关于逆向工程主题的道德辩论。我是1型糖尿病患者,目前正在接受泵治疗。我是OmniPod用户,这是一个一次性胶囊,可以粘在我的身上并分配胰岛素3天。它由个人糖尿病管理器[PDM](见下文)控制,该管理器控制进餐期间分配的胰岛素量、血糖读数,并且包含一个用于计算碳水化合物的食物指数。(来源:myomnipod.com)新的PDM有一个用于下载数据的USB端口。该软件对Windows用户免费(名为CoPilot的软件包),但不支持Mac。将PDM插入我的Mac后,它像任何其他USB设备一样安装,并为我提供了一个可读卷,
前言chatGPT越来越令人惊奇,有一些答案在百度上搜半天却找不到你想要的,但与chatGPT的聊天中就可以非常快的得到你想要的结果,不得不说人工智能很好用下面就是我与chatGPT的聊天内容chatGPT问答之Webpack5多入口打包如何指定打包文件名规定的文件名问1:Webpack5多入口打包如何指定打包文件名为规定的文件名答1:在Webpack5中,可以使用output.filename选项来指定多入口打包后的文件名规则。output.filename可以是一个字符串,也可以是一个函数。如果output.filename是一个字符串,可以使用占位符来指定打包后的文件名规则,例如:mod
快捷目录前言一、涉及到的相关技术简介二、具体实现过程及踩坑杂谈1.安卓手机改造成linux系统实现方案2.改造后的手机Linux中软件的安装3.手机Linux中安装MySQL5.7踩坑实录4.手机Linux中安装软件的正确方法三、Linux服务器部署前后端分离项目流程1.前提准备(安装必要软件,搭建环境):2.前后端分离项目的详细部署过程:总结前言总体概述:本篇文章隶属于“手机改造服务器部署前后端分离项目”系列专栏,该专栏将分多个板块,每个板块独立成篇来详细记录:手机(安卓)改造成个人服务器(Linux)、Linux中安装软件、配置开发环境、部署JAVA+VUE+MySQL5.7前后端分离项目
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。您对使用Ruby编写网络爬虫有何建议?有比mechanize更好的库吗?