Android 自定义变形 MD5 算法
版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/
MD5是一种哈希函数,用于将任意长度的数据映射为一个固定长度的哈希值。它由 Ron Rivest 在 1991 年设计,是继 MD4 之后的改进版本。
MD5 的基本特征:
-
固定长度输出:将任意长度的数据转换为 128 位(16 字节) 的哈希值,通常以 32 位十六进制 字符串表示。
-
不可逆性:无法从哈希值反推原始数据。
-
雪崩效应:输入的微小变化会导致哈希值完全不同。
-
抗碰撞性较弱:不同输入产生相同哈希值的概率较低,但已存在有效的碰撞攻击。
-
计算速度快:采用简单的位运算,处理速度快,适合大数据量。
标准 MD5
标准 MD5 的 C++ 实现如下:
md5.h
#ifndef __MD5_INCLUDE__/* typedef a 32-bit type */
#ifdef _LP64
typedef unsigned int UINT4;
typedef int INT4;
#else
typedef unsigned long UINT4;
typedef long INT4;
#endif
#define _UINT4_T/* Data structure for MD5 (Message-Digest) computation */
typedef struct {UINT4 i[2]; /* number of _bits_ handled mod 2^64 */UINT4 buf[4]; /* scratch buffer */unsigned char in[64]; /* input buffer */unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;void MD5_Init (MD5_CTX *mdContext);
void MD5_Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);
void MD5_Final (unsigned char hash[], MD5_CTX *mdContext);#define __MD5_INCLUDE__
#endif /* __MD5_INCLUDE__ */
md5.cpp
#include <string>
#include "md5.h"/* forward declaration */
static void Transform(UINT4 *buf, UINT4 *in);static unsigned char PADDING[64] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};/* F, G, H and I are basic MD5 functions */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) \{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \(a) = ROTATE_LEFT ((a), (s)); \(a) += (b); \}
#define GG(a, b, c, d, x, s, ac) \{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \(a) = ROTATE_LEFT ((a), (s)); \(a) += (b); \}
#define HH(a, b, c, d, x, s, ac) \{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \(a) = ROTATE_LEFT ((a), (s)); \(a) += (b); \}
#define II(a, b, c, d, x, s, ac) \{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \(a) = ROTATE_LEFT ((a), (s)); \(a) += (b); \}#ifdef __STDC__
#define UL(x) x##U
#else
#define UL(x) x
#endif/* The routine MD5_Init initializes the message-digest contextmdContext. All fields are set to zero.*/
void MD5_Init(MD5_CTX *mdContext) {mdContext->i[0] = mdContext->i[1] = (UINT4) 0;/* Load magic initialization constants.*/mdContext->buf[0] = (UINT4) 0x67452301;mdContext->buf[1] = (UINT4) 0xefcdab89;mdContext->buf[2] = (UINT4) 0x98badcfe;mdContext->buf[3] = (UINT4) 0x10325476;
}/* The routine MD5Update updates the message-digest context toaccount for the presence of each of the characters inBuf[0..inLen-1]in the message whose digest is being computed.*/
void MD5_Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen) {UINT4 in[16];int mdi;unsigned int i, ii;/* compute number of bytes mod 64 */mdi = (int) ((mdContext->i[0] >> 3) & 0x3F);/* update number of bits */if ((mdContext->i[0] + ((UINT4) inLen << 3)) < mdContext->i[0])mdContext->i[1]++;mdContext->i[0] += ((UINT4) inLen << 3);mdContext->i[1] += ((UINT4) inLen >> 29);while (inLen--) {/* add new character to buffer, increment mdi */mdContext->in[mdi++] = *inBuf++;/* transform if necessary */if (mdi == 0x40) {for (i = 0, ii = 0; i < 16; i++, ii += 4)in[i] = (((UINT4) mdContext->in[ii + 3]) << 24) |(((UINT4) mdContext->in[ii + 2]) << 16) |(((UINT4) mdContext->in[ii + 1]) << 8) |((UINT4) mdContext->in[ii]);Transform(mdContext->buf, in);mdi = 0;}}
}/* The routine MD5Final terminates the message-digest computation andends with the desired message digest in mdContext->digest[0...15].*/
void MD5_Final(unsigned char hash[], MD5_CTX *mdContext) {UINT4 in[16];int mdi;unsigned int i, ii;unsigned int padLen;/* save number of bits */in[14] = mdContext->i[0];in[15] = mdContext->i[1];/* compute number of bytes mod 64 */mdi = (int) ((mdContext->i[0] >> 3) & 0x3F);/* pad out to 56 mod 64 */padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);MD5_Update(mdContext, PADDING, padLen);/* append length in bits and transform */for (i = 0, ii = 0; i < 14; i++, ii += 4)in[i] = (((UINT4) mdContext->in[ii + 3]) << 24) |(((UINT4) mdContext->in[ii + 2]) << 16) |(((UINT4) mdContext->in[ii + 1]) << 8) |((UINT4) mdContext->in[ii]);Transform(mdContext->buf, in);/* store buffer in digest */for (i = 0, ii = 0; i < 4; i++, ii += 4) {mdContext->digest[ii] = (unsigned char) (mdContext->buf[i] & 0xFF);mdContext->digest[ii + 1] =(unsigned char) ((mdContext->buf[i] >> 8) & 0xFF);mdContext->digest[ii + 2] =(unsigned char) ((mdContext->buf[i] >> 16) & 0xFF);mdContext->digest[ii + 3] =(unsigned char) ((mdContext->buf[i] >> 24) & 0xFF);}memcpy(hash, mdContext->digest, 16);
}/* Basic MD5 step. Transforms buf based on in.*/
static void Transform(UINT4 *buf, UINT4 *in) {UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22FF (a, b, c, d, in[0], S11, UL(3614090360)); /* 1 */FF (d, a, b, c, in[1], S12, UL(3905402710)); /* 2 */FF (c, d, a, b, in[2], S13, UL(606105819)); /* 3 */FF (b, c, d, a, in[3], S14, UL(3250441966)); /* 4 */FF (a, b, c, d, in[4], S11, UL(4118548399)); /* 5 */FF (d, a, b, c, in[5], S12, UL(1200080426)); /* 6 */FF (c, d, a, b, in[6], S13, UL(2821735955)); /* 7 */FF (b, c, d, a, in[7], S14, UL(4249261313)); /* 8 */FF (a, b, c, d, in[8], S11, UL(1770035416)); /* 9 */FF (d, a, b, c, in[9], S12, UL(2336552879)); /* 10 */FF (c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */FF (b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */FF (a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */FF (d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */FF (c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */FF (b, c, d, a, in[15], S14, UL(1236535329)); /* 16 *//* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20GG (a, b, c, d, in[1], S21, UL(4129170786)); /* 17 */GG (d, a, b, c, in[6], S22, UL(3225465664)); /* 18 */GG (c, d, a, b, in[11], S23, UL(643717713)); /* 19 */GG (b, c, d, a, in[0], S24, UL(3921069994)); /* 20 */GG (a, b, c, d, in[5], S21, UL(3593408605)); /* 21 */GG (d, a, b, c, in[10], S22, UL(38016083)); /* 22 */GG (c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */GG (b, c, d, a, in[4], S24, UL(3889429448)); /* 24 */GG (a, b, c, d, in[9], S21, UL(568446438)); /* 25 */GG (d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */GG (c, d, a, b, in[3], S23, UL(4107603335)); /* 27 */GG (b, c, d, a, in[8], S24, UL(1163531501)); /* 28 */GG (a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */GG (d, a, b, c, in[2], S22, UL(4243563512)); /* 30 */GG (c, d, a, b, in[7], S23, UL(1735328473)); /* 31 */GG (b, c, d, a, in[12], S24, UL(2368359562)); /* 32 *//* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23HH (a, b, c, d, in[5], S31, UL(4294588738)); /* 33 */HH (d, a, b, c, in[8], S32, UL(2272392833)); /* 34 */HH (c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */HH (b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */HH (a, b, c, d, in[1], S31, UL(2763975236)); /* 37 */HH (d, a, b, c, in[4], S32, UL(1272893353)); /* 38 */HH (c, d, a, b, in[7], S33, UL(4139469664)); /* 39 */HH (b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */HH (a, b, c, d, in[13], S31, UL(681279174)); /* 41 */HH (d, a, b, c, in[0], S32, UL(3936430074)); /* 42 */HH (c, d, a, b, in[3], S33, UL(3572445317)); /* 43 */HH (b, c, d, a, in[6], S34, UL(76029189)); /* 44 */HH (a, b, c, d, in[9], S31, UL(3654602809)); /* 45 */HH (d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */HH (c, d, a, b, in[15], S33, UL(530742520)); /* 47 */HH (b, c, d, a, in[2], S34, UL(3299628645)); /* 48 *//* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21II (a, b, c, d, in[0], S41, UL(4096336452)); /* 49 */II (d, a, b, c, in[7], S42, UL(1126891415)); /* 50 */II (c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */II (b, c, d, a, in[5], S44, UL(4237533241)); /* 52 */II (a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */II (d, a, b, c, in[3], S42, UL(2399980690)); /* 54 */II (c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */II (b, c, d, a, in[1], S44, UL(2240044497)); /* 56 */II (a, b, c, d, in[8], S41, UL(1873313359)); /* 57 */II (d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */II (c, d, a, b, in[6], S43, UL(2734768916)); /* 59 */II (b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */II (a, b, c, d, in[4], S41, UL(4149444226)); /* 61 */II (d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */II (c, d, a, b, in[2], S43, UL(718787259)); /* 63 */II (b, c, d, a, in[9], S44, UL(3951481745)); /* 64 */buf[0] += a;buf[1] += b;buf[2] += c;buf[3] += d;
}std::string bytesToHex(const uint8_t *bytes, size_t length) {char hexStr[33];for (size_t i = 0; i < length; i++) {sprintf(&hexStr[i * 2], "%02x", bytes[i]);}hexStr[32] = '\0';return hexStr;
}
参考:https://cs.android.com/android/platform/superproject/+/master:external/ppp/pppd/md5.c;l=92
kotlin 层声明 md5 native 方法
package com.cyrus.example.md5class MD5Utils {companion object {// 加载 native 库init {System.loadLibrary("md5")}// 声明 native 静态方法@JvmStaticexternal fun md5(input: String): String}}
在 cpp 中实现 native 方法,调用 MD5_Init、MD5_Update、MD5_Final 完成 MD5 的计算并返回结果。
extern "C"
JNIEXPORT jstring JNICALL
Java_com_cyrus_example_md5_MD5Utils_md5(JNIEnv *env, jclass, jstring input) {const char *inputChars = env->GetStringUTFChars(input, nullptr);if (!inputChars) return nullptr;MD5_CTX ctx;MD5_Init(&ctx);MD5_Update(&ctx, (unsigned char *) inputChars, strlen(inputChars));uint8_t digest[16];MD5_Final(digest, &ctx);env->ReleaseStringUTFChars(input, inputChars);std::string md5Hash = bytesToHex(digest, 16);return env->NewStringUTF(md5Hash.c_str());
}
效果如下:
MD5Init
初始化上下文,包括计数器和状态缓冲区。
魔数初始化:这四个固定的 32 位数用于 MD5 的初始状态。
我们可以修改这四个魔数的初始值实现 MD5 算法的变形,比如修改如下:
void MD5_Init2(MD5_CTX *mdContext) {mdContext->i[0] = mdContext->i[1] = (UINT4) 0;mdContext->buf[0] = (UINT4) 0xaa452301;mdContext->buf[1] = (UINT4) 0xbbcdab89;mdContext->buf[2] = (UINT4) 0xccbadcfe;mdContext->buf[3] = (UINT4) 0xdd325476;
}
增加 changeMD5Init 方法
extern "C"
JNIEXPORT jstring JNICALL
Java_com_cyrus_example_md5_MD5Utils_changeMD5Init(JNIEnv *env, jclass, jstring input) {const char *inputChars = env->GetStringUTFChars(input, nullptr);if (!inputChars) return nullptr;MD5_CTX ctx;MD5_Init2(&ctx);MD5_Update(&ctx, (unsigned char *) inputChars, strlen(inputChars));uint8_t digest[16];MD5_Final(digest, &ctx);env->ReleaseStringUTFChars(input, inputChars);std::string md5Hash = bytesToHex(digest, 16);return env->NewStringUTF(md5Hash.c_str());
}
效果如下:
MD5_Update
每次调用 MD5_Update 时,它会将数据追加到 ctx->buffer。MD5_Update 可以多次调用。
我们可以通过调用 MD5_Update 去拼接自定义的字符串实现 MD5 变形,比如:
extern "C"
JNIEXPORT jstring JNICALL
Java_com_cyrus_example_md5_MD5Utils_changeMD5Update(JNIEnv *env, jclass, jstring input) {const char *inputChars = env->GetStringUTFChars(input, nullptr);if (!inputChars) return nullptr;MD5_CTX ctx;MD5_Init(&ctx);MD5_Update(&ctx, (unsigned char *) "cyrus", strlen(inputChars));MD5_Update(&ctx, (unsigned char *) "studio", strlen(inputChars));MD5_Update(&ctx, (unsigned char *) inputChars, strlen(inputChars));uint8_t digest[16];MD5_Final(digest, &ctx);env->ReleaseStringUTFChars(input, inputChars);std::string md5Hash = bytesToHex(digest, 16);return env->NewStringUTF(md5Hash.c_str());
}
- 相当于 md5(cyrus+studio+inputChars)
效果如下:
宏 FF、GG、HH、II
在 MD5 中,FF、GG、HH 和 II 是四个核心的轮函数(Round Functions),它们负责对数据块进行不同形式的混淆和非线性操作。每一轮都包含 16 次操作,共 64 次。
FF 宏(Round 1)
#define FF(a, b, c, d, x, s, ac) \{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \(a) = ROTATE_LEFT ((a), (s)); \(a) += (b); \}
参数解释:
-
a, b, c, d:四个 32 位寄存器变量。
-
x:当前数据块中的 32 位输入。
-
s:左旋转的位数。
-
ac:加法常数(T[i])。
F函数:
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
逻辑解析:
-
F(x, y, z) 实现了一个选择函数。
-
如果 x 的某位为 1,选择 y;否则选择 z。
-
这是一个条件赋值的模拟:x ? y : z。
作用:
-
FF 是一种条件性操作,它将输入数据和常数通过逻辑函数 F 混淆后,再执行旋转和累加操作。
-
Round 1 的特点是对输入数据的直接非线性处理。
GG 宏(Round 2)
#define GG(a, b, c, d, x, s, ac) \{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \(a) = ROTATE_LEFT ((a), (s)); \(a) += (b); \}
G函数:
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
逻辑解析:
-
G(x, y, z) 是一种少见的位运算,选择不同的输入进行混淆。
-
如果 z 的某位为 0,选择 x;否则选择 y。
作用:
-
GG 在第二轮中使用了不同的逻辑函数 G,进一步打乱数据。
-
它的特点是强调输入数据与寄存器的非线性关系。
HH 宏(Round 3)
cpp复制编辑#define HH(a, b, c, d, x, s, ac) \{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \(a) = ROTATE_LEFT ((a), (s)); \(a) += (b); \}
H函数:
cpp复制编辑#define H(x, y, z) ((x) ^ (y) ^ (z))
逻辑解析:
-
H(x, y, z) 是简单的按位异或操作。
-
异或操作具有混淆性强的特点,不可逆。
作用:
-
HH 使用异或操作对数据进行进一步的随机化。
-
它减少了数据之间的线性关系,增强了哈希的安全性。
II 宏(Round 4)
#define II(a, b, c, d, x, s, ac) \{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \(a) = ROTATE_LEFT ((a), (s)); \(a) += (b); \}
I函数:
#define I(x, y, z) ((y) ^ ((x) | (~z)))
逻辑解析:
-
I(x, y, z) 通过 OR 和 NOT 操作形成复杂的非线性映射。
-
这种逻辑是为了确保输入数据对输出的影响最大化。
作用:
-
II 是最后一轮变换,用于进一步打乱数据并确保不可逆性。
-
它将前几轮的结果进一步混淆,确保哈希值的独特性。
四轮计算:
-
Round 1:使用 FF,主要作用是与原始输入数据紧密结合。
-
Round 2:使用 GG,引入更多的非线性关系。
-
Round 3:使用 HH,通过异或增加数据的混淆性。
-
Round 4:使用 II,确保最终输出的不可预测性。
修改宏的常数实现 MD5 变形
我们可以通过修改宏的常数实现 MD5 变形,比如我这里改了 FF 中 1、2、3的常数:
/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22FF (a, b, c, d, in[0], S11, UL(1114090360)); /* 1 */FF (d, a, b, c, in[1], S12, UL(2205402710)); /* 2 */FF (c, d, a, b, in[2], S13, UL(336105819)); /* 3 */FF (b, c, d, a, in[3], S14, UL(3250441966)); /* 4 */FF (a, b, c, d, in[4], S11, UL(4118548399)); /* 5 */FF (d, a, b, c, in[5], S12, UL(1200080426)); /* 6 */FF (c, d, a, b, in[6], S13, UL(2821735955)); /* 7 */FF (b, c, d, a, in[7], S14, UL(4249261313)); /* 8 */FF (a, b, c, d, in[8], S11, UL(1770035416)); /* 9 */FF (d, a, b, c, in[9], S12, UL(2336552879)); /* 10 */FF (c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */FF (b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */FF (a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */FF (d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */FF (c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */FF (b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
其他不变,效果如下:
OLLVM MD5
通过 OLLVM 混淆 C/C++ 代码。
关于 OLLVM 的编译和移植到 NDK 可以参考下面的文章:
-
移植 OLLVM 到 LLVM 18,C&C++代码混淆
-
移植 OLLVM 到 Android NDK,Android Studio 中使用 OLLVM
比如,给 md5 方法添加下面注解启用虚假控制流
__attribute__((annotate("bcf")))
extern "C"
JNIEXPORT jstring JNICALL
__attribute__((annotate("bcf"))) Java_com_cyrus_example_md5_MD5Utils_changeConstant(JNIEnv *env, jclass, jstring input) {const char *inputChars = env->GetStringUTFChars(input, nullptr);if (!inputChars) return nullptr;MD5_CTX ctx;MD5_Init_(&ctx);MD5_Update_(&ctx, (unsigned char *) inputChars, strlen(inputChars));uint8_t digest[16];MD5_Final_(digest, &ctx);env->ReleaseStringUTFChars(input, inputChars);std::string md5Hash = bytesToHex(digest, 16);return env->NewStringUTF(md5Hash.c_str());
}
经过混淆后的 md5 方法反汇编视图
完整源码
完整源码地址:https://github.com/CYRUS-STUDIO/AndroidExample
相关文章:
Android 自定义变形 MD5 算法
版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/ MD5是一种哈希函数,用于将任意长度的数据映射为一个固定长度的哈希值。它由 Ron Rivest 在 1991 年设计,是继 MD4 之后的改进版本。 M…...
【SpringBoot】MorningBox小程序的完整后端接口文档
以下是「晨光宅配」小程序的完整接口文档,涵盖了所有12个表的接口。 每个接口包括请求方法、URL、请求参数、响应格式和示例 接口文档 1. 用户模块 1.1 获取用户信息 URL: /user/{userId}方法: GET请求参数: userId (路径参数): 用户ID响应格式:{"userId": 1,&qu…...
2025年01月03日微创网络(杭州银行外包)前端面试
目录 html 块级元素和行内元素有哪些阴影的几个属性垂直水平居中的实现方式定位的几种方式盒子模型的方式js的数组方法有哪些vue2 vue3 区别vuex哈希路由和浏览器路由的区别浏览器缓存的几个方式react hooks的优势react 组件传值vue 组件传值如何进行性能优化前端监控get post…...
工单分类总结
微调BERT-base模型,构建层次化分类器,Top-3准确率达97.2%,并自动识别出问题的关键类别 1. 具体微调的BERT-base模型是什么模型? BERT-base模型是一个预训练的Transformer模型,包含12个Transformer块、12个自注意头和隐藏大小为768。该模型在大规模文本数据上进行了预训练…...
2025年了,5G还有三个新变化
最近舆论开始讨论5G为什么不火了?5G是不是停滞发展了。 实际上,5G不仅在发展,还迎来了它的升级版5G-A。 在今年西班牙举行的世界移动通信大会上,5G-A就是焦点之一。 被誉为全球通信领域风向标的MWC,汇聚了华为、中兴通…...
区块链交易所平台开发全解析
在数字化飞速发展的今天,区块链技术已成为金融领域的核心驱动力之一。作为数字货币交易的关键平台,区块链交易所的开发不仅涉及复杂的技术环节,还需要兼顾用户体验、安全性、合规性等多个方面。本文将深入探讨区块链交易所平台的开发流程、关…...
hexo+butterfly博客功能完善和美化(四)---博客上传
hexobutterfly博客功能完善和美化(四)—博客上传 这是最后一期讲美化和功能完善了,笔者会陆续把csdn上面的博客转移到我的博客网站上面,大家可以来访问 Darlingの妙妙屋 文章目录 hexobutterfly博客功能完善和美化(…...
源码分析之Leaflet中dom模块DomEvent.DoubleTap的实现原理
概述 DomEvent.DoubleTap模块是Leaflet中用于模拟双击(dbclick)事件的模块,主要解决移动端浏览器对双击事件支持不完善或延迟的问题,同时避免与标签(<label>)关联的表单元素误触发。 源码分析 源码实现如下 DomEvent.DoubleTap的源码实现如下&…...
记录一次,rabbitmq开启stomp插件之后,还是连不上15674端口的问题
原因是装在docker 里面的rabbitmq 没有映射15674端口,需重新删除容器之后重新运行 docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 -p 15674:15674 -p 1883:1883 -p 15675:15675 rabbitmq:版本号 进入docker容器开启插件 docker exec -it rabbitm…...
git clone项目报错fatal: fetch-pack: invalid index-pack output问题
前情回顾:git项目放在公司服务器上面,克隆等操作需要连接VPN才能操作。由于项目比较大,网速比较慢,克隆项目经常出现fetch-pack: invalid index-pack output。在网上查找各种解决方法。也就这一种有点效果。仅供参考,不…...
【access开发】导入excel 并生成表
hi,大家好呀! 最近天气越来越暖了,在这个春暖花开的季节了,每天心情应该都是美美的,正所谓一年之计在于春,在这个美好的季节,大家一起努力学习学习吧!那我们来看看今天学点啥呢&…...
利用knn算法实现手写数字分类
利用knn算法实现手写数字分类 1.作者介绍2.KNN算法2.1KNN(K-Nearest Neighbors)算法核心思想2.2KNN算法的工作流程2.3优缺点2.4 KNN算法图示介绍 3.实验过程3.1安装所需库3.2 MNIST数据集3.3 导入手写数字图像进行分类3.4 完整代码3.5 实验结果 1.作者介…...
从零开始实现 C++ TinyWebServer 处理请求 HttpRequest类详解
文章目录 HTTP 请求报文HttpRequest 类实现 Init() 函数实现 ParseRequestLine() 函数实现 ParseHeader() 函数实现 ParsePath() 函数实现 ParseBody() 函数实现 ParsePost() 函数实现 ParseFromUrlEncoded() 函数实现 UserVerify() 函数实现 Parse() 函数HttpRequest 代码Http…...
Android开发layer-list
Android开发layer-list 它的用处可以在drawable上进行多图拼接,比如启动页,不想图片被拉伸就这么做。还有做某些线突出来。 示例代码: <?xml version"1.0" encoding"utf-8"?> <layer-list xmlns:android&q…...
如何提升库存系统的高并发和稳定性:算法与设计模式
库存系统是企业运营的核心模块,尤其是在电商、零售和供应链管理中,系统的高并发和稳定性直接影响订单处理的准确性和效率。面对海量订单、复杂的库存管理需求,如何在高并发环境下确保库存数据的准确性和系统的稳定性?本文将从架构…...
关于CNN,RNN,GAN,GNN,DQN,Transformer,LSTM,DBN你了解多少
以下是神经网络中常见的几种模型的简要介绍: 1. CNN (Convolutional Neural Network, 卷积神经网络) 用途: 主要用于图像处理和计算机视觉任务。特点: 通过卷积核提取局部特征,具有平移不变性,能够有效处理高维数据(如图像…...
设计模式之装饰器模式
装饰器模式(Decorator)依然是我们设计模式中的结构型模式,其中的构造思想仍然是对多个类进行组合使用,以达成系统调用实现指定功能的设计模式。装饰器模式不论在我们日常开发过程中还是在我们提升技术阅读源码过程中都是比较常见的,但是整体学…...
Mistral AI发布开源多模态模型Mistral Small 3.1:240亿参数实现超越GPT-4o Mini的性能
法国人工智能初创公司Mistral AI于2025年3月正式推出新一代开源模型Mistral Small 3.1 ,该模型凭借240亿参数的轻量级设计,在多项基准测试中表现优异,甚至超越了Google的Gemma 3和OpenAI的GPT-4o Mini等主流专有模型。 1、核心特性与优势 多…...
SpringBoot3实战(SpringBoot3+Vue3基本增删改查、前后端通信交互、配置后端跨域请求、数据批量删除(超详细))(3)
目录 一、从0快速搭建SpringBoot3工程、SpringBoot3集成MyBatis、PageHelper分页查询的详细教程。(博客链接) 二、实现前端与后端通信对接数据。(axios工具) (1)安装axios。(vue工程目录) (2)封装请求工具类。(request.js) <1&…...
LabVIEW发电平台数据采集系统
本文详细介绍了基于LabVIEW的摇臂式波浪发电平台数据采集系统的设计与实现。通过整合LabVIEW软件与多种传感器技术,本系统能够有效提升数据采集的准确性和效率,为波浪能的利用和发电设备的优化提供科学依据。 项目背景 随着全球能源需求增长和环境保…...
人工智能(AI)系统化学习路线
一、为什么需要系统化学习AI? 人工智能技术正在重塑各行各业,但许多初学者容易陷入误区: ❌ 盲目跟风:直接学习TensorFlow/PyTorch,忽视数学与算法基础。 ❌ 纸上谈兵:只看理论不写代码,无法解…...
oracle事务的组成
1)数据库事务由以下的部分组成: 一个或多个DML 语句 ; 一个 DDL(Data Definition Language – 数据定义语言) 语句; 一个 DCL(Data Control Language – 数据控制语言)语句; 2)事务的执行开始: 以第一个 DML 语句的执行作为开始 ,…...
第二十八篇 数据获取与数据分析:数仓体系下的专业化分工与协同
声明:文章内容仅供参考,需仔细甄别。文中技术名称属相关方商标,仅作技术描述;代码示例为交流学习用途,部分参考开源文档(Apache 2.0/GPLv3);案例数据已脱敏,技术推荐保持…...
SpringSecurity——前后端分离登录认证
SpringSecurity——前后端分离登录认证的整个过程 前端: 使用Axios向后端发送请求 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>登录</title><script src"https://cdn…...
【AI】Orin Nano+ubuntu22.04上移植YoloV11,并使用DeepStream测试成功
1、准备工作 使用 sdk-manager 烧写 OrinNano, JetPack版本为6.0 DP,对应操作系统为:Ubuntu22.04 参见博客:【NVIDIA】Jetson Orin Nano系列:烧写Ubuntu22.04 2、安装 PyTorch 2.1 下载依赖 1)安装onnx pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/sim…...
RHCE 使用nginx搭建网站
一。准备工作 Windows dns映射 创建目录网页 vim 编辑内容 添加如下 重启nginx服务,在Windows浏览器进行测试...
arm linux下的读写信号量rw_semphore的实现
本文基于arm linux 5.10来介绍内核中使用的读写信号量rw remphore的实现代码。 内核中信号量结构体struct rw_semaphore的定义在include/linux/rwsem.h 32位architectures下,结构体struct rw_semaphore中的count的使用如下: 先来看信号量的定义和初始化…...
搭建主从DNS、nfs、nginx
任务需求: 客户端通过访问 www.nihao.com 后,能够通过 dns 域名解析,访问到 nginx 服务中由 nfs 共享的首页文件,内容为:Very good, you have successfully set up the system. 各个主机能够实现时间同步,…...
Qt6+QML实现Windows屏幕录制
前言 Qt6提供了更丰富的多媒体支持类,使用Qt6 QMediaCaptureSession、QScreenCapture、QMediaRecorder,来实现一个屏幕录制的demo,其中QScreenCapture 最低版本 Qt6.5。支持录制的清晰度设置,选择视频保存位置,UI使用…...
python二级每日十题(1)
\ 第一题,在Python中,变量名的命名规则:以字母或下划线开头,后面跟字母、下划线和数字;不能以数字开头.故选c项,博主正确 缩进:在逻辑行首的空白(空格和制表符)用来决定逻辑行的缩进层次&…...
记录一次truncate导致MySQL夯住的故障
目录 环境信息: 故障描述: 处理过程: 原理分析: show processlist结果中的system lock含义: truncate原理: 1. TRUNCATE 的执行流程 2、TRUNCATE 表导致数据库夯住的原因 3、 TRUNCATE 表导致…...
Java Web应用程序实现用户登录、学生信息管理和验证码验证以及页面跳转等基本功能(IDEA)含(Ajax、JSTL)
一、具体框架以及代码功能的展示: 1. 文件结构 web03: 项目根目录。 src: 包含Java源代码。 cn.lvb: 主包。 bean: 包含实体类,如 Book 和 Student。 controller: 包含处理HTTP请求的Servlet类,如 DoLogin, Index, StuList1, VerifyCode。 …...
【Mybatis-plus】在mybatis-plus中 if test标签如何判断 list不为空
博主介绍:✌全网粉丝22W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
MySQL 事务(Transaction)详解
MySQL 事务(Transaction)详解 1. 什么是事务? 事务(Transaction)是一组要么全部执行,要么全部回滚的 SQL 语句,用于保证数据一致性。事务一般用于银行转账、订单支付等操作,确保多个…...
Redis 知识点梳理
第一章 NoSQL数据库发展历史简介 1、 Web的历史发展历程 web1.0时代简介 web 1.0是以编辑为特征,网站提供给用户的内容是网站编辑进行编辑处理后提供的,用户阅读网站提供的内容这个过程是网站到用户的单向行为web1.0时代的代表站点为新浪,…...
github上传操作简单说明
前期准备 0.下载git(如果已经有了就不用了) 1.在GitHub上新建一个存储库 2.先在本地创建一个目录作为本地库目录,在目录里打开git bash进行上传 上传过程 echo "# Garbled_repair" >> README.md 作用:创建一个…...
在 ASP .NET Core 9.0 中使用 Scalar 创建漂亮的 API 文档
示例代码:https://download.csdn.net/download/hefeng_aspnet/90407900 Scalar 是一款可帮助我们为 API 创建精美文档的工具。与感觉有些过时的默认 Swagger 文档不同,Scalar 为 API 文档提供了全新而现代的 UI。其简洁的设计让开发人员可以轻松找到测试…...
针对 pdf.mjs 文件因 MIME 类型错误导致的 Failed to load module script 问题解决方案
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “application/octet-stream”. Strict MIME type checking is enforced for module scripts per HTML spec. pdf.mjs 这种问题该如何处理 nginx 针对 pdf.…...
Flink介绍与安装
Apache Flink是一个在有界数据流和无界数据流上进行有状态计算分布式处理引擎和框架。Flink 设计旨在所有常见的集群环境中运行,以任意规模和内存级速度执行计算。 一、主要特点和功能 1. 实时流处理: 低延迟: Flink 能够以亚秒级的延迟处理数据流,非常…...
《双指针算法指南:LeetCode 经典题解(C++实现)》
《双指针算法指南:LeetCode 经典题解(C实现)》 —— 从快慢指针到对撞指针,刷题效率提升 200%! 常⻅的双指针有两种形式,⼀种是对撞指针,⼀种是左右指针。 对撞指针: ⼀般⽤于顺…...
kaggle上经典泰坦尼克项目数据分析探索
之前了解在kaggle上这个项目很火,最近想要加强一下python数据分析,所以在kaggle上找到这个项目进行学习探索,下面是将一些学习资料以及过程整理出来。 一、首先我们了解一下项目背景以及如何找到这个项目。 kaggle项目地址: https://www.k…...
【深度学习】多目标融合算法(五):定制门控网络CGC(Customized Gate Control)
目录 一、引言 二、CGC(Customized Gate Control,定制门控网络) 2.1 技术原理 2.2 技术优缺点 2.3 业务代码实践 2.3.1 业务场景与建模 2.3.2 模型代码实现 2.3.3 模型训练与推理测试 2.3.4 打印模型结构 三、总结 一、引言 上一…...
Ubuntu上查看GPU使用情况并释放内存
先用nvidia-smi查看GPU当前使用情况 再用fuser 命令查找对应显卡上占用 GPU 的进程 最后查到了用kill -9强制杀掉进程(PID)即可...
大数据学习栈记——HBase安装
本文介绍大数据技术中流行的非关系型数据库HBase的安装,操作系统:Ubuntu24.04 安装Zookeeper 安装HBase前需要先安装Zookeeper,HBase使用Zookeeper作为其分布式协同服务,存储了HBase集群的元数据信息,并提供了分布式…...
[入门]NUC13配置Ubuntu20.04详细步骤
文章目录 1. 安装Ubuntu20.041.1 制作系统启动盘1.1.1 下载镜像文件1.1.2 配置启动盘 1.2 安装内存条、硬盘1.3 安装系统 2. 网卡驱动配置2.1 关闭安全启动2.2 安装intel官方网卡驱动backport2.2.1 第四步可能会出现问题 2.3 ubuntu官方的驱动2.4 重启 3. 软件安装3.1 录屏软件…...
【实战指南】用MongoDB存储文档和图片等大文件(Java实现)
一、前言 在现代应用开发中,经常需要处理和存储大量的文档、图片等大文件。传统的关系型数据库在处理这类大文件时,往往会面临性能瓶颈、存储成本高等问题。而 MongoDB 作为一款流行的 NoSQL 数据库,提供了 GridFS 规范,能够很好地解决大文件存储的问题。GridFS 可以将大文…...
使用Gitee Go流水线部署个人项目到服务器指南
使用Gitee Go流水线部署个人项目到服务器指南 前言!!! 本文解决的问题: 你有一台ECS服务器,你在上面部署了一个Java服务也就是一个jar,你觉着你每次手动本地打包,上传,在通过命令去…...
使用Three.js渲染器创建炫酷3D场景
引言 在当今数字化的时代,3D图形技术正以其独特的魅力在各个领域掀起波澜。从影视制作到游戏开发,从虚拟现实到网页交互,3D场景以其强烈的视觉冲击力和沉浸式的体验,成为了吸引用户、传达信息的重要手段。而Three.js,…...
Spring Boot 集成 Elasticsearch怎样在不启动es的情况下正常启动服务
解释 在spingboot 集成es客户端后,每当服务启动时,服务默认都会查看es中是否已经创建了对应的索引,如果没有索引则创建。基于上面的规则我们可以通过配置不自动创建索引来达到在没有es服务的情况下正常启动服务。 解决办法 在entity类的Docu…...
明远智睿SD2351核心板:多接口融合,破解边缘计算难题
在边缘计算领域,明讯智睿SD2351核心板凭借丰富的接口资源与异构计算架构,成为工业网关与智能终端的理想选择。硬件配置升级 :处理器:四核Cortex-A35,256KB L2缓存,动态调频降低功耗;存储性能:emMC 5.0 HS400模式读写速度提升40%&a…...