零地址挂页

零地址

如果我们有比较好的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: 0000
    DirBase: 00185000  ObjectTable: 8ec01b28  HandleCount: 524.
    Image: System
................................................

PROCESS 9525cc50  SessionId: 1  Cid: 0cb8    Peb: 7ffd7000  ParentCid: 02b8
    DirBase: 8872c000  ObjectTable: b5fcfa98  HandleCount:  24.
    Image: 0_Address_Page_Alloc.exe

PROCESS 8780d3a8  SessionId: 1  Cid: 0de0    Peb: 7ffdc000  ParentCid: 01a8
    DirBase: 2875c000  ObjectTable: c6538298  HandleCount:  62.
    Image: conhost.exe

PROCESS 87591c08  SessionId: 1  Cid: 0f50    Peb: 7ffdf000  ParentCid: 0cb8
    DirBase: 2d9d6000  ObjectTable: ba055e68  HandleCount:  30.
    Image: cmd.exe

1: 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 0
        0x6a, 0,             // push 0
        0x6a, 0,             // push 0
        0x6a, 0,             // push 0
        0xb8, 0, 0, 0, 0,     // mov eax, <address of MessageBoxA>
        0xff, 0xd0,          // call eax
        0xc3,                // ret
    };

    // 将 MessageBoxA 的地址写入 bufcode 的适当位置
    *(void**)(&bufcode[9]) = (void*)MessageBoxA;

    // 将 bufcode 复制到 Base
    memcpy(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: 0000
    DirBase: 00185000  ObjectTable: 8ec01b28  HandleCount: 520.
    Image: System
    ...............................................................
PROCESS 875428a8  SessionId: 1  Cid: 0e34    Peb: 7ffdb000  ParentCid: 02b8
    DirBase: 31f7c000  ObjectTable: aef17ab8  HandleCount:  30.
    Image: 0_Address_Page_Alloc.exe

PROCESS 8779b838  SessionId: 1  Cid: 03b4    Peb: 7ffd5000  ParentCid: 01a8
    DirBase: 6cda0000  ObjectTable: baaaf2d0  HandleCount:  62.
    Image: conhost.exe

PROCESS 873e9d40  SessionId: 1  Cid: 09d4    Peb: 7ffda000  ParentCid: 0e34
    DirBase: 15210000  ObjectTable: c6538298  HandleCount:  30.
    Image: cmd.exe

0: 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 0
        0x6a, 0,             // push 0
        0x6a, 0,             // push 0
        0x6a, 0,             // push 0
        0xb8, 0, 0, 0, 0,     // mov eax, <address of MessageBoxA>
        0xff, 0xd0,          // call eax
        0xc3,                // ret
    };

    // 将 MessageBoxA 的地址写入 bufcode 的适当位置
    *(void**)(&bufcode[9]) = (void*)MessageBoxA;

    // 将 bufcode 复制到 Base
    memcpy(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: 0000
    DirBase: 00185000  ObjectTable: 8ec01b28  HandleCount: 529.
    Image: System

......................................................

PROCESS 87372b20  SessionId: 1  Cid: 0bc8    Peb: 7ffd5000  ParentCid: 062c
    DirBase: 2e224000  ObjectTable: af7f5fc0  HandleCount:  63.
    Image: notepad.exe

.........................................

PROCESS 878d65f0  SessionId: 1  Cid: 0b10    Peb: 7ffdf000  ParentCid: 02b8
    DirBase: 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的效果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode:222完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最左边的若干位置。若最…

【小白学机器学习36】关于独立概率,联合概率,交叉概率,交叉概率和,总概率等 概念辨析的例子

目录 1 先说结论 2 联合概率 3 边缘概率 4 (行/列)边缘概率的和 总概率1 5 条件概率 5.1 条件概率的除法公式 5.2 条件概率和联合概率区别 1 先说结论 关于独立概率&#xff0c;联合概率&#xff0c;交叉概率&#xff0c;交叉概率和&#xff0c;总概率 类型含义 …

【前端】ES6基础

1.开发工具 vscode地址 :https://code.visualstudio.com/download, 下载对应系统的版本windows一般都是64位的 安装可以自选目录&#xff0c;也可以使用默认目录 插件&#xff1a; 输入 Chinese&#xff0c;中文插件 安装&#xff1a; open in browser&#xff0c;直接右键文件…

《安富莱嵌入式周报》第346期:开源2GHz带宽,12bit分辨率,3.2Gsps采样率示波,开源固件安全分析器, 开源口袋电源,开源健康测量,FreeCAD

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频&#xff1a; https://www.bilibili.com/video/BV1TYBhYKECK/ 《安富莱嵌入式周报》第346期&#xff1a;开源2GHz带…

《白帽子讲Web安全》13-14章

《白帽子讲Web安全》13-14章 《白帽子讲Web安全》13-14章13、应用层拒绝服务攻击13.1、DDOS简介13.2、应用层DDOS13.2.1、CC攻击13.2.2、限制请求频率13.2.3、道高一尺&#xff0c;魔高一丈 13.3、验证码的那些事儿13.4、防御应用层DDOS13.5、资源耗尽攻击13.5.1、Slowloris攻击…

51单片机从入门到精通:理论与实践指南(一)

单片机在智能控制领域的应用已非常普遍&#xff0c;发展也很迅猛&#xff0c;学习和使用单片机的人员越来越多。虽然新型微控制器在不断推出&#xff0c;但51单片机价格低廉、易学易用、性能成熟&#xff0c;在家电和工业控制中有一定的应用&#xff0c;而且学好了51单片机&…

相亲交友小程序项目介绍

一、项目背景 在当今快节奏的社会生活中&#xff0c;人们忙于工作和事业&#xff0c;社交圈子相对狭窄&#xff0c;寻找合适的恋爱对象变得愈发困难。相亲交友作为一种传统而有效的社交方式&#xff0c;在现代社会依然有着巨大的需求。我们的相亲交友项目旨在为广大单身人士提…

Python中的简单爬虫

文章目录 一. 基于FastAPI之Web站点开发1. 基于FastAPI搭建Web服务器2. Web服务器和浏览器的通讯流程3. 浏览器访问Web服务器的通讯流程4. 加载图片资源代码 二. 基于Web请求的FastAPI通用配置1. 目前Web服务器存在问题2. 基于Web请求的FastAPI通用配置 三. Python爬虫介绍1. 什…

uni-app运行 安卓模拟器 MuMu模拟器

最近公司开发移动端系统&#xff0c;使用真机时每次调试的时候换来换去的麻烦&#xff0c;所以使用模拟器来调试方便。记录一下安装和连接的过程 一、安装MuMu模拟器 百度搜索MuMu模拟器并打开官网或者点这里MuMu模拟器官网 点击下载模拟器 安装模拟器&#xff0c;如果系统…

mydocker

Docker容器特点 轻量级&#xff1a;在同一台宿主机上的容器共享系统 Kerel &#xff0c;这使得它们可以迅速启动而且占用内存极少。镜像是以分层文件系统构造的&#xff0c;这可以让它们共享相同的文件&#xff0c;使得磁盘使用率和镜像下载速度得到提高。开放&#xff1a;Doc…

JVM详解:垃圾回收机制

java作为大型服务开发的主流语言&#xff0c;其运行会占用大量的内存空间&#xff0c;那么合理的使用有限的服务器资源至关重要。和大多数翻译性语言一样&#xff0c;java的运行环境jvm也内置垃圾回收机制&#xff0c;其通过一些合理的算法组合&#xff0c;定时来对堆中保存的不…

Kali2024.4切换xfce主题输入法失效问题

目前感觉linux下比较好用的输入法就是google pinyin&#xff0c;常规的安装 sudo apt install fcitx im-configsudo apt install fcitx-googlepinyin然而在切换主题后&#xff0c;输入法不好用了&#xff0c;手动添加输入法也是找不到的状态&#xff0c;进入排查步骤&#xff…

C++初阶学习第十三弹——容器适配器和优先级队列的概念

目录 一.容器适配器 1.2deque的原理介绍 1.3deque与vector和list的比较&#xff0c;以及deque的缺陷 1.4为什么选择deque作为stack和queue的底层默认容器&#xff1f; stack的模拟实现 queue的模拟实现 二.优先级队列 2.1priority_queue的使用 三、总结 一.容器适配器 s…

C++ 优先算法 —— 无重复字符的最长子串(滑动窗口)

目录 题目&#xff1a; 无重复字符的最长子串 1. 题目解析 2. 算法原理 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口&#xff08;同向双指针&#xff09; 3. 代码实现 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口 题目&#xff1a; 无重复字符的最长子串 1. 题目解析 题目截图&#xff1a; 此题所说的…

easyui combobox 只能选择第一个问题解决

easyui combobox 只能选择第一个问题解决 问题现象 在拆分开票的时候&#xff0c;弹出框上面有一个下拉框用于选择需要新增的明细行&#xff0c;但是每次只能选择到第一个 选择第二条数据的时候默认选择到第一个了 代码如下 /*新增发票编辑窗口*/function addTicketDialog…

机器学习周志华学习笔记-第6章<支持向量机>

机器学习周志华学习笔记-第6章<支持向量机> 卷王&#xff0c;请看目录 6支持向量机6.1 函数间隔与几何间隔6.1.1 函数间隔6.1.2 几何间隔 6.2 最大间隔与支持向量6.3 对偶问题6.4 核函数6.5 软间隔支持向量机6.6 支持向量机6.7核方法 6支持向量机 支持向量机是一种经典…

111. UE5 GAS RPG 实现角色技能和场景状态保存到存档

实现角色的技能存档保存和加载 首先&#xff0c;我们在LoadScreenSaveGame.h文件里&#xff0c;增加一个结构体&#xff0c;用于存储技能相关的所有信息 //存储技能的相关信息结构体 USTRUCT(BlueprintType) struct FSavedAbility {GENERATED_BODY()//需要存储的技能UPROPERT…

ArcGIS pro中的回归分析浅析(加更)关于广义线性回归工具的补充内容

在回归分析浅析中篇的文章中&#xff0c; 有人问了一个问题&#xff1a; 案例里的calls数据貌似离散&#xff0c;更符合泊松模型&#xff0c;为啥不采用泊松而采用高斯呢&#xff1f; 确实&#xff0c;在中篇中写道&#xff1a; 在这个例子中我们为了更好地解释变量&#x…

从 HTML 到 CSS:开启网页样式之旅(二)—— 深入探索 CSS 选择器的奥秘

从 HTML 到 CSS&#xff1a;开启网页样式之旅&#xff08;二&#xff09;—— 深入探索 CSS 选择器的奥秘 前言一、CSS基本选择器1. 通配选择器2. 元素选择器3. 类选择器4. id选择器5.基本选择器总结 二、CSS复合选择器1. 后代选择器2. 子选择器3. 相邻兄弟选择器4.交集选择器5…

【机器学习chp7】SVM

参考1&#xff0c;笔记 SVM笔记.pdf 参考2&#xff1a;王木头视频 什么是SVM&#xff0c;如何理解软间隔&#xff1f;什么是合叶损失函数、铰链损失函数&#xff1f;SVM与感知机横向对比&#xff0c;挖掘机器学习本质_哔哩哔哩_bilibili 目录 一、SVM模型 二、构建决策函…