Windows核心编程 跨进程操作

news2024/11/15 17:33:54

目录

进程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 process
  LPCVOID lpBaseAddress,        // base of memory area
  LPVOID lpBuffer,              // data buffer
  SIZE_T nSize,                 // number of bytes to read
  SIZE_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;
    }

    //获取进程ID
    DWORD 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.coloradmin.cn/o/1249841.html

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

相关文章

<蓝桥杯软件赛>零基础备赛20周--第7周--栈和二叉树

报名明年4月蓝桥杯软件赛的同学们,如果你是大一零基础,目前懵懂中,不知该怎么办,可以看看本博客系列:备赛20周合集 20周的完整安排请点击:20周计划 每周发1个博客,共20周(读者可以按…

AI人工智能对话系统网页版源码系统 附带完整的搭建教程

AI人工智能对话系统网页版源码系统的开发背景主要是基于自然语言处理技术和机器学习算法的不断发展。自然语言处理技术使得计算机能够理解和分析人类语言,而机器学习算法则能够让计算机自我学习和改进,不断提高对话系统的智能化水平。 此外,…

有序表的详解

目录 有序表的介绍 树的左旋和右旋操作 AVL树的详解 SB树的详解 红黑树的介绍 SkipList的详解 有序表的介绍 有序表是除具备哈希表所具备的功能外,有序表中的内容都是按照key有序排列的,并且增删改查等操作的时间复杂度都是,红黑树&…

单片非晶磁性测量系统非晶测量方法

非晶测量方法 单片法是国际主流的非晶测量方法之一,如美标 A932 和日标 H7152 均早已提出了该方法;2014 年 IEC 起草的标准,和我国 2015 年重新修订的 GB/T 19345.1 标准中均明确提出了单片法测量非晶磁性能。单片法与环样法相比&#xff0c…

表单考勤签到作业周期打卡打分评价评分小程序开源版开发

表单考勤签到作业周期打卡打分评价评分小程序开源版开发 表单打卡评分 表单签到功能:学生可以通过扫描二维码或输入签到码进行签到,方便教师进行考勤管理。 考勤功能:可以记录学生的出勤情况,并自动生成出勤率和缺勤次数等统计数…

SpringBoot项目连接,有Kerberos认证的Kafka

在连接Kerberos认证kafka之前,需要了解Kerberos协议 二、什么是Kerberos协议 Kerberos是一种计算机网络认证协议 ,其设计目标是通过密钥系统为网络中通信的客户机(Client)/服务器(Server)应用程序提供严格的身份验证服务,确保通信双方身份的真…

​LeetCode解法汇总2304. 网格中的最小路径代价

目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 描述: 给你一个下…

AMESim与MATLAB联合仿真demo

本文是AMESim与MATLAB联合仿真的demo,记录一下如何进行联合仿真。 AMESim与MATLAB联合仿真可以大幅度提高工作效率。 author:xiao黄 缓慢而坚定的生长 csdn:https://blog.csdn.net/Python_Matlab?typeblog主页传送门 博主的联合仿真环境如下&#xff…

用友BIP与用友BIP对接集成销售出库列表查询连通销售出库单个保存((红字)销售出库审核-v)

用友BIP与用友BIP对接集成销售出库列表查询连通销售出库单个保存((红字)销售出库审核-v) 源系统:用友BIP 面向数智化市场,用友倾力打造了全球领先的数智商业创新平台——用友BIP,定位为数智商业的应用级基础设施、企业服务产业的共…

SpringCloud实用-OpenFeign整合okHttp

文章目录 前言正文一、OkHttpFeignConfiguration 的启用1.1 分析配置类1.2 得出结论,需要增加配置1.3 调试 二、OkHttpFeignLoadBalancerConfiguration 的启用2.1 分析配置类2.2 得出结论2.3 测试 附录附1:本系列文章链接附2:OkHttpClient 增…

电源控制系统架构(PCSA)之电源管理基础设施组件

目录 6.5 电源管理基础设施组件 6.5.1 电源策略单元 6.5.2 时钟控制器 6.5.3 低功耗Distributor 6.5.4 低功耗Combiner 6.5.5 P-Channel到Q-Channel转换器 6.5 电源管理基础设施组件 6.5.1 电源策略单元 本节介绍电源策略单元(Power Policy Unit, PPU)。PPU的完整细节见…

记录一些免费的 API接口

主要记录一些日常开发中可以使用到的一些免费api接口,目前包括 ip地址查询、天气查询 通过 IP 查询地址 ip-api (不支持 https) 💡 api接口文档 🕹 调用接口 $ curl http://ip-api.com/json📝 返回信息(位置信息&…

提高工作效率的宝藏网站和宝藏工具(高级版)

一、参考资料 亲测:你这些网站都不知道,哪来时间去摸鱼? 提高工作效率的宝藏网站和宝藏工具(基础版) 二、好用的网站 HelloGitHub - 开源项目平台 HelloGitHub 是一个分享有趣、 入门级开源项目的平台。 希望大家能…

python-opencv轮廓检测(外轮廓检测和全部轮廓检测,计算轮廓面积和周长)

python-opencv轮廓检测(外轮廓检测和全部轮廓检测,计算轮廓面积和周长) 通过cv2.findContours,我们可以进行轮廓检测,当然也有很多检测模式,我们可以通过选择检测模式,进行外轮廓检测&#xff…

如何打造“面向体验”的音视频能力——对话火山引擎王悦

编者按:随着全行业视频化的演进,我们置身于一个充满创新与变革的时代。在这个数字化的浪潮中,视频已经不再只是传递信息的媒介,更是重塑了我们的交互方式和体验感知。作为字节跳动的“能力溢出”,火山引擎正在飞速奔跑…

网安融合新进展:Check Point+七云网络联合研发,加固大型企业边缘、分支侧安全

AI 爆火、万物互联,底层需要更灵活的网络设施提供支撑。据国际分析机构 Gartner 预测,到 2024 年,SD-WAN(软件定义的广域网)使用率将达到 60%。不过边缘和终端兴起,未经过数据中心的流量也在成为新的安全风…

超声波雪深传感器冬季里的科技魔法

在冬季的某个清晨,当你打开大门,被厚厚的积雪覆盖的大地映入眼帘,你是否曾想过,这片雪地的深度是多少?它又如何影响着我们的生活和环境?今天,我们将为你揭开这个谜团,介绍一款神秘的…

【三极管锯齿波电路】2022-3-23

缘由以晶体管作恒流源的锯齿波电路工作原理? - 24小时必答区

Arduino库之 LedControl 库说明文档

LedControl 库最初是为基于 8 位 AVR 处理器的 Arduino 板编写的。用于通过MAX7219芯片控制LED矩阵和7段数码管。但由于该代码不使用处理器的任何复杂的内部功能,因此具有高度可移植性,并且应该在任何支持 和 功能的 Arduino(类似&#xff09…

nginx知识梳理及配置详解

软件开发全文档获取:点我获取 nginx安装 #nginx安装 yum -y install gcc pcre-devel openssl-devel #依赖包 useradd -s /sbin/nologin nginx ./configure --prefix/usr/local/nginx #指定安装目录 --usernginx #指定用户 --with-http_ss…