52.x86游戏实战-XXX获取房间坐标

news2024/9/28 7:19:43

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

本次游戏没法给

内容参考于:微尘网络安全

工具下载:

链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd=6tw3

提取码:6tw3

复制这段内容后打开百度网盘手机App,操作更方便哦

上一个内容:51.x86游戏实战-XXX返回城镇的实现

上一个内容里把返回城镇和副本内瞬移地图搞好了,接下来找一下当前角色所在副本中的哪个房间里,这样就能定位我们的位置

找位置的方式,首先打开游戏打开CE并附加到游戏,然后上上个内容里知道了副本内地图的分布方式(x、y),x和y都是从0开始,所以进入副本,使用CE搜索0,然后切换地图让它修改x或y的值,比如x变成1了,那就使用CE再搜索1,直到留下几个地址为止

下面开始实际操作

打开CE并附加游戏

然后游戏中进入副本,然后输入0点首次扫描

扫描出的结果有很多

然后在副本中移动到下一个地图,然后输入1然后点再次扫描,下图是点完再次扫描之后截的

然后再次在副本中切换地图(移动到x为2的地图),然后输入2然后点再次扫描,下图是点完再次扫描之后截的

然后再次在副本中切换地图(移动到x为3的地图),然后输入3然后点再次扫描,下图是点完再次扫描之后截的,这里剩下的就很少了

然后经过多次切换地图最终剩下三个,然后下图红框圈出来的地址,它的值变化的比较慢,所以直接把它当做是一个没用的值

然后就剩下下图红框的两个地址,这俩地址用哪个都是,可以都看看,哪个好找用哪个

然后接下来就用到硬件断点了,然后这个游戏就检测,所以先过一下检测,下图红框过检测,过检测在34.x86游戏实战-XXX过检测代码分析里写了

然后打开OD并附加到游戏,然后输入下图红框里的内容,然后按回车(Enter键)

可以看到它下一个位置也是1,在经过观察所在地图的坐标,可以猜测0x60767E00是x坐标,0x60767E04是y坐标

然后鼠标右击下一个硬件访问断点

然后断下来,ESI+0x610位置访问了x坐标

然后取消断点

然后在下图红框位置输入esi+0x610,然后按回车键,可以看到内存区没有变化,这说明esi+0x61确实是地图的x坐标

然后继续找看看esi的值哪来的,然后往上翻,看下图红框位置是最近一次赋值

然后在下图红框位置打断点,断点住之后输入绿框位置的内容并且按回车键

然后这里游戏掉线了,所以坐标的地址与之前不一样了,但是可以确认 [esi+0x8C]+0x610 是副本地图的x坐标

然后接下来继续找esi的值哪来的,往上翻(翻之前记得双击取消断点),然后看到下图红框位置是最近一次的赋值,esi的值来自于eax,然后mov esi,eax上一行是call eax调用了一个函数,eax寄存器一般用于接收函数的返回值,所以eax的值来自于call eax的返回值

然后在下图红框位置打断点

断点之后按F7,按F7之前记得双击地址取消断点进入call eax,然后发现它里面是ecx+0x14

然后断点住的过程在下图红框位置输入dd [[ecx+0x14]+0x8C]+0x610,可以看到它还是副本地图的x坐标

然后ecx的值来自于esi,esi的值来自于eax

然后eax来自于0x752980函数,然后在下图红框位置打断点,断点住之后按F7,进入0x752980函数

进来,然后一路F8看它走到了下图红框位置

然后执行了jmp直接就来到下图位置,这个函数就没法找了,所以这条路线算是找不到基址了

然后现在可以得到副本内x的坐标,然后再次下硬件访问断点,看看还有没有别的位置访问它,尝试别的位置取追

然后看还有下图红框位置访问地图的x坐标,这里也访问了y坐标,然后尝试在这里追

然后看到最终esi的值来自于eax+0x8C,然后eax的值来自于call eax

然后在下图位置打断点,看看call eax里面的逻辑

然后取消断点之后按F7,看到是ecx+0x20A050

然后在下图红框位置写dd [[ecx+0x20A050]+0x8C]+0x610看看对不对,它的值是对的,所以接下来找ecx的值

然后ecx的值来自于0x1A5FB18

然后在下图红框位置写 dd [[[0x1A5FB18]+0x20A050]+0x8C]+0x610,然后这样就得到x和y的地址了

然后写到C++代码里

首先添加两个变量,如下图红框

然后写下图的内容

然后重新编译

重新编译完使用wctool.exe注入,然后使用Dbgview.exe观察,正常显示,人物在下图红框位置坐标正好是x的值是1,y的值是0

MyStrust.cpp文件的内容:修改InitMy函数

#include "pch.h"
#include "MyStrust.h"

void MyStrust::InitMy()
{
	//  [[0x1AB7CDC]+0x258] 名字
	/*
		*这个符号表示地址,在c++中被称为指针或指针类型
		int表示4字节数字
		int*就表示指针类型的int
		(int*)0x1AB7CDC;这样表示0x1AB7CDC地址里的内容是4字节的数字
	*/
	int* address = (int*)0x1AB7CDC;
	/*
		取出地址中的值,也就是取出0x1AB7CDC里的内容
		*address这样在左边只写一个*表示取内存地址里的值
		也就是取address它的值,address是0x1AB7CDC,也就是取0x1AB7CDC它的值

	*/
	int addressValue = *address;
	/*
		(*(int*)addressValue)意思是
		把addressValue转成int*,也就是把
		addressValue的值当成内存地址,addressValue的值现在是[0x1AB7CDC]+0x258这个
		现在这个地址里面的值是名字的地址,所以在左边加了一个*让把名字的地址去除了出来
		取出来之后就得到了名字,名字是UNICODE类型,UNICODE又被称为宽字节,宽字节的数据是用两个字节描述一个文字或字母
		在c++里wchar_t类型就是UNICODE
		然后在c++中名字这种数据被称为字符串,如果要用字符串必须用指针类型也就是wchar_t*
		右边加上*让wchar_t变成指针类型的wchar_t,才能在c++中使用字符串

	*/
	this->My.Name = (wchar_t*)(*(int*)(addressValue+0x258));
	// 一般函数名后面是W就表示有UNICODE,也就是要用宽字节
	// OutputDebugStringW(this->My.Name);
	// L""这两个"之间表示字符串,L""表示这个字符串是宽字节(使用Unicode编码)
	call_logW(L"wetool:人物姓名=%ws,测试=%ws", this->My.Name,L" 52am");
	//  [[0x1AB7CDC]+0x18C]x坐标
	//  [[0x1AB7CDC]+0x190]y坐标
	/*
		取出地址中的值,也就是取出0x1AB7CDC里的内容
		*address这样在左边只写一个*表示取内存地址里的值
		也就是取address它的值,address是0x1AB7CDC,也就是取0x1AB7CDC它的值

	*/
 
	this->My.X= *(float*)(addressValue + 0x18C);
	this->My.Y = *(float*)(addressValue + 0x190);
	char buf[256] = { 0 };
	// 拼接文字,%f表示拼接一个小数(单浮点数)
	sprintf(buf, "wetool:x=%f;y=%f", this->My.X, this->My.Y);
	OutputDebugStringA(buf);

	// [[0x1AB7CDC]+0x36A0]血量
	this->My.Blood = *(int*)(addressValue + 0x36A0);
	// 拼接文字,%d表示拼接一个整数(32位的整数)
	sprintf(buf, "wetool:血量 = %d", this->My.Blood);
	OutputDebugStringA(buf);

	My.RoomX = ReadDword(ReadDword(ReadDword(ReadDword(0x1A5FB18) + 0x20A050) + 0x8C) + 0x610);
	My.RoomY = ReadDword(ReadDword(ReadDword(ReadDword(0x1A5FB18) + 0x20A050) + 0x8C) + 0x614);
	call_logA("wetool:副本内x坐标:%d,副本内y坐标:%d", My.RoomX, My.RoomY);
}

void MyStrust::UseObject(DWORD object)
{
	object += 3; // 背包物品序号
	/*
	  try的作用
		如果
		__asm {
			pushad
			push object
			mov ecx, 0x1A5FB24 // 背包基址
			mov ecx, [ecx]
			mov eax, 0x7B9130 // 使用物品的函数地址
			call eax
			popad
		}
		这个代码运行过程中出现错误了,我不会让游戏崩溃,出现错误之后会执行
		catch (...) {
			OutputDebugStringA("MyStrust::UseObject error");
		}
		这个catch里面的代码,现在也就是执行OutputDebugStringA("MyStrust::UseObject error");这一行
	*/
	try { 
		__asm {
			pushad
			push object
			mov ecx, 0x1A5FB24 // 背包基址
			mov ecx, [ecx]
			mov eax, 0x7B9130 // 使用物品的函数地址
			call eax 
			popad
		}
	}
	catch (...) {
		OutputDebugStringA("MyStrust::UseObject error");
	}
}

void MyStrust::ChangeBlooad(int v)
{
	try {
		__asm {
			pushad
			push 0
			push 0
			push 0
			push v
			mov ecx, 0x1AB7CDC // 里面有我们玩家角色数据的基址
			mov ecx, [ecx]
			mov eax, 0x8174E0 // 修改血量的函数地址
			call eax
			popad
		}
	}
	catch (...) {
		OutputDebugStringA("MyStrust::ChangeBlooad error");
	}
}

void MyStrust::NewChangeBlooad(DWORD nEcx)
{
	try {
		__asm {
			pushad
			push 0
			push 0
			push 0
			push 0
			mov ecx, nEcx
			mov eax, 0x8174E0 // 修改血量的函数地址
			call eax
			popad
		}
	}
	catch (...) {
		OutputDebugStringA("MyStrust::NewChangeBlooad error");
	}
}

// 遍历怪物列表函数,加吸怪
void MyStrust::FindMaster()
{
	wchar_t* Tmp1;
	/* 
		[[[[[0x1A5E258]+3*4+0xA8]+0x14]+0x88]+0x10]
		下方 ReadDword 函数通过 [[[[[0x1A5E258]+3*4+0xA8]+0x14]+0x88]+0x10] 这个取值算法得到附近列表(怪物列表)
	*/
	DWORD Tmp = ReadDword(ReadDword(ReadDword(ReadDword(ReadDword(0x1A5E258) + 0x3 * 4 + 0xA8) + 0x14) + 0x88) + 0x10);
	if (Tmp != 0) {// 如果是0说明没有找到怪物列表
		for (size_t i = 0; i < 100; i++)// 这里的100是随便写的
		{
			if (ReadDword(Tmp + i * 4)>0 && (ReadDword(ReadDword(Tmp + i * 4) + 0x90) == 0x211)) {
			//if (ReadDword(Tmp + i * 4)>0) {
				Tmp1 = (wchar_t*)ReadDword(ReadDword(Tmp + i * 4) + 0x258); // 0x258位置是名字
				if (Tmp1 == 0) {// 如果是0说明没有名字
					 //call_logW(L"wetool:NULL\n");
					 this->masterNum.Name[i] = L"";
				}
				else {
					/*
						打印名字到 Dbgview.exe,其中 wetool这个是为了过滤 Dbgview.exe打印的一些跟我们不相关的日志

					*/
					//call_logW(L"wetool:%ws\n", Tmp1);
					this->masterNum.Name[i] = Tmp1;
				}
				// 血量与玩家角色不是一个位置,可以在修改血量的位置追,这个不重要,后面有机会再找
				//masterNum.Blood[i] = ReadDword(ReadDword(Tmp + i * 4) + 0x90); 
				this->masterNum.type[i] = ReadDword(ReadDword(Tmp + i * 4) + 0x90);
				this->masterNum.x[i] = ReadFloat(ReadDword(Tmp + i * 4) + 0x18C);
				this->masterNum.y[i] = ReadFloat(ReadDword(Tmp + i * 4) + 0x190);
				
				this->masterNum.x[i] = this->My.X;
				this->masterNum.y[i] = this->My.Y;
				this->masterNum.Object[i] = ReadDword(Tmp + i * 4);
				
				*(FLOAT*)(ReadDword(ReadDword(Tmp + i * 4) + 0xA8) + 0xC) = this->My.X; // 修改之后会瞬移的坐标,把它的值赋值成我们玩家的坐标
				*(FLOAT*)(ReadDword(ReadDword(Tmp + i * 4) + 0xA8) + 0x10) = this->My.Y; // 修改之后会瞬移的坐标,把它的值赋值成我们玩家的坐标
				call_logW(L"wetool:第%d个对象:%x 怪物名字:%ls type:0x%x x:%f y:%f", i, this->masterNum.Object[i], this->masterNum.Name[i], this->masterNum.type[i], this->masterNum.x[i], this->masterNum.y[i]);
			}
		}
	}
	else {
		call_logA("wetool:Tmp error");
	}
}

// 吸怪加秒杀
void MyStrust::AllKill()
{
	try {
	this->InitMy();
	this->FindMaster();
	for (size_t i = 0; i < 100; i++)
	{
		if (this->masterNum.Object[i] > 0 && (this->masterNum.type[i] == 0x211)) {
		
				call_logW(L"wetool:AllKill-第%d个对象:%x 怪物名字:%ls type:0x%x x:%f y:%f", i, this->masterNum.Object[i], this->masterNum.Name[i], this->masterNum.type[i], this->masterNum.x[i], this->masterNum.y[i]);
				this->NewChangeBlooad(this->masterNum.Object[i]);// 调用修改血量的函数
		}
	}
	}
	catch (...) {
		OutputDebugStringA("MyStrust::AllKill error");
	}
}

void MyStrust::StartIn()
{
	try {
		__asm
		{
			pushad
			// 切换地图
			push 0x26
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1127D60
			call eax

			push 0xE
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128550
			call eax

			push 0x2
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128550
			call eax

			push 0x1E
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128580
			call eax

			push 0x10F
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128580
			call eax

			push 0x5
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128550
			call eax

			push 0xE
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128580
			call eax

			push 0x1
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128580
			call eax

			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1127EC0
			call eax
			// 进入副本选择界面
			push 0xF
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1127D60
			call eax

			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1127EC0
			call eax
			// 进入副本
			push 0x10
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1127D60
			call eax

			push 0x68
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128580
			call eax

			push 0
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128550
			call eax

			push 0
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128550
			call eax

			push 0
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1128550
			call eax

			mov eax, 0x1127EC0
			call eax

			popad

			// 进入副本选择界面
			pushad

			push 0xF
			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1127D60
			call eax

			mov ecx, 0x1AEB6E4
			mov ecx, [ecx]
			mov eax, 0x1127EC0
			call eax
			popad

		}
	}
	catch (...)
	{
		OutputDebugStringA(" MyStrust::StartIn error");
	}

}

void MyStrust::MoveInMap(DWORD x, DWORD y)
{
	try {
		DWORD nEcx = *(DWORD*)0x1AEB6E4;
		__asm {
			pushad

			push 0x30
			mov ecx, nEcx
			mov eax, 0x1127D60
			call eax

			// 这里的0x2它是地图x的数据
			push x
			mov ecx, nEcx
			mov eax, 0x1128550
			call eax
			// 这里的0x1它是地图y的数据
			push y
			mov ecx, nEcx
			mov eax, 0x1128550
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x11285B0
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x11285B0
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x1128550
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x1128580
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x1128580
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x1128580
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x1128580
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x1128580
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x11285B0
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x11285B0
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x11285B0
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x11285B0
			call eax

			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x1128580
			call eax
			// 入参没用
			push 0x0
			mov ecx, nEcx
			mov eax, 0x11285B0
			call eax

			mov ecx, nEcx
			mov eax, 0x1127EC0
			call eax

			popad
		}
	}catch (...) {
		OutputDebugStringA(" MyStrust::StartIn error");
	}

}

void MyStrust::ComeBackTwon()
{
	try {
		DWORD nEcx = *(DWORD*)0x1AEB6E4;
		__asm {
			pushad
			mov ecx, 0x1A3CBF4
			mov ecx, [ecx]
			push 0x138D
			mov eax, 0x4E9740
			call eax
			popad
		}
	}
	catch (...) {
		OutputDebugStringA(" MyStrust::ComeBackTwon error");
	}
}

MyStrust.h文件的内容:修改 Myself结构体

#pragma once
struct Myself {
	DWORD Blood;// 血量
	FLOAT X; // x坐标
	FLOAT Y; // y坐标
	wchar_t* Name; // 名字
	DWORD RoomX; // 副本内的x坐标
	DWORD RoomY; // 副本内的y坐标
};

struct Master {
	DWORD Object[100];
	DWORD Blood[100];
	FLOAT x[100];
	FLOAT y[100];
	wchar_t* Name[100];
	DWORD type[100];
};

class MyStrust
{
public:
	Myself My;
	Master masterNum;
	void InitMy();// 玩家角色基本信息(血量、名字、坐标)
	void UseObject(DWORD object); // 修改血量
	void ChangeBlooad(int v); // 使用物品
	void NewChangeBlooad(DWORD nEcx);
	void FindMaster();// 遍历怪物
	void AllKill(); // 吸怪加秒杀
	void StartIn();// 秒进副本
	void MoveInMap(DWORD x, DWORD y); // 副本内瞬移
	void ComeBackTwon(); // 返回城镇
};

上方的代码不全,只有手写的代码

完整代码:以 51.x86游戏实战-XXX返回城镇的实现 它的代码为基础进行修改

链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg?pwd=q9n5

提取码:q9n5

复制这段内容后打开百度网盘手机App,操作更方便哦


img

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

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

相关文章

【Docker】个人笔记

文章目录 Docker三个基本概念镜像(Image)容器(Container)仓库(Repository) Docker命令基础命令查看版本信息显示详细信息从仓库拉取镜像列出本地存储的镜像删除一个或多个镜像列出所有运行中的容器运行一个新的容器停止一个运行中的容器启动一个已停止的容器重启一个容器删除一…

论文泛读: DETRs Beat YOLOs on Real-time Object Detection

[toc[ DETRs Beat YOLOs on Real-time Object Detection 论文地址: https://openaccess.thecvf.com/content/CVPR2024/html/Zhao_DETRs_Beat_YOLOs_on_Real-time_Object_Detection_CVPR_2024_paper.html 代码地址: https://zhao-yian.github.io/RTDETR 动机 现状 YOLO系列因…

车联网技术在智能交通系统中的设计与实现(论文+源码)

1系统方案设计 根据系统设计需求&#xff0c;展开系统详细方案设计。如图2.1所示为系统设计结构框图。系统以STM32单片机为主控制器&#xff0c;利用ATGM336 GPS模块实现车辆实时定位&#xff0c;借助倾斜检测模块监测车辆倾斜角度&#xff0c;并通过OLED液晶显示器实时显示监…

揭晓9款敏捷团队必备的协作工具选择

本文将介绍9款团队协作工具&#xff1a;1.Worktile&#xff1b;2. PingCode&#xff1b;3. 融云 (RongCloud)&#xff1b;4. 好团队&#xff1b;5. 微软Teams&#xff1b;6. 小钉贴&#xff1b;7. Lark&#xff1b;8. Bit.ai&#xff1b;9. Hive。 在敏捷开发团队中&#xff0c…

Veeam Backup Replication v12.2 发布,新增功能概述

Veeam Backup & Replication v12.2 发布&#xff0c;新增功能概述 Veeam Data Platform | 面向混合云和多云的 备份和恢复 监控和分析 恢复编排 请访问原文链接&#xff1a;https://sysin.org/blog/veeam-backup-12/&#xff0c;查看最新版。原创作品&#xff0c;转载请保…

烂大街的测试左移和右移

01 测试左移与右移的定义 通俗的讲&#xff1a;左移是往开发阶段移&#xff0c;右移是往发布之后移。 正常测试&#xff1a;提测后的测试工作——到——发布验证完成阶段。 测试左移&#xff1a;提测之前的测试。 如&#xff1a;代码单元测试&#xff0c;代码质量检测&#x…

数据结构的三要素以及数据类型和抽象数据类型

一.数据结构的三要素&#xff1a; 二.逻辑结构&#xff1a; 三.数据的运算&#xff1a; 三.数据的物理结构&#xff08;存储结构&#xff09;&#xff1a; 1.数据的存储结构&#xff1a;有4种 顺序存储 链式存储 索引存储 散列存储 注&#xff1a;顺序存储数据之间必须相…

没有编程基础?这款数据分析工具也能轻松上手

在当前快节奏的工业环境中&#xff0c;工厂管理者越来越依赖数据分析来优化生产流程、提升效率、降低成本。然而&#xff0c;很多传统的数据分析工具不仅操作复杂&#xff0c;而且费用高昂&#xff0c;让不少工厂望而却步。最近&#xff0c;我发现了一款非常实用的报表工具&…

[MySql]保姆级上手教程

介绍 通过数据库管理系统, 编写执行SQL语句, 实现对数据库数据的管理 数据库(DataBase): 储存和管理数据的仓库数据库管理系统(DBMS): 操作和管理数据库的软件SQL语言: 操作关系型数据库的通用语言数据库可以分为关系型数据库和非关系型数据库 相关产品 常见的关系型数据库产…

STM32G474之TIM1捕获1模式

STM32G474采用TIM8产生方波信号&#xff0c;使用TIM1工作于捕获1模式&#xff0c;并计算方波频率。捕获方波周期&#xff0c;在有些开发中&#xff0c;还是能用到。建议开发时使用HAL库自带的库函数。使用寄存器方法也可以实现&#xff0c;但是后期修改不太方便。 测试时&…

springboot学习(2)

1、springboot入门 需求&#xff1a;使用 Springboot 开发一个 web 应用&#xff0c;浏览器发起请求 /hello 后&#xff0c;给浏览器返回字符串 "hello world!" 2、基本尝试步骤 创建Maven工程导入 spring-boot-starter-web (起步依赖)编写Controller提供启动类 &…

无人机 PX4 飞控 | ROS应用层开发:offboard 模式切换详细总结

无人机 PX4 飞控 | ROS应用层开发&#xff1a;offboard 模式切换详细总结 PX4 offboard 模式介绍通过mavros 进行offboard模式切换代码测试 通过地面站进行offboard模式切换通过遥控器拨杆切换offboard模式 PX4 offboard 模式介绍 PX4 是一个广为熟知的开源飞控软件&#xff0…

Yolo环境搭建(深度学习基础环境)

需要安装的东西 CUDAcuDnn魔法 一、CUDA安装(Windows10环境) 第一&#xff1a;下载驱动 第二&#xff1a;查看显卡支持的最高CUDA的版本&#xff0c;以便下载对应的CUDA安装包 第三&#xff1a;确定CUDA版本对应的cuDNN版本&#xff0c;这个其实不用太关注&#xff0c;因为…

宾得相机sd卡格式化了怎么办?分享应对之策

对于摄影爱好者而言&#xff0c;‌相机不仅是捕捉美好瞬间的设备&#xff0c;‌更是珍藏回忆的宝库。‌然而&#xff0c;‌在使用宾得相机的过程中&#xff0c;‌可能会遇到SD卡意外格式化的情况&#xff0c;‌这无疑给许多摄影爱好者带来了不小的困扰。‌SD卡格式化后&#xf…

Shell脚本入门:多命令处理

我的后端学习大纲 我的Linux学习大纲 1.什么是多命令处理 1.多命令处理就是在Shell脚本文件中编写多个Shell命令 2.入门案例&#xff1a; 2.1.需求介绍&#xff1a; 1.在已知目录/root/itheima目录&#xff0c;执行batch.sh脚本&#xff0c;实现在/root/itheima/目录下创建一…

PDF文本指令解析与文本水印去除

上次我在《PDF批量加水印 与 去除水印实践》一文中完成了对图片水印和文字水印的去除。 链接&#xff1a;https://xxmdmst.blog.csdn.net/article/details/139483535 但是对于页面对象的内容对象是单层&#xff0c;不是数组的情况&#xff0c;无法去除水印。今天我们专门研究…

Error running tomcat: Can‘t find catalina.jar

一、错误描述&#xff1a; 在运行 java-web项目时出现报错&#xff1a;Error running tomcat: Can‘t find catalina.jar 二、错误原因&#xff1a; tomcat的路径错误&#xff0c;在idea中配置正确的tomcat路径 三、解决方法&#xff1a; 1.点击EditConfigurations 2.点…

如何通过WinRAR软件有效禁止RAR压缩包内文件的修改

RAR压缩包作为一种广泛使用的文件格式&#xff0c;凭借其高压缩比和强大的功能&#xff0c;成为了许多用户保存和传输文件的首选。然而&#xff0c;在某些情况下&#xff0c;我们可能希望确保RAR压缩包内的文件不被随意修改或删除&#xff0c;以维护文件的安全性和完整性。本文…

CANoe入门(四) :全真实节点阶段和真实节点和部分仿真节点共存阶段,读取和模拟数据

1. 前言 前篇文章我们在CANoe全仿真阶段&#xff0c;模拟数据和信号。这篇文章&#xff0c;我们来看下全真实节点阶段和真实节点和部分仿真节点共存阶段&#xff0c;怎么读取数据信号&#xff0c;和模拟发送数据信号。 2. 全真实节点阶段 全真实节点阶段&#xff0c;所有的 …

LeetCode_sql_day18(1841.联赛信息统计)

描述 表: Teams ------------------------- | Column Name | Type | ------------------------- | team_id | int | | team_name | varchar | ------------------------- team_id 是该表主键. 每一行都包含了一个参加联赛的队伍信息.表: Matches -------…