某小程序sign签名参数逆向分析

news2025/1/8 16:04:47

文章目录

  • 1. 写在前面
  • 2. 接口分析
  • 3. 分析还原

【🏠作者主页】:吴秋霖
【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作!
【🌟作者推荐】:对爬虫领域以及JS逆向分析感兴趣的朋友可以关注《爬虫JS逆向实战》《深耕爬虫领域》
未来作者会持续更新所用到、学到、看到的技术知识!包括但不限于:各类验证码突防、爬虫APP与JS逆向分析、RPA自动化、分布式爬虫、Python领域等相关文章

作者声明:文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者无关!如有侵权,请联系作者本人进行删除!

1. 写在前面

  做爬虫脑子一定要灵光~不然怎么当大佬!正所谓大路不通走水路,水路不通走山路!相信很多工程师在面对一个端采集遇到瓶颈的时候什么M端、APP端、小程序端、Web端都几乎会挑一个或多个去摸排分析一下。风控这个东西很奇妙也很玄学,有时候还真有那么一些低风控的接口或者端存在

小程序端这么说吧,体量大点的风控基本都拉的很强且有的跟某信有因果!除非真的没有其他端的数据源了,一般少有人去(总之非可选的主流战场


分析目标

5Lmd5YS/572R57uc

2. 接口分析

随便通过关键词在搜索接口看看发包情况,直接Curl重放是403无效的,会出现签名错误。这个如下所示:

在这里插入图片描述

也就是说上面的sign是动态实时生成的,另外还有一个token参数也是有时效性的,将请求参数拿出来看看,如下所示:

data = {
    "method": "serverless.function.runtime.invoke",
    "params": "{\"functionTarget\":\"DCloud-clientDB\",\"functionArgs\":{\"command\":{\"$db\":[{\"$method\":\"collection\",\"$param\":[\"a_novels\"]},{\"$method\":\"where\",\"$param\":[{\"novels_name\":{\"$regexp\":{\"source\":\"玄幻\",\"flags\":\"\"}}}]},{\"$method\":\"get\",\"$param\":[]}]},\"clientInfo\":{\"PLATFORM\":\"mp-weixin\",\"OS\":\"mac\",\"APPID\":\"__UNI__1B787A1\",\"DEVICEID\":\"17356293548006764541\",\"scene\":1089,\"deviceId\":\"17356293548006764541\",\"appId\":\"__UNI__1B787A1\",\"appName\":\"\",\"appVersion\":\"2.0.1\",\"appVersionCode\":\"201\",\"appLanguage\":\"zh-Hans\",\"uniCompilerVersion\":\"4.36\",\"uniRuntimeVersion\":\"4.36\",\"uniPlatform\":\"mp-weixin\",\"deviceBrand\":\"apple\",\"deviceModel\":\"MacBookPro15,2\",\"deviceType\":\"pc\",\"osName\":\"mac\",\"osVersion\":\"OS\",\"hostVersion\":\"3.8.7\",\"hostName\":\"WeChat\",\"locale\":\"zh-Hans\",\"LOCALE\":\"zh-Hans\"},\"uniIdToken\":\"\"}}",
    "spaceId": "mp-f510ce55-6e44-40b0-b249-d278726b813d",
    "timestamp": 1735785506387,
    "token": "63bc0ed6-f8a1-40ab-bb07-d11bf678ab21"
}

初看大概是MD5标准加密,拼接一下路径、参数加个时间戳啥的

3. 分析还原

在开始分析JS之前,可以通过反编译小程序的方式去分析也可以使用大佬开源的调试工具来辅助分析,有些Web端分析比较多的使用这个辅助还是蛮不错的。如下所示:

在这里插入图片描述

这里在页面直接搜索的话有时候资源多会比较慢,可以直接通过堆栈或者编译好的JS文件简单的进行静态分析,如下所示:

在这里插入图片描述

可以看到Ae就是生成签名的调用方法,而clientSecret是一段密文,后续它将参与加密用到,如下所示:

在这里插入图片描述

直接跳转到Ae方法处,可以看到Object.keys(e).sort()获取e对象里面的所有键进行一个排序,存在的话则使用&拼接,然后去掉所拼接字符串开头多余的一个&确保格式正确,如下所示:

在这里插入图片描述
在这里插入图片描述

接下来需要分析P方法,也就是最终的加密算法实现,进入当前方法直接来到了如下所示:

_createHmacHelper: function(e) {
	return function(t, n) {
	    return new d.HMAC.init(e,n).finalize(t)
	}
}

这里推测d.HMAC是个库框架中的HMAC实现,而init(e, n)finalize(t)是该HMAC对象的初始化和最终处理方法,注意入口处的时候是使用了密钥的,所以要分析是什么算法难度是不大的,肯定不是一个单纯的MD5,对应JS代码如下所示:

var k = A((function(e, t) {
    var n;
    e.exports = n = n || function(e, t) {
        var n = Object.create || function() {
            function e() {}
            return function(t) {
                var n;
                return e.prototype = t,
                n = new e,
                e.prototype = null,
                n
            }
        }()
          , r = {}
          , o = r.lib = {}
          , i = o.Base = {
            extend: function(e) {
                var t = n(this);
                return e && t.mixIn(e),
                t.hasOwnProperty("init") && this.init !== t.init || (t.init = function() {
                    t.$super.init.apply(this, arguments)
                }
                ),
                t.init.prototype = t,
                t.$super = this,
                t
            },
            create: function() {
                var e = this.extend();
                return e.init.apply(e, arguments),
                e
            },
            init: function() {},
            mixIn: function(e) {
                for (var t in e)
                    e.hasOwnProperty(t) && (this[t] = e[t]);
                e.hasOwnProperty("toString") && (this.toString = e.toString)
            },
            clone: function() {
                return this.init.prototype.extend(this)
            }
        }
          , a = o.WordArray = i.extend({
            init: function(e, t) {
                e = this.words = e || [],
                this.sigBytes = null != t ? t : 4 * e.length
            },
            toString: function(e) {
                return (e || c).stringify(this)
            },
            concat: function(e) {
                var t = this.words
                  , n = e.words
                  , r = this.sigBytes
                  , o = e.sigBytes;
                if (this.clamp(),
                r % 4)
                    for (var i = 0; i < o; i++) {
                        var a = n[i >>> 2] >>> 24 - i % 4 * 8 & 255;
                        t[r + i >>> 2] |= a << 24 - (r + i) % 4 * 8
                    }
                else
                    for (i = 0; i < o; i += 4)
                        t[r + i >>> 2] = n[i >>> 2];
                return this.sigBytes += o,
                this
            },
            clamp: function() {
                var t = this.words
                  , n = this.sigBytes;
                t[n >>> 2] &= 4294967295 << 32 - n % 4 * 8,
                t.length = e.ceil(n / 4)
            },
            clone: function() {
                var e = i.clone.call(this);
                return e.words = this.words.slice(0),
                e
            },
            random: function(t) {
                for (var n, r = [], o = function(t) {
                    t = t;
                    var n = 987654321
                      , r = 4294967295;
                    return function() {
                        var o = ((n = 36969 * (65535 & n) + (n >> 16) & r) << 16) + (t = 18e3 * (65535 & t) + (t >> 16) & r) & r;
                        return o /= 4294967296,
                        (o += .5) * (e.random() > .5 ? 1 : -1)
                    }
                }, i = 0; i < t; i += 4) {
                    var u = o(4294967296 * (n || e.random()));
                    n = 987654071 * u(),
                    r.push(4294967296 * u() | 0)
                }
                return new a.init(r,t)
            }
        })
          , u = r.enc = {}
          , c = u.Hex = {
            stringify: function(e) {
                for (var t = e.words, n = e.sigBytes, r = [], o = 0; o < n; o++) {
                    var i = t[o >>> 2] >>> 24 - o % 4 * 8 & 255;
                    r.push((i >>> 4).toString(16)),
                    r.push((15 & i).toString(16))
                }
                return r.join("")
            },
            parse: function(e) {
                for (var t = e.length, n = [], r = 0; r < t; r += 2)
                    n[r >>> 3] |= parseInt(e.substr(r, 2), 16) << 24 - r % 8 * 4;
                return new a.init(n,t / 2)
            }
        }
          , s = u.Latin1 = {
            stringify: function(e) {
                for (var t = e.words, n = e.sigBytes, r = [], o = 0; o < n; o++) {
                    var i = t[o >>> 2] >>> 24 - o % 4 * 8 & 255;
                    r.push(String.fromCharCode(i))
                }
                return r.join("")
            },
            parse: function(e) {
                for (var t = e.length, n = [], r = 0; r < t; r++)
                    n[r >>> 2] |= (255 & e.charCodeAt(r)) << 24 - r % 4 * 8;
                return new a.init(n,t)
            }
        }
          , l = u.Utf8 = {
            stringify: function(e) {
                try {
                    return decodeURIComponent(escape(s.stringify(e)))
                } catch (e) {
                    throw new Error("Malformed UTF-8 data")
                }
            },
            parse: function(e) {
                return s.parse(unescape(encodeURIComponent(e)))
            }
        }
          , f = o.BufferedBlockAlgorithm = i.extend({
            reset: function() {
                this._data = new a.init,
                this._nDataBytes = 0
            },
            _append: function(e) {
                "string" == typeof e && (e = l.parse(e)),
                this._data.concat(e),
                this._nDataBytes += e.sigBytes
            },
            _process: function(t) {
                var n = this._data
                  , r = n.words
                  , o = n.sigBytes
                  , i = this.blockSize
                  , u = o / (4 * i)
                  , c = (u = t ? e.ceil(u) : e.max((0 | u) - this._minBufferSize, 0)) * i
                  , s = e.min(4 * c, o);
                if (c) {
                    for (var l = 0; l < c; l += i)
                        this._doProcessBlock(r, l);
                    var f = r.splice(0, c);
                    n.sigBytes -= s
                }
                return new a.init(f,s)
            },
            clone: function() {
                var e = i.clone.call(this);
                return e._data = this._data.clone(),
                e
            },
            _minBufferSize: 0
        });
        o.Hasher = f.extend({
            cfg: i.extend(),
            init: function(e) {
                this.cfg = this.cfg.extend(e),
                this.reset()
            },
            reset: function() {
                f.reset.call(this),
                this._doReset()
            },
            update: function(e) {
                return this._append(e),
                this._process(),
                this
            },
            finalize: function(e) {
                return e && this._append(e),
                this._doFinalize()
            },
            blockSize: 16,
            _createHelper: function(e) {
                return function(t, n) {
                    return new e.init(n).finalize(t)
                }
            },
            _createHmacHelper: function(e) {
                return function(t, n) {
                    return new d.HMAC.init(e,n).finalize(t)
                }
            }
        });
        var d = r.algo = {};
        return r
    }(Math)
}
))
  , P = (A((function(e, t) {
    var n;
    e.exports = (n = k,
    function(e) {
        var t = n
          , r = t.lib
          , o = r.WordArray
          , i = r.Hasher
          , a = t.algo
          , u = [];
        !function() {
            for (var t = 0; t < 64; t++)
                u[t] = 4294967296 * e.abs(e.sin(t + 1)) | 0
        }();
        var c = a.MD5 = i.extend({
            _doReset: function() {
                this._hash = new o.init([1732584193, 4023233417, 2562383102, 271733878])
            },
            _doProcessBlock: function(e, t) {
                for (var n = 0; n < 16; n++) {
                    var r = t + n
                      , o = e[r];
                    e[r] = 16711935 & (o << 8 | o >>> 24) | 4278255360 & (o << 24 | o >>> 8)
                }
                var i = this._hash.words
                  , a = e[t + 0]
                  , c = e[t + 1]
                  , p = e[t + 2]
                  , h = e[t + 3]
                  , g = e[t + 4]
                  , v = e[t + 5]
                  , y = e[t + 6]
                  , m = e[t + 7]
                  , b = e[t + 8]
                  , w = e[t + 9]
                  , _ = e[t + 10]
                  , x = e[t + 11]
                  , S = e[t + 12]
                  , O = e[t + 13]
                  , A = e[t + 14]
                  , k = e[t + 15]
                  , P = i[0]
                  , T = i[1]
                  , j = i[2]
                  , E = i[3];
                P = s(P, T, j, E, a, 7, u[0]),
                E = s(E, P, T, j, c, 12, u[1]),
                j = s(j, E, P, T, p, 17, u[2]),
                T = s(T, j, E, P, h, 22, u[3]),
                P = s(P, T, j, E, g, 7, u[4]),
                E = s(E, P, T, j, v, 12, u[5]),
                j = s(j, E, P, T, y, 17, u[6]),
                T = s(T, j, E, P, m, 22, u[7]),
                P = s(P, T, j, E, b, 7, u[8]),
                E = s(E, P, T, j, w, 12, u[9]),
                j = s(j, E, P, T, _, 17, u[10]),
                T = s(T, j, E, P, x, 22, u[11]),
                P = s(P, T, j, E, S, 7, u[12]),
                E = s(E, P, T, j, O, 12, u[13]),
                j = s(j, E, P, T, A, 17, u[14]),
                P = l(P, T = s(T, j, E, P, k, 22, u[15]), j, E, c, 5, u[16]),
                E = l(E, P, T, j, y, 9, u[17]),
                j = l(j, E, P, T, x, 14, u[18]),
                T = l(T, j, E, P, a, 20, u[19]),
                P = l(P, T, j, E, v, 5, u[20]),
                E = l(E, P, T, j, _, 9, u[21]),
                j = l(j, E, P, T, k, 14, u[22]),
                T = l(T, j, E, P, g, 20, u[23]),
                P = l(P, T, j, E, w, 5, u[24]),
                E = l(E, P, T, j, A, 9, u[25]),
                j = l(j, E, P, T, h, 14, u[26]),
                T = l(T, j, E, P, b, 20, u[27]),
                P = l(P, T, j, E, O, 5, u[28]),
                E = l(E, P, T, j, p, 9, u[29]),
                j = l(j, E, P, T, m, 14, u[30]),
                P = f(P, T = l(T, j, E, P, S, 20, u[31]), j, E, v, 4, u[32]),
                E = f(E, P, T, j, b, 11, u[33]),
                j = f(j, E, P, T, x, 16, u[34]),
                T = f(T, j, E, P, A, 23, u[35]),
                P = f(P, T, j, E, c, 4, u[36]),
                E = f(E, P, T, j, g, 11, u[37]),
                j = f(j, E, P, T, m, 16, u[38]),
                T = f(T, j, E, P, _, 23, u[39]),
                P = f(P, T, j, E, O, 4, u[40]),
                E = f(E, P, T, j, a, 11, u[41]),
                j = f(j, E, P, T, h, 16, u[42]),
                T = f(T, j, E, P, y, 23, u[43]),
                P = f(P, T, j, E, w, 4, u[44]),
                E = f(E, P, T, j, S, 11, u[45]),
                j = f(j, E, P, T, k, 16, u[46]),
                P = d(P, T = f(T, j, E, P, p, 23, u[47]), j, E, a, 6, u[48]),
                E = d(E, P, T, j, m, 10, u[49]),
                j = d(j, E, P, T, A, 15, u[50]),
                T = d(T, j, E, P, v, 21, u[51]),
                P = d(P, T, j, E, S, 6, u[52]),
                E = d(E, P, T, j, h, 10, u[53]),
                j = d(j, E, P, T, _, 15, u[54]),
                T = d(T, j, E, P, c, 21, u[55]),
                P = d(P, T, j, E, b, 6, u[56]),
                E = d(E, P, T, j, k, 10, u[57]),
                j = d(j, E, P, T, y, 15, u[58]),
                T = d(T, j, E, P, O, 21, u[59]),
                P = d(P, T, j, E, g, 6, u[60]),
                E = d(E, P, T, j, x, 10, u[61]),
                j = d(j, E, P, T, p, 15, u[62]),
                T = d(T, j, E, P, w, 21, u[63]),
                i[0] = i[0] + P | 0,
                i[1] = i[1] + T | 0,
                i[2] = i[2] + j | 0,
                i[3] = i[3] + E | 0
            },
            _doFinalize: function() {
                var t = this._data
                  , n = t.words
                  , r = 8 * this._nDataBytes
                  , o = 8 * t.sigBytes;
                n[o >>> 5] |= 128 << 24 - o % 32;
                var i = e.floor(r / 4294967296)
                  , a = r;
                n[15 + (o + 64 >>> 9 << 4)] = 16711935 & (i << 8 | i >>> 24) | 4278255360 & (i << 24 | i >>> 8),
                n[14 + (o + 64 >>> 9 << 4)] = 16711935 & (a << 8 | a >>> 24) | 4278255360 & (a << 24 | a >>> 8),
                t.sigBytes = 4 * (n.length + 1),
                this._process();
                for (var u = this._hash, c = u.words, s = 0; s < 4; s++) {
                    var l = c[s];
                    c[s] = 16711935 & (l << 8 | l >>> 24) | 4278255360 & (l << 24 | l >>> 8)
                }
                return u
            },
            clone: function() {
                var e = i.clone.call(this);
                return e._hash = this._hash.clone(),
                e
            }
        });
        function s(e, t, n, r, o, i, a) {
            var u = e + (t & n | ~t & r) + o + a;
            return (u << i | u >>> 32 - i) + t
        }
        function l(e, t, n, r, o, i, a) {
            var u = e + (t & r | n & ~r) + o + a;
            return (u << i | u >>> 32 - i) + t
        }
        function f(e, t, n, r, o, i, a) {
            var u = e + (t ^ n ^ r) + o + a;
            return (u << i | u >>> 32 - i) + t
        }
        function d(e, t, n, r, o, i, a) {
            var u = e + (n ^ (t | ~r)) + o + a;
            return (u << i | u >>> 32 - i) + t
        }
        t.MD5 = i._createHelper(c),
        t.HmacMD5 = i._createHmacHelper(c)
    }(Math),
    n.MD5)
}
)),
A((function(e, t) {
    var n;
    e.exports = (n = k,
    void function() {
        var e = n
          , t = e.lib.Base
          , r = e.enc.Utf8;
        e.algo.HMAC = t.extend({
            init: function(e, t) {
                e = this._hasher = new e.init,
                "string" == typeof t && (t = r.parse(t));
                var n = e.blockSize
                  , o = 4 * n;
                t.sigBytes > o && (t = e.finalize(t)),
                t.clamp();
                for (var i = this._oKey = t.clone(), a = this._iKey = t.clone(), u = i.words, c = a.words, s = 0; s < n; s++)
                    u[s] ^= 1549556828,
                    c[s] ^= 909522486;
                i.sigBytes = a.sigBytes = o,
                this.reset()
            },
            reset: function() {
                var e = this._hasher;
                e.reset(),
                e.update(this._iKey)
            },
            update: function(e) {
                return this._hasher.update(e),
                this
            },
            finalize: function(e) {
                var t = this._hasher
                  , n = t.finalize(e);
                return t.reset(),
                t.finalize(this._oKey.clone().concat(n))
            }
        })
    }())
}
)),
A((function(e, t) {
    e.exports = k.HmacMD5
}

通过对上面的JS代码进行静态分析可发现最终使用的加密为HmacMD5,结合有密钥参与加密,可以直接Python进行算法还原测试验证即可,算法实现如下所示:

def sign(e, t):
    sorted_keys = sorted(e.keys())
    n = ""
    for key in sorted_keys:
        if e[key]:
            n += f"&{key}={e[key]}"
    n = n[1:]
    signature = hmac.new(t.encode('utf-8'), n.encode('utf-8'), hashlib.md5).hexdigest()
    return signature

HMAC-MD5是基于MD5哈希算法的消息认证码,HMAC是一种利用密钥的哈希算法,用于生成一个“签名”,并且常用于消息的完整性验证和认证(如API请求签名)

最终简单的编写一个搜索代码查看一下是否可以正常获取到相关的数据,如下所示:

在这里插入图片描述

案列比较简单,适合正在或想要学习逆向新手小伙伴练练手

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

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

相关文章

医学图像分析工具02:3D Slicer || 医学影像可视化与分析工具 支持第三方插件

3D Slicer 是一款功能全面的开源医学影像分析软件&#xff0c;广泛应用于影像处理、三维建模、影像配准和手术规划等领域。它支持多种医学影像格式&#xff08;如 DICOM、NIfTI&#xff09;和丰富的插件扩展&#xff0c;是神经科学、放射学和生物医学研究中不可或缺的工具。 在…

Linux系统安装es详细教程

一、下载es及插件 从下面的网址进行对应es版本的下载https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.15.2-linux-x86_64.tar.gz &#xff0c;想要不同版本的es只需更换对应的版本号即可。 插件下载地址&#xff08;ik分词器、pinyin等&#xff09;es…

电子电气架构 --- 汽车总线基础介绍

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 简单&#xff0c;单纯&#xff0c;喜欢独处&#xff0c;独来独往&#xff0c;不易合同频过着接地气的生活…

安装PyQt5-tools卡在Preparing metadata (pyproject.toml)解决办法

为了在VS code中使用PyQt&#xff0c;在安装PyQt5-tools时总卡在如下这一步 pyqt5 Preparing metadata (pyproject.toml)经过各种尝试&#xff0c;最终问题解决&#xff0c;在此记录方法。 首先进入PyQt5-tools官网查看其适配的Python版本&#xff0c;网址如下&#xff1a; h…

38 Opencv HOG特征检测

文章目录 HOGDescriptor 构造函数setSVMDetector 设置支持向量机&#xff08;SVM&#xff09;检测器&#xff0c;用于目标检测。compute 用于计算图像区域的HOG描述符。detectMultiScale 多尺度检测目标。示例 HOGDescriptor 构造函数 HOGDescriptor(); HOGDescriptor(const S…

分布式搜索引擎之elasticsearch基本使用3

分布式搜索引擎之elasticsearch基本使用3 1.部署单点es 1.1.创建网络 因为我们还需要部署kibana容器&#xff0c;因此需要让es和kibana容器互联。这里先创建一个网络&#xff1a; docker network create es-net1.2.加载镜像 这里我们采用elasticsearch的7.12.1版本的镜像&…

人工智能知识分享第九天-机器学习_集成学习

集成学习 概念 集成学习是机器学习中的一种思想&#xff0c;它通过多个模型的组合形成一个精度更高的模型&#xff0c;参与组合的模型称为弱学习器&#xff08;基学习器&#xff09;。训练时&#xff0c;使用训练集依次训练出这些弱学习器&#xff0c;对未知的样本进行预测时…

在线机考|2024华为实习秋招春招编程题(最新)——第3题_个性化歌单推荐系统_300分(十一)

题目内容 假设你是音乐服务的开发者,为了提高用户体验需要解决推荐歌单的同质化问题,保证推荐给用户的所有歌单不包含相同歌曲的。给定一个包含N个歌单和M条歌单重复记录,每个歌单用一个从1到N的整数编号,歌单重复记录包含两个歌单的ID,表示两个歌单有相同的歌曲。 你的任…

学英语学压测:02jmeter组件-测试计划和线程组ramp-up参数的作用

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#xff1a;先看关键单词&#xff0c;再看英文&#xff0c;最后看中文总结&#xff0c;再回头看一遍英文原文&#xff0c;效果更佳&#xff01;&#xff01; 关键词 Functional Testing功能测试[ˈfʌŋkʃənəl ˈtɛstɪŋ]Sample样…

最新最详细的配置Node.js环境教程

配置Node.js环境 一、前言 &#xff08;一&#xff09;为什么要配置Node.js&#xff1f;&#xff08;二&#xff09;NPM生态是什么&#xff08;三&#xff09;Node和NPM的区别 二、如何配置Node.js环境 第一步、安装环境第二步、安装步骤第三步、验证安装第四步、修改全局模块…

PHP框架+gatewayworker实现在线1对1聊天--接收消息(7)

文章目录 接收消息的原理接收消息JavaScript代码 接收消息的原理 接收消息&#xff0c;就是接受服务器转发的客户端消息。并不需要单独创建函数&#xff0c;因为 ws.onmessage会自动接收消息。我们需要在这个函数里进行处理。因为初始化的时候&#xff0c;已经处理的init类型的…

当算法遇到线性代数(四):奇异值分解(SVD)

SVD分解的理论与应用 线性代数系列相关文章&#xff08;置顶&#xff09; 1.当算法遇到线性代数&#xff08;一&#xff09;&#xff1a;二次型和矩阵正定的意义 2.当算法遇到线性代数&#xff08;二&#xff09;&#xff1a;矩阵特征值的意义 3.当算法遇到线性代数&#xff0…

科研绘图系列:R语言科研绘图之标记热图(heatmap)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据数据预处理画图系统信息参考介绍 科研绘图系列:R语言科研绘图之标记热图(heatmap) 加载R包 library(tidyverse) library(ggplot2) library(reshape)…

Mysql--基础篇--SQL(DDL,DML,窗口函数,CET,视图,存储过程,触发器等)

SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是用于管理和操作关系型数据库的标准语言。它允许用户定义、查询、更新和管理数据库中的数据。SQL是一种声明性语言&#xff0c;用户只需要指定想要执行的操作&#xff0c;而不需要详细说明如何…

Excel重新踩坑5:二级下拉列表制作;★数据透视表;

0、在excel中函数公式不仅可以写在单元格里面&#xff0c;还可以写在公式里面。 1、二级下拉列表制作&#xff1a; 2、数据透视表&#xff1a; 概念&#xff1a;通过拖拉就能实现复杂函数才能实现的数据统计问题。 概览&#xff1a;在插入选项中有个数据透视表&#xff0c;数…

Linux-----进程处理(waitpid,进程树,孤儿进程)

目录 waitpid等待 进程树 孤儿进程 waitpid等待 Linux中父进程除了可以启动子进程&#xff0c;还要负责回收子进程的状态。如果子进程结束后父进程没有正常回收&#xff0c;那么子进程就会变成一个僵尸进程——即程序执行完成&#xff0c;但是进程没有完全结束&#xff0c;其…

解决报错net.sf.jsqlparser.statement.select.SelectBody

在我们项目集成mybatis-plus时,总会遇到奇奇怪怪的报错,比如说下面的这个报错 而这个报错,是告诉我们的分页依赖冲突,要加个jsqlparser依赖来解决这个冲突,也相当于平衡,但是可能因为我们版本的不匹配,还是会报错,例如下面这样 但是我们是不知道到底是什么依赖冲突的,这个时候就…

感知器的那些事

感知器的那些事 历史背景Rosenblatt和Minsky关于感知机的争论弗兰克罗森布拉特简介提出感知器算法Mark I感知机争议与分歧马文明斯基简介单层感知器工作原理训练过程多层感知器工作原理单层感知机 vs 多层感知机感知器模型(Perceptron),是由心理学家Frank Rosenblatt在1957年…

内核链表 例题 C语言实现

问题&#xff1a; 将下面的数据节点信息转换为链表结构&#xff0c;并遍历输出。要求根据type的值来决定val的类型。 type为1代表bool类型&#xff0c;2代表整形&#xff0c;3代表浮点型。无需解析文本&#xff0c;直接赋值形成节点即可。 代码&#xff1a; list.c #includ…

C语言结构体数组

上次我们讲解了结构体&#xff0c;这里还有高级应用就是结构体数组&#xff08;集合的集合&#xff09; &#xff08;这里提醒一句&#xff0c;想要在北京参加NCRE考试的朋友们今天开始报名了&#xff09; 定义 还是拿上回那个学生数据的结构体 typedef struct {int year;i…