Windows核心编程 跨进程操作

目录

进程A拿到进程B句柄是否能用

句柄的权限

关于句柄表

跨进程使用句柄-继承

CreateProcess:bInheritHandles 

OpenProcess

FindWinodw

GetCurrentProcess

跨进程使用句柄-拷贝

跨进程操作内存

WriteProcessMemory

VirtualProtectEx

ReadProcessMemory


进程A拿到进程B句柄是否能用

创建两个基于对话框的MFC分别为A,B

MFC A

ZeroMemory(&si, sizeof(si)); 是一段用于清空内存的代码,它使用了Windows操作系统提供的ZeroMemory函数。

该函数接受两个参数:第一个参数是指向要清空的内存块的指针,第二个参数是要清空的内存块的大小(以字节为单位)。

在这段代码中,&si 是指向变量 si 的指针,sizeof(si) 则是获取变量 si 所占用的内存块的大小。ZeroMemory函数将会将此内存块中的所有字节都设置为0。

void CADlg::OnBnClickedButton1()
{STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));// Start the child process. if (!CreateProcess(NULL, // No module name (use command line). "B.exe", // Command line. NULL,             // Process handle not inheritable. NULL,             // Thread handle not inheritable. FALSE,            // Set handle inheritance to FALSE. 0,                // No creation flags. NULL,             // Use parent's environment block. NULL,             // Use parent's starting directory. &si,              // Pointer to STARTUPINFO structure.&pi)             // Pointer to PROCESS_INFORMATION structure.){AfxMessageBox("CreateProcess failed.");}//显示句柄值SetDlgItemInt(EDT_HANDLE, (UINT)pi.hProcess);
}

MFC B

void CBDlg::OnBnClickedButton1()
{HANDLE hProc = (HANDLE)GetDlgItemInt(EDT_HANDLE);::TerminateProcess(hProc, 0);}

修改输出目录

输出目录如下: 

经过实验后:进程B是无法结束进程A的

剖析:一个进程,它所打开的句柄(或者说它所获得的句柄),进程都会把句柄存起来,这样就会形成一个表记录进程拿到哪些句柄;这个表叫做句柄表;

在B进程的句柄表中,并没有自己的进程的句柄,所以就算手动把A进程的句柄给B进程;让B进程结束——B进程表示在自己的句柄表中找不到自己的进程的句柄,所以报错,传入的句柄是无效句柄;

句柄的权限

句柄的权限是指操作系统对于句柄所代表的对象所授予的操作权限。不同类型的对象(如文件、进程、线程等)具有不同的权限集合。以下是一些常见的句柄权限:

  1. 文件权限:
  • FILE_READ_DATA:允许读取文件内容。
  • FILE_WRITE_DATA:允许写入文件内容。
  • FILE_APPEND_DATA:允许在文件末尾追加数据。
  • FILE_EXECUTE:允许执行文件。
  • FILE_DELETE:允许删除文件。
  • FILE_READ_ATTRIBUTES:允许读取文件属性。
  • FILE_WRITE_ATTRIBUTES:允许修改文件属性。
  1. 进程和线程权限:
  • PROCESS_CREATE_PROCESS:允许创建子进程。
  • PROCESS_TERMINATE:允许终止进程。
  • PROCESS_QUERY_INFORMATION:允许查询进程信息。
  • THREAD_CREATE_THREAD:允许创建线程。
  • THREAD_TERMINATE:允许终止线程。
  • THREAD_QUERY_INFORMATION:允许查询线程信息。
  1. 窗口权限:
  • GWL_STYLE:允许设置窗口样式。
  • GWL_EXSTYLE:允许设置窗口扩展样式。
  • WM_CLOSE:允许关闭窗口。
  • WM_DESTROY:允许销毁窗口。

这些仅是一些常见的句柄权限示例,实际上句柄的权限取决于所代表对象的类型和操作系统的安全策略。在使用句柄进行操作时,需要根据具体的需求和操作对象的类型来确定所需的权限,以确保在合法范围内进行操作。

关于句柄表

Windows操作系统中的句柄表通常被划分为以下三层:

  1. 用户层:用户层是最高层,包含了应用程序和操作系统之间的交互接口。在用户层,开发人员可以使用操作系统提供的API函数来创建和操作各种内核对象,如文件、进程、线程、窗口、消息等。
  2. 内核层:内核层是操作系统的核心,包括了内核、设备驱动程序等。在内核层,操作系统可以直接访问硬件资源,提供更加底层的操作接口。
  3. 硬件层:硬件层包含了操作系统所运行的计算机的物理硬件设备,如CPU、内存、硬盘、网络设备等。

句柄表通常被放置在内核层,用于管理应用程序和内核对象之间的关系。操作系统为每个进程维护一个独立的句柄表,该句柄表包含了该进程所拥有的句柄。在内核层,操作系统使用句柄来标识和访问内核对象。句柄通常被视为指向内核对象的指针,开发人员可以使用操作系统提供的API函数来获取、创建、操作句柄,并使用句柄来操作内核对象。

父进程和子进程:(A创建的进程都是A的子进程)
父进程和子进程从使用的角度讲,没有什么非常特殊操作的关系,是两个单独的进程,各有4g内存,各自有各自的线程,堆和栈,是独立的;使用的过程中,特别:进程句柄的时候用到父子进程,让项目的结构方便一点,
子进程有父进程的进程id,系统管理进程是由结构体管理的,由表管理,在内核里面,子进程的内核存有父进程的id信息;

跨进程使用句柄-继承

继承父进程的条件:

句柄本身可以被继承,CreateProcess的bInHeritHandle为TRUE。

子进程只能继承在自身被创建之前父进程打开的句柄,自身创建后父进程打开的句柄无法继承。

也就是说,CreateProcess创建进程B,进程B不能继承自身的句柄,自身句柄创建完之后才能拿到。解决办法是:

  1. 获取自己进程的句柄:GetCurrentProcess。返回值为-1,是个伪句柄,该句柄用于操作自身。
  2. 句柄本身也是带有私有公有属性的,和C++的继承很像,所以句柄都有一个是否可被继承的属性,这个属性由OpenProcess函数决定

CreateProcess:bInheritHandles 

新进程是否继承来自父进程的句柄。TRUE则继承。

子进程继承父进程已经打开了的句柄,只能在父子进程之间使用,CreateProcess中的第五个参数可以设置继承关系,TRUE就是可以被子进程继承,FALSE就不会被继承:

CreateProcess:参数三四安全属性指明创建出的子进程的进程句柄和线程句柄能否被继承

安全描述符是一个结构体SECURITY_ATTRIBUTES;定义如下

第一个参数是长度大小,第二个参数一般填NULL,第三个成员决定是否被继承

OpenProcess

OpenProcess函数将打开指定PID的进程,并返回一个与该进程关联的句柄。如果成功,返回的句柄可用于后续的操作,如读取或写入进程的内存、终止进程等。如果操作失败,返回NULL或INVALID_HANDLE_VALUE。

1 // 作用:打开一个存在的进程对象。(获取进程句柄)
2 // 返回值:成功返回进程句柄,失败返回NULL。
3 HANDLE OpenProcess(
4  DWORD dwDesiredAccess, 	// 权限标志,一般填PROCESS_ALL_ACCESS通杀
5  BOOL bInheritHandle, 	// OpenProcess打开的句柄能否被子进程继承
6  DWORD dwProcessId 		// 进程ID
7  );

OpenProcess函数是Windows操作系统提供的函数之一,用于打开一个已存在的进程并返回一个与该进程关联的句柄。它的参数如下:

  1. dwDesiredAccess:指定打开进程的访问权限,即访问级别。可以使用以下常量进行设置:

    • PROCESS_ALL_ACCESS:具有完全访问权限的句柄,可以执行任意操作。
    • PROCESS_CREATE_PROCESS:允许创建进程。
    • PROCESS_CREATE_THREAD:允许创建线程。
    • PROCESS_DUP_HANDLE:允许复制句柄。
    • PROCESS_QUERY_INFORMATION:允许查询进程信息。
    • PROCESS_QUERY_LIMITED_INFORMATION:允许有限查询进程信息。
    • PROCESS_SET_INFORMATION:允许设置进程信息。
    • PROCESS_SET_QUOTA:允许设置进程配额。
    • PROCESS_SUSPEND_RESUME:允许挂起或恢复进程。
    • PROCESS_TERMINATE:允许终止进程。
    • PROCESS_VM_OPERATION:允许对进程进行虚拟内存操作。
    • PROCESS_VM_READ:允许读取进程的虚拟内存。
    • PROCESS_VM_WRITE:允许写入进程的虚拟内存。
  2. bInheritHandle:指定打开的句柄是否可被子进程继承。如果为TRUE,则可被子进程继承;如果为FALSE,则不能被子进程继承。

  3. dwProcessId:要打开的进程的标识符(PID)。可以通过其他函数(如EnumProcesses)获取进程的PID,或者使用特定的值来表示特定的进程,如GetCurrentProcessId()表示当前进程的PID。

FindWinodw

FindWindow函数是Windows操作系统提供的函数之一,用于查找具有指定类名和窗口名的顶级窗口。它的参数如下:

  1. lpClassName:指定要查找的窗口类名。可以是一个字符串指针,指向类名的字符串,也可以是预定义的常量,如"Button"、"Edit"等。如果想要查找所有窗口,请将该参数设置为NULL。

  2. lpWindowName:指定要查找的窗口名。可以是一个字符串指针,指向窗口名的字符串。如果想要查找具有指定类名但没有特定窗口名的窗口,请将该参数设置为NULL。

FindWindow函数将根据提供的类名和窗口名在系统中查找匹配的顶级窗口。如果找到匹配的窗口,将返回该窗口的句柄(HWND)。否则,返回NULL。

// 作用:获取窗口句柄。
// 返回值:成功返回窗口句柄,失败返回NULL。
// 备注:参数二填一即可,另一个写NULL。
HWND FindWindow(LPCTSTR lpClassName, // 类名LPCTSTR lpWindowName // 窗口名);

GetCurrentProcess

// 作用:获取自身进程句柄。
// 返回值:恒为‐1。对任何进程而言,‐1代表自身进程的句柄,‐1是个伪句柄。
HANDLE GetCurrentProcess(void);

测试代码

一个设置句柄权限包括是否可被继承,一个设置可被子进程继承。

//使用继承跨进程使用句柄
void CADlg::OnBnClickedButton1()
{STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));SECURITY_ATTRIBUTES sa = {};sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; //允许进程句柄被子进程继承(赋予保护/公有属性)sa.lpSecurityDescriptor = NULL;// Start the child process. if (!CreateProcess(NULL, // No module name (use command line). "B.exe", // Command line. &sa,             // 允许此句柄被继承NULL,             // Thread handle not inheritable. TRUE,            // 允许子进程继承句柄0,                // No creation flags. NULL,             // Use parent's environment block. NULL,             // Use parent's starting directory. &si,              // Pointer to STARTUPINFO structure.&pi)             // Pointer to PROCESS_INFORMATION structure.){AfxMessageBox("CreateProcess failed.");}//显示句柄值SetDlgItemInt(EDT_HANDLE, (UINT)pi.hProcess);}

跨进程使用句柄-拷贝

把句柄拷贝到别的进程,有没有父子关系都无所谓,从自己的句柄表里拷贝到对方的句柄表里,注意是拷贝一个句柄而不是一个句柄表,继承才是把句柄表打包一份。说是拷贝实际上对方是重新获取了。

拷贝函数DuplicateHandle

BOOL DuplicateHandle(HANDLE   hSourceProcessHandle,  // 源进程句柄HANDLE   hSourceHandle,         // 源句柄HANDLE   hTargetProcessHandle,  // 目标进程句柄LPHANDLE lpTargetHandle,        // 目标句柄DWORD    dwDesiredAccess,       // 访问权限BOOL     bInheritHandle,        // 是否可被继承DWORD    dwOptions              // 选项
);

参数说明: 

  • hSourceProcessHandle:源进程的句柄,即拥有要复制句柄的进程。
  • hSourceHandle:要复制的句柄,即源句柄。
  • hTargetProcessHandle:目标进程的句柄,即要将复制的句柄关联到的进程。
  • lpTargetHandle:指向目标句柄的指针,用于接收复制后的句柄。

当调用DuplicateHandle函数时,有三个参数需要指定具体的取值:

  1. dwDesiredAccess:表示复制后句柄的访问权限。可以使用以下访问权限常量进行设置,也可以通过逻辑或运算符(|)组合多个权限:
  • GENERIC_READ:允许对对象进行读取操作。
  • GENERIC_WRITE:允许对对象进行写入操作。
  • GENERIC_EXECUTE:允许对对象进行执行操作。
  • GENERIC_ALL:允许对对象进行所有操作。

此外,还可以使用特定对象类型的访问权限常量,例如FILE_READ_DATA、FILE_WRITE_DATA等。具体取值取决于复制的句柄所代表的对象类型。

  1. bInheritHandle:表示目标句柄是否可被子进程继承。如果值为TRUE,则子进程可以继承目标句柄;如果值为FALSE,则子进程不会继承目标句柄。

  2. dwOptions:表示一些额外的选项。可以使用以下常量进行设置:

  • 0:没有额外的选项。
  • DUPLICATE_SAME_ACCESS:复制后的句柄将具有与源句柄相同的访问权限。

使用DUPLICATE_SAME_ACCESS选项时,dwDesiredAccess参数中的访问权限可以省略,复制后的句柄将具有与源句柄相同的访问权限。

适用场景:跨权限操作一些东西。比如有system权限的进程拿到句柄给管理员权限的进程用。

伪句柄:把进程自身-1的句柄值拷贝给自己,可以获取进程自身真正的句柄值。

此时 -1 对应的就是当前获取的句柄,它操作的是它自己,这就是伪句柄。

void CADlg::OnBnClickedButton1()
{STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));// Start the child process. if (!CreateProcess(NULL, // No module name (use command line). "B.exe", // Command line. NULL,             // 不允许此句柄被继承NULL,             // Thread handle not inheritable. TRUE,             // 不允许子进程继承句柄0,                // No creation flags. NULL,             // Use parent's environment block. NULL,             // Use parent's starting directory. &si,              // Pointer to STARTUPINFO structure.&pi)              // Pointer to PROCESS_INFORMATION structure.){AfxMessageBox("CreateProcess failed.");}HANDLE hProcInDst = NULL;BOOL fSuccess = DuplicateHandle(GetCurrentProcess(), pi.hProcess, //被拷贝的句柄pi.hProcess, //拷贝到B进程&hProcInDst,0,FALSE,DUPLICATE_SAME_ACCESS);if (!fSuccess)AfxMessageBox("DuplicateHandle failed");//显示句柄值SetDlgItemInt(EDT_HANDLE, (UINT)hProcInDst);}

句柄表里没有自身进程的记录

跨进程操作内存

跨进程读写内存的办法

1. Winhex手动修改进程内存:open Memory - 目标进程 - 修改完保存(写入进程内存)。

2. API修改:跨进程写内存 - WriteProcessMemory。内存属性不可写会写入失败。

3. 跨进程读内存 - ReadProcessMemory。

内存属性

1. 内存访问属性:R读,W写,X执行,C写时拷贝。修改内存访问属性:VirtualProtectEx。

2. ProcessHacker看内存属性:exe双击 - Memory - Protection。

3. WriteProcessMemory不用判断内存属性,每次写之前修改内存属性,写完后还原内存属性。

4. 写完数据不还原属性:会被检测(向只读内存写入数据,看是否触发异常,触发则表明正常)

PS:内存的基本单位4k【一个分页0x1000】,所以当修改0x1225的内存属性实则修改了0x0 ~ 0x2048的内存属性

内存分页

1. 内存分页:大小0x1000(4096),4kb。系统管理内存的基本单位。属性改一字节影响一个分页。

2. 申请内存时,系统至少分配一个分页,一个字节也分配一个分页。

3. new和malloc是在系统分配的基础上再次分配,在系统分配的分页中再次分配需要的字节。

再次以内存属性来看常量区等可读不可写区域

操作系统喜欢将统一权限属性的放在一起的原因是方便管理,且不浪费内存,也更容易维护。

WriteProcessMemory

1 // 作用:将数据写入指定进程内存。
2 BOOL WriteProcessMemory(
3  HANDLE hProcess, // 目标进程句柄
4  LPVOID lpBaseAddress, // 需要修改目标进程的地址
5  LPCVOID lpBuffer, // 写入数据缓冲区
6  SIZE_T nSize, // 写入数据缓冲区的大小
7  SIZE_T * lpNumberOfBytesWritten // 传出参数(可选),写入成功的数据大小,不
需要可以填NULL
8  );

VirtualProtectEx

 // 作用:修改内存的访问属性。
BOOL VirtualProtectEx(HANDLE hProcess, // 目标进程句柄LPVOID lpAddress, // 修改属性的内存地址SIZE_T dwSize, // 修改属性的内存大小DWORD flNewProtect, // 修改后的内存访问属性PDWORD lpflOldProtect // 传出参数,修改前的内存访问属性,填NULL会调用失败
);参数3:修改属性的内存大小
修改内存属性会影响到这一段地址空间涉及到的所有内存分页。
跨越页面边界的2字节范围会导致两个页面的保护属性都被更改。参数4:内存属性
PAGE_READONLY 只读
PAGE_READWRITE 可读可写
PAGE_WRITECOPY 写时拷贝
PAGE_EXECUTE 可执行
PAGE_EXECUTE_READ 可执行可读
PAGE_EXECUTE_READWRITE 可执行可读写
PAGE_EXECUTE_WRITECOPY 可执行可写时拷贝

ReadProcessMemory

BOOL ReadProcessMemory(  HANDLE hProcess,              // handle to the processLPCVOID lpBaseAddress,        // base of memory areaLPVOID lpBuffer,              // data bufferSIZE_T nSize,                 // number of bytes to readSIZE_T * lpNumberOfBytesRead  // number of bytes read);

飞机躲子弹-无敌模式

1.编写飞机躲子弹工具0x00406D6C   4   nplanX,  当前飞机位置
0x00406D70   4   nplanY,
0x00406E10   4   子弹数组首地址
0x00406DA8   4   当前子弹的个数
0x00406D80   4   死亡标志
0x004020F5   1   速度
0x00403616   0xeb  __asm jmp    无敌模式0x74  __asm je     普通模式
0x0040469E   4    初始子弹个数nBulletX >>= 6;nBulletX -= 4;nBulletY >>= 6;nBulletY -= 4;+=0xF子弹:
x坐标 = ary[i * 0xf +0] >>= 6 -= 4
y坐标 = ary[i * 0xf =4] >>= 6 -= 4

代码如下


void CGameAssistDlg::Wudi(BYTE bt)
{//获取窗口句柄HWND hWndGame = ::FindWindow(NULL, "摿孭");if (hWndGame == NULL){AfxMessageBox("获取窗口句柄失败");return;}//获取进程IDDWORD dwProId = 0;DWORD dwThreadId = GetWindowThreadProcessId(hWndGame, &dwProId);if (dwThreadId == 0){AfxMessageBox("获取进程id失败");return;}//获取进程句柄HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProId);if (hProc == NULL){AfxMessageBox("获取进程句柄失败");return;}//修改内存属性LPVOID pAddrGod = (LPVOID)0x00403616;//BYTE bt = 0xeb;DWORD dwOldProc = 0;BOOL bRet = VirtualProtectEx(hProc, pAddrGod, sizeof(bt), PAGE_READWRITE, &dwOldProc);if (!bRet){AfxMessageBox("修改内存属性失败");return ;}//修改内存bRet = WriteProcessMemory(hProc, pAddrGod, &bt, sizeof(bt), NULL);if (!bRet){AfxMessageBox("无敌失败");}//修改完后还原内存属VirtualProtectEx(hProc, pAddrGod, sizeof(bt), dwOldProc, &dwOldProc);//释放进程句柄CloseHandle(hProc);
}

 修改前0x400000是可读的

修改后

还原内存属性

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

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

相关文章

浏览器缓存控制讲解

缓存的作用 在你访问互联网中的任何资源其所产生的任何链路中的每一个节点几乎都会进行缓存,整个缓存体系和细节十分复杂。比如浏览器缓存,服务器缓存,代理服务器缓存,CDN缓存等。 但是缓存又十分重要,不可缺少&…

NX二次开发UF_CURVE_ask_curve_struct_data 函数介绍

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_curve_struct_data Defined in: uf_curve.h int UF_CURVE_ask_curve_struct_data(UF_CURVE_struct_p_t curve_struct, int * type, double * * curve_data ) overview…

情感对话机器人的任务体系

人类在处理对话中的情感时,需要先根据对话场景中的蛛丝马迹判断出对方的情感,继而根据对话的主题等信息思考自身用什么情感进行回复,最后结合推理出的情感形成恰当的回复。受人类处理情感对话的启发,情感对话机器人需要完成以下几…

从0开始学习JavaScript--深入了解JavaScript框架

JavaScript框架在现代Web开发中扮演着关键角色,为开发者提供了丰富的工具和抽象层,使得构建复杂的、高性能的Web应用变得更加容易。本文将深入探讨JavaScript框架的核心概念、常见框架的特点以及它们在实际应用中的使用。 JavaScript框架的作用 JavaSc…

STM32 寄存器配置笔记——USART配置中断接收乒乓缓存处理

一、概述 本文主要介绍如何配置USART接收中断,使用乒乓缓存的设计接收数据并将其回显在PC 串口工具上。以stm32f10为例,配置USART1 9600波特率。具体配置参考上一章节STM32 寄存器配置笔记——USART配置 打印。 乒乓缓存的设计应用场景:当后面…

【ceph】如何打印一个osd的op流程,排查osd在干什么

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》:python零基础入门学习 《python运维脚本》: python运维脚本实践 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8…

canvas高级动画001:文字瀑布流

canvas实例应用100 专栏提供canvas的基础知识,高级动画,相关应用扩展等信息。 canvas作为html的一部分,是图像图标地图可视化的一个重要的基础,学好了canvas,在其他的一些应用上将会起到非常重要的帮助。 文章目录 示例…

elk 简单操作手册

1.1. 基础概念 EFK不是一个软件,而是一套解决方案,开源软件之间的互相配合使用,高效的满足了很多场合的应用,是目前主流的一种日志系统。 EFK是三个开源软件的缩写,分别表示:Elasticsearch , Filebeat, Kibana , 其中Elasticsearch负责日志保存和搜索,Filebeat负责收集日志,Ki…

EI期刊完整程序:MEA-BP思维进化法优化BP神经网络的回归预测算法,可作为对比预测模型,丰富内容,直接运行,免费

适用平台:Matlab 2020及以上 本程序参考中文EI期刊《基于MEA⁃BP神经网络的建筑能耗预测模型》,程序注释清晰,干货满满,下面对文章和程序做简要介绍。 适用领域:风速预测、光伏功率预测、发电功率预测、碳价预测等多…

eclipse项目移到idea上部署运行

1.配置web模块 另外,模块这里,也要加上Spring 2.配置Artifact (用于tomcat) 就是从上面配置的web模块,产生的工件 3.添加lib 一般是在web-inf/lib , 遇到的坑: jdk版本问题,这里…

使用STM32+SPI Flash模拟U盘

试验目的:使用STM32F103C8T6 SPI Flash(WSQ16)实现模拟U盘的功能 SPI Flash读写说明: Step1 设置SPI1 用于读取SPI Flash; Step2:设置SPI Flash 的使能信号 Step3:使能USB通信 Step4&#xf…

人机交互2——任务型多轮对话的控制和生成

1.自然语言理解模块 2.对话管理模块 3.自然语言生成模块

C++模拟如何实现vector的方法

任意位置插入,insert的返回值为新插入的第一个元素位置的迭代器;因为插入可能会进行扩容,导致start的值改变,所以先定义一个变量保存pos与start的相对位置;判断是否需要扩容;从插入位置开始,将所…

WorldWind Android上加载白模数据

这篇文章介绍下如何加载白模数据。这个白模数据的格式是shapefile格式的文件。白模数据拷贝到手机本地,然后读取白模数据,进行加载展示。 worldwind android本身是不支持加载白模数据的,但是可以根据现有提供的加载Polygons的方式&#xff0c…

【JUC】一篇通关JUC并发之共享模型

目录 1. 共享带来的问题1-1. 临界区 Critical Section1-2. 竞态条件 Race Condition1-3. synchronized 解决方案 1. 共享带来的问题 1-1. 临界区 Critical Section 一个程序运行多个线程本身是没有问题的问题出在多个线程访问共享资源 多个线程读共享资源其实也没有问题在多个…

Linux:Ubuntu实现远程登陆

1、查看sshd服务是否存在 Ubuntu默认是没有安装sshd服务的,所以,无法远程登陆。 检查22端口是否存在 netstat -anp 该命令执行后,查看不到22端口的进程。 如果netstat无法使用,我们需要安装一下netstat服务 sudo apt-get install…

模板初阶(1):函数模板,类模板

一、函数模板 1.1 概念 函数模板代表了一个函数家族&#xff0c;该函数模板与类型无关&#xff0c;在使用时被参数化&#xff0c;根据实参类型产生函数的特定类型版本。 格式&#xff1a; template <typename T>或template <class T> template <class T>…

jetson NX部署Yolov8

一,事情起因,由于需要对无人机机载识别算法进行更新,所以需要对yolov8算法进行部署到边缘端。 二,环境安装 安装虚拟环境管理工具,这个根据个人喜好。 我们需要选择能够在ARM架构上运行的conda,这里我们选择conda-forge 下载地址 安装即可 剩下的就是和conda 创建虚拟…

管理类联考——数学——汇总篇——知识点突破——应用题——路程——记忆

路程——【考频&#xff1a;高】——【解题提示&#xff1a;根据题意画图&#xff0c;找等量关系&#xff08;一般是时间和路程&#xff09;&#xff0c;列方程求解。】 【 应用题 ⟹ \Longrightarrow ⟹ 路程 ⟹ \Longrightarrow ⟹ 直线 ⟹ \Longrightarrow ⟹ 匀速、相遇、…

Kafka 集群如何实现数据同步

Kafka 介绍 Kafka 是一个高吞吐的分布式消息系统&#xff0c;不但像传统消息队列&#xff08;RaabitMQ、RocketMQ等&#xff09;那样能够【异步处理、流量消峰、服务解耦】 还能够把消息持久化到磁盘上&#xff0c;用于批量消费。除此之外由于 Kafka 被设计成分布式系统&…