92.网络游戏逆向分析与漏洞攻防-游戏技能系统分析-利用哈希表实现快速读取文本内容

news2025/1/17 5:58:53

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

如果看不懂、不知道现在做的什么,那就跟着做完看效果,代码看不懂是正常的,只要会抄就行,抄着抄着就能懂了

内容参考于:易道云信息技术研究院

上一个内容:91.加载游戏语言文件到内存

码云版本号:aafa72010a0c9ffb42274c1c2ff3a61e627eb49f

代码下载地址,在 titan 目录下,文件名为:titan-利用哈希表实现快速读取文本内容.zip

链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg

提取码:q9n5

--来自百度网盘超级会员V4的分享

HOOK引擎,文件名为:黑兔sdk升级版.zip

链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw

提取码:78h8

--来自百度网盘超级会员V4的分享

以 91.加载游戏语言文件到内存 它的代码为基础进行修改

现在已经把游戏里的语言文件写到了本次磁盘里,并且把这个文件加载到了我们程序的内存中

找有冲突的中文

下图红框里是 textDatas 变量的地址,也就是从磁盘文件中加载的语言包的地址

然后打开x96dbg,然后附加到游戏

鼠标单击下图红框位置,也就是x96dbg的内存窗口位置

然后ctrl+g,然后输入,textDatas 变量的地址

如下图,在7CCFF27C位置鼠标右击选择在内存窗口中转到知道DWORD

然后就来到了语言包的内存区域,现在还没有赋值所以全是0

然后回到游戏点击确定,如下图红框

点击完确定就会有值了

这个原因是,弹框的代码是在解析语言包之前

然后第一个不是-1,它就是存在哈希冲突

然后找它的链表,上图是链表第一个数据,通过下图得出的589A8740是链表的第二个数据,现在要找链表的最后一个数据,找最后一个数据的愿意是为了测试我们通过磁盘文件加载的语言包是否可以用,然后DAC*30,这个30是十六进制的,30的十进制是48,这个48是 TextTable 结构的大小

TextTable 结构的大小也就是下图红框位置

然后鼠标单击x96dbg的内存窗口,然后按ctrl+g,然后输入地址,然后点确定转到

然后发现它还不是-1,所以它不是最后一个数据

继续找

看到它还不是-1

继续

然后就找到-1了

它的中文是,水系咏唱法术

0x58D6F9D0位置字符串的效果图

然后发现个事情0x7CCFF27C这个位置的值是0x5897B020,但是x96dbg跳过去之后不是了,如下图,是刚开始的地方,x96dbg给我们跳到了0x5897B050位置了,但是找哈希冲突的值也还是上方那样的找发,图都截完了才发现x96dbg给跳错了

TextManger.cpp文件的修改:修改了 LoadTextData函数、ReadTextById函数

#include "pch.h"
#include "TextManger.h"

unsigned TextManger::ReadTextProc = 0x10295FB0;
const wchar_t TextManger::NullText[2]{};

bool TextManger::CreateTextDat(const char* _filename)
{
	if (!textTable) {
		return false;
	}
	std::ofstream out(_filename, std::ios::out|std::ios::binary);

	if (out.bad())return false;
	out.write((char*)&hashCount, sizeof(hashCount));
	for (int i = 0; i < hashCount; i++) {
		// 游戏中的中文表结构是 中文名英文id 这样的
		int lenId = strlen(textTable[i]->TxtId) + 1;
		// 宽字节一个字是2字节,wcslen函数返回值是字的个数
		int lenTxt = wcslen(textTable[i]->Txt) + 1;
		lenTxt = lenTxt * 2;
		out.write(textTable[i]->TxtId, lenId);
		out.write((char*)textTable[i]->Txt, lenTxt);
	}
	out.close();
	return true;
}

bool TextManger::LoadTextData(const char* _filename)
{
	CString txt;
	if (textDatas)return false;
	std::ifstream file(_filename, std::ios::in | std::ios::binary|std::ios::ate);

	if(file.bad()) {
		return false;
	}
	unsigned buffSize = file.tellg();
	TextBuff = new char[buffSize];
	file.seekg(std::ios::beg);
	file.read(TextBuff, buffSize);
	// textTable = new PTextTable[Count[0]];
	textDatas = new TextTable[Count[0]];
	txt.Format(L"%X", &textDatas);
	AfxMessageBox(txt);
	char* buffStart = TextBuff + 4;
	char* buffEnd = buffStart + buffSize;
	int icount = 0;
	while(buffStart < buffEnd){// 读取语言文件的数据到 textDatas 变量里
		int lenId = strlen(buffStart) + 1;
		memcpy(textDatas[icount].TxtId, buffStart, 0x24);
		buffStart = buffStart + lenId;
		int lenTxt = wcslen((wchar_t*)buffStart) + 1;
		lenTxt = lenTxt * 2;
		textDatas[icount].Txt = (wchar_t*)buffStart;
		buffStart = buffStart + lenTxt;
		icount++;
	}

	hashCount = Count[0];
	HashIndexTable = new unsigned[hashCount];
	memset(HashIndexTable, 0xFF, hashCount * sizeof(unsigned));

	for (int i = 0; i < Count[0]; i++) {// 给 textDatas 变量添加哈希算法索引(哈希表存放 textDatas的下标)
		unsigned hash = Hashcode(textDatas[i].TxtId);
		hash = hash % (hashCount + 1);
		if (HashIndexTable[hash] == -1) {
			HashIndexTable[hash] = i;
		}
		else {
			PTextTable nullTable = GetNullText(&textDatas[HashIndexTable[hash]]);
			nullTable->next = i;
		}
	}

	return false;
}

const wchar_t* TextManger::ReadTextById(const char* _id)
{
	// unsigned callProc = 0x10295FB0;

	if (textTable) {
		int index;
		_asm {
			push ebx
			mov ebx, this
			push _id
			call ReadTextProc
			mov index, eax
			pop ebx
		}
		if (index < 0)return NullText;
		PTextTable* _table = textTable;

		return (wchar_t*)_table[index]->Txt;
	}
	else {
		unsigned hash = Hashcode(_id);
		hash = hash % (hashCount + 1);
		unsigned index = HashIndexTable[hash];
		if (index > hashCount) {// index的值如果是-1那么它肯定比hashCount大
			return NullText;
		}
		while (strcmp(textDatas[index].TxtId, _id)) {
			index = textDatas[index].next;
			if (index > hashCount)return NullText;
		}
		return textDatas[index].Txt;
	}
}

unsigned TextManger::Hashcode(const char* id)
{
	unsigned hash = 0;
	for (int i = 0; id[i]; i++)
	{
		hash = hash * 131 + id[i];
	}
	return hash;
}

PTextTable TextManger::GetNullText(PTextTable _table)
{
	while (_table->next != -1) {// 从链表中找出最后一个(next的值是-1的)
		_table = &textDatas[_table->next];
	}
	return _table;
}

TextManger.h文件的修改:修改了 TextTable结构体

#pragma once
#include <iostream>
#include <fstream>

/*
03E1B73B | 68 58120304              | push fxgamelogic.4031258         | 4031258:"gui"
03E1B740 | E8 7BEF0F00              | call fxgamelogic.3F1A6C0         |
03E1B745 | 83C4 04                  | add esp,4                        |
03E1B748 | 85C0                     | test eax,eax                     |
03E1B74A | 0F84 10090000            | je fxgamelogic.3E1C060           |
03E1B750 | 68 4C120304              | push fxgamelogic.403124C         | 403124C:"TextManager"
03E1B755 | 50                       | push eax                         |
03E1B756 | 8D4C24 64                | lea ecx,dword ptr ss:[esp+64]    |
03E1B75A | 51                       | push ecx                         |
03E1B75B | E8 00091000              | call fxgamelogic.3F1C060         |
03E1B760 | 8D5424 68                | lea edx,dword ptr ss:[esp+68]    |
03E1B764 | 52                       | push edx                         |
03E1B765 | E8 16EF0F00              | call fxgamelogic.3F1A680         | 111111111111
03E1B76A | 83C4 10                  | add esp,10                       |
03E1B76D | 85C0                     | test eax,eax                     |
03E1B76F | 894424 14                | mov dword ptr ss:[esp+14],eax    | [esp+14]:CD3DDDIDX10_DrawIndexedPrimitive+113
*/
// 游戏中的中文表结构是 中文名英文id 这样的
typedef class TextTable {
public:
	int next = ((int)0xFFFFFFFF);
	int un = sizeof(TextTable);
	wchar_t* Txt;// 中文
	char TxtId[0x24];// 中文对应的英文id
}*PTextTable;

typedef class TextManger
{
public:
	static unsigned ReadTextProc;
	static const wchar_t NullText[2];
private:
	//int un[0x20];// 0x20 * 0x4 = 0x80
	int un[0x1E];
	union {
		char* TextBuff;
		unsigned* Count;
	};
	PTextTable textDatas = nullptr; // 中文结构
public:
	PTextTable* textTable = nullptr; // 暂时无用
private:
	int un1;
public:
	unsigned hashCount;
	unsigned* HashIndexTable = nullptr; // 哈希表
public:
	bool CreateTextDat(const char* filename); // 导出语言包
	bool LoadTextData(const char* _filename); // 加载 CreateTextDat函数写出的文件
	const wchar_t* ReadTextById(const char* _id); // 根据id获取中文名
	unsigned Hashcode(const char* id);// 哈希函数
	// 获取一个未使用的中文与对应id结构,用与存放从文件中读取的中文与对应id
	PTextTable GetNullText(PTextTable _table);
}*PTextManger;


CUIWnd_0.cpp文件的修改:修改了 OnBnClickedButton2函数

// CUIWnd_0.cpp: 实现文件
//

#include "pch.h"
#include "htdMfcDll.h"
#include "CUIWnd_0.h"
#include "afxdialogex.h"
#include "extern_all.h"
#include "GameOBJECTDef.h"

// CUIWnd_0 对话框
float _xNext = 0.0f;
float _yNext = 0.0f;
void _stdcall loops(HWND, UINT, UINT_PTR, DWORD) {
	PAIM aim = Client->GetAimByName(L"r");
	if (aim == nullptr) {
		return;
	}
	//AfxMessageBox(aim->Name);
	float xDis = fabs(Client->Player.x - aim->x);
	float hDis = fabs(Client->Player.h - aim->h);
	float yDis = fabs(Client->Player.y - aim->y);

	float xNext, yNext, thisx, thisy;

	int v[2]{ -1, 1 };

	if (xDis > 12) {
		// 强制修改角色x坐标的值
		thisx = Client->Player.x;
		Client->Player.x = Client->Player.x + 6 * v[Client->Player.x < aim->x];
		xNext = Client->Player.x;
	}
	else {
		xNext = aim->x;
	}
	if (yDis > 12) {
		// 强制修改角色y坐标的值
		thisy = Client->Player.y;
		Client->Player.y = Client->Player.y + 6 * v[Client->Player.y < aim->y];
		yNext = Client->Player.y;
	}else{
		yNext = aim->y;
	}
	if ((xDis < 2)&&(hDis < 2)&&(yDis < 2)) {
		Client->MoveStop(aim->x, aim->h, aim->y, 0.0f);
	}
	else {
		Client->MoveWalk(Client->Player.x,aim->h, Client->Player.x, 0.0f, 0.0f, xNext, yNext);
	}
}

IMPLEMENT_DYNAMIC(CUIWnd_0, CDialogEx)

CUIWnd_0::CUIWnd_0(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_PAGE_0, pParent)
{

}

CUIWnd_0::~CUIWnd_0()
{
}

void CUIWnd_0::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CUIWnd_0, CDialogEx)
	ON_BN_CLICKED(IDC_BUTTON1, &CUIWnd_0::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CUIWnd_0::OnBnClickedButton2)
END_MESSAGE_MAP()


// CUIWnd_0 消息处理程序


void CUIWnd_0::OnBnClickedButton1()
{
	// 发送坠落数据包
	//Client->Fall();
	
	 设置移动速度
	float Speed = 30.0;
	Client->SetProperty(Client->Player.lId, INDEX_MoveSpeed, &Speed);
	/*
	// 修改血量
	int HP = 10000000;
	Client->SetProperty(Client->Player.lId, INDEX_HP, &HP);*/
	/*CString txt;
	txt.Format(L"通过AIM类获取角色信息 名字:%s,x坐标:%f", Client->Player.Name, Client->Player.x);
	AfxMessageBox(txt);*/
	// Client->HeartBeep();
	// Client->TalkTo(L"r", L"打架吗?");
	// Client->Talk(L"[欢迎来到麟科思]");
	// Client->SelectRole(L"今晚打老虎");
	/*Client->CreateRole(L"am4", 1.0, 2.0, 4.0, 8.0, "gui\BG_team\TeamRole\Teamrole_zq_humF_001.PNG",
		"Face,0;Hat,0;Eyes,0;Beard,0;Ears,0;Tail,0;Finger,0;Cloth,0;Pants,0;Gloves,0;Shoes,0;Trait,0;HairColor,0;SkinColor,0;SkinMtl,0;Tattoo,0;TattooColor,16777215;",
		"", 0.0);*/
	//Client->SelectCamp("xuanrenZQ");
	//Client->StartCreateRole();
	//Client->DelRole(L"ranzhi11111");
	/*
	char buff[] = {
		0xA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x4, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 00 ,0x00,
		0x00, 0x07, 0x0E, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x31, 0x00, 0x32 ,0x00,
		0x33, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	WinSock->OnSend(buff, sizeof(buff));
	*/
	/*char buff[] = {
		0x27, 0x46, 0x92, 0x02, 0x00, 0x00, 0x89, 0x02, 0x00, 0x00, 0x06, 0x00, 0x06, 0x05, 
		0x00, 0x00, 0x00, 0x63, 0x68, 0x61, 0x74, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x07, 
		0x0A, 0x00, 0x00, 0x00, 0x34, 0x00, 0x33, 0x00, 0x39, 0x00, 0x39, 0x00, 0x00, 0x00, 
		0x07, 0x5A, 0x02, 0x00, 0x00, 0x31, 0x00, 0x32, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 
		0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 
		0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 
		0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 
		0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 
		0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 
		0x00, 0x32, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 
		0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 
		0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 
		0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 
		0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 
		0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,
		0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x35, 
		0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 
		0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 
		0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 
		0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 
		0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 
		0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x34, 
		0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 
		0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 
		0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 
		0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 
		0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 
		0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36,
		0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 
		0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 
		0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x37, 
		0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 
		0x38, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00
	};
	WinSock->OnRecv(buff, sizeof(buff));*/
}

TextManger txtMangerMain;
void CUIWnd_0::OnBnClickedButton2()
{
	// 根据语言表获取文字
	//CString txt = txtManger->ReadTextById("npc_GRZJ_0001");// PGameProc->GetTextName("npc_GRZJ_0001");
	//AfxMessageBox(txt);
	//txtManger->CreateTextDat("F:\\语言包.txt");
	// 读取导出到本地的语言包
	txtMangerMain.LoadTextData("F:\\语言包.txt");
	// CString txt = txtMangerMain.ReadTextById("npc_GRZJ_0001");// npc_GRZJ_0001没有哈希冲突
	/* 
		Hui_event_3_1有哈希冲突,通过打印 textDatas 变量的内存地址
		去x96db找的(第一个就冲突了,ui_event_3_1是第一个哈希表里的链表的最后一个)
		如果第一个没有冲突,那就找一个 next 不是 -1 的,不是-1说明是链表,然后找链表最后一个就可以了
	*/

	CString txt = txtMangerMain.ReadTextById("ui_event_3_1");
	AfxMessageBox(txt);
	txt = txtMangerMain.ReadTextById("desc_Item_A550001_01_2");
	AfxMessageBox(txt);
	// 瞬移
	//float decX = 3843.776123f;
	//float decH = 11.731983f;
	//float decY = -2005.533813f;
	//float face = 0.0f;
	//Client->Teleport(decX, decH, decY, face);
	//PAIM aim = Client->GetAimByName(L"r");
	//if (aim == nullptr) {
	//	return;
	//}
	//Client->Teleport(aim->x, aim->h, aim->y, aim->face);
	// 修正坐标
	/*PAIM aim = Client->GetAimByName(L"r");
	if (aim == nullptr) {
		return;
	}
	Client->SetCoord(Client->Player.lId, aim->x, aim->h, aim->y, aim->face);*/
	// 面向
	// Client->FaceTo(L"r");
	// 飞天
	// Client->HideMode = true;
	// 遁地
	//Client->MoveStop(Client->Player.x, Client->Player.h - 5, Client->Player.y, 0.0f);
	// 跟随
	// ::SetTimer(m_hWnd, 0x1000, 2000, loops);
	// 
	// Client->Backtoroles();
}


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

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

相关文章

车间人员作业行为智能检测 AI视觉在生产车间制造中的应用

车间人员作业行为智能检测系统基于神经网络人工智能视觉算法&#xff0c;车间人员作业行为智能检测通过对车间监控摄像头获取的视频图像进行分析和识别&#xff0c;实现了对人员操作行为的智能检测。系统对工人的操作环节进行分解&#xff0c;根据时间、动作标准等方面制定了规…

Django5+React18前后端分离开发实战13 使用React创建前端项目

先将nodejs的版本切换到18&#xff1a; 接着&#xff0c;创建项目&#xff1a; npx create-react-app frontend接着&#xff0c;使用webstorm打开这个刚创建的项目&#xff1a; 添加一个npm run start的配置&#xff1a; 通过start启动服务&#xff1a; 浏览器访问&…

STranslate即开即用、即用即走的翻译(OCR)工具 v1.1.3.514

软件介绍 STranslate 是一款面向 Windows 操作系统用户设计的翻译软件&#xff0c;该软件具备开源性质并且免费。它结合了翻译功能与光学字符识别&#xff08;OCR&#xff09;技术&#xff0c;允许用户高效且直接地在屏幕上进行文字的翻译和识别。在开发过程中&#xff0c;STr…

Nginx/阿里云/二级域名的配置和使用

阿里云域名解析配置如下&#xff1a; nginx配置如下&#xff1a; 访问地址&#xff1a; zhadmin.iotzzh.com image.png

二叉搜索数之删除节点

看题目&#xff1a; 给定一个二叉搜索树的根节点 root 和一个值 key&#xff0c;删除二叉搜索树中的 key 对应的节点&#xff0c;并保证二叉搜索树的性质不变。返回二叉搜索树&#xff08;有可能被更新&#xff09;的根节点的引用。 一般来说&#xff0c;删除节点可分为两个步…

详解ArcGIS 水文分析模型构建

目录 前言 项目环境、条件 Dem 数据预览 ArcGIS模型构建器 模型搭建 填洼 流向 流量 河流长度 栅格计算器 河流链接 河网分级 栅格河网矢量化 绘制倾泻点 栅格流域提取 集水区 盆域分析 栅格转面 模型应用 导出 py 文件 完善脚本 最终效果 结束语 前言 …

【NumPy】关于numpy.loadtxt()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

有没有适合女性做的副业?盘点9个适合女生做的赚钱兼职副业

亲爱的女神们&#xff0c;你们是否也想在忙碌的生活中寻找一些额外的乐趣和收入呢&#xff1f;今天&#xff0c;就为大家揭秘九种特别适合女性的副业&#xff0c;让你在追求美丽的同时&#xff0c;也能轻松赚取零花钱&#xff0c;秒变“小金库”&#xff01; 一、宅富社任务赚钱…

Default Folder X for Mac v6.0.7激活版:高效、智能的文件管理新选择

在快节奏的工作与生活中&#xff0c;高效管理文件已成为每个Mac用户的迫切需求。Default Folder X for Mac正是为了满足这一需求而生&#xff0c;它以其卓越的性能和丰富的功能&#xff0c;为Mac用户带来了前所未有的文件管理体验。 Default Folder X for Mac拥有直观易用的界面…

攻防世界---web---warmup

1、题目描述 2、查看源码&#xff0c;发现有个source.php 3、访问该文件&#xff0c;得到这一串代码 4、分析代码 5、访问hint.php&#xff0c;提示flag在ffffllllaaaagggg这个文件下 6、构造payload ?filesource.php?/../../../../../../ffffllllaaaagggg

Java基础之进制转换和位运算专题

什么是进制&#xff1f; 是数学中的一个概念&#xff0c;就是数据“逢几进位”。 例如&#xff1a;生活中用的计数方法 ---- 十进制。十进制就是数字逢十就要进一位。 例如&#xff1a;一个星期有7天&#xff0c;就是逢七进一&#xff1b;一个月有30天就是逢30进一&#xff1b;…

多尺度注意力机制突破性成果!低成本、高性能兼备

与传统的注意力机制相比&#xff0c;多尺度注意力机制引入了多个尺度的注意力权重&#xff0c;让模型能够更好地理解和处理复杂数据。 这种机制通过在不同尺度上捕捉输入数据的特征&#xff0c;让模型同时关注局部细节和全局结构&#xff0c;以提高对细节和上下文信息的理解&a…

【openlayers系统学习】3.5colormap详解(颜色映射)

五、colormap详解&#xff08;颜色映射&#xff09; ​colormap​ 包是一个很好的实用程序库&#xff0c;用于创建颜色图。该库已作为项目的依赖项添加&#xff08;1.7美化&#xff08;设置style&#xff09;&#xff09;。要导入它&#xff0c;请编辑 main.js​ 以包含以下行…

AWS安全性身份和合规性之Identity and Access Management(IAM)

通过AWS Identity and Access Management&#xff08;IAM&#xff09;&#xff0c;您可以指定谁或什么能够访问AWS中的服务和资源、集中管理精细权限&#xff0c;并分析访问权限以优化跨AWS的权限。 比如一家软件开发公司需要在AWS上创建多个开发人员账户&#xff0c;并对其进…

使用Python生成一束玫瑰花

520到了&#xff0c;没时间买花&#xff1f;我们来生成一个电子的。 Python不仅是一种强大的编程语言&#xff0c;用于开发应用程序和分析数据&#xff0c;它也可以用来创造美丽的艺术作品。在这篇博客中&#xff0c;我们将探索如何使用Python生成一束玫瑰花的图像。 准备工作…

绿联硬盘数据恢复方法:安全、高效找回珍贵数据

在数字化时代&#xff0c;硬盘承载着大量的个人和企业数据&#xff0c;一旦数据丢失或损坏&#xff0c;后果往往不堪设想。绿联硬盘以其稳定的性能和良好的口碑赢得了众多用户的信赖&#xff0c;但即便如此&#xff0c;数据恢复问题仍然是用户可能面临的一大挑战。本文将为您详…

【NOIP2013普及组复赛】题4:车站分级

题4&#xff1a;车站分级 【题目描述】 一条单向的铁路线上&#xff0c;依次有编号为 1 , 2 , … , n 1,2,…,n 1,2,…,n 的 n n n 个火车站。每个火车站都有一个级别&#xff0c;最低为 1 1 1 级。现有若干趟车次在这条线路上行驶&#xff0c;每一趟都满足如下要求&#…

Snowy2.x 版本使用 Yaml

代码&#xff1a;https://gitee.com/xiaonuobase/snowy/tree/Snowy2.5.2/ 直接将 properties 转换成 yaml 那么你大概率会遇到下面报错&#xff1a; 然后你上网搜索&#xff0c;发现是 snakeyaml 版本的问题&#xff0c;1.x 版本的 snakeyaml 有安全隐患&#xff0c;要升级到…

C语言程序的编译

目录 一、预处理&#xff08;预编译&#xff09; 二、编译 三、汇编 四&#xff0c;链接 在前面讲到了宏的定义&#xff0c;那么宏在编译时候是如何发生替换的&#xff1f;接下来做一下详细的介绍C语言程序的编译过程主要包括以下几个步骤&#xff1a;预处理、编译、汇编和…

【paper】基于分布式采样的多机器人编队导航信念传播模型预测控制

Distributed Sampling-Based Model Predictive Control via Belief Propagation for Multi-Robot Formation NavigationRAL 2024.4Chao Jiang 美国 University of Wyoming 预备知识 马尔可夫随机场&#xff08;Markov Random Field, MRF&#xff09; 马尔可夫随机场&#xff…