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.pswp.cn/bicheng/78883.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78883.shtml
英文地址,請注明出處:http://en.pswp.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;避免各種隱蔽的內存問題。本文將從底層原理出發&…