爬虫-Webpack逆向实战 有习题

news2024/11/28 2:53:21

爬虫-Webpack逆向实战

我只要喝点果粒橙关注IP属地: 青海

0.1052022.04.30 19:21:46字数 4,875阅读 5,142

全文目录

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的通用方法:

  1. 先去找加密网站的加密入口。这应该是加密网站都必须要做的==> 直接根据参数名搜索参数

  2. 找到分发器的位置,或者说是加载器,n["xxx"]这种的n就是分发器,就比如下方中的exports的位置,最后执行了d函数==>一般是runtimexxx.js中(提供环境);一般以! function(e) {的形式出现

分发器.jpg

  1. 寻找分发编号、加密使用模块(用到了哪些模块就导入哪些模块)==>一般在chunk-lib.js,以(window.webpackJsonp = window.webpackJsonp || []).push([的形式出现

  2. 将函数入口的地方返回全局变量,最终返回: var sign; var window = global;!function(){... sign = d}, 赋值为分发器返回的d

  3. 使用自定义的sign代替webpack代码中的n进行加密

from: https://blog.csdn.net/weixin_41586984/article/details/116268341

调试技巧

定位请求参数

  1. 打开开发者工具后,F5刷新后Ctrl + Shift + F搜索参数名,如signdata,会显示多个JS文件,选择后仔细查看(点击左下角{}美观格式化按钮)。

    more: 如果文件太多,则直接通过请求的链接去找,比如user/login

  2. Network找到新发出的xhr条目后,查看Initiator里的调用栈信息,如Login;

注: 如果加密参数名称比较简单如s,比较难定位的话,可以借助请求的其他参数来查找,比如verificationCode

调试工具

  • 断点调试breakpoints
  • XHR断点: XHR/fetch breakpoints

附录-Js记录

  • 时间戳: (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());
    

做题记录

n["str"]题型:

天安财险

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模块扒下来

中远海运

  • n("MuMZ")中又有r = n("XBrZ");,在另一个文件中,module需要放两个

天翼云

var t = encodeURIComponent(c["c"].Des.encrypt(this.form.email, this.form.pwd)),

webpack实现

c = (mycode("ac6a"), mycode("b3ae"))

  • 分发器和ac6a模块在同一个文件中、而ac6a模块依赖模块在另一个文件内;
  • 分发器()({}),无感叹号
  • 分发器()({})大括号中自带较多依赖模块

自己实现:直接扒下来encrypt加密的JS内容

看准网

  • 分发器n("xxx")定位后跟一般的固定格式返回a、n、r不同,写的是个函数==>还是可以根据obj.Func来赋值mycode = obj;
  • JS逆向实战分析--看准网webpack加解密分析——Python中使用execjs示范

企名片

  • 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))
     }
    

n[num]题型:

大麦

  • 删除分发器多余代码
  • var navigator = {}

掌上高考:

  1. 分发器在html文件内
  2. o = (u=a(42), a.n(u)),使用到了a.n(u)即点n函数
  3. 依赖函数的给出是以数组的形式,而不是字典的形式
  4. 模块中依赖更多模块==>引入整个模块文件,但是跟"xxx"模式不同的是,由于没有用字典{"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)就补充拿什么

    • n.n(l)是传入什么就返回什么:https://www.bilibili.com/video/BV1gq4y1D781?from=search&seid=7720105602891609746&spm_id_from=333.337.0.0
    // 如果不删分发器中其他部分
    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(函数或类作用域内为函数或者类实例)

    • from:JS中document和window的区别

心得

①所有webpack打包的的js都要先看懂打包后代码运行的顺序,找到加密处;②找到webpack对象,一般是 n(数字) 调用③确定分发器。④找依赖模块,有时候各包的依赖关系太多,可以直接把文件爬下来引入,如果各个包的依赖关系不多,就可以只把调用到的函数找出来放到依赖中。⑤最后剩下的就是找到你要的代码,慢慢复现调用加密/解密函数就好了。

做题案例学习视频

  • webpack师承:爬取webpack流程-视频——大多都是n("Xvmd")
  • 而如果n中调用的不是字典的形式,而是列表的形式,则看js逆向安全指南(3)-- webpack解包指南、使用 webpack 的 js 加密参数的分析——酷我

进阶资料

  • 9-爬虫高级实战【js逆向】
  • JS逆向学习笔记 - 持续更新中
  • webpack补充依赖项做法:
    • 逆向webpack - 简书
    • webpack4之《模块运行机制原理》
  • JS逆向视频
    • 爬虫工程师进阶必会之JS逆向(反爬)
    • 遇到网站加密爬不了??这几个视频教你如何学会爬虫高阶内容js逆向,入狱必学!

掌上高考解密过程

解析响应data.text

相应的data.text是加密的,页面通过JS解密后渲染

  1. 确定加密位置

    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,
    
  2. 确定分发器位置,在html内

    通过打断o = (u=a(42), a.n(u)) // 等价于 o = a(42)

  3. 确定依赖模块:给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)
}

可以看到需要依赖多个,因此直接把整个文件引入

  1. 扣解密函数:注意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)

获得加密参数signsafe

大致流程跟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))直接替换出的问题

  1. 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,
    
  2. 往上找c和o.a: o = (u = a(42),a.n(u))c = (u = a(291),a.n(u))

  3. 找到分发器扣出==>这次不能删除分发器中多余的函数,比如r.a、r.d、r.n因为后面得用

  4. 将依赖模块跟data.text一样,放入分发器依赖模块中

  5. 扣加密函数

    网页上是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,但难免有时会有不一样,因此谨慎期间,还是还原到底最好。

Python调用

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)

RSA的加密步骤

  1. 获取公钥
  2. 实例化 ===> 扣出网站RSA实例化对象的代码
  3. 设置公钥
  4. 对文本进行加密 ==> 扣出复现RSA加密的逻辑代码

注: var window=globalvar navigator={}

  • B站RSA:

    // 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

urlencode是一个函数,可将字符串以URL编码,用于编码处理。

URL编码(URL encoding),也称作百分号编码(Percent-encoding), 是特定上下文的统一资源定位符 (URL)的编码机制。

Base64特征

最常见的用于传输8Bit字节码的编码方式之一

  • 相同内容,结果是相同的
  • a-zA-Z,0-9,+/共64个字符进行编码;每3个字节编码成4个字节,不足的在结尾有无意义的=来填补
    • 一般情况下结尾都会有1个或者2个等号,明文长度是3的倍数时没有=;
  • 内容越长,结果越长

注:跟下面的算法区分一下,base64是编码方式,并不能算加密算法。应用场景还有传输图片:data:image/jpg;base64,/9j/4QMZRXhpZgAASUk...

md5特征

消息摘要算法

  • 确定唯一性:相同内容,结果是相同的;但一般会有时间戳等参数,所以导致了每次不同
  • 不可逆性:有损的加密过程,理论上无法解密(逆向推出),除非暴力破解。安全,这也是其成为校验是否被修改的最关键的性质
  • 碰撞性:原始数据与其MD5值并不是一一对应的,有可能多个原始数据计算出来的MD5值是一样的,这就是碰撞。
  • 一般MD5值是32位,由数字“0-9”和字母“a-f”所组成的字符串;字母可以是全大写或者全小写
    • 密文一般为 16 位或者 32 位,其中 16 位是取的 32 位第 9~25 位的值;
  • 长度:32个十六进制字符组成的字符串 (128位)

RSA特征

  • 相同内容,结果也是不同的
  • 明文长度需要小于密钥长度,而密文长度则等于密钥长度。一般为1024、2048、3072、4096或512(低于1024的安全不建议)
  • 通过公钥加密结果,必须私钥解密。 同样私钥加密结果,公钥可以解密

注:RSA加解密中必须考虑到的密钥长度、明文长度和密文长度问题;

▲.一般会使用 JSEncrypt 库,会有 new 一个实例对象的操作;

SHA 系列

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 等

AES、DES、3DES、RC4、Rabbit 等加密算法的密文通常没有固定的长度,他们通常使用crypto-js库来实现

参考:https://juejin.cn/post/7052978567390429215

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/573020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R语言混合效应(多水平/层次/嵌套)模型及贝叶斯实现技术

回归分析是科学研究中十分重要的数据分析工具。随着现代统计技术发展,回归分析方法得到了极大改进。混合效应模型(Mixed effect model),即多水平模型(Multilevel model)/分层模型(Hierarchical Model)/嵌套…

linuxOPS基础_linux安装配置

Linux系统下载 Linux系统版本选择:CentOS7.6 x64,【镜像一般都是CentOS*.iso文件】 问题:为什么不选择最新版的8 版本? 7.x 目前依然是主流 7.x 的各种系统操作模式是基础 官网:https://www.centos.org/ ,…

mysql8.0 修改密码

我使用的是 docker,但是这一期主要是讲解 mysql8 版本修改密码,我相信 linux、windows 和不使用 docker 应该都是可以的。 先说一下我的情况: 我在本地 windows 玩 docker 部署 mysql8.0.25 版本,无问题啦~ 然后我在 linux 里面玩…

模拟strcpy函数,assert,const修饰指针与凉皮男孩的故事

那么好了好了,宝子们,今天给大家介绍一下strcpy函数及其模拟,还有assert,const与凉皮男孩间的爱恨情仇,来吧,开始整活!⛳️(今天的内容和故事非常的有趣,希望大家一键三连…

黑马学生入职B站1年,晒出21K月薪:我想跳槽华为

现在的Z时代,嘴上说着不要,身体却很诚实。 前两天,黑马发布了《2022年度互联网平均薪资出炉!高到离谱!》,信息传输、软件和信息技术服务业薪资遥遥领先!Z时代举头望着天花板,故作潇…

jsvmp逆向实战x-s、x-t算法还原

jsvmp逆向实战x-s、x-t算法还原 什么是jsvmp定位关键点log插桩日志分析代码还原 什么是jsvmp jsvmp就是将js源代码首先编译为自定义的字节码,只有对应的解释器才能执行这种字节码,这是一种前端代码虚拟化保护技术。 整体架构流程是服务器端通过对JavaS…

Sui基金会联合Tencent Cloud和Numen在香港举办的生态交流会圆满结束

5月24日,由Sui基金会、Tencent Cloud和Numen Cyber联合举办的Sui生态交流会在香港圆满结束。感谢Tencent Cloud为本次活动提供了场地支持。本次活动共吸引了60余名行业同仁线上和线下的参与。 本次活动旨在提升Web3产业对Sui生态的认识,并为生态中的开发…

调用华为API实现图像搜索

调用华为API实现图像搜索 1、作者介绍2、华为API介绍2.1 华为云图像搜索2.2 图像搜索应用场景2.2.1商品图片搜索2.2.2版权图片搜索 2.3 调用华为API实现图像标签 3、实验过程3.1完整代码3.2运行结果3.3常见错误 1、作者介绍 张勇进,男,西安工程大学电子…

通过Python的pdfplumber库将pdf转为图片

文章目录 前言一、pdfplumber库是什么?二、安装pdfplumber库三、查看pdfplumber库版本四、pdf素材五、将pdf转为图片1.引入库2.定义pdf路径3.打开PDF文件4.遍历每一页5.将PDF页面转换为Image对象6.将Image对象保存为图片文件7.效果 总结 前言 大家好,我是…

ChatGLM-6B之SSE通信(Server-sent Events)

写这篇博客还是很激动开心的,因为是我经过两周的时间,查阅各个地方的资料,经过不断的代码修改,不断的上传到有显卡的服务器运行才得出的可行的接口调用解决方案,在这里记录并分享一下。 研究历程(只是感受&…

更适合iPhone的手柄,按键手感真不赖,LEADJOY M1B上手

很多朋友平时玩手游的时候,操作体验往往不是很好,特别是到了夏天,手机玩久了总是热气腾腾的,对此,只需要配上一副手游手柄,就可以获得媲美掌机的游戏体验。最近我就在用一款LEADJOY M1B游戏手柄&#xff0c…

如何选择语音芯片?主流语音方案如何选,九芯电子来推荐

市场分析 近年来,随着我国半导体的不断发展和技术领域的不断突破,语音芯片实现了越来越多的国产化。其中涌现出的像NVD系列、NRK330X系列等不乏国产优秀产品。凭借其优秀的性能、设计,赢得了市场上的好评如潮。 对比分析 OTP语音芯片&#…

webAPI学习笔记3——BOM浏览器对象模型

目录 1、BOM概述 1.1 什么是 BOM 1.2 BOM 的构成 2. window 对象的常见事件 2.1 窗口加载事件 2.2 调整窗口大小事件 3. 定时器 3.1 两种定时器 3.2 setTimeout() 定时器 案例: 5秒后自动关闭的广告 3.3 停止 setTimeout() 定时器 3.4 setInterval() 定时…

解决不联网环境pip安装librosa、numba、llvmlite报错和版本兼容问题

项目场景: 项目是需要在内网不联网环境部署GitHub上一个有关音频、视频处理的深度学习Python工程,因此许多包需要下载好wheel包或tar包后在内网环境安装。 这个过程遇到了许多兼容性问题引起的报错。Python版本与librosa、numba、llvmlite版本兼容问题…

小狗避障-第14届蓝桥杯省赛Scratch中级组真题第4题

[导读]:超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成,后续会不定期解读蓝桥杯真题,这是Scratch蓝桥杯真题解析第139讲。 小狗避障,本题是2023年5月7日举行的第14届蓝桥杯省赛Scratch图形化编程中级组编程第4题&#xf…

从代码审计的角度分析 Ruoyi v4.7.6 的任意文件下载漏洞

前言 Ruoyi 的 v4.7.6 是 2022 年 12 月 16 日发布的一个版本,而任意文件下载漏洞实际上 12 月底的时候就已经爆出了,也陆续有一些文章在写这个漏洞,但是 Ruoyi 一直没有更新修复。 上月中旬(2023 年 5 月)&#xff0c…

内网渗透(八十四)之ADCS配置启用基于SSL的LDAP(LDAPS)

ADCS配置启用基于SSL的LDAP(LDAPS) 打开AD CS,选择证书颁发机构 选择证书模板,右键管理 选择Kerberos身份验证,右键 复制模板 然后会有一个Kerberos身份验证的副本,右键更改名称,更改为LDAPS 选择LDAPS,右键属性 设置模板属性,请求处理——>允许导出私钥(O) 创建证书…

最快实现一个自己的扫地机

​ 作者:良知犹存 转载授权以及围观:欢迎关注微信公众号:羽林君 或者添加作者个人微信:become_me 扫地机介绍 扫地机器人行业本质是技术驱动型行业,产品围绕导航系统的升级成为行业发展的主旋律。按功能划分&a…

【武汉万象奥科】瑞芯微RK3568芯片

▎产品展示 RK3568核心板是基于Rockchip的RK3568设计的一款高性能核心板。该处理器集成了最新的高性能CPU、GPU,并拥有丰富的接口,非常适用于工业自动化控制、人机界面、中小型医疗分析器、电力等多种行业应用。 ▎RK3568产品特点 ▎高性能处理器 ○ 采用…

linuxOPS基础_vmware虚拟机安装及介绍

虚拟机概念 什么是虚拟机? 虚拟机,有些时候想模拟出一个真实的电脑环境,碍于使用真机安装代价太大,因此而诞生的一款可以模拟操作系统运行的软件。 虚拟机目前有2 个比较有名的产品:vmware 出品的vmware workstatio…