零地址挂页

零地址

如果我们有比较好的C编程基础,我们就会知道,我们在代码中定义了一个零地址或者空指针,那么它实际上会指向虚拟内存的零地址,多数操作系统,包括Win,在进程创建的时候,都会空出前64k的空间大小,来确保NULL等值不指向任何地方。

我们使用CE来打开一个记事本,可以看见0地址处确实被分配了64k的大小(0x10000),这里提一下,操作系统的内存分配最低是64k,哪怕你只是申请一个字节,那么也会至少给你64k。

在这里插入图片描述

这个零地址处,我们正常来说是不能利用的,这里随便写一段代码试一试

// 0_Address_Page_Alloc.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include<windows.h>int* x = 0;int _tmain(int argc, _TCHAR* argv[])
{system("pause");*x = 100;return 0;
}

我们正常运行这段代码,报错C0005,再看下面的内存全部是??,这就是说明这一块内存并没有被挂上页

在这里插入图片描述

那么,针对这一块内存,我们既然之前学习了页的一些知识,我们是不是可以想办法利用一下呢?

实操

思路

修改我们的代码,申请一块内存空间之后,用这块已经挂上页的内存空间的PTE写入到我们零地址对应的PTE处,实现可以修改零地址处的值(实际上还是共享了页)

// 0_Address_Page_Alloc.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include<windows.h>int* x = 0;int _tmain(int argc, _TCHAR* argv[])
{int* Base =(int*) VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_READWRITE);memset(Base,0,0x1000);printf("%x\r\n",Base);system("pause");*x = 100;system("pause");printf("Base is %d\r\n",*Base);return 0;
}

我们首先知道了地址是d0000

在这里插入图片描述

先看看我们的零地址处,果不其然没挂页

1: kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 86cdd8e8  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000DirBase: 00185000  ObjectTable: 8ec01b28  HandleCount: 524.Image: System
................................................PROCESS 9525cc50  SessionId: 1  Cid: 0cb8    Peb: 7ffd7000  ParentCid: 02b8DirBase: 8872c000  ObjectTable: b5fcfa98  HandleCount:  24.Image: 0_Address_Page_Alloc.exePROCESS 8780d3a8  SessionId: 1  Cid: 0de0    Peb: 7ffdc000  ParentCid: 01a8DirBase: 2875c000  ObjectTable: c6538298  HandleCount:  62.Image: conhost.exePROCESS 87591c08  SessionId: 1  Cid: 0f50    Peb: 7ffdf000  ParentCid: 0cb8DirBase: 2d9d6000  ObjectTable: ba055e68  HandleCount:  30.Image: cmd.exe1: kd> !dd 8872c000
#8872c000 3e885867 25abb867 1d784867 00000000
#8872c010 00000000 00000000 00000000 00000000
#8872c020 00000000 00000000 00000000 00000000
#8872c030 00000000 00000000 00000000 00000000
#8872c040 00000000 00000000 00000000 00000000
#8872c050 00000000 00000000 00000000 00000000
#8872c060 00000000 00000000 00000000 00000000
#8872c070 00000000 00000000 00000000 00000000
1: kd> !dd 3e885000
#3e885000 00000000 00000000 00000000 00000000
#3e885010 00000000 00000000 00000000 00000000
#3e885020 00000000 00000000 00000000 00000000
#3e885030 00000000 00000000 00000000 00000000
#3e885040 261a0867 00000000 00000000 00000000
#3e885050 00000000 00000000 00000000 00000000
#3e885060 00000000 00000000 00000000 00000000
#3e885070 00000000 00000000 00000000 00000000

然后再看我们申请的内存,相关区域以及全部被置为了0

1: kd> !dd 3e885000 + d0*4
#3e885340 419d3867 00000000 00000000 00000000
#3e885350 00000000 00000000 00000000 00000000
#3e885360 00000000 00000000 00000000 00000000
#3e885370 00000000 00000000 00000000 00000000
#3e885380 00000000 00000000 00000000 00000000
#3e885390 00000000 00000000 00000000 00000000
#3e8853a0 00000000 00000000 00000000 00000000
#3e8853b0 00000000 00000000 00000000 00000000
1: kd> !dd 419d3867
#419d3864 00000000 00000000 00000000 00000000
#419d3874 00000000 00000000 00000000 00000000
#419d3884 00000000 00000000 00000000 00000000
#419d3894 00000000 00000000 00000000 00000000
#419d38a4 00000000 00000000 00000000 00000000
#419d38b4 00000000 00000000 00000000 00000000
#419d38c4 00000000 00000000 00000000 00000000
#419d38d4 00000000 00000000 00000000 00000000

这时候,把我们的PTE(419d3867),放到零地址对应的PTT里面

1: kd> !ed 3e885000 419d3867
1: kd> !dd 3e885000
#3e885000 419d3867 00000000 00000000 00000000
#3e885010 00000000 00000000 00000000 00000000
#3e885020 00000000 00000000 00000000 00000000
#3e885030 00000000 00000000 00000000 00000000
#3e885040 261a0867 00000000 00000000 00000000
#3e885050 00000000 00000000 00000000 00000000
#3e885060 00000000 00000000 00000000 00000000
#3e885070 00000000 00000000 00000000 00000000

继续放行程序,可以看见我们的代码就没有报错,成功将0地址处的值改为了100

在这里插入图片描述

所以我们就知道,在10-10-12分页的条件下,MMU本身并不会直接验证所接收到的地址的合法性,只要指向的物理页是真实存在的即可

继续深入的想想

上面我们通过了手动修改PTE向零地址里面存储字节,那么这个存储的字节能不能是一段shellcode呢,我们先手动得到MessageBox的地址,然后用硬编码来调用

#include "stdafx.h"
#include<windows.h>
#include<cstdio>typedef void(__stdcall * FuncProc)();int _tmain(int argc, _TCHAR* argv[])
{FuncProc func = NULL;int* Base = (int*)VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);if (Base == NULL) {printf("Memory allocation failed!\n");return 1;}memset(Base, 0, 0x1000);char bufcode[] = {0x6a, 0,             // push 00x6a, 0,             // push 00x6a, 0,             // push 00x6a, 0,             // push 00xb8, 0, 0, 0, 0,     // mov eax, <address of MessageBoxA>0xff, 0xd0,          // call eax0xc3,                // ret};// 将 MessageBoxA 的地址写入 bufcode 的适当位置*(void**)(&bufcode[9]) = (void*)MessageBoxA;// 将 bufcode 复制到 Basememcpy(Base, bufcode, sizeof(bufcode));printf("%x\r\n",Base);system("pause");// 将 Base 转换为 FuncProc 类型并调用func = (FuncProc)Base;func();// 释放分配的内存VirtualFree(Base, 0, MEM_RELEASE);return 0;
}

这是能够正常弹出框的

在这里插入图片描述

那我们按照之前的思路,注释掉bufcode对fun的赋值,然后运行程序,修改零地址处的PTE,来调用MessageBoxA

在这里插入图片描述

按照上面的偏移找到我们所申请的地址,里面的硬编码已经存好了

0: kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 86cdd8e8  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000DirBase: 00185000  ObjectTable: 8ec01b28  HandleCount: 520.Image: System...............................................................
PROCESS 875428a8  SessionId: 1  Cid: 0e34    Peb: 7ffdb000  ParentCid: 02b8DirBase: 31f7c000  ObjectTable: aef17ab8  HandleCount:  30.Image: 0_Address_Page_Alloc.exePROCESS 8779b838  SessionId: 1  Cid: 03b4    Peb: 7ffd5000  ParentCid: 01a8DirBase: 6cda0000  ObjectTable: baaaf2d0  HandleCount:  62.Image: conhost.exePROCESS 873e9d40  SessionId: 1  Cid: 09d4    Peb: 7ffda000  ParentCid: 0e34DirBase: 15210000  ObjectTable: c6538298  HandleCount:  30.Image: cmd.exe0: kd> !dd 31f7c000
#31f7c000 8bf9d867 319e4867 2349c867 00000000
#31f7c010 00000000 00000000 00000000 00000000
#31f7c020 00000000 00000000 00000000 00000000
#31f7c030 00000000 00000000 00000000 00000000
#31f7c040 00000000 00000000 00000000 00000000
#31f7c050 00000000 00000000 00000000 00000000
#31f7c060 00000000 00000000 00000000 00000000
#31f7c070 00000000 00000000 00000000 00000000
0: kd> !dd 8bf9d000 + 1f0*4
#8bf9d7c0 1940f867 00000000 00000000 00000000
#8bf9d7d0 00000000 00000000 00000000 00000000
#8bf9d7e0 00000000 00000000 00000000 00000000
#8bf9d7f0 00000000 00000000 00000000 00000000
#8bf9d800 00000000 00000000 00000000 00000000
#8bf9d810 00000000 00000000 00000000 00000000
#8bf9d820 00000000 00000000 00000000 00000000
#8bf9d830 00000000 00000000 00000000 00000000
0: kd> !db 1940f000
#1940f000 6a 00 6a 00 6a 00 6a 00-b8 11 ea f4 75 ff d0 c3 j.j.j.j.....u...
#1940f010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#1940f020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#1940f030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#1940f040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#1940f050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#1940f060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#1940f070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

此时我们在代码里面将fun声明为NULL,所以我们还是一样,把我们的PTE填入零地址对应的PTT里面

0: kd> !dd 8bf9d000
#8bf9d000 00000000 00000000 00000000 00000000
#8bf9d010 00000000 00000000 00000000 00000000
#8bf9d020 00000000 00000000 00000000 00000000
#8bf9d030 00000000 00000000 00000000 00000000
#8bf9d040 65fb9847 00000000 00000000 00000000
#8bf9d050 00000000 00000000 00000000 00000000
#8bf9d060 00000000 00000000 00000000 00000000
#8bf9d070 00000000 00000000 00000000 00000000
0: kd> !ed 8bf9d000 1940f867
0: kd> !dd 8bf9d000
#8bf9d000 1940f867 00000000 00000000 00000000
#8bf9d010 00000000 00000000 00000000 00000000
#8bf9d020 00000000 00000000 00000000 00000000
#8bf9d030 00000000 00000000 00000000 00000000
#8bf9d040 65fb9847 00000000 00000000 00000000
#8bf9d050 00000000 00000000 00000000 00000000
#8bf9d060 00000000 00000000 00000000 00000000
#8bf9d070 00000000 00000000 00000000 00000000

之后我们继续放行程序,可以看见被声明为了NULL的函数指针还是调用了我们的shellcode,弹窗成功了

在这里插入图片描述

这更进一步验证了我们的学习,CPU读这些数据的时候不会真的去验证虚拟地址的真实性,只要对应的物理地址是可以被访问的,那么虚拟地址即使被更改只要不触发页异常就不会有问题

更加深入的想想

既然我们已经可以向一块被标记为Free的内存写入字节,那么,我们可不可以向一个进程里面的零地址写入字节然后远程线程跑我们的shellcode呢

先把代码贴出来

#include "stdafx.h"
#include<windows.h>
#include<cstdio>typedef void(__stdcall * FuncProc)();int _tmain(int argc, _TCHAR* argv[])
{FuncProc func = NULL;char* Base = (char*)VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);if (Base == NULL) {printf("Memory allocation failed!\n");return 1;}memset(Base, 0, 0x1000);char bufcode[] = {0x6a, 0,             // push 00x6a, 0,             // push 00x6a, 0,             // push 00x6a, 0,             // push 00xb8, 0, 0, 0, 0,     // mov eax, <address of MessageBoxA>0xff, 0xd0,          // call eax0xc3,                // ret};// 将 MessageBoxA 的地址写入 bufcode 的适当位置*(void**)(&bufcode[9]) = (void*)MessageBoxA;// 将 bufcode 复制到 Basememcpy(Base+0x200, bufcode, sizeof(bufcode));printf("%x\r\n",Base);system("pause");// 将 Base 转换为 FuncProc 类型并调用//func = (FuncProc)Base;//func();HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,3016);HANDLE hThread = CreateRemoteThread(hProcess,NULL,NULL,(LPTHREAD_START_ROUTINE)0x200,NULL,NULL,NULL);CloseHandle(hThread);CloseHandle(hProcess);system("pause");// 释放分配的内存VirtualFree(Base, 0, MEM_RELEASE);return 0;
}

上面的代码打开了一个notepad(3016)进程,然后朝里面写入了一个shellcode

首先还是先查到我们所申请内存的PTE

在这里插入图片描述

1: kd> !process 0 0//找到我们需要的进程
**** NT ACTIVE PROCESS DUMP ****
PROCESS 86cdd8e8  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000DirBase: 00185000  ObjectTable: 8ec01b28  HandleCount: 529.Image: System......................................................PROCESS 87372b20  SessionId: 1  Cid: 0bc8    Peb: 7ffd5000  ParentCid: 062cDirBase: 2e224000  ObjectTable: af7f5fc0  HandleCount:  63.Image: notepad.exe.........................................PROCESS 878d65f0  SessionId: 1  Cid: 0b10    Peb: 7ffdf000  ParentCid: 02b8DirBase: 41ffb000  ObjectTable: b9f3aa50  HandleCount:  30.Image: 0_Address_Page_Alloc.exe

我们可以看见,在页中我们也挂到了对应偏移0x200的位置, 这个2c7e0847就是我们要找的值

1: kd> !dd 41ffb000+ 1*4
#41ffb004 00ab5867 ae4e1867 0be6d867 00000000
#41ffb014 00000000 00000000 00000000 00000000
#41ffb024 00000000 00000000 00000000 00000000
#41ffb034 00000000 00000000 00000000 00000000
#41ffb044 00000000 00000000 00000000 00000000
#41ffb054 00000000 00000000 00000000 00000000
#41ffb064 00000000 00000000 00000000 00000000
#41ffb074 00000000 00000000 00000000 00000000
1: kd> !dd 00ab5000 + 4*e0
#  ab5380 2c7e0847 00000000 00000000 00000000
#  ab5390 00000000 00000000 00000000 00000000
#  ab53a0 00000000 00000000 00000000 00000000
#  ab53b0 00000000 00000000 00000000 00000000
#  ab53c0 00000000 00000000 00000000 00000000
#  ab53d0 00000000 00000000 00000000 00000000
#  ab53e0 00000000 00000000 00000000 00000000
#  ab53f0 00000000 00000000 00000000 00000000
1: kd> !dd 2c7e0000
#2c7e0000 00000000 00000000 00000000 00000000
#2c7e0010 00000000 00000000 00000000 00000000
#2c7e0020 00000000 00000000 00000000 00000000
#2c7e0030 00000000 00000000 00000000 00000000
#2c7e0040 00000000 00000000 00000000 00000000
#2c7e0050 00000000 00000000 00000000 00000000
#2c7e0060 00000000 00000000 00000000 00000000
#2c7e0070 00000000 00000000 00000000 00000000
1: kd> !db 2c7e0000+0x200
#2c7e0200 6a 00 6a 00 6a 00 6a 00-b8 11 ea f4 75 ff d0 c3 j.j.j.j.....u...
#2c7e0210 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#2c7e0220 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#2c7e0230 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#2c7e0240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#2c7e0250 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#2c7e0260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#2c7e0270 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

我们打开notepad的零地址,把这个值填进去

1: kd> !dd 2e224000
#2e224000 3d720867 6c21f867 11cc2867 00000000
#2e224010 3f78c867 7468d847 2e4c8867 40304867
#2e224020 0c707867 06e09867 00000000 00000000
#2e224030 00000000 00000000 00000000 00000000
#2e224040 00000000 00000000 00000000 00000000
#2e224050 00000000 00000000 00000000 00000000
#2e224060 00000000 00000000 00000000 00000000
#2e224070 00000000 00000000 00000000 00000000
1: kd> !dd 3d720000
#3d720000 00000000 00000000 00000000 00000000
#3d720010 00000000 00000000 00000000 00000000
#3d720020 00000000 00000000 00000000 00000000
#3d720030 00000000 00000000 00000000 00000000
#3d720040 41e37847 00000000 00000000 00000000
#3d720050 00000000 00000000 00000000 00000000
#3d720060 00000000 00000000 00000000 00000000
#3d720070 00000000 00000000 00000000 00000000
1: kd> !ed 3d720000 2c7e0847
1: kd> !dd 3d720000
#3d720000 2c7e0847 00000000 00000000 00000000
#3d720010 00000000 00000000 00000000 00000000
#3d720020 00000000 00000000 00000000 00000000
#3d720030 00000000 00000000 00000000 00000000
#3d720040 41e37847 00000000 00000000 00000000
#3d720050 00000000 00000000 00000000 00000000
#3d720060 00000000 00000000 00000000 00000000
#3d720070 00000000 00000000 00000000 00000000

放行程序,继续运行,这时候我们的弹框就跑在notepad的进程中了

在这里插入图片描述

最后

我们现在是用windbg手动去修改PTE,但是随着我们学习的深入,我们就可以使用程序来自动化这一过程,来达到我们注入shellcode的效果

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

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

相关文章

QT6学习第四天 感受QT的文件编译

QT6学习第四天 感受QT的文件编译 使用纯代码编写程序新建工程 使用其他编辑器纯代码编写程序并在命令行运行使用 .ui 表单文件生成界面使用自定义 C 窗口类使用现成的QT Designer界面类 使用纯代码编写程序 我们知道QT Creator中可以用拖拽的方式在 .ui 文件上布局&#xff0c…

windows安全中心,永久卸载工具分享

使用方法 2024Goby红队版工具分享&#xff0c;附2024年漏洞POC下载 下载链接&#xff1a; https://pan.quark.cn/s/4fc2712a2afc一路回车&#xff0c;选项Y即可 耐心等待几秒种&#xff0c;自动重启 此时打开windows安全中心&#xff0c;已经完全不能使用了&#xff0c;响应…

jvm核心组件介绍

1. 类加载器&#xff08;ClassLoader&#xff09;&#xff1a; • 想象它是一个快递员&#xff0c;负责把Java类&#xff08;.class文件&#xff09;这个“包裹”从磁盘这个“发货地”送到JVM内部这个“目的地”。类加载器确保每个类只被加载一次&#xff0c;并维护一个类的层级…

目标检测,图像分割,超分辨率重建

目标检测和图像分割 目标检测和图像分割是计算机视觉中的两个不同任务&#xff0c;它们的输出形式也有所不同。下面我将分别介绍这两个任务的输出。图像分割又可以分为&#xff1a;语义分割、实例分割、全景分割。 语义分割&#xff08;Semantic Segmentation&#xff09;&…

Python编程技巧:多变量赋值的优雅艺术

在Python编程的世界里&#xff0c;有许多令人惊叹的语法特性&#xff0c;而多变量赋值就像是一颗闪耀的明珠&#xff0c;它不仅让代码更优雅&#xff0c;还能提升程序的执行效率。今天我们就深入探讨这个看似简单却蕴含深意的编程技巧。 基础认识 传统的变量赋值方式&#xff…

CentOS 7 安装部署 KVM

1.关闭虚拟机 打开相关选项 打开虚拟机centos7 连接xshell 测试网络&#xff0c;现在就是没问题的&#xff0c;因为我们要使用网络源 安装 GNOME 桌面环境 安装KVM 模块 安装KVM 调试工具 构建虚拟机的命令行工具 qemu 组件,创建磁盘、启动虚拟机等 输入这条命令&#xff0c;…

微信小程序学习指南从入门到精通

&#x1f5fd;微信小程序学习指南从入门到精通&#x1f5fd; &#x1f51d;微信小程序学习指南从入门到精通&#x1f51d;✍前言✍&#x1f4bb;微信小程序学习指南前言&#x1f4bb;一、&#x1f680;文章列表&#x1f680;二、&#x1f52f;教程文章的好处&#x1f52f;1. ✅…

【C++】读取数量不定的输入数据

读取数量不定的输入数据 似乎是一个很实用的东西&#xff1f; 问题&#xff1a; 我们如何对用户输入的一组数&#xff08;事先不知道具体有多少个数&#xff09;求和&#xff1f; 这需要不断读取数据直至没有新的输入为止。&#xff08;所以我们的代码就是这样设计的&#x…

基于vite创建的react18项目的单元测试

题外话 最近一个小伙伴进了字节外包&#xff0c;第一个活就是让他写一个单元测试。 嗯&#xff0c;说实话&#xff0c;在今天之前我只知道一些理论&#xff0c;但是并没有实操过&#xff0c;于是我就试验了一下。 通过查询资料&#xff0c;大拿们基本都说基于vite的项目&…

如何用通义灵码助力项目开发 | OceanBase obdiag 项目共建实践

本文来自 obdiag 项目共建的用户分享 一、背景 我的数据库探索之旅始于OceanBase。作为一位满怀好奇心的DBA&#xff0c;我内心始终怀揣着对数据库内部运作机制的无尽向往。开源如同一把钥匙&#xff0c;为我们这些求知欲旺盛的“好奇猫”解锁了通往新知的神秘大门。在众多分布…

idea_卸载与安装

卸载与安装 卸载1、设置 -> 应用2、查找到应用&#xff0c;点击卸载3、把删除记录和设置都勾选上4、删除其它几个位置的残留 安装1、下载安装包2、欢迎安装 -> Next3、选择安装目录 -> Next4、创建快捷图标和添加到环境变量5、确认文件夹的名称 -> Install6、完成安…

day01

Hm-Footer.vue <template><div class"hm-footer">我是hm-footer</div></template><script>export default {}</script><style>.hm-footer{height:100px;line-height:100px;text-align:center;font-size:30px;background-…

NLP 1、人工智能与NLP简介

人人都不看好你&#xff0c;可偏偏你最争气 —— 24.11.26 一、AI和NLP的基本介绍 1.人工智能发展流程 弱人工智能 ——> 强人工智能 ——> 超人工智能 ① 弱人工智能 人工智能算法只能在限定领域解决特定的问题 eg&#xff1a;特定场景下的文本分类、垂直领域下的对…

基于混合ABC和A*算法复现

基于混合ABC和A*算法复现 一、背景介绍二、算法原理&#xff08;一&#xff09;A*算法原理&#xff08;二&#xff09;人工蜂群算法原理&#xff08;三&#xff09;混合ABC和A*算法策略 三、代码实现&#xff08;一&#xff09;数据准备&#xff08;二&#xff09;关键函数实现…

解决SpringBoot连接Websocket报:请求路径 404 No static resource websocket.

问题发现 最近在工作中用到了WebSocket进行前后端的消息通信&#xff0c;后端代码编写完后&#xff0c;测试一下是否连接成功&#xff0c;发现报No static resource websocket.&#xff0c;看这个错貌似将接口变成了静态资源来访问了&#xff0c;第一时间觉得是端点没有注册成…

VITE+VUE3+TS环境搭建

前言&#xff08;与搭建项目无关&#xff09;&#xff1a; 可以安装一个node管理工具&#xff0c;比如nvm&#xff0c;这样可以顺畅的切换vue2和vue3项目&#xff0c;以免出现项目跑不起来的窘境。我使用的nvm&#xff0c;当前node 22.11.0 目录 搭建项目 添加状态管理库&…

红外小目标检测

目录 背景概述算法原理演示效果核心逻辑 使用方式基础镜像配置环境直接运行 参考文献 文章声明&#xff0c;非广告&#xff0c;仅个人体验。 背景 红外图像在许多领域中都有所应用。例如军事领域中&#xff0c;经常需要通过红外成像设备对远距离的目标进行侦察和监视&#xff…

【滑动窗口】找到字符串中所有字母异位词

文章目录 找到字符串中所有字母异位词 class Solution { public:vector<int> findAnagrams(string s, string p) {vector<int> ret;int sLen s.size(), pLen p.size(), validChar;// 母串长度比子串长度还小 直接返回空vectorif (sLen < pLen)return ret;// …

nodepad配置c/c++ cmd快速打开创建项目文件

前提:下载MinGw,并且配置环境变量 点击阅读次篇文章配置MinGw 无论是哪个编译器&#xff0c;执行c文件都是经历以下步骤: 编译文件生成exe文件执行该exe文件 我们先手动完成这两部 手动编译文件使用指令 gcc {你的c文件} -o {生成文件名}生成exe文件 第二步运行exe直接点击该文…

Opencv+ROS实现颜色识别应用

目录 一、工具 二、原理 概念 本质 三、实践 添加发布话题 主要代码 四、成果 五、总结 一、工具 opencvros ubuntu18.04 摄像头 二、原理 概念 彩色图像&#xff1a;RGB&#xff08;红&#xff0c;绿&#xff0c;蓝&#xff09; HSV图像&#xff1a;H&#xff0…