安装包分析3

在这里插入图片描述
接上文,在主函数我们看到下载的函数InstallFunc,在这个下载的函数中,根据指引我们可以看见
下载所需要的函数
也就是
在这里插入图片描述这段函数是一个安装程序的主要功能函数。它的作用是从文件中读取数据,并根据这些数据执行安装相关的操作。以下是该函数的逻辑解释:

  1. 获取模块文件名和大小
    首先获取当前执行的模块(可执行文件)的文件名,并计算文件的大小。

  2. 获取资源缓冲区
    通过调用NsResGetBuff函数获取资源缓冲区的信息。如果未能获取到资源缓冲区,则将安装程序的数据区清零,并返回。

  3. 打开文件并读取数据
    打开当前模块的文件流,并将文件流的指针移动到资源偏移量处,然后从文件流中读取数据,填充安装程序的数据区。

  4. 初始化路径和报告初始化安装程序的路径,并向指定的 URL 发送安装报告。

  5. 检查有效性和安装组件
    检查安装的有效性,并安装相关组件。

  6. 检查目录和提取文件
    检查目录,然后从文件中提取指定的文件。

  7. 根据条件提取文件和执行操作

    • 如果存在指定的资源缓冲区,则循环读取文件数据并提取文件,然后执行一些后续操作,如删除临时文件、执行脚本等。
    • 如果提取失败或其他条件满足,则根据情况返回不同的结果,如安装成功或失败的标志。
  8. 处理异常情况
    如果出现异常情况,如文件操作失败或没有写权限等,则根据情况返回不同的错误码,并进行相应的处理,如显示错误消息、退出程序等。

总的来说,这个函数负责执行安装过程中的一系列操作,包括读取文件数据、提取文件、执行脚本等,并根据执行结果返回相应的结果码。

这里面最重要的是EtractFile函数

char __thiscall CNsInstaller::ExtractFile(CNsInstaller *this, wchar_t *a2, struct _iobuf *a3)
{const wchar_t *v3; // eaxconst WCHAR *v4; // eaxint v5; // esiint v6; // esiCNsProcess *v7; // eaxCNsHook *v8; // eaxconst wchar_t *v9; // eaxconst WCHAR *v11; // eaxconst wchar_t *v12; // [esp-4h] [ebp-27Ch]const wchar_t *v13; // [esp-4h] [ebp-27Ch]int v14; // [esp+14h] [ebp-264h] BYREFint v15; // [esp+18h] [ebp-260h] BYREFvoid *v16; // [esp+1Ch] [ebp-25Ch]void *v17; // [esp+20h] [ebp-258h]void *Src; // [esp+24h] [ebp-254h]CNsInstaller *v19; // [esp+28h] [ebp-250h]int v20; // [esp+2Ch] [ebp-24Ch] BYREFchar v21[4]; // [esp+30h] [ebp-248h] BYREFWPARAM wParam; // [esp+34h] [ebp-244h]void *v23; // [esp+38h] [ebp-240h]int i; // [esp+3Ch] [ebp-23Ch]int Buffer[2]; // [esp+40h] [ebp-238h] BYREFvoid *v26; // [esp+48h] [ebp-230h]FILE *Stream; // [esp+4Ch] [ebp-22Ch]char v28; // [esp+51h] [ebp-227h]char v29; // [esp+53h] [ebp-225h]int v30; // [esp+54h] [ebp-224h] BYREFCNsInstaller *v31; // [esp+58h] [ebp-220h]int v32; // [esp+5Ch] [ebp-21Ch] BYREFWCHAR String1[260]; // [esp+60h] [ebp-218h] BYREFint v34; // [esp+274h] [ebp-4h]v31 = this;CNsInstaller::CheckDir(this, a2, 0);sub_F397C0(&v30);v34 = 0;sub_F39D70((int)&v30, (wchar_t *)L"%s\\%s", *((_DWORD *)v31 + 1452));v3 = (const wchar_t *)Json::StaticString::c_str((Json::StaticString *)&v30);Stream = _wfopen(v3, L"wb");if ( !Stream ){v4 = (const WCHAR *)Json::StaticString::c_str((Json::StaticString *)&v30);if ( !PathFileExistsW(v4) ){CNsInstaller::MovePos(v31, (struct tagPacketInfo *)a2, a3);v34 = -1;sub_F39680(&v30);return 0;}sub_F3D410(&v30);v5 = sub_F3ED80((wchar_t *)L".exe", 0);if ( v5 == sub_F397F0(&v30) - 4 ){v6 = sub_F397F0(&v30);Src = (void *)(v6 - sub_F46640(92) - 1);sub_F41EB0((int)&v20, Src);LOBYTE(v34) = 1;v12 = (const wchar_t *)Json::StaticString::c_str((Json::StaticString *)&v20);v7 = CNsProcess::Instance();CNsProcess::KillProcess(v7, v12);LOBYTE(v34) = 0;sub_F39680(&v20);}else{v13 = (const wchar_t *)Json::StaticString::c_str((Json::StaticString *)&v30);v8 = CNsHook::Instance();CNsHook::CloseUsedProc(v8, v13);}v9 = (const wchar_t *)Json::StaticString::c_str((Json::StaticString *)&v30);Stream = _wfopen(v9, L"wb");if ( !Stream ){CNsInstaller::MovePos(v31, (struct tagPacketInfo *)a2, a3);v29 = 1;v34 = -1;sub_F39680(&v30);return v29;}}sub_F397C0(v21);LOBYTE(v34) = 2;sub_F395C0(a2);if ( !sub_F397F0((char *)v31 + 5612) && sub_F3ED80((wchar_t *)L"\\", 0) < 0 ){v32 = 1;v11 = (const WCHAR *)Json::StaticString::c_str((Json::StaticString *)&v30);lstrcpyW(String1, v11);sub_F4F5D0(&v32);}for ( i = 0; i < *((_DWORD *)a2 + 100); ++i ){memset(Buffer, 0, sizeof(Buffer));fread(Buffer, 8u, 1u, a3);v17 = (void *)unknown_libname_48(Buffer[0]);v26 = v17;_NsReadFile(a3, v17, Buffer[0]);v16 = (void *)unknown_libname_48(Buffer[1]);v23 = v16;v14 = Buffer[1];v15 = Buffer[0] - 5;sub_FA8A50(v16, &v14, (char *)v26 + 5, &v15, v26, 5);_NsWriteFile(Stream, v23, Buffer[1]);j_j_j___free_base(v26);j_j_j___free_base(v23);v19 = v31;if ( *((__int64 *)v31 + 2) > 0 ){*((_QWORD *)v31 + 3) += 8i64;*((_QWORD *)v31 + 3) += Buffer[0];wParam = 10000i64 * *((_QWORD *)v31 + 3) / *((_QWORD *)v31 + 2);if ( (int)wParam >= 10000 )wParam = 9900;PostMessageW(*(HWND *)v31, 0x7E9u, wParam, *((_DWORD *)v31 + 8));}}fclose(Stream);v28 = 1;LOBYTE(v34) = 0;sub_F39680(v21);v34 = -1;sub_F39680(&v30);return v28;
}

这段代码是 CNsInstaller::ExtractFile 函数的实现,其功能是从输入流 a3 中提取文件,并将其写入到指定的文件流 Stream 中。

函数的主要逻辑如下:

  1. 首先调用 CNsInstaller::CheckDir 检查目录,然后初始化一些变量。

  2. 调用 PathFileExistsW 检查文件是否存在,如果文件不存在,则调用 CNsInstaller::MovePos 移动文件指针并返回失败。

  3. 如果文件存在,则尝试打开文件流,并写入数据。如果打开文件失败,则再次调用 CNsInstaller::MovePos 移动文件指针并返回失败。

  4. 调用 sub_F395C0 函数输出错误消息,并进行一些其他的异常处理。

  5. 循环读取文件数据,每次读取 8 字节数据,然后将数据写入到指定文件流中。

  6. 如果读取到的文件数据不为空,则更新文件指针位置,并通过 PostMessageW 发送消息更新进度。

  7. 当读取完所有文件数据后,关闭文件流,返回成功。

在这里插入图片描述
其中还有个函数计算偏移位置的大小

在这里插入图片描述

函数的主要逻辑如下:

  1. 首先初始化一个包含 3 个整数的数组 Offset,并将当前对象指针存储在数组的第三个元素中。

  2. 使用循环迭代结构体 tagPacketInfo 的 100 个整数成员(假设为 _DWORD 类型),依次进行以下操作:

    a. 使用 memset 函数将数组 Offset 中的前 8 字节清零。

    b. 使用 fread 函数从文件流中读取 8 字节数据到数组 Offset 中。

    c. 使用 fseek 函数将文件指针从当前位置向前移动 Offset[0] 字节。
    具体来说,它用于在文件流中按照一系列预定义的偏移量依次移动文件指针的位置。这个函数在文件流处理的过程中使用,用于定位到特定数据或者跳过特定的数据段

根据上面的代码逻辑

代码:

import os
import struct
import lzma
import hashlibDEBUG = False
BASE_ADDRESS = 0x00120200class Base:def __init__(self):self.startFilePos = 0self.data = bytearray(0x15C8)class SingleFileData:def __init__(self):self.fileInt = [0, 0]self._dataSize = 0self.fileData = bytearray()self.nextSingleFileData = Noneclass SingleFile:def __init__(self):self.startFilePos = 0self.data = bytearray(0x194)self._times = 0self._isFolder = Falseself._fileSize = 0self.firstFileData = Nonedef read_base(file):file.seek(BASE_ADDRESS)base = Base()base.startFilePos = file.tell()base.data = bytearray(file.read(0x15C8))return basedef read_next_file(file, need_data):single_file = SingleFile()single_file.startFilePos = file.tell()single_file.data = bytearray(file.read(0x194))single_file._isFolder = (single_file.data[200] == -1)single_file._times = single_file.data[0x190]first_file_data = Nonefor i in range(single_file._times):file_data = SingleFileData()file_data.fileInt = struct.unpack('<2I', file.read(8))single_file._fileSize += file_data.fileInt[0]if not single_file._isFolder:if not DEBUG:file_data.fileData = bytearray(file.read(file_data.fileInt[0]))else:file.seek(file_data.fileInt[0], os.SEEK_CUR)if first_file_data is None:single_file.firstFileData = file_datafirst_file_data = file_dataelse:first_file_data.nextSingleFileData = file_datafirst_file_data = file_datareturn single_fileimport redef extract_file(f, output_folder):filename = re.sub(r'[^\w\-_. ]', '', f.data.decode("utf-16le").replace("\x00", ""))path = os.path.join(output_folder, filename)os.makedirs(os.path.dirname(path), exist_ok=True)with open(path, "wb") as file_handle:file_data = f.firstFileDatawhile file_data is not None:if file_data.fileData is not None:file_handle.write(file_data.fileData)file_data = file_data.nextSingleFileDatareturn pathdef calculate_md5(file_path):hasher = hashlib.md5()with open(file_path, "rb") as file:for chunk in iter(lambda: file.read(4096), b""):hasher.update(chunk)return hasher.hexdigest()def main():output_folder = "F:\The couers of He predecessor\The fourth lesson\data"  with open("F:/The couers of He predecessor/The fourth lesson/MeiqiaWinLatest.exe", "rb") as f:base = read_base(f)print(f"baseStartPos: {base.startFilePos:0x}")while True:file = read_next_file(f, not DEBUG)if file._fileSize <= 0:breakextracted_file_path = ""if not DEBUG:extracted_file_path = extract_file(file, output_folder)md5 = ""if extracted_file_path:md5 = calculate_md5(extracted_file_path)print(f"fileStartPos: {file.startFilePos:0x}\t\tisFolder: {file._isFolder}")print(f"fileName: {file.data.decode('utf-16le')}\t\tfileZipSize: 0x{file._fileSize:0x}\n")print(f"MD5: {md5}\n")if __name__ == "__main__":main()

这个extract_file函数(ExtractFile)用于提取单个文件并将其保存到指定的输出文件夹中

获取文件名:从参数 f 中获取文件名,并在给定的输出文件夹路径 output_folder 中构建文件的完整路径。创建文件夹:如果文件所在的文件夹不存在,则创建文件夹以保存提取的文件。打开文件:使用二进制写入模式以追加数据的方式打开文件,如果文件不存在,则创建新文件。提取文件数据:遍历文件的每个数据节点,如果数据节点中包含文件数据,则将文件数据写入到已打开的文件中。返回文件路径:返回提取的文件的完整路径
  1. 基地址数据 (Base)

    • 包含在安装包的指定位置 (BASE_ADDRESS)。
    • 数据长度为 0x15C8 字节。
  2. 单个文件数据 (SingleFile)

    • 每个单个文件的信息存储在一块 0x194 字节大小的数据块中。
    • 文件信息包括文件名、文件大小、是否是文件夹等。
    • 如果是文件夹,则还会存储其包含的子文件数量。
    • 如果不是文件夹,则会存储每个子文件的大小和其他属性。
  3. 文件数据 (SingleFileData)

    • 每个文件数据节点存储在单个文件数据 (SingleFile) 对象中。
    • 用于存储文件的实际数据。
    • 文件数据以字节流的形式存储。
    • 如果单个文件包含多个数据块,则会使用链表连接这些数据块。
import os
import struct
import lzma
import hashlibDEBUG = False
BASE_ADDRESS = 0x00120200class Base:def __init__(self):self.startFilePos = 0self.data = bytearray(0x15C8)class SingleFileData:def __init__(self):self.fileInt = [0, 0]self._dataSize = 0self.fileData = bytearray()self.nextSingleFileData = Noneclass SingleFile:def __init__(self):self.startFilePos = 0self.data = bytearray(0x194)self._times = 0self._isFolder = Falseself._fileSize = 0self.firstFileData = Nonedef read_base(file):file.seek(BASE_ADDRESS)base = Base()base.startFilePos = file.tell()base.data = bytearray(file.read(0x15C8))return basedef read_next_file(file, need_data):single_file = SingleFile()single_file.startFilePos = file.tell()single_file.data = bytearray(file.read(0x194))single_file._isFolder = (single_file.data[200] == -1)single_file._times = single_file.data[0x190]first_file_data = Nonefor i in range(single_file._times):file_data = SingleFileData()file_data.fileInt = struct.unpack('<2I', file.read(8))single_file._fileSize += file_data.fileInt[0]if not single_file._isFolder:if not DEBUG:file_data.fileData = bytearray(file.read(file_data.fileInt[0]))else:file.seek(file_data.fileInt[0], os.SEEK_CUR)if first_file_data is None:single_file.firstFileData = file_datafirst_file_data = file_dataelse:first_file_data.nextSingleFileData = file_datafirst_file_data = file_datareturn single_fileimport redef extract_file(f, output_folder):filename = re.sub(r'[^\w\-_. ]', '', f.data.decode("utf-16le").replace("\x00", ""))path = os.path.join(output_folder, filename)os.makedirs(os.path.dirname(path), exist_ok=True)with open(path, "wb") as file_handle:file_data = f.firstFileDatawhile file_data is not None:if file_data.fileData is not None:file_handle.write(file_data.fileData)file_data = file_data.nextSingleFileDatareturn pathdef calculate_md5(file_path):hasher = hashlib.md5()with open(file_path, "rb") as file:for chunk in iter(lambda: file.read(4096), b""):hasher.update(chunk)return hasher.hexdigest()def main():output_folder = "F:\The couers of He predecessor\The fourth lesson\data"  with open("F:/The couers of He predecessor/The fourth lesson/MeiqiaWinLatest.exe", "rb") as f:base = read_base(f)print(f"baseStartPos: {base.startFilePos:0x}")while True:file = read_next_file(f, not DEBUG)if file._fileSize <= 0:breakextracted_file_path = ""if not DEBUG:extracted_file_path = extract_file(file, output_folder)md5 = ""if extracted_file_path:md5 = calculate_md5(extracted_file_path)print(f"fileStartPos: {file.startFilePos:0x}\t\tisFolder: {file._isFolder}")print(f"fileName: {file.data.decode('utf-16le')}\t\tfileZipSize: 0x{file._fileSize:0x}\n")print(f"MD5: {md5}\n")if __name__ == "__main__":main()

提取出来
在这里插入图片描述在这里插入图片描述

特别不过代码中没有用到解压的函数,意思是数据还是压缩的形式,MD5没对上
在这里插入图片描述看看同学的

// main.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <Windows.h>
#pragma comment(lib, "7zra.lib")
#pragma comment(lib, "zlibstat.lib")
#include "LzmaLib.h"
#include "pathcch.h"
#pragma comment(lib, "pathcch.lib")
//#pragma comment(lib, "zlibwapi.lib")
#define BYTE unsigned char
#include <iostream>
#define BASE_ADDRESS 0x00120200
bool debug = false;
struct Base
{long startFilePos;BYTE data[0x15C8];
};
struct SingleFileData {unsigned int fileInt[2];size_t _dataSize;BYTE* fileData;struct SingleFileData* nextSingleFileData;
};
struct SingleFile
{long startFilePos;BYTE data[0x194]; // first:name [0x190]:times [200]:folder?unsigned int _times; //DWORDbool _isFolder;size_t _fileSize;SingleFileData* firstFileData;
};
SingleFileData* callocSingleFileData() {SingleFileData* p = (SingleFileData*)malloc(sizeof(SingleFileData));memset(p, 0, sizeof(SingleFileData));return p;
}
void appendSingleFileData(SingleFile* file, SingleFileData* fileData) {auto pre = file->firstFileData;if (pre == NULL){file->firstFileData = fileData;return;}while (pre->nextSingleFileData) {pre = pre->nextSingleFileData;}pre->nextSingleFileData = fileData;
}
Base* readBase(FILE* f) {fseek(f, BASE_ADDRESS, SEEK_SET);Base* base = (Base*)malloc(sizeof(Base));base->startFilePos = ftell(f);memset(base->data, 0, sizeof(base->data));fread_s(base->data, sizeof(base->data), 1, sizeof(base->data), f);return base;
}
SingleFile* readNextFile(FILE* f, bool needData) {SingleFile* singleFile = (SingleFile*)malloc(sizeof(SingleFile));memset(singleFile, 0, sizeof(SingleFile));//singleFile->firstFileData = NULL;singleFile->startFilePos = ftell(f);//memset(singleFile->data, 0, sizeof(singleFile->data));fread_s(singleFile->data, sizeof(singleFile->data), 1, sizeof(singleFile->data), f);singleFile->_isFolder = (singleFile->data[200] == -1);singleFile->_times = (unsigned int)(singleFile->data[0x190]);//int debugI = 0;for (size_t i = 0; i < singleFile->_times; i++){// read 8 bytesauto fileData = callocSingleFileData();fread_s(fileData->fileInt, sizeof(fileData->fileInt), 8, 1, f);singleFile->_fileSize = singleFile->_fileSize + fileData->fileInt[0];//if (!lstrcmpW((wchar_t*)singleFile->data, L"icudtl.dat"))//{//	debugI++;//	if (debugI == 4)//	{//		int a = 0;//	}//	// 前三次是正确的。//	// 第四次少了。(第四次有问题!)//	// 第五次没少。//	// 第六次没少。//}fileData->_dataSize = fileData->fileInt[0];appendSingleFileData(singleFile, fileData);if (!singleFile->_isFolder){if (!debug){fileData->fileData = (BYTE*)malloc(fileData->_dataSize);fread_s(fileData->fileData, fileData->_dataSize, 1, fileData->_dataSize, f);}else {printf_s("fileDataStart: 0x%x\n", ftell(f));fseek(f, fileData->_dataSize, SEEK_CUR);}}else {}}return singleFile;
}
int lzmaTest() {FILE* f;fopen_s(&f, "1.lzma", "rb");//get sizefseek(f, 0, SEEK_END);long _fileSize = ftell(f);unsigned char* buff = (unsigned char*)malloc(_fileSize);// 重置文件指针位置到文件开头rewind(f);size_t flen = fread_s(buff, _fileSize, 1, _fileSize, f); // 读入整个文件size_t buff5len = flen - 5;size_t outBufLen = 0x399999;unsigned char* outBuf = (unsigned char*)malloc(outBufLen);LzmaUncompress(outBuf, &outBufLen, buff + 5, &buff5len, buff, 5);FILE* fout;fopen_s(&fout, "2.out", "wb");fwrite(outBuf, 1, outBufLen, fout);return 0;
}
void extractFile(SingleFile* f) {wchar_t path[MAX_PATH] = {0};wcscat(path, L"data/");wcscat(path, (wchar_t*)f->data);WCHAR folderPath[MAX_PATH];wcscpy_s(folderPath, MAX_PATH, path);PathCchRemoveFileSpec(folderPath,MAX_PATH);CreateDirectory(folderPath, NULL);HANDLE hFile = CreateFileW(path, FILE_APPEND_DATA, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);DWORD dwBytesWritten;if (hFile == INVALID_HANDLE_VALUE) {printf("Error creating/opening file. Error code: %d\n", GetLastError());return;}// 移动文件指针到文件末尾SetFilePointer(hFile, 0, NULL, FILE_END);auto p = f->firstFileData;size_t fileDataBufLen = p->_dataSize;size_t fileDataBufLenMinus5 = fileDataBufLen - 5;/*if (f->_times > 1){printf("f->_times>1\n");}*/size_t outBufLen = 0;unsigned char* outBuf;//int debugI = 0;for (size_t i = 0; i < f->_times; i++){fileDataBufLen = p->_dataSize;fileDataBufLenMinus5 = fileDataBufLen - 5;outBufLen = p->fileInt[1];outBuf = (unsigned char*)malloc(outBufLen);if (p->fileData == NULL){continue;}//if (!lstrcmpW((wchar_t*)f->data,L"icudtl.dat"))//{//	debugI++;//	if (debugI == 4)//	{//		int a = 0;//	}//	// 前三次是正确的。//	// 第四次少了。(第四次有问题!)//	// 第五次没少。//	// 第六次没少。//}LzmaUncompress(outBuf, &outBufLen, p->fileData + 5, &fileDataBufLenMinus5, p->fileData, 5);/*if (!lstrcmpW((wchar_t*)f->data, L"icudtl.dat")){if (debugI == 4){int a = 0;}}*/// 写入数据到文件if (!WriteFile(hFile, outBuf, outBufLen, &dwBytesWritten, NULL)) {printf("Error writing to file. Error code: %d\n", GetLastError());CloseHandle(hFile); // 关闭文件句柄outBufLen = 0;free(outBuf);return;}outBufLen = 0;free(outBuf);p = p->nextSingleFileData;}printf("Data extract to file successfully.\n");CloseHandle(hFile);}
int main()
{//return lzmaTest();FILE* f1,*f;fopen_s(&f, "MeiqiaWinLatest.exe.data", "rb");if (f == NULL) return 0;Base* base = readBase(f);printf_s("baseStartPos: 0x%x\n", base->startFilePos);while (!feof(f)){SingleFile* file = readNextFile(f, !debug);if (file->_fileSize <= 0){break;}if (!debug){extractFile(file);}else {}printf_s("fileStartPos: 0x%x\t\tisFolder: %d\n", file->startFilePos, file->_isFolder);printf_s("fileName: %ws\t\tfileZipSize: 0x%x\n", (wchar_t*)file->data, file->_fileSize);printf_s("\n");}fclose(f);return 0;
}

在这里插入图片描述

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

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

相关文章

【MySQL】C# 连接MySQL

C# 连接MySQL 1. 添加MySQL引用 安装完MySQL之后&#xff0c;在安装的默认目录 C:\Program Files (x86)\MySQL\Connector NET 8.0 中查找MySQLData.dll文件。 在Visual Studio 中为项目中添加引用。 2. 引入命名空间 using MySql.Data.MySqlClient;3. 构建连接 private …

AI服务平台replicate

Replicate是一个提供优秀AI模型和工具的平台&#xff0c;旨在帮助用户实现各种人工智能任务。该平台汇集了来自各个领域的顶尖模型&#xff0c;涵盖了文本到图像生成、语言模型、图像编辑、超分辨率等多个领域。用户可以通过Replicate平台快速获取和应用先进的模型&#xff0c;…

设计模式学习笔记 - 设计模式与范式 -行为型:8.状态模式:游戏、工作流引擎中常用的状态机是如何实现的?

概述 本章学习状态模式。在实际的开发中&#xff0c;状态模式并不是很常用&#xff0c;但是在能够用到的场景里&#xff0c;它可以发挥很大的作用。从这一点上看&#xff0c;它有点像我们之前讲到的组合模式。 状态模式一般用来实现状态机&#xff0c;而状态机常用在游戏、工…

机器学习模型——GBDT和Xgboost

GBDT基本概念&#xff1a; GBDT&#xff08;Gradient Boosting Decision Tree&#xff0c;简称GBDT&#xff09;梯度提升决策树&#xff0c;是Gradient Boost 框架下使用较多的一种模型&#xff0c;且在GBDT中&#xff0c;其基学习器是分类回归树也就是CART&#xff0c;且使用…

【LeetCode: 2529. 正整数和负整数的最大计数 + 模拟 + 计数】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【c 语言】结构体的定义格式及变量初始化

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&…

【计算机考研】408算法大题怎么练?

先说结论&#xff1a;基础阶段学好各个数据结构与&#xff0c;重点是数组、链表、树、图。然后强化阶段突破算法提 在基础阶段&#xff0c;并不需要过于专门地练习算法。相反&#xff0c;基础阶段的重点应该放在对各种数据结构原理的深入理解上。在我个人的经验中&#xff0c;…

网络协议——VRRP(虚拟路由冗余协议)原理与配置

1. VRRP概述 单网关出现故障后下联业务中断&#xff0c;配置两个及以上的网关时由于IP地址冲突&#xff0c;导致通讯时断时续甚至通信中断。VRRP组播类的网络层协议 2. 协议版本 VRRP v2: 支持认证,仅适用于IPv4网络 VRRP v3: 不支持认证&#xff0c; 适用于IPv4和IPv6两种网…

数据结构—图

图的基本概念 图就是由顶点的有穷非空集合和顶点之间的边组成的集合。通常表示为&#xff1a;G(V,E)&#xff0c;其中&#xff0c;G 表示一个图&#xff0c;V 表示顶点的集合&#xff0c;E 表示边的集合。 顶点 图中的数据元素&#xff0c;我们称之为顶点&#xff0c;图至少有…

Redis 八种常用数据类型常用命令和应用场景

5 种基础数据类型&#xff1a;String&#xff08;字符串&#xff09;、List&#xff08;列表&#xff09;、Set&#xff08;集合&#xff09;、Hash&#xff08;散列&#xff09;、Zset&#xff08;有序集合&#xff09;。 3 种特殊数据类型&#xff1a;HyperLogLog&#xff0…

C语言自定义类型:联合与枚举的奇幻之旅

** 前言 ** 在C语言的世界中&#xff0c;数据类型犹如魔术师手中的魔法道具&#xff0c;各有其神奇之处。今天&#xff0c;我们就来揭开其中两种自定义类型——联合&#xff08;union&#xff09;和枚举&#xff08;enum&#xff09;的神秘面纱&#xff0c;带你一起探索它们背…

《荒野大镖客》游戏提示emp.dll文件丢失如何解决?

emp.dll它作为一种动态链接库&#xff08;DLL&#xff09;文件&#xff0c;在Windows操作系统中扮演着重要角色。当打开一个程序时&#xff0c;操作系统会将程序的代码和数据加载到内存中&#xff0c;并创建一个进程来运行该程序。在这个过程中&#xff0c;emp.dll负责将这些代…

Hot100【十一】:合并区间

// 先排个序 // 这里巧用链表&#xff0c;可以快速的获取到last&#xff0c;通过last数组的第二个元素和当前数组的第一个元素对比&#xff0c;如果当前数组的第一个元素<last数组的第二个元素, 就需要合并 class Solution { public int[][] merge(int[][] intervals) { // …

实现几何对象按照一定距离向外缓冲

1、首先&#xff0c;确保你已经引入了Turf.js库。你可以通过在HTML文件中添加以下代码来引入 <script src"https://cdn.jsdelivr.net/npm/turf/turf6.5.0/turf.min.js"></script>2、使用turf.buffer实现几何对象按照设定距离扩充 let originalCoordinat…

Linux系统安装内网穿透实现固定公网地址访问本地MinIO服务

文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. 远程调用MinIO服务小结5. 固定连接TCP公网地址6. 固定地址连接测试 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&am…

2024/4/1—力扣—主要元素

代码实现&#xff1a; 思路&#xff1a;摩尔投票算法 int majorityElement(int *nums, int numsSize) {int candidate -1;int count 0;for (int i 0; i < numsSize; i) {if (count 0) {candidate nums[i];}if (nums[i] candidate) {count;} else {count--;}}count 0;…

【资源分享】这个网站我愿称之为年度学术最伟大的发现

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…

嵌入式学习51-单片机4

知识零碎&#xff1a; nop空指令 CRC校验 为了保证51单片与温度传感18b20 之间的高电平 采用一个上拉电阻改变电平的高低 温度寄存器原理

【Spring AOP】@Aspect结合案例详解(一): @Pointcut使用@annotation + 五种通知Advice注解(已附源码)

文章目录 前言AOP与Spring AOPAspect简单案例快速入门 一、Pointcutannotation 二、五种通知Advice1. Before前置通知2. After后置通知3. AfterRunning返回通知4. AfterThrowing异常通知5. Around环绕通知 总结 前言 在微服务流行的当下&#xff0c;在使用SpringCloud/Springb…

Vue和FastAPI实现前后端分离

前言 近期接触了一些开源大模型应用服务&#xff0c;发现很多用的都是FastAPI web框架&#xff0c;于是乎研究了一下它的优势&#xff0c;印象最深有两个&#xff1a;一个是它的异步处理性能比较好&#xff0c;二是它可以类似java swagger的API交互文档&#xff0c;这个对应前…