网易云VIP音乐NCM文件转MP3,C语言版本

news2024/11/25 0:31:16

前言

网易云的Vip音乐下载下来,格式不是mp3/flac这种通用的音乐格式,而是经过加密的ncm文件。只有用网易云的音乐App才能够打开。于是想到可不可以把.ncm文件转换成mp3或者flac文件,上google查了一下,发现有不少人已经做了这件事,但没有发现C语言版本的,就想着写一个纯C语言版本的ncm转mp3/flac。

NCM文件结构

ncm文件的结构,网上有人解析出来了,分为下面几个部分

信息大小说明
Magic Header10 bytes文件头
Key Length4 bytesAES128加密后的RC4密钥长度,字节是按小端排序。
Key DataKey Length用AES128加密后的RC4密钥。
1. 先按字节对0x64进行异或。
2. AES解密,去除填充部分。
3. 去除最前面’neteasecloudmusic’17个字节,得到RC4密钥。
Music Info Length4 bytes音乐相关信息的长度,小端排序。
Music Info DataMusic Info LengthJson格式音乐信息数据。1. 按字节对0x63进行异或。
2. 去除最前面22个字节。
3. Base64进行解码。
4. AES解密。
6. 去除前面6个字节得到Json数据。
CRC4 bytes跳过
Gap5 bytes跳过
Image Size4 bytes图片的大小
ImageImage Size图片数据
Music Data-1. RC4-KSA生成S盒。
2. 用S盒解密(自定义的解密方法),不是RC4-PRGA解密。

两个AES对应密钥
unsigned char meta_key[] = { 0x23,0x31,0x34,0x6C,0x6A,0x6B,0x5F,0x21,0x5C,0x5D,0x26,0x30,0x55,0x3C,0x27,0x28 };
unsigned char core_key[] = { 0x68,0x7A,0x48,0x52,0x41,0x6D,0x73,0x6F,0x35,0x6B,0x49,0x6E,0x62,0x61,0x78,0x57 };
不得不佩服当初破解这个东西的人,不仅把文件结构摸得请清楚楚,还把密钥也搞到手,应该是个破解大神。有了上面的东西,剩下的就很简单了,按部就班来就行了。

一些算法准备

开始前我们需要把AES算法,BASE64算法,RC4算法和Json解析算法先写好。
除此之外还有一个编码问题,解析出来的ncm文件是用utf-8编码存储的,所以它在中文windows系统下汉字会出现乱码,因为中文windows系统采用的编码是GBK,两者不兼容,所以我们要写一个编码转换算法,将utf8格式字符串转位GBK的。Linux下不用转换,Linux本身就是用UTF-8的。
C语言没有这些库,都要自己来。

  • AES用GitHub上的
    tiny-AES-c
  • JSON用GitHub上的CJSON
    cJSON
  • Base64和RC4算法比较简单我们自己写
unsigned char* base64_decode(unsigned char* code,int len,int * actLen)
{
    //根据base64表,以字符找到对应的十进制数据  
    int table[] = { 0,0,0,0,0,0,0,0,0,0,0,0,
             0,0,0,0,0,0,0,0,0,0,0,0,
             0,0,0,0,0,0,0,0,0,0,0,0,
             0,0,0,0,0,0,0,62,0,0,0,
             63,52,53,54,55,56,57,58,
             59,60,61,0,0,0,0,0,0,0,0,
             1,2,3,4,5,6,7,8,9,10,11,12,
             13,14,15,16,17,18,19,20,21,
             22,23,24,25,0,0,0,0,0,0,26,
             27,28,29,30,31,32,33,34,35,
             36,37,38,39,40,41,42,43,44,
             45,46,47,48,49,50,51
    };
    long str_len;
    unsigned char* res;
    int i, j;

    //计算解码后的字符串长度  
    //判断编码后的字符串后是否有=
    if (strstr(code, "=="))
        str_len = len / 4 * 3 - 2;
    else if (strstr(code, "="))
        str_len = len / 4 * 3 - 1;
    else
        str_len = len / 4 * 3;

    *actLen = str_len;
    res = malloc(sizeof(unsigned char) * str_len + 1);
    res[str_len] = '\0';

    //以4个字符为一位进行解码  
    for (i = 0, j = 0; i < len - 2; j += 3, i += 4)
    {
        res[j] = ((unsigned char)table[code[i]]) << 2 | (((unsigned char)table[code[i + 1]]) >> 4); 
        res[j + 1] = (((unsigned char)table[code[i + 1]]) << 4) | (((unsigned char)table[code[i + 2]]) >> 2); 
        res[j + 2] = (((unsigned char)table[code[i + 2]]) << 6) | ((unsigned char)table[code[i + 3]]);
    }
    return res;

}
  • RC4生成S盒
//用key生成S盒
/*
* s: s盒
* key: 密钥
* len: 密钥长度
*/
void rc4Init(unsigned char* s, const unsigned char* key, int len) 
{   
    int i = 0, j = 0;
    unsigned char T[256] = { 0 };
  
    for (i = 0; i < 256; i++)
    {
        s[i] = i;
        T[i] = key[i % len];
    }
  
    for (i = 0; i < 256; i++) 
    {
        j = (j + s[i] + T[i]) % 256;
        unsigned tmp = s[i];
		s[i]=s[j];
		s[j]=tmp;
    }
}
//针对NCM文件的解密
//异或关系
/*
* s: s盒
* data: 要加密或者解密的数据
* len: data的长度
*/
void rc4PRGA(unsigned char* s, unsigned char* data, int len) 
{
    int i = 0;
    int j = 0;
    int k = 0;
    int idx = 0;
    for (idx = 0; idx < len; idx++) 
    {
        i = (idx + 1) % 256;
        j = (i + s[i]) % 256;
        k= (s[i] + s[j]) % 256;
        data[idx]^=s[k];  //异或
    }
}
  • Windows下utf8转GBK
#ifdef WIN32
#include<Windows.h>
//返回转换好的字符串指针
unsigned char* utf8ToGbk(unsigned char*src,int len)
{
	wchar_t* tmp = (wchar_t*)malloc(sizeof(wchar_t) * len+2);
	unsigned char* newSrc = (unsigned char*)malloc(sizeof(unsigned char) * len + 2);
	
	MultiByteToWideChar(CP_UTF8, 0, src, -1, tmp, len);
	WideCharToMultiByte(CP_ACP, 0, tmp, -1, newSrc, len+2, NULL,NULL);
	return newSrc;
}
#endif

NCM文件解析

按照NCM文件结构一步一步读取数据来进行解析

//fileName:要转换的文件
void readFileData(const char* fileName)
{
	FILE* f;
	f = fopen(fileName, "rb");
	if (!f)
	{
		printf("No such file: %s\n", fileName);
		return;
	}
	
	unsigned char buf[16];
	int len=0;
	int i = 0;

	unsigned char meta_key[] = { 0x23,0x31,0x34,0x6C,0x6A,0x6B,0x5F,0x21,0x5C,0x5D,0x26,0x30,0x55,0x3C,0x27,0x28 };
	unsigned char core_key[] = { 0x68,0x7A,0x48,0x52,0x41,0x6D,0x73,0x6F,0x35,0x6B,0x49,0x6E,0x62,0x61,0x78,0x57 };
	
	fseek(f, 10, SEEK_CUR); //f从当前位置移动10个字节
	fread(buf, 1, 4, f);    //读取rc4 key 的长度

	len = (buf[3] << 8 | buf[2]) << 16 | (buf[1] << 8 | buf[0]);
	unsigned char* rc4Key= (unsigned char*)malloc(sizeof(unsigned char) * len);
	fread(rc4Key, 1, len, f);   //读取rc4数据

	//解密rc4密钥
	for (i = 0; i < len; i++)
	{
		rc4Key[i] ^= 0x64;
	}
	
	struct AES_ctx ctx;	
	AES_init_ctx(&ctx, core_key);	//使用core_key密钥
	int packSize = len / 16;	//采用的是AES-ECB加密方式,和Pkcs7padding填充
	for (i = 0; i < packSize; i++)
	{
		AES_ECB_decrypt(&ctx, &rc4Key[i * 16]);
	}
	int pad = rc4Key[len - 1];	//获取填充的长度
	rc4Key[len - pad] = '\0';	//去除填充的部分,得到RC4密钥


	fread(buf, 1, 4, f);    //读取Music Info 长度数据
	len = ((buf[3] << 8 | buf[2]) << 16) | (buf[1] << 8 | buf[0]);
	unsigned char* meta = (unsigned char*)malloc(sizeof(unsigned char) * len);
	fread(meta, 1, len, f); //读取Music Info数据
	//解析Music info信息
	for (i = 0; i < len; i++)
	{
		meta[i] ^= 0x63;
	}
	int act = 0;
	unsigned char* data = base64_decode(&meta[22], len - 22, &act);	//base64解码
	AES_init_ctx(&ctx, meta_key);	//AES解密
	packSize = act / 16;
	for (i = 0; i < packSize; i++)
	{
		AES_ECB_decrypt(&ctx, &data[i * 16]);
	}
	pad = data[act - 1];
	data[act - pad] = '\0';	//去除填充部分
	unsigned char* newData = data;
#ifdef WIN32
	
	newData = utf8ToGbk(data, strlen(data));
	
#endif
	
	cJSON* cjson = cJSON_Parse(&newData[6]);	//json解析,获取格式和名字等
	if (cjson == NULL)
	{
		printf("cjson parse failed\n");
		return;
	}
	//printf("%s\n", cJSON_Print(cjson));	//输出json



	fseek(f, 9, SEEK_CUR);  //从当前位置跳过9个字节
	fread(buf, 1, 4, f);    //读取图片大小
	len = (buf[3] << 8 | buf[2]) << 16 | (buf[1] << 8 | buf[0]);
	unsigned char* img = (unsigned char*)malloc(sizeof(unsigned char) * len);
	fread(img, 1, len, f);  //读取图片数据



	int offset= 1024 * 1024 * 10;    //10MB 音乐数据一般比较大一次读入10MB
	int total = 0;
	int reSize = offset;
	unsigned char* musicData = (unsigned char*)malloc(offset); //10m
	
	while (!feof(f))
	{
		len = fread(musicData+total, 1, offset, f);	//每次读取10M
		total += len;
		reSize += offset;
	    musicData=realloc(musicData,reSize);	//扩容
	}
	
	unsigned char sBox[256] = { 0 };	//s盒
	rc4Init(sBox, &rc4Key[17], strlen(&rc4Key[17]));	//用rC4密钥进行初始化s盒
	rc4PRGA(sBox, musicData, total);	//解密

	//拼接文件名(artist + music name+format)
	char* musicName = cJSON_GetObjectItem(cjson, "musicName")->valuestring;
	cJSON* sub = cJSON_GetObjectItem(cjson, "artist");
	char*artist=cJSON_GetArrayItem(cJSON_GetArrayItem(sub, 0),0)->valuestring;
	char* format = cJSON_GetObjectItem(cjson, "format")->valuestring;
	char* saveFileName =(char*)malloc(strlen(musicName) + strlen(artist) + strlen(format)+5);
	sprintf(saveFileName, "%s - %s.%s", artist, musicName, format);
	FILE* fo=fopen(saveFileName, "wb");
	if (fo == NULL)
	{
		printf("The fileName - '%s' is invalid in this system\n", saveFileName);
	}
	else
	{
		fwrite(musicData, 1, total, fo);
		fclose(fo);
	}
	
	
#ifdef WIN32
	free(newData);
#endif
	free(data);
	free(meta);
	free(img);
	free(musicData);
	fclose(f);
	
}
  1. AES采用的是AES-ECB模式,pack7padding填充方式。即16个字节为一组,如果不够16个字节,那就缺几个字节就填充几个字节,每个字节的值都是缺少的字节数。所以获取最后一个字节的值就知道要填充了几个字节。
  2. RC4解密那里,不是按RC4的来的,虽说叫RC4,但只有生成S盒那里是一样的,其它的不是按RC4算法来的。
  3. 有些解析出来音乐的名字,系统是不支持的,比如带’/'的,在创建新文件写入时会失败。
  4. 以"結束バンド - ギターと孤独と蒼い惑星.ncm"为例看看它的json数据是怎么样的

{
“musicId”: 1991012773,
“musicName”: “ギターと孤独と蒼い惑星”,
“artist”: [[“結束バンド”, 54103171]],
“albumId”: 153542094,
“album”: “ギターと孤独と蒼い惑星”,
“albumPicDocId”: “109951167983448236”,
“albumPic”: “https://p4.music.126.net/rfstzrVK05hCPjU-4mzSFA==/109951167983448236.jpg”,
“bitrate”: 320000,
“mp3DocId”: “f481d20151f01d5d681d2768d753ad64”,
“duration”: 229015,
“mvId”: 0,
“alias”: [“TV动画《孤独摇滚!》插曲”],
“transNames”: [],
“format”: “mp3”,
“flag”: 4
}

可以根据需要自由提取需要的信息

完整代码

点击查看代码
/*
* date:2022-12-12
* author: FL
* purpose: ncm file to mp3
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "aes.h"
#include "cJSON.h"

#ifdef WIN32
#include<Windows.h>
//返回转换好的字符串指针
unsigned char* utf8ToGbk(unsigned char*src,int len)
{
	wchar_t* tmp = (wchar_t*)malloc(sizeof(wchar_t) * len+2);
	unsigned char* newSrc = (unsigned char*)malloc(sizeof(unsigned char) * len + 2);
	
	MultiByteToWideChar(CP_UTF8, 0, src, -1, tmp, len);	//转为unicode
	WideCharToMultiByte(CP_ACP, 0, tmp, -1, newSrc, len+2, NULL,NULL); //转gbk
	
	return newSrc;
}
#endif



void swap(unsigned char* a, unsigned char* b)
{
	unsigned char t = *a;
	*a = *b;
	*b = t;
}

//用key生成S盒
/*
* s: s盒
* key: 密钥
* len: 密钥长度
*/
void rc4Init(unsigned char* s, const unsigned char* key, int len)
{
	int i = 0, j = 0;
	unsigned char T[256] = { 0 };

	for (i = 0; i < 256; i++)
	{
		s[i] = i;
		T[i] = key[i % len];
	}

	for (i = 0; i < 256; i++)
	{
		j = (j + s[i] + T[i]) % 256;
		swap(s + i, s + j);
	}
}
//针对NCM文件的解密
//异或关系
/*
* s: s盒
* data: 要加密或者解密的数据
* len: data的长度
*/
void rc4PRGA(unsigned char* s, unsigned char* data, int len)
{
	int i = 0;
	int j = 0;
	int k = 0;
	int idx = 0;
	for (idx = 0; idx < len; idx++)
	{
		i = (idx + 1) % 256;
		j = (i + s[i]) % 256;
		k = (s[i] + s[j]) % 256;
		data[idx] ^= s[k];  //异或
	}
}

//base64 解码
/*
* code: 要解码的数据
*/
unsigned char* base64_decode(unsigned char* code, int len, int* actLen)
{
	//根据base64表,以字符找到对应的十进制数据  
	int table[] = { 0,0,0,0,0,0,0,0,0,0,0,0,
			 0,0,0,0,0,0,0,0,0,0,0,0,
			 0,0,0,0,0,0,0,0,0,0,0,0,
			 0,0,0,0,0,0,0,62,0,0,0,
			 63,52,53,54,55,56,57,58,
			 59,60,61,0,0,0,0,0,0,0,0,
			 1,2,3,4,5,6,7,8,9,10,11,12,
			 13,14,15,16,17,18,19,20,21,
			 22,23,24,25,0,0,0,0,0,0,26,
			 27,28,29,30,31,32,33,34,35,
			 36,37,38,39,40,41,42,43,44,
			 45,46,47,48,49,50,51
	};
	long str_len;
	unsigned char* res;
	int i, j;

	//计算解码后的字符串长度  
	//判断编码后的字符串后是否有=
	if (strstr(code, "=="))
		str_len = len / 4 * 3 - 2;
	else if (strstr(code, "="))
		str_len = len / 4 * 3 - 1;
	else
		str_len = len / 4 * 3;

	*actLen = str_len;
	res = malloc(sizeof(unsigned char) * str_len + 1);
	res[str_len] = '\0';

	//以4个字符为一位进行解码  
	for (i = 0, j = 0; i < len - 2; j += 3, i += 4)
	{
		res[j] = ((unsigned char)table[code[i]]) << 2 | (((unsigned char)table[code[i + 1]]) >> 4); 
		res[j + 1] = (((unsigned char)table[code[i + 1]]) << 4) | (((unsigned char)table[code[i + 2]]) >> 2);  
		res[j + 2] = (((unsigned char)table[code[i + 2]]) << 6) | ((unsigned char)table[code[i + 3]]); 
	}
	return res;

}
void readFileData(const char* fileName)
{
	FILE* f;
	f = fopen(fileName, "rb");
	if (!f)
	{
		printf("No such file: %s\n", fileName);
		return;
	}
	
	unsigned char buf[16];
	int len=0;
	int i = 0;

	unsigned char meta_key[] = { 0x23,0x31,0x34,0x6C,0x6A,0x6B,0x5F,0x21,0x5C,0x5D,0x26,0x30,0x55,0x3C,0x27,0x28 };
	unsigned char core_key[] = { 0x68,0x7A,0x48,0x52,0x41,0x6D,0x73,0x6F,0x35,0x6B,0x49,0x6E,0x62,0x61,0x78,0x57 };
	
	fseek(f, 10, SEEK_CUR); //f从当前位置移动10个字节
	fread(buf, 1, 4, f);    //读取rc4 key 的长度

	len = (buf[3] << 8 | buf[2]) << 16 | (buf[1] << 8 | buf[0]);
	unsigned char* rc4Key= (unsigned char*)malloc(sizeof(unsigned char) * len);
	fread(rc4Key, 1, len, f);   //读取rc4数据

	//解密rc4密钥
	for (i = 0; i < len; i++)
	{
		rc4Key[i] ^= 0x64;
	}
	
	struct AES_ctx ctx;	
	AES_init_ctx(&ctx, core_key);	//使用core_key密钥
	int packSize = len / 16;	//采用的是AES-ECB加密方式,和Pkcs7padding填充
	for (i = 0; i < packSize; i++)
	{
		AES_ECB_decrypt(&ctx, &rc4Key[i * 16]);
	}
	int pad = rc4Key[len - 1];	//获取填充的长度
	rc4Key[len - pad] = '\0';	//去除填充的部分,得到RC4密钥


	fread(buf, 1, 4, f);    //读取Music Info 长度数据
	len = ((buf[3] << 8 | buf[2]) << 16) | (buf[1] << 8 | buf[0]);
	unsigned char* meta = (unsigned char*)malloc(sizeof(unsigned char) * len);
	fread(meta, 1, len, f); //读取Music Info数据
	//解析Music info信息
	for (i = 0; i < len; i++)
	{
		meta[i] ^= 0x63;
	}
	int act = 0;
	unsigned char* data = base64_decode(&meta[22], len - 22, &act);	//base64解码
	AES_init_ctx(&ctx, meta_key);	//AES解密
	packSize = act / 16;
	for (i = 0; i < packSize; i++)
	{
		AES_ECB_decrypt(&ctx, &data[i * 16]);
	}
	pad = data[act - 1];
	data[act - pad] = '\0';	//去除填充部分
	unsigned char* newData = data;
#ifdef WIN32
	
	newData = utf8ToGbk(data, strlen(data));
	
#endif
	
	cJSON* cjson = cJSON_Parse(&newData[6]);	//json解析,获取格式和名字等
	if (cjson == NULL)
	{
		printf("cjson parse failed\n");
		return;
	}
	//printf("%s\n", cJSON_Print(cjson));	//输出json



	fseek(f, 9, SEEK_CUR);  //从当前位置跳过9个字节
	fread(buf, 1, 4, f);    //读取图片大小
	len = (buf[3] << 8 | buf[2]) << 16 | (buf[1] << 8 | buf[0]);
	unsigned char* img = (unsigned char*)malloc(sizeof(unsigned char) * len);
	fread(img, 1, len, f);  //读取图片数据



	int offset= 1024 * 1024 * 10;    //10MB 音乐数据一般比较大一次读入10MB
	int total = 0;
	int reSize = offset;
	unsigned char* musicData = (unsigned char*)malloc(offset); //10m
	
	while (!feof(f))
	{
		len = fread(musicData+total, 1, offset, f);	//每次读取10M
		total += len;
		reSize += offset;
	    musicData=realloc(musicData,reSize);	//扩容
	}
	
	unsigned char sBox[256] = { 0 };	//s盒
	rc4Init(sBox, &rc4Key[17], strlen(&rc4Key[17]));	//用rC4密钥进行初始化s盒
	rc4PRGA(sBox, musicData, total);	//解密

	//拼接文件名(artist + music name+format)
	char* musicName = cJSON_GetObjectItem(cjson, "musicName")->valuestring;
	cJSON* sub = cJSON_GetObjectItem(cjson, "artist");
	char*artist=cJSON_GetArrayItem(cJSON_GetArrayItem(sub, 0),0)->valuestring;
	char* format = cJSON_GetObjectItem(cjson, "format")->valuestring;
	char* saveFileName =(char*)malloc(strlen(musicName) + strlen(artist) + strlen(format)+5);
	sprintf(saveFileName, "%s - %s.%s", artist, musicName, format);
	FILE* fo=fopen(saveFileName, "wb");
	if (fo == NULL)
	{
		printf("The fileName - '%s' is invalid in this system\n", saveFileName);
	}
	else
	{
		fwrite(musicData, 1, total, fo);
		fclose(fo);
	}
	
	
#ifdef WIN32
	free(newData);
#endif
	free(data);
	free(meta);
	free(img);
	free(musicData);
	fclose(f);
	
}

int main(int argc,char**argv)
{
	readFileData("結束バンド - ギターと孤独と蒼い惑星.ncm");
	return 0;
}

GitHub项目

ncmToMp3

星期五女孩

image

博客园链接

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

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

相关文章

go : 无法将“go”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

先安装go环境 https://blog.csdn.net/csl12919/article/details/128372584?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22128372584%22%2C%22source%22%3A%22csl12919%22%7Dhttps://blog.csdn.net/csl12919/article/details/1…

C案例:最小覆盖圆问题

文章目录一、提出任务 - 最小覆盖圆&#xff08;一&#xff09;描述&#xff08;二&#xff09;输入&#xff08;三&#xff09;输出&#xff08;四&#xff09;样例输入输出二、完成任务&#xff08;一&#xff09;编程思路&#xff08;二&#xff09;编写代码&#xff0c;实现…

魔百和M401A刷入Armbian系统EMMC

魔百和M401A刷入Armbian系统 准备工具 1. 电视盒子、U盘、键盘、显示器、HDMI线 2. armbian系统镜像包&#xff1a; Armbian_23.02.0_amlogic_s905l3a_bullseye_5.15.82_server_2022.12.12.img.gz 3. U盘写入工具&#xff1a; refus/usbWriter/balenaEtcher文件链接&#xff…

阻塞队列的使用

&#x1f388;专栏链接:多线程相关知识详解 目录 一.阻塞队列的介绍 二.使用阻塞队列/生产者消费者模型的好处 1.使用阻塞队列,有利于代码"解耦合" 2.削峰填谷 三.阻塞队列的使用 四.模拟实现阻塞队列 一.阻塞队列的介绍 1.线程是安全的 2.当进行入队操作的时候…

[附源码]计算机毕业设计Node.js吃天下美食网站(程序+LW)

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

【AI with ML】第 12 章 :TensorFlow Lite 简介

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

css浮动

浮动的顺序贴靠特性 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>浮动</title><style>.box{width: 250px;height: 100px;border: 1px solid #000;}.box .c1{width: 150px;height: 100p…

云上在野容器攻防战:“杀”不掉的挖矿木马

编者按 数字化浪潮蓬勃兴起&#xff0c;企业面临的安全挑战亦日益严峻。 腾讯安全近期将复盘2022年典型的攻击事件&#xff0c;帮助企业深入了解攻击手法和应对措施&#xff0c;完善自身安全防御体系。 本篇是第二期&#xff0c;讲述了国内某高端制造厂商遭遇云上在野容器攻…

将scss文件转换成css文件

大家平时做项目肯定都习惯了使用scss或者less去写样式&#xff0c;如果是使用工程化的项目我们可以借助插件很方便的将scss或者less转换成css。那如果我们没有使用工程化&#xff0c;比如简单的demo或者官网等项目又希望可以通过scss去编写文件应该怎么办呢&#xff0c;我们可以…

200 万年薪能拿多久?因 ChatGPT 爆红的「提示工程师」竟面临光速失业

【简介】ChatGPT大火后&#xff0c;“提示工程师”开始流行。然而&#xff0c;他们很可能被光速下岗&#xff1f; 最近爆发的ChatGPT真的让人上瘾。 但是&#xff0c;你只是在玩游戏&#xff0c;有些人已经在上面赚取了数百万的年薪&#xff01; 这位名叫莱利古德塞德的小弟最…

Codeforces Round #839 (Div. 3)题解

A. AB? 直接读入字符串然后把下标0和2的数字提取出来就行 // Problem: A. AB? // Contest: Codeforces - Codeforces Round #839 (Div. 3) // URL: https://codeforces.com/contest/1772/problem/A // Memory Limit: 512 MB // Time Limit: 2000 ms // // Powered by CP E…

还在堆人力处理工单?找准耗时源头才是关键!

对于提供企业级服务的公司来说&#xff0c;服务质量与效率日益受到关注。服务质量的本质是整体团队的效能&#xff0c;重中之重则是站在客户视角的工单解决效率。 当下很多这个领域的企业都会设立客户成功中心&#xff0c;其中就有专门对接客户工单处理的职责&#xff1b;而随…

Lifelong Embedding Learning and Transfer for Growing Knowledge Graphs

摘要 现有的知识图谱(KG)嵌入模型主要关注静态KG,但真实世界的KG并不是静态的,而是随着KG应用程序的发展而发展和增长。因此,新的事实和以前看不到的实体和关系不断出现,需要一个嵌入模型,可以通过增长快速学习和转移新知识。基于此,本文研究了KG嵌入的一个扩展领域,即…

96.第十九章 MySQL数据库 -- 多表查询(六)

3.7.2 多表查询 多表查询,即查询结果来自于多张表 子查询:在SQL语句嵌套着查询语句,性能较差,基于某语句的查询结果再次进行的查询 联合查询:UNION,表和表的纵向合并 交叉连接:笛卡尔乘积 内连接: 等值连接:让表之间的字段以“等值”建立连接关系 不等值连接 自然连接…

python数据清洗的三个常用的处理方式!

关于python数据处理过程中三个主要的数据清洗说明&#xff0c;分别是缺失值/空格/重复值的数据清洗。 这里还是使用pandas来获取excel或者csv的数据源来进行数据处理。若是没有pandas的非标准库需要使用pip的方式安装一下。 pip install pandas准备一下需要处理的脏数据&…

【愚公系列】2022年12月 .NET CORE工具案例-PLG轻量级日志可视化服务

文章目录前言1.Serilog简介2.Grafana简介3.Loki是什么一、Serilog对接Grafana轻量级日志可视化服务1.Grafana部署2.Loki部署3.promtail部署4.测试.NET Core写入日志效果5.测试查询日志总结前言 日志功能是几乎所有程序或系统都必备的一个功能。该文章通过使用LokiGrafana来实现…

算法题:N个元素之和

做题思路&#xff1a; 1&#xff09;首先对数组进行排序 2&#xff09;创建一个for循环&#xff1a; 第一个元素指向for循环 3&#xff09;然后创建一个while循环&#xff1b;第二个元素指向for循环的下一个元素&#xff0c;第三个元素指向最后一个元素 4&#xff09;如果三个元…

Java基础之《netty(15)—HTTP服务》

一、使用netty开发一个简单的http服务 1、netty服务器在6668端口监听&#xff0c;浏览器发出请求http://localhost:6668/ 在写netty的http server的例子过程中&#xff0c;发现浏览器使用端口号6668一直无法连接&#xff0c;报错ERR_UNSAFE_PORT。改成7000就可以了。 2、服务器…

2018年高职组——信息评估与管理赛题(解析)

这篇文章为2018年赛题第一阶段DCRS解析 都是自己的想法(仅供参考)不对请指正评论 先来张拓扑养养眼: 2018年拓扑 接下来是IP地址规划表: IP地址的配置就不用我再多赘述了吧,接下来是DCRS的题目 23、DCRS 为接入交换机,为终端产生防止 MAC 地址防洪攻击,请配置端口安全,…

【嵌入式Linux】开发环境搭建

一、概述 在进行某一个芯片平台开发前&#xff0c;一般都需要在电脑上安装一系列软件&#xff0c;然后在这些软件上阅读、编写、编译和调试在该平台上运行的代码&#xff0c;最后将编写好的代码通过某种方式烧录到该芯片的对应地址运行。在电脑上安装的这一系列软件的过程&…