60.网络游戏逆向分析与漏洞攻防-利用数据包构建角色信息-根据数据包内容判断数据包作用

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

如果看不懂、不知道现在做的什么,那就跟着做完看效果

现在的代码都是依据数据包来写的,如果看不懂代码,就说明没看懂数据包

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

上一个内容:59.角色上线过程数据逻辑分析

从本章开始就开始分析人物数据了,目标是通过网络数据包分析不去逆向不去读取内存,然后构建出角色信息,通过上一个内容,把09数据包屏蔽,客户端还是可以正常读取角色信息,所以接下来就分析屏蔽09数据包之后的那些数据包,通过这些数据包我们把角色信息给构建出来,原则上游戏可以搞的事我们也可以搞,然后如果数据包过于复杂根据数据约定解不出来,还是要去逆向

然后进入游戏

从下往上分析

然后下图红框两个大的数据包先不解读,现在没感觉解不出来

然后就从10开头数据包下手

10数据包如下图前12字节都是一样的,后面是一个字符串

然后这个01 00现在倾向于它是数据参数个数

下图红框是数据参数

然后现在游戏处于一种半进不进的状态,这些数据包肯定跟客户端初始化有关系,与角色有关系,然后接下来重新选择角色看看,下图红框位置的数据会不会变

在返回角色选择时,发现无法进入角色选择界面了,这说明09数据包还是影响返回角色选择的

所以做测试10数据包变不变之前,要把09数据包放掉,如下图把if判断注释掉就可以了

然后现在的10数据包

同样一个角色重新登录之后它就变了,所以这些字节就是跟角色有关,可以把D4 44 00 01 12 32 DC 03 猜测为它与角色有关

现在就可以这样拆分 10 00是数据头,D4 44 00 01 12 32 DC 03 代表了角色,01 00代表数据参数个数,剩下的就是数据参数,这个意思是角色它肯定有很多属性,根据下图的数据包来说,这个数据包代表了人物第72个属性

第72个属性是21063,它应该就这样的一个意思

然后现在周围有一个r角色

接下来选中它,看看选中的数据包是什么,选中的数据包是07,但是现在看不懂什么意思

然后自己选中自己,然后就看到,07数据包里我们看不懂的东西是角色id

然后现在确认10的数据是角色信息的更新,然后看看附近角色的数据更新是不是也是10,然后首先选中附近角色,看看它的id,它的id现在是 F8 44 00 01 51 13 DB 03

然后我想她发起决斗打它一下血量会变,然后现在变成了1794

接下来通过内容搜索附近角色id,发现2D开头的数据包会更新附近角色信息,所以除了10还有2d会更新角色信息

整理说明:

下图意思是把角色id为 D4 44 00 01 12 32 DC 03 的第AB(十进制是171)个数据改成一个空字符(为什么是空字符?因为下图中AB 00 01这个01后面有5个0,这样的数据不符合内存对齐,所以只能是01 00 00 00然后还剩一个0是字符串结尾符,这样的就是一个空字符,所以它是一个空字符),然后角色id是一个long long类型

然后通过下图知道了 29 是血量

然后把我们的血量进行一个修改,验证29是不是血量,现在血量是1531

然后把加血量的装备下掉,然后变成了1180

然后搜索1180,可以百分百确认29代表的是血量了,然后还有一些看不懂的数据,这些看不懂的先不管

有了这个概念之后,再来看28数据包,然后发现它的数据包很大,全部搞出来有点费力,所以接下来对它逆向分析,游戏既然可以用,它肯定会有一个表,就是04代表什么类型05代表什么类型,这样的一个表,逆向分析就是去找它这个表,因为现在知道它的一个套路了,就差这关键的信息了,找到这张表关键信息也就是知道了

然后打开x96dbg

来到下图红框位置0x1061157E,为什么是下图红框位置看53.逆向分析寻找消息数据解压缩过程,这个位置是决定数据包是否解压的位置,ecx值就是数据包头

然后下一个条件断点

然后返回到角色选择界面重新进入游戏,来到断点

然后按f8,来到下图蓝框位置时,在红框位置打个断点,然后按f9,下图蓝框位置是我们HOOK点

然后来到下图红框位置

再按F8,来到28数据处理函数

它的参数有一个长度,一个指针,一个我们的数据包

然后往下滑可以看到一堆st寄存器的使用,st寄存器是用来存放浮点数的

然后通过上方我们手动的分析28数据包,可以看到开头确实是有多个浮点数坐标,所以直接把断点打到下图位置,因为我们现在要找后面以数据解析约定的数据,它既然是在处理浮点数,这就说明是处理前面的,并不是我们要找的,所以在下图红框位置打断点不影响什么

然后一路f8 会来到下图红框位置,这个位置是处理完前面浮点数之后第一次调用函数的位置

函数的参数这里从数据包3D位置取了一个值,这个值可能是数据参数个数

然后它的栈情况,一个长度一个不知道什么的字符串

然后鼠标双击进入函数,先通过静态的方式过一遍代码

过了一遍之后并没有发现[XX*4+XXXX]这样的写法(这样的写法是符合读取表的写法),所以接下来直接对数据包做访问断点,给1B下一个1字节的访问断点

然后来到下图红框位置,发现它变成了0,这说明在访问之前有人对它进行了修改

然后它的附近有一个像是表的东西,如下图红框

然后也看不出是个什么东西来

然后现在先结束,现在东西已经很多了,然后下一次再下一个写断点试一下

总结:

通过分析10数据包得出一个id,然后通过选择自己确认了10数据包里就是角色id,然后通过修改血量也确定了29,也就是第29个位置是血量,然后通过这样一个新思路去尝试解析28号数据,然后发现28号数据可以这样分析出来,但是它有很多东西,人工分析不好,所以又去逆向找游戏的类型表(29代表了第29位置是血量,类型表的意思是,通过读取表的第29位置就能确定是血量,以及数据类型,这样的一个意思,以后为了方便都会称为类型表)

本次代码就修改了一行,没有提交百度网盘,只提交了码云

GameWinSock.cpp文件的修改:修改了 OnSend函数

#include "pch.h"
#include "GameWinSock.h"
#include "extern_all.h"
#include "NetClass.h"
#include "EnCode.h"

typedef bool(*DealProc)(char*&, unsigned&);

DealProc SendDealProc[0x100];
DealProc RecvDealProc[0x100];


GameWinSock::PROC GameWinSock::_OnConnect{};
GameWinSock::PROC GameWinSock::_OnSend{};
GameWinSock::PROC GameWinSock::_OnRecv{};

bool DeafaultDeal(char*&, unsigned&) { return true; }

// 登录数据包的处理
bool Onlogin(char*& buff, unsigned& len) {
	PDATALOGIN _data = (PDATALOGIN)(buff + 1);
	char* _id = _data->Id;
	_data = (PDATALOGIN)(buff + 1 + _data->lenId - 0x10);
	char* _pass = _data->Pass;

	Client->Onlogin(_id, _pass);

	/* 修改账号密码
	len = sizeof(DATA_LOGIN) + 1;
	buff = new char[len];
	DATA_LOGIN data;
	PDATALOGIN _data = &data;
	buff[0] = 0x2;

	CStringA _id = "";// 补充账号
	CStringA _pass = "";// 补充密码
	memcpy(_data->Id, _id.GetBuffer(), _id.GetLength());
	memcpy(_data->Pass, _pass.GetBuffer(), _pass.GetLength());
	memcpy(buff + 1, _data, len - 1);
	*/
	/* 监控登录数据
	PDATALOGIN _data = (PDATALOGIN)buff;
	CStringA _id = _data->Id;
	_data = (PDATALOGIN)(buff + _data->lenId - 0x10);
	CStringA _pass = _data->Pass;
	CStringA _tmp;
	// 请求登录 账号[% s]密码[% s] 这个内容别人在逆向的时候就会看到
	// 所以这种东西需要自己搞个编码来代替它

	 _tmp.Format("请求登录 账号[%s]密码[%s]", _id, _pass);
#ifdef  Anly
	anly->SendData(TTYPE::I_DIS, 1, _tmp.GetBuffer(), _tmp.GetAllocLength());
#endif
	*/

	/*
		返回false,游戏无法发送数据包
		原因看调用此此函数的位置 OnSend 函数(if (SendDealProc[buff[0]]((buff + 1), len - 1)))
	*/
	return true;
}

bool OnTips(char*& buff, unsigned& len) {
	int* code = (int*)&buff[1];
	return Client->Tips(code[0]);
}

bool OnSelectRole(char*& buff, unsigned& len) {
	PNS_SELECTROLE p = (PNS_SELECTROLE)buff;
	return Client->OnSelectRole((wchar_t*)(p->buff));
}

bool OnDelRole(char*& buff, unsigned& len) {

	PDATADELROLE p = (PDATADELROLE)buff;
	return Client->OnDelRole((wchar_t*)(p->buff), p->len);



	// 返回值改为false将拦截发送的删除角色数据包
	// 详情看注册 OnDelRole 函数的位置,Init函数
	// return true;
}

bool OnloginOk(char*& buff, unsigned& len) {

	PDATALOGINOK _p = (PDATALOGINOK)&buff[1];
	ROLE_DATA* roleDatas = nullptr;
	if (_p->RoleCount > 0) {
		char* buffStart = buff + 1 + sizeof(DATA_LOGIN_OK);
		WinSock->AnlyBuff(buffStart, buff + len, buff[0]);
		roleDatas = new ROLE_DATA[_p->RoleCount];
		for (int i = 0; i < _p->RoleCount; i++)
		{
			roleDatas[i].byte.Init(buffStart, 0);
			roleDatas[i].index.Init(buffStart, 0);
			roleDatas[i].un1.Init(buffStart, 0);
			roleDatas[i].name.Init(buffStart, 0);
			roleDatas[i].infos.Init(buffStart, 0);
			roleDatas[i].un2.Init(buffStart, 0);
			roleDatas[i].un3.Init(buffStart, 0);
		}
		Client->loginok(roleDatas, _p->RoleCount);
	}
	return true;
}

bool OnStartCreateRole(char*& buff, unsigned& len){
	// 申请进入创建角色界面
	int* code = (int*)&buff[1];
	return Client->OnStartCreateRole(code[0]);
}

bool OnCreateRole(char*& buff, unsigned& len) {
	PNS_CREATEROLE head = (PNS_CREATEROLE)(buff - 3);
	int icount = head->count;
	if (icount < 1)return true;
	char* buffStart = (char*)head + sizeof(NET_SEHD_CREATEROLE_HEAD);
	
#ifdef  Anly
	WinSock->AnlyBuff(buffStart, buff + len, buff[0], 1);// 翻译解析约定数据
#endif

	EnCode codes[sizeof(CREATE_ROLE_DATAS) / sizeof(EnCode)]{};
	int stDecode = 0;
	while (stDecode < icount) {
		codes[stDecode++] = buffStart;
	}


	/* 
		Client->OnCreateRole(head, (PCREATE_ROLE_DATAS)codes) 数据包传给虚函数
		如果想对发送创建角色数据包做些什么直接继承NetClient重写OnCreateRole函数既可以了
	*/
	return Client->OnCreateRole(head, (PCREATE_ROLE_DATAS)codes);// 返回false屏蔽05开头的数据包,也就是创建角色发送的数据包
}

bool OnSendCustom(char*& buff, unsigned& len) {
	PNET_SEND_HEAD head = (PNET_SEND_HEAD)(buff - 1);
	int icount = head->count;
	if (icount < 1)return true;
	char* buffStart = (char*)head + sizeof(NET_SEND_HEAD);
	if (buffStart[0] != 0x02) {

#ifdef  Anly
		if(icount < MAX_SEND_COUNT)
			anly->SendData(TTYPE::I_DIS, I_SEND_CUSTOM, "SEND_CUSTOM MAX_SEND_COUNT 内存解码器空间不足", 46);

		anly->SendData(TTYPE::I_DIS, I_SEND_CUSTOM, "SEND_CUSTOM 发现异常数据", 25);
#endif
		return true;
	}

#ifdef  Anly
	WinSock->AnlyBuff(buffStart, buff + len, buff[0], 1);
#endif

	int stDecode = 0;
	EnCode codes[MAX_SEND_COUNT]{};
	while (stDecode < icount) {
		codes[stDecode++] = buffStart;
	}

	/*
		Client->OnSendCustom((PNET_SEND_CHEAD)codes, buff, len); 数据包传给虚函数
		如果想对发送数据的0A开头的据包做些什么直接继承NetClient重写OnSendCustom函数既可以了
	*/
	return Client->OnSendCustom((PNET_SEND_CHEAD)codes, buff, len);

}

/*
 OnSverrNotice函数处理的数据包格式如下
	1E 06 00 
	06 11 00 00 00 70 6C 61 79 5F 70 6F 69 6E 74 5F 73 6F 75 6E 64 00 
	06 01 00 00 00 00 
	04 2C 92 87 C5 
	04 FA 03 BF 42 
	04 33 14 BD 45 
	02 00 00 00 00 
	1E 06 00 是 PNR_NOTICE_HEAD
	06 11 00 00 00 70 6C 61 79 5F 70 6F 69 6E 74 5F 73 6F 75 6E 64 00是一个EnCode
	06 01 00 00 00 00是一个EnCode
	04 2C 92 87 C5是一个EnCode
	04 FA 03 BF 42是一个EnCode
	04 33 14 BD 45是一个EnCode
	02 00 00 00 00是一个EnCode
*/
bool OnSverrNotice(char*& buff, unsigned& len) {
	PNR_NOTICE_HEAD head = (PNR_NOTICE_HEAD)(buff - 1);
	int icount = head->count;
	char* buffStart = (char*)head + sizeof(NR_NOTICE_HEAD);
	if (icount < 1) {
		return true;
	}
	if (icount > MAX_RECV_COUNT) {
#ifdef  Anly
		anly->SendData(TTYPE::I_DIS, S_NOTICE, "S_NOTICE 解码器内存不足", 24);
#endif
		return true;
	}
#ifdef  Anly
	WinSock->AnlyBuff(buffStart, buff + len, buff[0], 1);
#endif
	int stDecode = 0;
	EnCode codes[MAX_RECV_COUNT]{};
	while (stDecode < icount) {
		codes[stDecode++] = buffStart;
	}
	return Client->OnSvrNotice((PNET_SEND_CHEAD)codes, icount, buff, len);
}
bool OnSvrStartCreateRole(char*& buff, unsigned& len) {
	short* _st = (short*)&buff[1];
	wchar_t* _txt = (wchar_t*)&buff[3];
#ifdef  Anly
	CString txt;
	CStringA txtA;
	txt.Format(L"code:%d\r\n%s", _st[0], _txt);
	txtA = txt;
	//AfxMessageBox(txtA);
	anly->SendData(TTYPE::I_DIS, S_CREATEROLE_START, txtA.GetBuffer(), txt.GetAllocLength() + 1);
#endif
	/*
		Client->OnSendCustom((PNET_SEND_CHEAD)codes, buff, len); 数据包传给虚函数
		如果想对0A开头的据包做些什么直接继承NetClient重写OnSendCustom函数既可以了
	*/
	return Client->OnScrStartCreateRole(_st[0], _txt);
}

// 这个函数拦截了游戏的连接
bool GameWinSock::OnConnect(char* ip, unsigned port)
{
#ifdef  Anly
	// 长度24的原因,它是宽字节要,一个文字要2个字节,一共是10个文字加上结尾的0是11个
	// 所以 11 乘以2,然后再加2 
	anly->SendData(TTYPE::I_LOG, 0, L"服务器正在连接。。。", 24);
#endif
    // this是ecx,HOOK的点已经有ecx了
    WinSock = this;
	Client->Init(this);
	bool b = (this->*_OnConnect)(ip, port);
	// 下方注释的代码时为了防止多次注入,导致虚函数地址不恢复问题导致死循环,通过一次性HOOK也能解决
	/*unsigned* vtable = (unsigned*)this;
	vtable = (unsigned*)vtable[0];
	union {
		unsigned value;
		bool(GameWinSock::* _proc)(char*, unsigned);
	} vproc;

	vproc._proc = _OnConnect;

	DWORD oldPro, backProc;
	VirtualProtect(vtable, 0x10x00, PAGE_EXECUTE_READWRITE, &oldPro);
	vtable[0x34 / 4] = vproc.value;
	VirtualProtect(vtable, 0x10x00, oldPro, &backProc);*/

    return b;
}

bool GameWinSock::OnSend(char* buff, unsigned len)
{
	// if (buff[0] == 0x09)return true;
	
	/*
		这里就可以监控游戏发送的数据了
	*/

#ifdef  Anly
	anly->SendData(TTYPE::I_SEND, buff[0], buff, len);
#endif
	/*
		数据包的头只有一字节所以它的取值范围就是0x0-0xFF
	*/
	if (SendDealProc[buff[0]]((buff), len)) {// 执行失败不让游戏发送数据包
		return (this->*_OnSend)(buff, len);
	}
	else {// 发送失败屏蔽消息
		return true;// 屏蔽消息
	}

}

bool GameWinSock::Recv(char* buff, unsigned len)
{
//#ifdef  Anly
//	anly->SendData(1, buff, len);
//#endif
	return (this->*_OnRecv)(buff, len);
}

void GameWinSock::Init()
{
	for (int i = 0; i < 0x100; i++) {
		SendDealProc[i] = &DeafaultDeal;
		RecvDealProc[i] = &DeafaultDeal;
	}
	// 注册登录数据包处理函数
	SendDealProc[I_LOGIN] = &Onlogin;
	SendDealProc[I_DELROLE] = &OnDelRole;
	SendDealProc[I_CREATEROLE_START] = &OnStartCreateRole;
	SendDealProc[I_SEND_CUSTOM] = &OnSendCustom;
	SendDealProc[I_CREATEROLE] = &OnCreateRole;
	SendDealProc[I_SELECT_ROLE] = &OnSelectRole;
	// 注册数据登录失败数据包处理函数
	RecvDealProc[S_TIPS] = &OnTips;
	RecvDealProc[S_LOGINOK] = &OnloginOk;
	RecvDealProc[S_CREATEROLE_START] = &OnSvrStartCreateRole;
	RecvDealProc[S_NOTICE] = &OnSverrNotice;
	RecvDealProc[S_NOTICE_COM] = &OnSverrNotice;
}

// 它会生成一个结构体,详情看效果图
void GameWinSock::AnlyBuff(char* start, char* end, int MsgId, char index)
{
#ifdef  Anly
	CStringA txt;
	CStringA tmp;
	CString utmp;
	EnCode _coder;

	GBYTE* _bytecoder;
	GSHORT* _shortcoder;
	GINT* _intcoder;
	GFLOAT* _floatcoder;
	GDOUBLE* _doublecoder;
	GCHAR* _asccoder;
	GUTF16* _utfcoder;
	GINT64* _int64coder;



	while (start < end) {
		_coder.Init(start, index);
		CStringA _opname = data_desc[_coder.index][_coder.op].name;
		// _opname.MakeLower()是变为小写字母,会影响 _opname它的值
		// 所以又写了一边 data_desc[_coder.index][_coder.op].name
		tmp.Format("%s %s;//", data_desc[_coder.index][_coder.op].name, _opname.MakeLower());
		txt = txt + tmp;
		if (_coder.index == 0) {
			switch (_coder.op)
			{
			case 1:
				_shortcoder = (GSHORT*)&_coder;
				tmp.Format("%d\r\n", _shortcoder->value());
				txt = txt + tmp;
				break;
			case 2:
				_intcoder = (GINT*)&_coder;
				tmp.Format("%d\r\n", _intcoder->value());
				txt = txt + tmp;
				break;
			case 4:
				_floatcoder = (GFLOAT*)&_coder;
				tmp.Format("%f\r\n", _floatcoder->value());
				txt = txt + tmp;
				break;
			case 6:
				_bytecoder = (GBYTE*)&_coder;
				tmp.Format("%d\r\n", _bytecoder->value());
				txt = txt + tmp;
				break;
			case 7:
				_utfcoder = (GUTF16*)&_coder;
				utmp.Format(L"[%s]\r\n", _utfcoder->value());
				tmp = utmp;
				txt = txt + tmp;
				break;
			// 5号之前分析的忘记截图了,现在找不到它的数据包了,如果后面再见到05的时候再详细补充说明
			// 之前的分析05就是double类型
			case 5:
				_doublecoder = (GDOUBLE*)&_coder;
				tmp.Format("%lf\r\n", _doublecoder->value());
				txt = txt + tmp;
				break;
			case 8:
			case 3:
				_int64coder = (GINT64*)&_coder;
				tmp.Format("%lld\r\n", _int64coder->value());
				txt = txt + tmp;
				break;
			default:
				break;
			}
		}

		if (_coder.index == 1) {
			switch (_coder.op)
			{
			case 1:
				_shortcoder = (GSHORT*)&_coder;
				tmp.Format("%d\r\n", _shortcoder->value());
				txt = txt + tmp;
				break;
			case 2:
				_intcoder = (GINT*)&_coder;
				tmp.Format("%d\r\n", _intcoder->value());
				txt = txt + tmp;
				break;
			case 4:
				_floatcoder = (GFLOAT*)&_coder;
				tmp.Format("%f\r\n", _floatcoder->value());
				txt = txt + tmp;
				break;
			case 6:
				_asccoder = (GCHAR*)&_coder;
				tmp.Format("%s\r\n", _asccoder->value());
				txt = txt + tmp;
				break;
			case 7:
				_utfcoder = (GUTF16*)&_coder;
				utmp.Format(L"[%s]\r\n", _utfcoder->value());
				tmp = utmp;
				txt = txt + tmp;
				break;
			case 5:
				_doublecoder = (GDOUBLE*)&_coder;
				tmp.Format("%lf\r\n", _doublecoder->value());
				txt = txt + tmp;
				break;
			case 8:
			case 3:
				_int64coder = (GINT64*)&_coder;
				tmp.Format("%lld\r\n", _int64coder->value());
				txt = txt + tmp;
				break;
			default:
				break;
			}
		}
	} 
	anly->SendData(TTYPE::I_DIS, MsgId, txt.GetBuffer(), txt.GetAllocLength() + 1);
#endif
}

bool GameWinSock::OnRecv(char* buff, unsigned len)
{
	// 解除压缩后的数据
#ifdef  Anly
	anly->SendData(TTYPE::I_RECV, buff[0], buff, len);
#endif
	return RecvDealProc[buff[0]](buff, len);
}


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SAP SD 销售业务中免费货物之免费货物主数据

销售业务中&#xff0c;免费货物在您与客户协商价格时起着重要作用。在零售、化工或消费品这样的行业部门中&#xff0c;通常以免费货物的形式向客户提供折扣。如需了解SAP系统针对销售与分销业务中提供的标准解决方案概览&#xff0c;可先了解本博客博文&#xff1a;SAP销售与…

Visual Studio2010源码编译curl_7_60

一、源码解压目录内容 很开心里面可以找到CMakeLists.txt文件&#xff0c;说明可以实用CMake工具进行构建&#xff0c;由于多数开源项目都选择实用CMake作为构建编译工具&#xff0c;大家蝇该都比较熟练了。 二、实用CMake开始构建Visual Studio 2010工程 很顺利整个构建过程没…

机器学习基本流程

Jupyter Notebook 代码连接&#xff1a; machine_learning_demo machine_learning_ensembles Step 1: Imports and Configuration import pandas as pd import numpy as np import copy import json import pickle import joblib import lightgbm as lgb import optuna impor…

vscode设置conda默认python环境,简单有效

本地conda 可能安装了各种环境&#xff0c;默认的vscode总是base环境&#xff0c;这时你想要在vscode调试python代码&#xff0c;使用默认的环境没有安装对应的包就会遇到报错解决这个问题的方法很简单ctrlshiftp 调出命令面板 再输入 select interpreter , 选择 python 选择解…

【Pytorch】PytorchCPU版或GPU报错异常处理(10X~4090D)

Pytorch为CPU版或GPU使用报错异常处理 文章目录 Pytorch为CPU版或GPU使用报错异常处理0.检查阶段1. 在conda虚拟环境中安装了torch2.卸载cpuonly3.从tsinghua清华源安装不完善误为cpu版本4.用tsinghua清华源安装成cpu错误版本5.conda中torch/vision/cudatoolkit版本与本机cuda版…

安装第三方包报错 import pcapy ... ImportError: DLL load failed: 找到不到指定的模块——解决办法

1、问题描述 安装pcapy时&#xff0c;安装正常&#xff0c;但引用失败。具体过程如下&#xff1a;下载pcapy&#xff0c;下载地址&#xff1a;pcapy PyPI ​下载WinPcap开发工具包&#xff0c;下载地址&#xff1a;WinPcap 的 开发人员资源 ​安装pcapy&#xff0c;进入\pcap…

达梦数据库的DMRMAN工具-管理备份(备份集校验)

达梦数据库的DMRMAN工具-管理备份&#xff08;备份集校验&#xff09; DMRMAN 中使用 CHECK 命令对备份集进行校验&#xff0c;校验备份集是否存在及合法。 语法如下&#xff1a; CHECK BACKUPSET <备份集目录> [DEVICE TYPE <介质类型> [PARMS <介质参数>…

企业网盘搭建——LNMP

php包链接&#xff1a;https://pan.baidu.com/s/1RElYTQx320pN6452N_7t1Q?pwdp8gs 提取码&#xff1a;p8gs 网盘源码包链接&#xff1a;https://pan.baidu.com/s/1BaYqwruka1P6h5wBBrLiBw?pwdwrzo 提取码&#xff1a;wrzo 目录 一.手动部署 二.自动部署 一.手动部署 …

一次Redis访问超时的“捉虫”之旅

01 引言 作为后端开发人员&#xff0c;对Redis肯定不陌生&#xff0c;它是一款基于内存的数据库&#xff0c;读写速度非常快。在爱奇艺海外后端的项目中&#xff0c;我们也广泛使用Redis&#xff0c;主要用于缓存、消息队列和分布式锁等场景。最近在对一个老项目使用的docker镜…

Springboot+Vue项目-基于Java+MySQL的校园周边美食探索及分享平台系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

MySQL数据库企业级开发技术(下篇)

使用语言 MySQL 使用工具 Navicat Premium 16 代码能力快速提升小方法&#xff0c;看完代码自己敲一遍&#xff0c;十分有用 拖动表名到查询文件中就可以直接把名字拉进来中括号&#xff0c;就代表可写可不写 目录 1. 视图 1.1 需要视图的原因 1.2 视图介绍 1.2.1 …

[笔试强训day03]

文章目录 BC149 简写单词dd爱框框除2&#xff01; BC149 简写单词 BC149 简写单词 #include<iostream> #include<string>using namespace std; string s; int main() {while(cin>>s){if(s[0]>a&&s[0]<z) cout<<char(s[0]-32);else cout…

元数据管理Atlas

文章目录 一、Atlas概述1、Atlas入门2、Atlas架构原理 二、Atlas安装1、安装环境准备1.1 安装Solr-7.7.31.2 Atlas2.1.0安装 2、Atlas配置2.1 Atlas集成Hbase2.2 Atlas集成Solr2.3 Atlas集成Kafka2.4 Atlas Server配置2.5 Kerberos相关配置2.6 Atlas集成Hive 3、Atlas启动 三、…

Python可视化数据分析-柱状图/折线图

一、前言 使用python编写一个图表生成器&#xff0c;输入各公司的不良品数量&#xff0c;可以在一张图中同时展示数据的柱状图和折线图。 效果如下&#xff1a; 二、基础知识 绘制折线图和柱状图主要使用到了 pyecharts.charts 模块中的 Line 和 Bar 类。它们允许用户通过简…

拓展网络技能:利用lua-http库下载www.linkedin.com信息的方法

引言 在当今的数字时代&#xff0c;网络技能的重要性日益凸显。本文将介绍如何使用Lua语言和lua-http库来下载和提取LinkedIn网站的信息&#xff0c;这是一种扩展网络技能的有效方法。 背景介绍 在当今科技潮流中&#xff0c;Lua语言以其轻量级和高效的特性&#xff0c;不仅…

【单调栈】力扣85.最大矩形

好久没更新了 ~ 我又回来啦&#xff01; 两个好消息&#xff1a; 我考上研了&#xff0c;收到拟录取通知啦&#xff01;开放 留言功能 了&#xff0c;小伙伴对于内容有什么疑问可以在文章底部评论&#xff0c;看到之后会及时回复大家的&#xff01; 前面更新过的算法&#x…

经典目标检测YOLOV1模型的训练及验证

1、前期准备 准备好目录结构、数据集和关于YOLOv1的基础认知 1.1 创建目录结构 自己创建项目目录结构&#xff0c;结构目录如下&#xff1a; network CNN Backbone 存放位置 weights 权重存放的位置 test_images 测试用的图…

OpenFeign使用demo

OpenFeign使用demo 1. OpenFeign的作用2. OpenFeign使用demo2.1 使用方2.2 提供方 1. OpenFeign的作用 原来我们调用别人的接口&#xff0c;通常都是通过Http请求来(如下图1)&#xff0c;而现在有了OpenFeign我们就可以像调用接口的方式来完成调用。 OpenFeign 并不是一个严格…

Leetcode算法训练日记 | day31

专题九 贪心算法 一、分发饼干 1.题目 Leetcode&#xff1a;第 455 题 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的…

Matlab|含sop的配电网重构(含风光|可多时段拓展)

目录 1 主要内容 2 部分程序 3 下载链接 1 主要内容 之前分享了很多配电网重构的程序&#xff0c;每个程序针对场景限定性比较大&#xff0c;程序初学者修改起来难度较大&#xff0c;本次分享一个基础程序&#xff0c;针对含sop的配电网重构模型&#xff0c;含风电和光伏&am…