CTF-PWN-沙箱逃脱-【seccomp和prtcl-1】

文章目录

  • 啥是seccomp
  • #ifndef #define #endif使用
    • 使用格式
  • seccomp
    • 无参数条件禁用系统调用
    • 有参数条件禁用系统调用
  • prctl
    • 实例
  • seccomp_export_bpf

啥是seccomp

就是可以禁用掉某些系统调用,然后只能允许某些系统调用
在这里插入图片描述

#ifndef #define #endif使用

#ifndef #define #endif作用就是防止头文件被重复引用,

其实“被重复引用”是指一个头文件在同一个cpp文件中被include了多次,这种错误常常是由于include嵌套造成的或者是简单地include多次。比如:存在a.h文件 #include "c.h"而此时b.cpp文件还有了=#include “a.h” 和#include "c.h"此时就会造成c.h重复引用。

头文件被重复引用引起的后果:
有些头文件重复引用只是增加了编译工作的工作量,不会引起太大的问题,仅仅是编译效率低一些,但是对于大工程而言编译效率低下那就比较严重了。
有些头文件重复包含,会引起错误,比如在头文件中定义了全局变量(虽然这种方式不被推荐,但确实是C规范允许的),在重复引用后会引起重复定义。这样就可能会报错、

    下面给一个#ifndef/#define/#endif的格式:

    #ifndef A_H意思是"if not define a.h"  如果不存在a.h

    接着的语句应该#define A_H 然后相关头文件的内容

    最后一句应该写#endif  A_H 结束过程

使用格式

#ifndef <标识> 
#define <标识> 
....
#endif <标识> 

<标识>在理论上来说可以 是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h 对应得标识为 STDIO_H

例如要编写头文件sys.h,需要在sys.h文件开头写上:
#ifndef SYS_H
#define SYS_H
....
#endif SYS_H
那么当#include"sys.h"时会判断是否sys.h已经被导入了
如果此时是第一次#include"sys.h",那么会执行#define SYS_H,此时_SYS_H被定义了
当第二次#include"sys.h",由于此时已经定义了SYS_H,所以不会执行#define SYS_H以及之后的内容

seccomp

seccomp学习

一般seccomp得使用流程

ctx = seccomp_init(SCMP_ACT_ALLOW);

seccomp_init(uint32_t def_action)

def_action 是过滤器工作模式
seccomp_init是初始化的过滤状态,这里用的是SCMP_ACT_ALLOW,表示默认允许所有的syscacll.如果初始化状态为SCMP_ACT_KILL,则表示默认不允许所有的syscall

seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);

int seccomp_rule_add(scmp_filter_ctx " ctx ", uint32_t " action ",int " syscall ",unsigned int " arg_cnt ", " ... ");

ctx :初始化定义的过滤器
action :规则模式,匹配到系统调用后执行的操作,和初始化过滤器的 def_action类型一样
syscall :系统调用号,可以使用 SCMP_SYS(函数名) 代替具体调用号
arg_cnt :需要参数限制规则个数 seccomp_rule_add 限制参数接口定义在 seccomp.h.in 。主要是取参数操作 SCMP_AX ,运算比较 scmp_compare 。当这些规则都满足后才能此seccomp_rule_add函数成功执行

只要匹配系统调用,不管参数内容:那么arg_cnt=0。匹配系统调用后,根据参数内容决定是否执行 action :arg_cnt=N(规则条数),后面再跟N个参数

seccomp_load(ctx);

seccomp_load是应用过滤,加载沙箱规则,如果不调用seccomp_load则上面所有的过滤都不会生效

无参数条件禁用系统调用

  seccomp_rule_add(ctx,SCMP_ACT_KILL,SCMP_SYS(execve),0); //add roles into filter
    seccomp_rule_add(ctx,SCMP_ACT_KILL,SCMP_SYS(write),0); //add roles into filter

此时禁止write和execve的系统调用,不管其系统调用对应函数的参数咋样

有参数条件禁用系统调用

当有限制规则时,对应规则通过以下宏编写

/**
 * Specify an argument comparison struct for use in declaring rules
 * @param arg the argument number, starting at 0
 * @param op the comparison operator, e.g. SCMP_CMP_*
 * @param datum_a dependent on comparison
 * @param datum_b dependent on comparison, optional
 */
#define SCMP_CMP(...)		((struct scmp_arg_cmp){__VA_ARGS__})

/**
 * Specify an argument comparison struct for argument 0
 */
#define SCMP_A0(...)		SCMP_CMP(0, __VA_ARGS__)

/**
 * Specify an argument comparison struct for argument 1
 */
#define SCMP_A1(...)		SCMP_CMP(1, __VA_ARGS__)

/**
 * Specify an argument comparison struct for argument 2
 */
#define SCMP_A2(...)		SCMP_CMP(2, __VA_ARGS__)

/**
 * Specify an argument comparison struct for argument 3
 */
#define SCMP_A3(...)		SCMP_CMP(3, __VA_ARGS__)

/**
 * Specify an argument comparison struct for argument 4
 */
#define SCMP_A4(...)		SCMP_CMP(4, __VA_ARGS__)

/**
 * Specify an argument comparison struct for argument 5
 */
#define SCMP_A5(...)		SCMP_CMP(5, __VA_ARGS__)



/**
 * Comparison operators
 */
enum scmp_compare {
	_SCMP_CMP_MIN = 0,
	SCMP_CMP_NE = 1,		/**< not equal */
	SCMP_CMP_LT = 2,		/**< less than */
	SCMP_CMP_LE = 3,		/**< less than or equal */
	SCMP_CMP_EQ = 4,		/**< equal */
	SCMP_CMP_GE = 5,		/**< greater than or equal */
	SCMP_CMP_GT = 6,		/**< greater than */
	SCMP_CMP_MASKED_EQ = 7,		/**< masked equality */
	_SCMP_CMP_MAX,
};

/**
 * Argument datum
 */
typedef uint64_t scmp_datum_t;

/**
 * Argument / Value comparison definition
 */
struct scmp_arg_cmp {
	unsigned int arg;	/**< argument number, starting at 0 */
	enum scmp_compare op;	/**< the comparison op, e.g. SCMP_CMP_* */
	scmp_datum_t datum_a;
	scmp_datum_t datum_b;
};

 seccomp_rule_add(ctx,SCMP_ACT_KILL,SCMP_SYS(write),1,SCMP_A0(SCMP_CMP_LE,0x10)); //add roles into filter
    /*read的第0个参数为文件描述符,其小于等于0x10时不能使用*/
 seccomp_rule_add(ctx,SCMP_ACT_KILL,SCMP_SYS(read),2,
                    SCMP_A0(SCMP_CMP_LE,0x10),
                    SCMP_A2(SCMP_CMP_GT,0x8)); //add roles into filter此时read有两天规则,第0个参数需要小于等于0x10,第2个参数需要大于0x8,那么将禁止其使用
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(write),1,SCMP_A2(SCMP_CMP_EQ,0x10));//第2(从0开始数起)个参数等于0x10 此时如果write函数的第2个参数即写入长度等于0x10将使用失败

prctl

int prctl(int option, unsigned long arg2, unsigned long arg3,
          unsigned long arg4, unsigned long arg5);
prctl(PR_SET_NO_NEW_PRIVS,1,0,0,0);

当option为PR_SET_NO_NEW_PRIVS(38),且arg2为1时,将无法获得特权,即能getshell,但无法获得root权限
在这里插入图片描述
当option为PR_SET_SECCOMP(22)时,效果就是我们上面的seccomp了,只不过这里的格式略有不同。此时还与参数2有关
如果arg2为SECCOMP_MODE_STRICT(1),则只允许调用read,write,_exit(not exit_group),sigreturn这几个系统调用
如果arg2为SECCOMP_MODE_FILTER(2),则为过滤模式,其中对syscall的限制通过arg3用BPF(Berkeley Packet Filter)的形式传进来,是指向struct sock_fprog数组的指针

/*
 *	Try and keep these values and structures similar to BSD, especially
 *	the BPF code definitions which need to match so you can share filters
 */
 
struct sock_filter {	/* Filter block */
	__u16	code;   /* Actual filter code */
	__u8	jt;	/* Jump true 符合jmp条件时跳过的规则数*/
	__u8	jf;	/* Jump false不符合jmp条件时跳过的规则数 */
	__u32	k;      /* Generic multiuse field */
};
struct sock_fprog {	/* Required for SO_ATTACH_FILTER. */
	unsigned short		len;	/* Number of filter blocks */
	struct sock_filter *filter;
};

关于filter中的格式其实可以分为BPF_STMT和BPF_JUMP两种格式,注意k的位置在宏定义中的参数和对应的filter中是不同,k在filter中都是第四个,但BPF_JUMP(code, k, jt, jf)为第二个

#ifndef BPF_STMT
#define BPF_STMT(code, k) { (unsigned short)(code), 0, 0, k }
#endif
#ifndef BPF_JUMP
#define BPF_JUMP(code, k, jt, jf) { (unsigned short)(code), jt, jf, k }
#endif

此时两种格式中code的值是由各种宏或得到的

/* Instruction classes */                    
#define BPF_CLASS(code) ((code) & 0x07)    //指定操作的类别
#define        BPF_LD        0x00               //将值复制到累加器中
#define        BPF_LDX        0x01               //将值加载到索引寄存器中
#define        BPF_ST        0x02               //将累加器中的值存到暂存器
#define        BPF_STX        0x03               //将索引寄存器的值存储在暂存器中
#define        BPF_ALU        0x04               //用索引寄存器或常数作为操作数在累加器上执行算数或逻辑运算
#define        BPF_JMP        0x05               //跳转
#define        BPF_RET        0x06               //返回
#define        BPF_MISC        0x07           // 其他类别
 
/* ld/ldx fields */
#define BPF_SIZE(code)  ((code) & 0x18)
#define        BPF_W        0x00 /* 32-bit */       //字
#define        BPF_H        0x08 /* 16-bit */       //半字
#define        BPF_B        0x10 /*  8-bit */       //字节
/* eBPF        BPF_DW        0x18    64-bit */       //双字
#define BPF_MODE(code)  ((code) & 0xe0)
#define        BPF_IMM        0x00                  //常数 
#define        BPF_ABS        0x20                  //固定偏移量的数据包数据(绝对偏移)
#define        BPF_IND        0x40                  //可变偏移量的数据包数据(相对偏移)
#define        BPF_MEM        0x60                  //暂存器中的一个字
#define        BPF_LEN        0x80                  //数据包长度
#define        BPF_MSH        0xa0
 
/* alu/jmp fields */
#define BPF_OP(code)    ((code) & 0xf0)       //当操作码类型为ALU时,指定具体运算符   
#define        BPF_ADD        0x00        
#define        BPF_SUB        0x10
#define        BPF_MUL        0x20
#define        BPF_DIV        0x30
#define        BPF_OR        0x40
#define        BPF_AND        0x50
#define        BPF_LSH        0x60
#define        BPF_RSH        0x70
#define        BPF_NEG        0x80
#define        BPF_MOD        0x90
#define        BPF_XOR        0xa0
                                               //当操作码是jmp时指定跳转类型
#define        BPF_JA        0x00
#define        BPF_JEQ        0x10
#define        BPF_JGT        0x20
#define        BPF_JGE        0x30
#define        BPF_JSET        0x40
#define BPF_SRC(code)   ((code) & 0x08)
#define        BPF_K        0x00                    //常数
#define        BPF_X        0x08                    //索引寄存器

k也可以是以下宏定义

/*
 * All BPF programs must return a 32-bit value.
 * The bottom 16-bits are for optional return data.
 * The upper 16-bits are ordered from least permissive values to most,
 * as a signed value (so 0x8000000 is negative).
 *
 * The ordering ensures that a min_t() over composed return values always
 * selects the least permissive choice.
 */
#define SECCOMP_RET_KILL_PROCESS 0x80000000U /* kill the process */
#define SECCOMP_RET_KILL_THREAD	 0x00000000U /* kill the thread */
#define SECCOMP_RET_KILL	 SECCOMP_RET_KILL_THREAD
#define SECCOMP_RET_TRAP	 0x00030000U /* disallow and force a SIGSYS */
#define SECCOMP_RET_ERRNO	 0x00050000U /* returns an errno */
#define SECCOMP_RET_USER_NOTIF	 0x7fc00000U /* notifies userspace */
#define SECCOMP_RET_TRACE	 0x7ff00000U /* pass to a tracer or disallow */
#define SECCOMP_RET_LOG		 0x7ffc0000U /* allow after logging */
#define SECCOMP_RET_ALLOW	 0x7fff0000U /* allow */

/* Masks for the return value sections. */
#define SECCOMP_RET_ACTION_FULL	0xffff0000U
#define SECCOMP_RET_ACTION	0x7fff0000U
#define SECCOMP_RET_DATA	0x0000ffffU


下面这段代码定义了一些编写seccomp BPF code可能会用到的东西,根据注释可知,我们可以在BPF code中获取该系统调用的:系统调用号、处理器架构、指令地址、6个参数的值。具体选择获取什么通过字段k来决定,k相当于seccomp_data结构体的偏移量,若指定k=0,则为获取nr,即系统调用号,若k=4,则为获取处理器架构等。

/**
 * struct seccomp_data - the format the BPF program executes over.
 * @nr: the system call number
 * @arch: indicates system call convention as an AUDIT_ARCH_* value
 *        as defined in <linux/audit.h>.
 * @instruction_pointer: at the time of the system call.
 * @args: up to 6 system call arguments always stored as 64-bit values
 *        regardless of the architecture.
 */
struct seccomp_data {
	int nr;
	__u32 arch;
	__u64 instruction_pointer;
	__u64 args[6];
};

实例

K指的是AUDIT_ARCH_X86_64,定义于/include/uapi/linux/audit.h,其中为所有架构都定义了独特的标识符,而0xc000003e则是AUDIT_ARCH_X86_64的值。对于整个seccomp code而言,可能需要的外部数据也就只有seccomp_data了。

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  LD | ABS | Word, R0 = arch
 0001: 0x15 0x00 0x19 0xc000003e  JMP | JEQ after 0x19, R0 == AUDIT_ARCH_X86_64 
 0002: 0x20 0x00 0x00 0x00000000  LD | ABS | Word, R0 = nr
 0003: 0x35 0x00 0x01 0x40000000  JMP | JGE after 0x01, R0 >= 0x40000000 ?
 0004: 0x15 0x00 0x16 0xffffffff  JMP | JEQ after 0x16, R0 == 0xFFFFFFFF ?
 0005: 0x15 0x15 0x00 0x00000000  JMP | JEQ after 0x15, R0 == 0 ?
 0006: 0x15 0x14 0x00 0x00000001  JMP | JEQ after 0x14, R0 == 1 ?
 0007: 0x15 0x13 0x00 0x00000002  JMP | JEQ after 0x13, R0 == 2 ?
 ...
 0026: 0x06 0x00 0x00 0x7fff0000  return SECCOMP_RET_ALLOW
 0027: 0x06 0x00 0x00 0x00000000  return SECCOMP_RET_KILL

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  LD | ABS | Word, R0 = arch

code为0x20是BDF_LD(0x00)|BDF_ABS(0X20)|BOF_W的结果,就是将一个字的值通过固定偏移量复制到累加器中,此时k对应为偏移量4,即seccomp_data偏移量为4的位置正好是arch的结构

 line  CODE  JT   JF      K
=================================
 0001: 0x15 0x00 0x19 0xc000003e  JMP | JEQ after 0x19, R0 == AUDIT_ARCH_X86_64 

此时code 15是BPF_JMP(0x05)|BPF_JEQ(0x10)的结果,此时是相等跳转指令,相等则跳转到下一条指令,不相等则跳转到下条指令+0x19的位置,将累加器与k的值做对比,此时累加器的值是之前取的arch

seccomp_export_bpf

参考
seccomp_export_bpf的函数能够将设置的seccomp以bpf的形式导出

//gcc -g simple_syscall_seccomp.c -o simple_syscall_seccomp -lseccomp
#include <unistd.h>
#include <seccomp.h>
#include <linux/seccomp.h>
#include <fcntl.h>
int main(void){

	scmp_filter_ctx ctx;
	ctx = seccomp_init(SCMP_ACT_ALLOW);
	seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(write),1,SCMP_A2(SCMP_CMP_EQ,0x10));
	seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve),0);
	seccomp_load(ctx);

	int fd = open("bpf.out",O_WRONLY);
	seccomp_export_bpf(ctx,fd);
	close(fd);


	char * filename = "/bin/sh";
	char * argv[] = {"/bin/sh",NULL};
	char * envp[] = {NULL};
	write(1,"i will give you a shell\n",24);
	write(1,"1234567812345678",0x10);
	syscall(0x4000003b,filename,argv,envp);//execve
	return 0;
}

得到对应的bpf的二进制文件

$ hexdump bpf.out
0000000 0020 0000 0004 0000 0015 0900 003e c000
0000010 0020 0000 0000 0000 0035 0007 0000 4000
0000020 0015 0006 003b 0000 0015 0400 0001 0000
0000030 0020 0000 0024 0000 0015 0200 0000 0000
0000040 0020 0000 0020 0000 0015 0001 0010 0000
0000050 0006 0000 0000 7fff 0006 0000 0000 0000
0000060 0000 0000 0000 0000 0000 0000 0000 0000

改用prctl

#include <unistd.h>
#include <sys/prctl.h>
#include <linux/filter.h>
#include <linux/seccomp.h>

int main(void){
	
	prctl(PR_SET_NO_NEW_PRIVS,1,0,0,0);
	struct sock_filter sfi[] = {
		{0x20,0x00,0x00,0x00000004},
		{0x15,0x00,0x09,0xc000003e},
		{0x20,0x00,0x00,0x00000000},
		{0x35,0x07,0x00,0x40000000},
		{0x15,0x06,0x00,0x0000003b},
		{0x15,0x00,0x04,0x00000001},
		{0x20,0x00,0x00,0x00000024},
		{0x15,0x00,0x02,0x00000000},
		{0x20,0x00,0x00,0x00000020},
		{0x15,0x01,0x00,0x00000010},
		{0x06,0x00,0x00,0x7fff0000},
		{0x06,0x00,0x00,0x00000000}
	};
	struct sock_fprog sfp = {12,sfi};

	prctl(PR_SET_SECCOMP,SECCOMP_MODE_FILTER,&sfp);
	
	char * filename = "/bin/sh";
	char * argv[] = {"/bin/sh",NULL};
	char * envp[] = {NULL};
	write(1,"i will give you a shell\n",24);
	write(1,"1234567812345678",0x10);
	syscall(0x4000003b,filename,argv,envp);//execve
	return 0;
}

成功拦截函数

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

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

相关文章

Java可视化大屏智慧工地云平台源码(SaaS模式)

智慧工地是一种崭新的工程现场一体化管理模式&#xff0c;是互联网与传统建筑行业的深度融合。它充分利用移动互联、物联网、云计算、大数据等新一代信息技术&#xff0c;围绕人、机、料、法、环等各方面关键因素&#xff0c;彻底改变传统建筑施工现场参建各方现场管理的交互方…

鸿蒙开发已解决The module to import is incompatible with the current project

文章目录 项目场景:问题描述原因分析:解决方案:心得体会:知识点OpenHarmony:HarmonyOS:项目场景: 报错: The module to import is incompatible with the current project 问题描述 希望通过 import module 将该模块引入到我的项目。 导入后出现错误,因为项目和模

从事涉密测绘业务的人员应当具有中华人民共和国国籍,签订保密责任书,接受保密教育。

从事涉密测绘业务的人员应当具有中华人民共和国国籍&#xff0c;签订保密责任书&#xff0c;接受保密教育。 1、从事涉密测绘业务并签署保密责任书的人员清单&#xff08;包括&#xff1a;姓名、身份证号码、工作岗位、责任书签署日期&#xff09; 2、近三年内&#xff08;或…

【Java 设计模式】设计原则

文章目录 ✨单一职责原则&#xff08;SRP&#xff09;✨开放/封闭原则&#xff08;OCP&#xff09;✨里氏替换原则&#xff08;LSP&#xff09;✨依赖倒置原则&#xff08;DIP&#xff09;✨接口隔离原则&#xff08;ISP&#xff09;✨合成/聚合复用原则&#xff08;CARP&#…

项目管理:放权并非推卸责任,项目经理如何做好授权管理

项目经理作为项目的管理者&#xff0c;肩负着对项目整体结果的重大责任。然而&#xff0c;项目的成功并非项目经理一人之力所能完成&#xff0c;因此&#xff0c;恰当地授权给团队成员显得尤为重要。 但是&#xff0c;项目经理的能力和精力有限&#xff0c;只有通过授权&…

【推文】企业级AI问答知识库训练营,火热开营中!

简介&#xff1a;阿里云人工智能平台PAI【企业AI成长营】系列课程上线&#xff01;第一弹&#xff1a;企业AI问答知识库训练营&#xff0c;手把手带你从入门到实操快速完成知识库搭建&#xff0c;助力企业AI应用落地。 &#x1f4da; 企业AI问答知识库训练营&#xff1a;点击报…

性能分析与调优: Linux 内存观测工具

目录 一、实验 1.环境 2.vmstat 3.PSI 4.swapon 5.sar 6.slabtop 7.numstat 8.ps 9.top 10.pmap 11.perf 12.bpftrace 二、问题 1.接口读写报错 2.slabtop如何安装 3.numactl如何安装 4.numad启动服务与关闭NUMA 5. perf如何安装 6. kernel-lt-doc与kern…

Java Stream介绍和实战

目录 1. 引言 2. Stream 的基本特性 3. 创建 Stream 4. Stream 的中间操作 5. Stream 的终端操作 6. Stream 的性能优化 7. 实例演示 8. 注意事项 9. 结语 1. 引言 Java 中的 Stream 是 Java 8 引入的一种用于对集合进行操作的工具&#xff0c;为开发者提供了一种更便…

苹果在美国被禁售有望反转!

都说开门大吉,可2024年似乎对苹果公司并不友好,一会儿是Apple Watch系列在美国被禁售,一会儿又是分析师唱衰iPhone 16,总之各种风声杂糅,给人一种苹果正遭遇重大危机的感觉。 此前美国国际贸易委员会(ITC)下达了对苹果旗下部分智能手表的进口禁令,Apple Watch Series9和…

优思学院|为什么医疗行业供应商需要六西格玛管理?

什么是六西格玛管理&#xff1f; 六西格玛管理是一种旨在提高产品和服务质量的方法论。它通过减少过程中的错误和变异性&#xff0c;来提高效率和性能。自20世纪80年代由摩托罗拉公司首创以来&#xff0c;六西格玛已经在各行各业得到广泛应用。 医疗行业的特点 医疗行业是一…

C#.Net学习笔记——设计模式六大原则

***************基础介绍*************** 1、单一职责原则 2、里氏替换原则 3、依赖倒置原则 4、接口隔离原则 5、迪米特法原则 6、开闭原则 一、单一职责原则 举例&#xff1a;类T负责两个不同的职责&#xff1a;职责P1&#xff0c;职责P2。当由于职责P1需求发生改变而需要修…

【leetcode】力扣热门之回文链表【简单难度】

题目描述 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 用例 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true 输入&#xff1a;head [1,2] 输出&#xff1a;f…

TikTok电商年度洞察:出海到底“卖什么”?各国多类目爆款洞察,迅速掌握市场领先优势

很多卖家在尝试出海时&#xff0c;常面临两大核心痛点&#xff1a;一是“卖什么”&#xff0c;即选择何种商品进行销售&#xff1b;二是“怎么卖”&#xff0c;即如何通过有效的营销策略将商品销售出去。TikTok主打的内容电商模式&#xff0c;通过短视频和直播等形式&#xff0…

LeetCode-1822/1502/896/13

1.数组元素积的符号&#xff08;1822&#xff09; 题目描述&#xff1a; 已知函数 signFunc(x) 将会根据 x 的正负返回特定值&#xff1a; 如果 x 是正数&#xff0c;返回 1 。 如果 x 是负数&#xff0c;返回 -1 。 如果 x 是等于 0 &#xff0c;返回 0 。 给你一个整数数组…

2.SPSS数据文件的建立和管理

文章目录 数据文件的特点建立SPSS数据文件步骤 数据文件的结构变量的规则 数据的录入和保存录入数据保存文件 数据的编辑数据定位 数据文件的特点 SPSS数据库文件包括文件结构和数据两部分 SPSS数据文件中的一列数据称为一个变量。每个变量都应有一个名称&#xff0c;即&…

如何搭建WampServer并结合cpolar内网穿透实现公网访问本地服务

文章目录 推荐前言1.WampServer下载安装2.WampServer启动3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4.固定公网地址访问 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&am…

视图与索引连表查询内/外联和子查询

1.视图 先介绍一下视图&#xff1a; 从SQL的角度来看&#xff0c;视图和表是相同的&#xff0c;两者的区别在于表中存储的是实际的数据&#xff0c;而视图中保存的是SELECT语句&#xff08;视图本身并不存储数据&#xff09;。 使用视图可以轻松完成跨多表查询数据等复杂操作…

案例分享:当前高端低延迟视频类产品方案分享(内窥镜、记录仪、车载记录仪、车载环拼、车载后视镜等产品)

若该文为原创文章&#xff0c;转载请注明出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/135439369 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

Qt QWidget窗口基类

文章目录 1 QWidget介绍2 如何显示 QWidget窗口2.1 新建基于QWidget的窗口类2.2 再添加一个QWidget窗口类2.3 显示新添加的 QWidget窗口 3 常用的属性和方法3.1 窗口位置3.2 窗口大小3.3 窗口标题3.4 窗口图标3.5 资源文件 4 实例 1 QWidget介绍 Qt 中的常用控件&#xff0c;比…

flex弹性盒子常用的布局属性详解

想必大家在开发中经常会用到flex布局。而且还会经常用到 justify-content 属性实现分栏等等 接下来给大家分别讲一下 justify-content 的属性值。 以下是我敲的效果图大家可以清晰看出区别 space-between 属性值可以就是说两端对齐 space-evenly 属性值是每个盒子之间的…