wx读书某sign算法详解

未加固

版本:9.2.3

前置知识:

(v41 & 0xFFFFFFFFFFFFFFFELL) 是一种高效的奇偶检查方法,用于判断数值 v41 是否为奇数。

std::sort<std::lessstd::string,std::string &,std::string>(a1, v6, s); 排序算法

# 完全等价的字符串列表排序
strings = ["banana", "apple", "cherry"]
strings.sort()  # 原地排序
# 或
sorted_strings = sorted(strings)  # 返回新列表

hash常见系列防护:

1.加盐salt的值

2.魔改算法,修改算法的部分常量

3.也就是我们今天遇到的,利用自定义的校验和计算与数据重排算法

我们可以先认识一下这段代码:生成校验值(0-10)然后对其进行重新排序

def reorder_before_sha256(input_hex):"""SHA256前的重排序算法(精确还原C++逻辑):param input_hex: 输入hex字符串:return: 重排后的hex字符串"""# 1. 将hex转换为可变字节数组data = bytearray.fromhex(input_hex)length = len(data)if length == 0:return ""# 2. 计算校验值(模拟C++的v19计算)checksum = 0i = 0# 成对处理字节(偶数部分)paired_len = length & 0xFFFFFFFFFFFFFFFE  # 取偶数长度while i < paired_len:checksum ^= data[i] ^ data[i + 1]i += 2# 处理可能的最后一个字节(奇数长度)if length % 2 != 0:checksum ^= data[-1]checksum %= 11  # 最终校验值(0-10)# 3. 动态重排(核心逻辑)reordered = bytearray(length)for original_pos in range(length):# 计算新位置:(校验值 + 原位置) % 总长度new_pos = (checksum + original_pos) % lengthreordered[new_pos] = data[original_pos]return reordered

一、抓包确定位置:

这里的signature,触发在登录之后每次点击我的页面会触发:相关类是 weread.encrypt.EncryptUtils 的nativeGetSignatures方法

我们可以看到输入一个strArr数组 返回的是64位 通过下表我们可以猜测可能是经过了sha256的加密。

找到关键so libencrypt.so 这个上面jadx关键类下就有就不多提了。

构建主动调用:

function call() {Java.perform(function () {// 1. 获取 EncryptUtils 类let EncryptUtils = Java.use("weread.encrypt.EncryptUtils");let instance = EncryptUtils.$new();
// 2. 构造主动调用函数try {let inputArray = ["09cdcfd7f","1045","1145656655","12676517_1736697599_1779983999_0_1_0_935_34327344_23181744",]// let inputArray = [//     "sgh256245",//     "7895",//     "1745675066",//     "52676517_1736697599_1779983999_0_1_0_935_34327344_23181744",// ]// 3. 将 JavaScript 数组转换为 Java String[]let javaStringArray = Java.array('java.lang.String', inputArray);// 4. 调用 nativeGetSignatures 方法let result = instance.nativeGetSignatures(javaStringArray);// 5. 打印结果console.log("主动调用 nativeGetSignatures 结果:", result);return result;} catch (e) {console.error("主动调用失败:", e);}})
}

二、算法分析:

Java_weread_encrypt_EncryptUtils_nativeGetSignatures(JNIEnv *a1, __int64 a2, void *rucan_list)

此函数是我们加密生成Signature的函数:

可以看到这个位置 调用了生成GenSignature

这个n其实是我们的js_string类型的strArr数组:我们可以hook weread::GenSignature(n);

这里我们只看到了第一个的值 其他值应该是在指针里面 或者是一个结构体 这里我们只是合理猜测 但是没具体去实践。

但是我是直接hook的 weread::GenSignature 中的 std::string::append(&v66, v14, v15);函数

我们可以看到 他是先进行了排序在进行拼接成一个字符串。 我们可以看到我们这里就有5个参数进行了append

那么我们传递了四个参数为什么是5个进行了append

let inputArray = [
    "09cdcfd7f",
    "1045",
    "1145656655",
    "12676517_1736697599_1779983999_0_1_0_935_34327344_23181744",
]

而且拼接的也有规律 是按照了 sort排序 我们由下图可以看出。

原来这里 的5a6f1其实是盐的值呢

那下面我们可以解决一下为什么我们的

let inputArray = [
    "09cdcfd7f",
    "1045",
    "1145656655",
    "12676517_1736697599_1779983999_0_1_0_935_34327344_23181744",
] 以及盐的值

明文变成了上述那些字符嘞?他的上一层函数中有weread::RemapString(n); 很是可疑。weread::RemapString 很可能是一个字符串重映射函数

关键byte_D9FC字符数组

byte_D9FC = [0x34, 0xCA, 0x55, 0x40, 0x1D, 0xB6, 0x93, 0xC6, 0x31,0x30, 0x29, 0x35, 0x32, 0xA7, 0xB8, 0x11, 0xC2, 0xB5,0x16, 0xFA, 0x8B, 0xB1, 0x24, 0xA4, 0x10, 0x90, 4,0xE9, 8, 0xF8, 0x3B, 0x8A, 0x9C, 0x8C, 0x44, 0xF9,0xBC, 0x5C, 0x69, 0xE2, 0xA1, 0xDA, 0xD2, 0xD3, 0x75,0x89, 0xF7, 0x1E, 0x2D, 0x50, 0x56, 0xD7, 0x72, 0x53,0xBF, 0x22, 0xFB, 0x20, 0xF, 1, 0x2E, 0x45, 0x87, 0x6E,0x66, 0x48, 0xF2, 0xE0, 0xCD, 0xFE, 0x67, 0xA9, 0x43,0xF4, 0x94, 0x51, 0xCE, 0xA5, 0x4A, 0xEE, 0x13, 0x26,0x8E, 0xCC, 0xAA, 0x33, 0x14, 0x5D, 0xE, 0x39, 0xBB,0xCF, 0x91, 0x2B, 0x81, 0x4D, 0xEA, 0x99, 0xEC, 0x1A,0x2C, 0x85, 0xC5, 0xD9, 0x36, 0x74, 0x4B, 0x18, 0xE1,0xF1, 0x3D, 0x9D, 0x41, 0x9F, 0xB4, 0x17, 0xD, 0xD6,0x4C, 0xBE, 0xDC, 0xAF, 0x97, 0x28, 0x77, 0xF0, 0x62,0xFF, 0x71, 0xC1, 0xC8, 0x27, 0x8F, 0x6C, 0x68, 0xA8,0x9B, 0xE6, 0x59, 0x1C, 0x1B, 0x12, 9, 0x98, 0x4E,0x3F, 6, 0x37, 0, 0xBA, 0x1F, 0xA, 0x19, 0x2F, 0xC9,0xD5, 0xD0, 0x57, 0x49, 0x6F, 0xFD, 0x25, 0xE4, 0x61,0xC, 0x42, 0xCB, 0x96, 0x64, 0x5F, 0xDB, 0xAD, 0x60,0x23, 0x8D, 0x9A, 0x6D, 0xC3, 0xC4, 0x5E, 0x3E, 0xB9,0x92, 0x6A, 0xBD, 0x5B, 7, 0x7F, 0x76, 0x95, 0xED,0x4F, 0xAB, 0x84, 0x7A, 0x80, 0xE7, 0x78, 0xC7, 0xE5,0xEB, 0x73, 0x83, 0x6B, 0xFC, 0x38, 0x46, 0x7D, 0x47,0x65, 0xB3, 0x52, 0x63, 0x3A, 5, 0xD1, 0xEF, 0xA3,0xA6, 0xDE, 0x9E, 0x3C, 2, 0xAE, 0xB2, 0x7B, 0xA0,0xF6, 0xF3, 0x2A, 0xC0, 0xAC, 0x86, 3, 0x5A, 0x54,0xB, 0xF5, 0x82, 0xD4, 0x7E, 0xE3, 0xDF, 0xB0, 0xD8,0xDD, 0x21, 0xE8, 0x7C, 0x88, 0xA2, 0x79, 0x58, 0x70,0xB7, 0x15]

这里不带大家验证了 其实就是我们的传入的数组做了这个的映射

代码:

def Tranfrom(input_str):byte_D9FC = [0x34, 0xCA, 0x55, 0x40, 0x1D, 0xB6, 0x93, 0xC6, 0x31,0x30, 0x29, 0x35, 0x32, 0xA7, 0xB8, 0x11, 0xC2, 0xB5,0x16, 0xFA, 0x8B, 0xB1, 0x24, 0xA4, 0x10, 0x90, 4,0xE9, 8, 0xF8, 0x3B, 0x8A, 0x9C, 0x8C, 0x44, 0xF9,0xBC, 0x5C, 0x69, 0xE2, 0xA1, 0xDA, 0xD2, 0xD3, 0x75,0x89, 0xF7, 0x1E, 0x2D, 0x50, 0x56, 0xD7, 0x72, 0x53,0xBF, 0x22, 0xFB, 0x20, 0xF, 1, 0x2E, 0x45, 0x87, 0x6E,0x66, 0x48, 0xF2, 0xE0, 0xCD, 0xFE, 0x67, 0xA9, 0x43,0xF4, 0x94, 0x51, 0xCE, 0xA5, 0x4A, 0xEE, 0x13, 0x26,0x8E, 0xCC, 0xAA, 0x33, 0x14, 0x5D, 0xE, 0x39, 0xBB,0xCF, 0x91, 0x2B, 0x81, 0x4D, 0xEA, 0x99, 0xEC, 0x1A,0x2C, 0x85, 0xC5, 0xD9, 0x36, 0x74, 0x4B, 0x18, 0xE1,0xF1, 0x3D, 0x9D, 0x41, 0x9F, 0xB4, 0x17, 0xD, 0xD6,0x4C, 0xBE, 0xDC, 0xAF, 0x97, 0x28, 0x77, 0xF0, 0x62,0xFF, 0x71, 0xC1, 0xC8, 0x27, 0x8F, 0x6C, 0x68, 0xA8,0x9B, 0xE6, 0x59, 0x1C, 0x1B, 0x12, 9, 0x98, 0x4E,0x3F, 6, 0x37, 0, 0xBA, 0x1F, 0xA, 0x19, 0x2F, 0xC9,0xD5, 0xD0, 0x57, 0x49, 0x6F, 0xFD, 0x25, 0xE4, 0x61,0xC, 0x42, 0xCB, 0x96, 0x64, 0x5F, 0xDB, 0xAD, 0x60,0x23, 0x8D, 0x9A, 0x6D, 0xC3, 0xC4, 0x5E, 0x3E, 0xB9,0x92, 0x6A, 0xBD, 0x5B, 7, 0x7F, 0x76, 0x95, 0xED,0x4F, 0xAB, 0x84, 0x7A, 0x80, 0xE7, 0x78, 0xC7, 0xE5,0xEB, 0x73, 0x83, 0x6B, 0xFC, 0x38, 0x46, 0x7D, 0x47,0x65, 0xB3, 0x52, 0x63, 0x3A, 5, 0xD1, 0xEF, 0xA3,0xA6, 0xDE, 0x9E, 0x3C, 2, 0xAE, 0xB2, 0x7B, 0xA0,0xF6, 0xF3, 0x2A, 0xC0, 0xAC, 0x86, 3, 0x5A, 0x54,0xB, 0xF5, 0x82, 0xD4, 0x7E, 0xE3, 0xDF, 0xB0, 0xD8,0xDD, 0x21, 0xE8, 0x7C, 0x88, 0xA2, 0x79, 0x58, 0x70,0xB7, 0x15]encoded_bytes = []for char in input_str:# 获取字符的ASCII码作为索引index = ord(char)# 确保索引在查找表范围内if index < 0 or index >= len(byte_D9FC):raise ValueError(f"字符 '{char}' (ASCII: {index}) 超出查找表范围")# 使用查找表进行编码encoded_byte = byte_D9FC[index]encoded_bytes.append(encoded_byte)# 将编码后的字节转换为十六进制字符串hex_str = ''.join([f"{b:02x}" for b in encoded_bytes])return hex_str

三、两次sha256算法

ida中的代码

  v18 = 0;if ( (mingwen_str & 1) != 0 )v19 = v17;elsev19 = mingwen_str >> 1;if ( (mingwen_str & 1) != 0 )v20 = v16;elsev20 = &mingwen_strv66 + 1;if ( v19 ){v21 = v20;if ( v19 == 1 )goto LABEL_34;v22 = 0;v23 = 0;v21 = &v20[v19 & 0xFFFFFFFFFFFFFFFELL];v24 = v20 + 1;v25 = v19 & 0xFFFFFFFFFFFFFFFELL;do{v26 = *(v24 - 1);v27 = *v24;v24 += 2;v25 -= 2LL;v22 ^= v26;v23 ^= v27;}while ( v25 );v18 = v23 ^ v22;if ( v19 != (v19 & 0xFFFFFFFFFFFFFFFELL) ){
LABEL_34:v28 = &v20[v19];do{v29 = *v21++;v18 ^= v29;}while ( v28 != v21 );}v18 %= 11;}v63[1] = 0LL;v64 = 0LL;v63[0] = 0LL;if ( v19 << 32 ){std::string::append(v63, v19, 0);if ( v19 <= 0 )goto LABEL_47;}else{*(v63 + v19 + 1) = 0;LOBYTE(v63[0]) = 2 * v19;if ( v19 <= 0 )goto LABEL_47;}v30 = 0LL;do{v31 = v67;v32 = (v18 + v30) % v19;v33 = v64;if ( (mingwen_strv66 & 1) == 0 )v31 = &mingwen_strv66 + 1;v34 = v31[v30++];if ( (v63[0] & 1) == 0 )v33 = v63 + 1;v33[v32] = v34;}while ( v19 != v30 );
LABEL_47:
============================================
SHA256();v36 = 0LL;v37 = s;v74 = 0;v72 = 0u;v73 = 0u;v71 = 0u;*s = 0u;do{sub_3684(v37, -1LL, v35, v75[v36++]);v37 += 2;}while ( v36 != 32 );std::string::basic_string<decltype(nullptr)>(&sha256_res, s);v38 = v62;v39 = 0;if ( (sha256_res & 1) != 0 )v40 = *&v61[7];elsev40 = sha256_res >> 1;if ( (sha256_res & 1) == 0 )v38 = v61;if ( v40 ){v41 = v38;if ( v40 == 1 )goto LABEL_59;v42 = 0;v43 = 0;v41 = &v38[v40 & 0xFFFFFFFFFFFFFFFELL];v44 = v38 + 1;v45 = v40 & 0xFFFFFFFFFFFFFFFELL;do{v46 = *(v44 - 1);v47 = *v44;v44 += 2;v45 -= 2LL;v42 ^= v46;v43 ^= v47;}while ( v45 );v39 = v43 ^ v42;if ( v40 != (v40 & 0xFFFFFFFFFFFFFFFELL) ){
LABEL_59:v48 = &v38[v40];do{v49 = *v41++;v39 ^= v49;}while ( v48 != v41 );}v39 %= 11;}v58[1] = 0LL;v59 = 0LL;v58[0] = 0LL;if ( v40 << 32 ){std::string::append(v58, v40, 0);if ( v40 <= 0 )goto LABEL_72;}else{*(v58 + v40 + 1) = 0;LOBYTE(v58[0]) = 2 * v40;if ( v40 <= 0 )goto LABEL_72;}v50 = 0LL;do{v51 = v62;v52 = (v39 + v50) % v40;v53 = v59;if ( (sha256_res & 1) == 0 )v51 = v61;v54 = v51[v50++];if ( (v58[0] & 1) == 0 )v53 = v58 + 1;v53[v52] = v54;}while ( v40 != v50 );
LABEL_72:
============================================SHA256();

我们可以看到有两次sha256算法我们hook一下sha256函数看下入参:

进入Sha256================
"rr- ,�,"�5a6f1P-rSPPrS�S��SSPV�"�SP"MP"׿� "S  MP""  ��   M-MPM-M �SM�r�V"�rrMV�P�P
             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
79b4efde50  22 72 72 2d 20 1a 2c 1a c5 2c 22 c5 35 61 36 66  "rr- .,..,".5a6f
79b4efde60  31 50 2d 72 53 50 50 72 53 bf 53 bf bf 53 53 50  1P-rSPPrS.S..SSP
79b4efde70  56 bf 22 bf 53 50 22 4d 50 22 d7 bf bf 20 22 53  V.".SP"MP"... "S
79b4efde80  20 20 4d 50 22 22 20 20 fb d7 20 20 20 4d 2d 4d    MP""  ..   M-M
79b4efde90  50 4d 2d 4d 20 d7 53 4d d7 72 d7 56 22 d7 72 72  PM-M .SM.r.V".rr
79b4efdea0  4d 56 d7 50 fb 50                                MV.P.P
长度 86
Sha256 result=             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
778d94dac8  ac 03 64 81 c4 68 6f 92 94 7a ed 19 bd 46 7d f5  ..d..ho..z...F}.
778d94dad8  6c 82 1b 96 10 cd b8 f4 ef f7 da 61 84 fc 43 e8  l..........a..C.
进入Sha256================
3e8ac036481c4686f92947aed19bd467df56c821b9610cdb8f4eff7da6184fc4
             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
79a4edb990  33 65 38 61 63 30 33 36 34 38 31 63 34 36 38 36  3e8ac036481c4686
79a4edb9a0  66 39 32 39 34 37 61 65 64 31 39 62 64 34 36 37  f92947aed19bd467
79a4edb9b0  64 66 35 36 63 38 32 31 62 39 36 31 30 63 64 62  df56c821b9610cdb
79a4edb9c0  38 66 34 65 66 66 37 64 61 36 31 38 34 66 63 34  8f4eff7da6184fc4
长度 64
Sha256 result=             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
778d94dac8  36 c0 8d b7 02 cb 2f 47 7e f9 92 31 f2 97 5d 1b  6...../G~..1..].
778d94dad8  97 d7 a7 87 75 81 93 0a c4 67 34 28 3b 97 d1 45  ....u....g4(;..E
主动调用 nativeGetSignatures 结果: 36c08db702cb2f477ef99231f2975d1b97d7a7877581930ac46734283b97d145
 

对比append函数:

进入append================

             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
7a2505af71  2d 20 1a 2c 1a c5 2c 22 c5                       - .,..,".
进入append================

             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
7a2505af89  35 61 36 66 31                                   5a6f1
进入append================

             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
7a2505afa1  50 2d 72 53                                      P-rS
进入append================

             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
7a2505afb9  50 50 72 53 bf 53 bf bf 53 53                    PPrS.S..SS
进入append================

             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
7994eb1450  50 56 bf 22 bf 53 50 22 4d 50 22 d7 bf bf 20 22  PV.".SP"MP"... "
7994eb1460  53 20 20 4d 50 22 22 20 20 fb d7 20 20 20 4d 2d  S  MP""  ..   M-
7994eb1470  4d 50 4d 2d 4d 20 d7 53 4d d7 72 d7 56 22 d7 72  MPM-M .SM.r.V".r
7994eb1480  72 4d 56 d7 50 fb 50 22 72 72                    rMV.P.P"rr
 

我们发现两次sha256之前均进行了重排序。

两次重排序:

  1. 计算校验和:通过异或运算生成一个0-10的校验值

  2. 数据重排序:根据校验值对输入字节进行循环位移

def process_sha256_result(sha256_res):# sha256_res = bytearray.fromhex(input_hex)# 1. 初始化参数v40 = 0length = len(sha256_res)# 2. 计算校验和(异或)if length >= 2:v43 = v44 = 0for i in range(0, length - 1, 2):v43 ^= sha256_res[i]v44 ^= sha256_res[i + 1]v40 = (v43 ^ v44) % 11# 3. 数据重排result = bytearray(length)for i in range(length):new_pos = (v40 + i) % lengthresult[new_pos] = sha256_res[i]return bytes(result)

这些代码 根据ida 代码翻译得来:

例如翻译这个:

   do{v46 = *(v44 - 1);v47 = *v44;v44 += 2;v45 -= 2LL;v42 ^= v46;v43 ^= v47;}while ( v45 );v39 = v43 ^ v42;if ( v40 != (v40 & 0xFFFFFFFFFFFFFFFELL) ){
LABEL_59:v48 = &v38[v40];do{v49 = *v41++;v39 ^= v49;}while ( v48 != v41 );}v39 %= 11;}v58[1] = 0LL;v59 = 0LL;v58[0] = 0LL;if ( v40 << 32 ){std::string::append(v58, v40, 0);if ( v40 <= 0 )goto LABEL_72;}else{*(v58 + v40 + 1) = 0;LOBYTE(v58[0]) = 2 * v40;if ( v40 <= 0 )goto LABEL_72;}v50 = 0LL;do{v51 = v62;v52 = (v39 + v50) % v40;v53 = v59;if ( (sha256_res & 1) == 0 )v51 = v61;v54 = v51[v50++];if ( (v58[0] & 1) == 0 )v53 = v58 + 1;v53[v52] = v54;}while ( v40 != v50 );

所以我们在两次sha256之前 进行重排序即可。

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

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

相关文章

Django的异步任务队列管理_Celery

1 基本原理 Celery 是一个异步任务队列&#xff0c;能够将耗时操作&#xff08;如发邮件、处理图片、网络爬虫等&#xff09;从 Django 主线程中分离出来&#xff0c;由后台的 worker 处理&#xff0c;避免阻塞请求。Celery 作为独立运行的后台进程&#xff08;Worker&#xf…

【计算机网络】Linux网络的几个常用命令

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 相关文章&#xff1a;计算机网络专栏 目录 ping&#xff08;检测网络连通性&#xff09;…

全开源、私有化部署!轻量级用户行为分析系统-ClkLog

ClkLog是一款支持私有化部署的全开源埋点数据采集与分析系统&#xff0c;兼容Web、App、小程序多端埋点&#xff0c;快速洞察用户访问路径、行为轨迹&#xff0c;并生成多维用户画像。助力中小团队搭建轻量灵活的用户行为分析平台。 为什么需要一款私有化的埋点分析系统&#x…

golang定时器的精度

以 go1.23.3 linux/amd64 为例。 定时器示例代码&#xff1a; package mainimport ("context""fmt""time" )var ctx context.Contextfunc main() {timeout : 600 * time.Secondctx, _ context.WithTimeout(context.Background(), timeout)dea…

svn 远程服务搜索功能

svn服务器没有远程搜索功能&#xff0c;靠人工检索耗时耗力&#xff0c;当服务器文件过多时&#xff0c;全部checkout到本地检索&#xff0c;耗时太久。 1. TortoiseSVN 安装注意事项 下载官网地址&#xff1a;https://tortoisesvn.en.softonic.com/download 安装时选中 co…

uniapp-商城-39-shop 购物车 选好了 进行订单确认4 配送方式2 地址页面

上面讲基本的样式和地址信息&#xff0c;但是如果没有地址就需要添加地址&#xff0c;如果有不同的地址就要选地址。 来看看处理方式&#xff0c; 1、回顾 在delivery-layout中 methods:{goAddress(){uni.navigateTo({url:"/pagesub/pageshop/address/addrlist"})…

Linux命令-iostat

iostat 命令介绍 iostat 是一个用于监控 Linux 系统输入/输出设备加载情况的工具。它可以显示 CPU 的使用情况以及设备和分区的输入/输出统计信息&#xff0c;对于诊断系统性能瓶颈&#xff08;如磁盘或网络活动缓慢&#xff09;特别有用。 语法&#xff1a; iostat [options…

vue2关于Node.js17及以上报digital envelope错误的解决办法

文章目录 简介错误原因解决方案设置环境变量修改package.json安装旧版本Node.js更新依赖项更改加密设置 简介 digital envelope routines::unsupported错误‌通常发生在Node.js版本升级到17或更高版本后&#xff0c;因为这些版本开始使用OpenSSL 3.0&#xff0c;它对算法和密钥…

LLM - Large Language Model

回顾2024&#xff1a;与LLM又相伴一年的经历与思考 - 知乎万字长文入门大语言模型&#xff08;LLM&#xff09; - 知乎“大模型本质就是两个文件&#xff01;”特斯拉前AI总监爆火LLM科普&#xff0c;时长1小时&#xff0c;面向普通大众 - 知乎大模型本质及趋势剖析&#xff0c…

Linux 内核网络协议栈中的关键数据结构:inet_skb_parm 与 ip_options

在 Linux 内核的网络协议栈中,数据包的高效处理依赖于一系列精心设计的数据结构。这些结构体不仅需要存储网络数据的元信息,还需支持复杂的协议逻辑(如路由、分片、安全策略等)。本文聚焦两个核心结构体 struct inet_skb_parm 和 struct ip_options,解析它们的设计原理、功…

如何修复卡在恢复模式下的 iPhone:简短指南

Apple 建议使用恢复模式作为最后的手段&#xff0c;以便在 iPhone 启动循环或显示 Apple 标志时恢复 iPhone。这是解决持续问题的简单方法&#xff0c;但您很少使用。但是&#xff0c;当您的 iPhone 卡住恢复模式本身时&#xff0c;您会怎么做&#xff1f;虽然 iPhone 卡在这种…

10前端项目----商品详情页/滚轮行为

商品详情页面 商品详情组件发送请求获取相应商品详情信息组件展示数据 优化一下路由配置代码滚轮自动置顶 商品详情组件 路由配置 点击商品进行跳转—将Detail组件变成路由组件 从商品到详情&#xff0c;肯定需要传参(产品ID)告诉Detail是哪个商品&#xff0c;需要展示哪个商品…

DIFY 又跟新了,来到 1.3.0 版本,看正文

欢迎来到 1.3.0 版本&#xff01;添加了各种巧妙的功能、修复了错误&#xff0c;并带来了一些新功能&#xff1a; 一、核心亮点&#xff1a; 结构化输出 1、LLM 节点新增JSON Schema编辑器&#xff0c;确保大语言模型能够返回符合预设格式的JSON数据。这一功能有助于提升数据…

git检查提交分支和package.json的version版本是否一致

这里写自定义目录标题 一、核心实现步骤‌1.安装必要依赖‌2.初始化 Husky‌3.创建校验脚本‌4.配置 lint-staged‌5.更新 Husky 钩子‌ 三、工作流程说明‌四、注意事项‌ 以下是基于 Git Hooks 的完整解决方案&#xff0c;通过 husky 和自定义脚本实现分支名与版本号一致性校…

react-navigation-draw抽屉导航

心得写在前面分享给大家&#xff1a; 我的实现方法&#xff0c;并没有完全安装官网来做&#xff0c;而是进行了简化&#xff0c;效果是一样的。没有按照官网说的修改metro.config.js文件&#xff0c;同时也没有 react-native-gesture-handler 的安装后&#xff0c;我们需要有条…

【计算机视觉】CV实战项目-高分辨率遥感图像语义分割:High-Resolution-Remote-Sensing-Semantic-Segmentation

高分辨率遥感图像语义分割技术解析与实战指南 项目背景与意义核心技术解析1. **膨胀预测&#xff08;Dilated Prediction&#xff09;**2. **后处理优化**3. **半监督学习&#xff1a;伪标签&#xff08;Pseudo Labeling&#xff09;**4. **可视化与监控** 实战指南&#xff1a…

免费送源码:Java+SSM+MySQL 基于SSM开发的校园心理咨询平台系统的设计与实现 计算机毕业设计原创定制

目 录 1 绪论 1 1.1 研究背景 1 1.2开发现状 1 1.3论文结构与章节安排 2 2 校园心理咨询平台系统系统分析 3 2.1 可行性分析 3 2.1.1 技术可行性分析 3 2.1.2 经济可行性分析 3 2.1.3 法律可行性分析 3 2.2 系统功能分析 3 2.2.1 功能性分析 4 2.2.2 非功能性分析…

学习笔记:Qlib 量化投资平台框架 — GETTING STARTED

学习笔记&#xff1a;Qlib 量化投资平台框架 — GETTING STARTED Qlib 是微软亚洲研究院开源的一个面向人工智能的量化投资平台&#xff0c;旨在实现人工智能技术在量化投资中的潜力&#xff0c;赋能研究&#xff0c;并创造价值&#xff0c;从探索想法到实施生产。Qlib 支持多种…

cmake qt 项目编译

当前MAC 编译命令 rm -rf build 删除之前build记录 mkdir build && cd build 重新生成build文件夹 cmake -DCMAKE_PREFIX_PATH"/usr/local/opt/qt" .. Cmake编译指定我的qt路径 cmake --build . 生成程序 程序生成后如此 第三方库单独下载 在CMakeLis…

Swift与iOS内存管理机制深度剖析

前言 内存管理是每一位 iOS 开发者都绕不开的话题。虽然 Swift 的 ARC&#xff08;自动引用计数&#xff09;极大简化了开发者的工作&#xff0c;但只有深入理解其底层实现&#xff0c;才能写出高效、健壮的代码&#xff0c;避免各种隐蔽的内存问题。本文将从底层原理出发&…