• 程序可信任路径代码执行漏洞

    日期:2013-05-07 | 分类:软件漏洞

    作者:riusksk

    博客:http://riusksk.blogbus.com

    时间:2012-09-26

     

    【漏洞描述】

          在使用CreateProcess函数时,当第一个参数lpApplicationName为NULL,而第二个参数lpCommandLine中包含有空格,且未加双引号时,会导致在执行函数时会被截断,比如:c:\program files\sub dir\program name,程序将会以下列顺序来搜索程序:

     

    c:\program.exe files\sub dir\program name

    c:\programfiles\sub.exe dir\program name

    c:\programfiles\sub dir\program.exe name

    c:\programfiles\sub dir\program name.exe

     

    演示代码:

     

    #include <stdio.h>

    #include <windows.h>

     

    int main()

    {

             char cmd[] = "C:\\Program Files\\test.exe";                  // test.exe为命令控制台cmd.exe,而C:\Program.exe为计算器calc.exe

             STARTUPINFO si = { sizeof(si) };

             PROCESS_INFORMATION pi;

             si.dwFlags = STARTF_USESHOWWINDOW; 

             si.wShowWindow = TRUE;

             CreateProcess(NULL,cmd,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);   

             return 0;

     

    }

     

    执行后会打开计算器calc.exe,而不是cmd.exe:

     

     

     

    【漏洞修复】

     

    主要有以下两种修复方式:

    1、  将执行命令字符串放置在第1个参数lpApplicationName中:

     

             CreateProcess(cmd,NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);   

     

    2、当将命令字符串放置在第2个参数时,应用双引号包括进来:

     

            char cmd[] = "\”C:\\Program Files\\test.exe\”";   

  • Satellite DLL Hijacking

    日期:2013-05-07 | 分类:软件漏洞

    作者:riusksk

    主页:http://riusksk.blogbus.com

    时间:2012年3月7日

     

    【概述】

     

    微软从VS2003/MFC7.0开始就提供对Satellite DLL的增强支持,主要用于创建针对多种语言进行本地化的应用程序。Satellite DLL属于纯资源DLL,它包含应用程序针对特定语言进行本地化的资源。当应用程序开始执行时,MFC会自动加载最适合于当前运行环境的本地化资源,比如在中文系统上,应用程序会优先使用中文资源,若是英文系统,则使用英文资源。Satellite DLL的命名规范为ApplicationNameXXX.dll,其中ApplicationName是使用MFC的*.EXE或者*.DLL的名称,而XXX为由资源语言的三个字母组成,比如中文为CHS,英文为ENU。由于经MFC编译的应用程序会自动加载相应语言的本地化资源(即Satellite DLL),且对加载的资源文件的合法性未作有效检测,因此可能被恶意程序利用DLL劫持来实现任意代码执行。

     

    【技术分析】

     

    MFC主要按照以下顺序加载每种语言的资源DLL,找到一个后将停止加载下面的其它DLL:

     

    1. 当前用户的默认界面语言(UI Language)(适用于 Windows 2000 或更高版本),该语言从 GetUserDefaultUILanguage() Win32 API 返回;

    2. 当前用户的默认界面语言(适用于Windows 2000 或更高版本),没有任何特定子语言(即 ENC [加拿大英语] 变成 ENU [美国英语]);

    3. 系统的默认界面语言(适用于Windows 2000 或更高版本),这是从 GetSystemDefaultUILanguage() API 返回的语言。 在其他平台上,这是操作系统本身的语言;

    4. 系统的默认界面语言,没有任何特定的子语言;

    5. 具有 3 个字母代码 LOC 的“虚设”语言。

     

    比如使用MFC的应用程序Example.exe,系统的用户界面语言是ENU(美国英语),而当前用户的用户界面语言为FRC(加拿大法语),那么MFC将按照以下顺序查找资源DLL文件:

     

    1. ExampleFRC.dll(当前用户的界面语言,此例为加拿大法语);

    2. ExampleFRA.dll(当前用户的界面语言,不包含子语言,此例为法语(法国));

    3. ExampleENU.dll(系统默认的用户界面语言,此例为美国英语);

    4. ExampleLOC.dll。

     

    如果未找到上面DLL中任何一个,则MFC会使用Example.exe自带的资源。当应用程序自带有界面语言资源DLL文件时,它也会按照上述顺序来加载。比如在Win7简体中文系统上,应用程序Example.exe拥有自己的UI资源文件MainUI.dll,那么就会首先去加载MainUICHS.dll。

    因此,恶意程序如果在程序相当目录下,比如上面MainUI.dll所在目录下,再放置一个包含恶意代码的MainUICHS.dll后,打开主程序Example.exe后,就会优先加载包含恶意代码的MainUICHS.dll,而非MainUI.dll,从而执行任意代码,如下图所示:

     

     

    由于多数MFC程序默认会动态链接mfc70.dll、mfc80.dll、mfc90.dll等dll文件(具体文件名与MFC版本号相关),因此在中文系统下,如果在相应的程序目录下放置mfc**chs.dll或者mfc**loc.dll都有可能达到DLL劫持的目的。

     

    【参考资源】

     

    1、Localized Resources in MFC Applications: Satellite DLLs

    http://msdn.microsoft.com/en-us/library/8fkteez0(v=vs.90).aspx

     

    2、Localization of MFC Components

    http://msdn.microsoft.com/en-us/library/x6h91d9w(v=vs.90).aspx

     

  • 关于MS13-011

    日期:2013-03-07 | 分类:软件漏洞

     

    作者:riusksk【TSRC】
    博客:http://riusksk.blogbus.com
    微博:http://t.qq.com/riusksk
    时间:2013年2月12日

     

    前言


    2012年10月15日exploit-db漏洞公布站点上发布了《QQPlayer 3.7.892 m2p quartz.dll Heap Pointer Overwrite PoC》,后被人提交至乌云和CNCERT。但经过腾讯安全应急响应团队的分析,确认该漏洞与QQ影音无关,而是微软DirectShow quartz.dll在解析M2P文件时存在堆溢出漏洞,随后腾讯安全团队及时报与微软应急响应中心(MSRC),微软回复确认漏洞存在并于2013/2/12发布补丁修复,其对应的微软编号及CVE编号分别为MS13-011和CVE-2013-0077,具体漏洞公告参见:http://technet.microsoft.com/zh-cn/security/bulletin/ms13-011

     

     

    技术分析

     

    Windbg附加QQ影音进程运行后打开poc.m2p,触发异常:

    (4c8.6bc): Access violation - code c0000005 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    eax=41414141 ebx=003f0000 ecx=41414141 edx=03128e40 esi=03128e38 edi=00000012
    eip=7c930efe esp=0465f998 ebp=0465fbb8 iopl=0         nv up ei pl zr na pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
    ntdll!RtlAllocateHeap+0x653:
    7c930efe 8b39            mov     edi,dword ptr [ecx]  ds:0023:41414141=*****???

     

     

    开启堆尾检查htc后,重新加载执行后可知这里发生堆溢出:

    0:003> g
    HEAP[QQPlayer.exe]: Heap block at 030609F0 modified at 03060D48 past requested size of 350
    (668.7b8): Break instruction exception - code 80000003 (first chance)
    eax=030609f0 ebx=03060d48 ecx=7c93eab5 edx=02a5f842 esi=030609f0 edi=00000350
    eip=7c92120e esp=02a5fa44 ebp=02a5fa48 iopl=0         nv up ei pl nz na po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
    ntdll!DbgBreakPoint:
    7c92120e cc              int     3

     

     

     

    更为详细的内容请参见TSRC博客:http://security.tencent.com/index.php/blog/msg/15

  • 最近exploit-db上面爆了不少IE和office的crash poc(听binjo说那老外最近在找工作,所以发点poc赚RP),比如bugtraq上刚爆的IE9 crash poc,其实这些漏洞大多是没法利用的(在特定漏洞场景下还是有可能造成安全风险的),因为这些漏洞都是属于stack overflow,也叫stack exhaustion,即栈耗尽异常,报给微软的话,估计也只是当bug处理,不会认为是安全漏洞。

    stack overflow(stack exhaustion)与我们平常所说的栈溢出或者栈缓冲区溢出还是有区别的,stack overflow 主要是指由于栈空间被耗尽,导致无法继续入栈而导致的异常,也称为栈上溢,一般出现异常的都是push指令,如下图(ie9 crash)所示:

     

     

    我们平常所说的栈溢出漏洞(stack buffer overflow)是指栈下溢,由于复制数据到栈上时超出栈空间大小,导致数据覆盖到下一栈空间,可能被用于执行任意代码,异常一般出现在出栈返回时触发的,通过控制返回地址或者SEH就有可能被利用。

  • Adobe Flash APSB12-22 Sample

    日期:2012-10-13 | 分类:软件漏洞

     

    华为网盘:http://dl.vmall.com/c08ibbdec1

    QQ邮箱中转站下载:http://mail.qq.com/cgi-bin/ftnExs_download?k=2a383965559d9ccd0e6bbb7f4066511d565b5d06575155034e0d0a5c044b5705020b14075451511f5508095703515b5607590f5366726373336b7b54544b5100436b5808160a061c1951496523&t=exs_ftn_download&code=c89effc2

     

  • Heap Spray 技术

    日期:2012-10-07 | 分类:软件漏洞

     

    1、堆喷射堆块大小 ≈ 程序堆块分配大小,以减小堆空隙大小。

     

    2、不能使用堆缓存块,否则可能破坏地址的可预测性,可通过申请6块相应大小的堆块来清空缓存。

     

    3、精确定位ROP地址,目标地址如0x0c0c0c0c至堆块数据起始地址的offset = ( 0x0c0c0c0c - UserPtr(堆数据起始地址))/2,IE7:0x5FA,IE8:0x5F4/0x5F6,IE9:0x5FC/0x5FE,Firefox9:0x606,可能不同语言版本会存在偏差。

     

    4、不同系统、不同浏览器版本喷射块大小:

    XP SP3 – IE7 block = shellcode.substring(2,0x10000-0×21);

    XP SP3 – IE8 block = shellcode.substring(2, 0x40000-0×21);

    Vista SP2 – IE7 block = shellcode.substring(0, (0x40000-6)/2);

    Vista SP2 – IE8 block = shellcode.substring(0, (0x40000-6)/2);

    Win7 – IE8 block = shellcode.substring(0, (0x80000-6)/2);

    Vista/Win7 – IE9 block = shellcode.substring(0, (0x40000-6)/2);

    XP SP3/VISTA SP2/WIN7 - Firefox9 block = shellcode.substring(0, (0x40000-6)/2);

     

    5、Nozzle保护机制(IE):检测是否存在重复可转换成汇编代码的字段,若存在则阻止其内存申请。

     

    6、BuBBle保护机制(Firefox):检测JavaScript是否尝试重复申请 NOPs + shellcode (padding + rop chain + shellcode + padding)的内存块,若发现包含这些字段则阻止其内存申请。

     

    7、分配 随机数 + rop + shellcode + 随机数 的堆块,以保证各分配块都是不同的,以此绕过上述保护机制,主要针对IE9。

     

    8、利用随机变量名 + 随机块绕过 Firefox9 的保护。

     

    9、HTML5 Heap Spray:EUSecWest2012上的演讲主题,通杀Chrome、Firefox、IE9和Safari

    a、利用canvas标签定义图形,通过脚本控制每个像素的数据再进行喷射;

    b、利用Web Worker的多线程功能,加速堆喷射过程,但IE不支持Worker。

     

  • 总结近期Adobe漏洞

    日期:2012-09-29 | 分类:软件漏洞

     

    CVE-2012-1525:Adobe PDF Reader XSLT 解析堆溢出漏洞

     

    Adobe PDF Reader 在解析嵌入PDF中的XSL文件的可扩展样式表转换语言XSLT时,会将 xsl:attribute 中的 name 属性值(utf8)转换成utf16,当utf8字符数>0x40时就分配堆空间,否则使用本地栈空间。在UTF8ToUTF16转换过程中,分配的堆空间大小heapsize = (utf8字符数 + 1)* 2,当UTF8字符中包含有 “\xF3\xA0\x81\x8D"时,此4字节数据会被当作单个utf8字符“ ó  ”,比如这里的name值为8字节的“\xF3\xA0\x81\x8D\xF3\xA0\x81\x8D",那么heapsize = (2+1)*2 = 6 < 8,由于需要utf8字符数>0x40时才会分配堆空间,因此我们还需要填充更多的“\xF3\xA0\x81\x8D",复制过去后就可导致堆溢出!

     

    CVE-2012-2049:Adobe Acrobat Reader U3D Continuation Image URL 栈溢出漏洞

     

    Adobe Acrobat Reader 在解析U3D文件里的Texture Declaration块(块类型值为0xFFFFFF55)时,若其中的Continuation Image是由外部引入时(属性值为0x1),那么它会通过Image URL数组来索引的,起初该字符串为无符号16位整数类型,然后转换成unicode字符串,该字符串最大为0xFFFF字节,而用于保存 Image URL的栈空间只有0x260大小,调用wcscpy复制后导致栈溢出!

     

    CVE-2012-2050:Adobe PDF Reader WKT 堆溢出漏洞

     

    Well-Known Text(WKT)是一种文本标记语言,用于表示矢量几何对象、空间参照系统及空间参照系统之间的转换,主要应用在地图和卫星图像数据上面。在调用malloc用于分配存放的WKT堆空间大小限制为1024字符(0x400,包括NULL结束符),但在拷贝WKT字符串时未对PDF中的WKT字符串长度进行检测,导致复制过长的字符串到堆中,最终导致堆溢出!

     

    CVE-2012-4147:Adobe PDF Reader RMAs 堆内存破坏漏洞

     

     Rich Media Annotations (RMAs) 允许在PDF中嵌入视频、音频及Flash等富媒体内容,可在PDF中播放各种多媒体文件。在Adobe提供的Javascript API 函数 getAnnotsRichMedia可获取到指定PDF页(通过唯一参数传递特定的PDF页号)的RMA对象数组,而该数组实际上是一个Javascript数组,因此可通过array.shift()、array.splice()和array.pop()等方法来操作并控制数组内容,可能清空数组(用0x80000001填充),导致后面在引用数组中的对象类成员时触发异常,导致崩溃或者执行任意代码。

     

    CVE-2012-4148:Adobe PDF Reader annotation 内存破坏漏洞

     

    PDF文档中的annotation对象主要为用户提供与鼠标键盘进行交互的方式,交互方式主要通过widget annotation来设定域类型和值,它主要提供4个方式:

    Button (/Btn)、Text Field(/Tx)、Choice Field(/Ch)、Signature (/Sig),当上面这些域类型未被设置时,就可能导致Adobe Reader 空指针引用,造成崩溃!

     

  • 2011年的工具DroidAppAuditter用于实现Android软件自动化安全测试,文章也是之前写的了,扔出来与各位分享。

    【标题】:浅谈Android软件安全自动化审计
    【作者】:riusksk(泉哥)
    【邮箱】:riusksk@qq.com
    【博客】:http://riusksk.blogbus.com
    【微博】:http://t.qq.com/riusksk

    【目录】
    0x00 前言
    0x10 Android软件常见漏洞原理及检测
    0x11 敏感信息明文保存
    0x12 程序文件及进程权限问题
    0x13 网络数据明文传输
    0x14 组件权限安全问题
    0x15 其它
    0x20 自动化审计工具——DroidAppAuditter
    0x30 业界Android软件安全现状
    0x40 总结
    0x50 关于我们

    顺便打个广告:


  •  

    作者:泉哥

    主页:http://riusksk.blogbus.com

     

    漏洞描述

             CVE-2012-0809Sudo 1.8.0 ~ 1.8.3p1版本之间的sudo_debug函数存在格式化字符串漏洞,当把程序名作为格式化字符串的一部分传递给fprintf() 函数时就会触发该漏洞。而程序名可通过ln命令来创建符号连接或者其它一些方式来被利用。例如:

      /tmp $ ln -s /usr/bin/sudo %n
      /tmp $ ./%n -D9

    借助通用的格式化字符串漏洞利用技术可能执行任意代码,进而获得Root权限。

     

    源码比对

           下面是对版本号1.8.3p11.8.3p2的源码比较,在漏洞函数sudo_debug中,getprogname用于获取程序名,相当于argv[0],将其保存在fmt2中,然后将它作为格式化字符串的一部分通过vfprintf函数传递给stderr,导致格式化字符串漏洞的发生。修复后的版本,则不再使用fmt2参数来传递格式化字符,而是直接将"%s: %s\n"作为参数,这样格式化字符参数就不可控制的,从而修复格式化字符串漏洞。

    关于该漏洞的利用,老外已经有分析过,具体见《Exploiting Sudofromat string vunerability》:http://www.vnsecurity.net/2012/02/exploiting-sudo-format-string-vunerability/

     

     

  • CVE-2011-3026漏洞分析与修复

    日期:2012-02-26 | 分类:软件漏洞

    作者:riusksk(泉哥)

    主页:http://riusksk.blogbus.com

     

    漏洞描述

        CVE-2011-3026libpng库的png_decompress_chunk函数存在整数溢出漏洞,该库被许多应用程序所使用,包括ChromeFirefox及其它部分使用WebKit内核的浏览器,因此漏洞影响涉及的范围也是比较广泛的,后面的分析我主要是基于Firefox来分析的,因为它是开源的,并且有提供符号表,对于定位漏洞更为方便。

     

    漏洞分析

    Windbg附加Firefox,并运行,然后用它打开Poc.png文件:

     

    0:000> g

    (12a0.7e4): Access violation - code c0000005 (first chance)

    First chance exceptions are reported before any exception handling.

    This exception may be expected and handled.

    eax=00000041 ebx=00008000 ecx=3ffe47ff edx=00000000 esi=061ffffe edi=00498400

    eip=6206768e esp=0026efc0 ebp=0026efc8 iopl=0         nv up ei pl nz na pe nc

    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206

    MOZCRT19!LeadUpVec+0x52:

    6206768e f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

     

    0:000> kb

    ChildEBP RetAddr  Args to Child             

    0026efc8 51b47130 0042a402 06192000 fffffffa MOZCRT19!LeadUpVec+0x52 [F:\SP\vctools\crt_bld\SELF_X86\crt\src\intel\memcpy.asm @ 271]

    0026f02c 51b47246 09200102 003fb2b2 0042a402 xul!png_inflate+0x8a [e:\builds\moz2_slave\rel-192-w32-bld\build\modules\libimg\png\pngrutil.c @ 243]

    0026f0a4 51b4849d 059f1200 00000000 003fb3b4 xul!MOZ_PNG_decomp_chunk+0xa7 [e:\builds\moz2_slave\rel-192-w32-bld\build\modules\libimg\png\pngrutil.c @ 353]

     

    根据漏洞公告我们可以知道漏洞主要出现在 png_decompress_chunk 函数中,其实这里就相当于Firefox中的xul!MOZ_PNG_decomp_chunk,调试前记得先加载Firefox符号表,这也是我为什么选用Firefox来调试libpng漏洞的原因。接下来我们直接通常IDAxul.dll,然后加载xul.pdb,就可以直接找到MOZ_PNG_decomp_chunk函数。不过这里我们先来看下png_inflate函数:

     

    unsigned int __usercall png_inflate(png_struct_def *png_ptr, const char *data, unsigned int size, char *output, unsigned int output_size)

    {

      png_struct_def *v5; // esi@1

      z_stream_s *v6; // edi@1

      int v7; // eax@2

      int v8; // ebx@2

      size_t v9; // eax@7

      unsigned int result; // eax@13

      const char *v11; // eax@17

      int count; // [sp+10h] [bp-40h]@1 count默认为有符号整数

      int ret; // [sp+14h] [bp-3Ch]@2

      char umsg[52]; // [sp+18h] [bp-38h]@20

      unsigned int v15; // [sp+4Ch] [bp-4h]@1

      int v16; // [sp+50h] [bp+0h]@1

     

      v15 = (unsigned int)&v16 ^ __security_cookie;

      count = 0;

      v5 = png_ptr;

      v6 = &png_ptr->zstream;

      png_ptr->zstream.next_in = (char *)data;

      png_ptr->zstream.avail_in = size;

      do

      {

        v5->zstream.next_out = v5->zbuf;

        v5->zstream.avail_out = v5->zbuf_size;

        v7 = MOZ_Z_inflate(v6, 0);

        v8 = v5->zbuf_size - v5->zstream.avail_out;

        ret = v7;

        if ( (!v7 || v7 == 1) && v8 > 0 )

        {

          if ( output && output_size > count )

          {

            v9 = output_size - count;   // 样本测试时的值为 0xFFFFFFFA - 0

            if ( v8 < (signed int)(output_size - count) )      

              v9 = v5->zbuf_size - v5->zstream.avail_out;   // 未执行到这里

            memcpy(&output[count], v5->zbuf, v9);          // 把负数当作size参数时即可触发溢出!!!

          }

          count += v8;

        }

      }

      while ( !ret );

      v5->zstream.avail_in = 0;

      MOZ_Z_inflateReset(v6);

      if ( ret == 1 )

      {

        result = count;                  // 注意这里,countint类型,默认为有符号整数,而result是无符号整数,当count为负数时,result会变得很大,比如0xFFFFFFFA

      }

      else

      {

        ……省略部分代码……

        }

        result = 0;                 

      }

      return result;

    }

     

    下面是通过设置条件记录断点,记录了v7v8output_sizecountmemcpy参数。

    注意:这里记录的countMOZ_PNG_decomp_chunk函数里面的第二个png_inflate里的count值:

    跟进MOZ_PNG_decomp_chunk函数作进一步分析:

    void __cdecl MOZ_PNG_decomp_chunk(png_struct_def *png_ptr, int comp_type, unsigned int chunklength, unsigned int prefix_size, unsigned int *newlength)

    {

      unsigned int v5; // edi@1

      unsigned int v6; // eax@4

      unsigned int v7; // ebx@4

      unsigned int v8; // eax@4

      void *v9; // eax@6

      unsigned int v10; // eax@7

      void *v11; // eax@11

      unsigned int v12; // [sp+14h] [bp-40h]@4

      char *v13; // [sp+14h] [bp-40h]@11

      char *text; // [sp+18h] [bp-3Ch]@6

      char umsg[50]; // [sp+1Ch] [bp-38h]@10

      unsigned int v16; // [sp+50h] [bp-4h]@1

      int v17; // [sp+54h] [bp+0h]@1

     

      v16 = (unsigned int)&v17 ^ __security_cookie;

      v5 = prefix_size;

      if ( prefix_size <= chunklength )

      {

        if ( comp_type )

        {

          __snprintf(umsg, 0x32u, "Unknown zTXt compression type %d", comp_type);

        }

        else

        {

          v6 = png_inflate(png_ptr, &png_ptr->chunkdata[prefix_size], chunklength - prefix_size, 0, 0); 

          v7 = v6;                  // 通过对png_inflate的分析,我们知道这里v6可能为一个很大的数据,而v6-count(count作为计数器,从0开始)最终会作为png_inflate中的memcpysize参数,就有可能导致复制很大一块内存过去,另外,它也可能导致整数上溢,造成内存分配过小,具体见下面分析。

          v8 = prefix_size + v6;

          v12 = v8;

          if ( v8 < 0x3D08FF )

          {

            if ( v7 )

            {

              v9 = MOZ_PNG_malloc_warn(png_ptr, v8 + 1);      // 分配缓冲区text,大小为 prefix_size + v6 + 1,这里prefix_sizev6均为无符号整数,若 prrfix_size + v6 + 1 > 0xFFFFFFFF时就会造成整数上溢,得到的值反而更小。

     

              text = (char *)v9;

              if ( v9 )

              {

                memcpy(v9, png_ptr->chunkdata, prefix_size);

                v10 = png_inflate(                               // 该函数触发崩溃,跟进

                        png_ptr,

                        &png_ptr->chunkdata[prefix_size],

                        chunklength - prefix_size,

                        &text[prefix_size],

                        v7);                             

          ……省略部分代码……

    }

     

    下面是设置条件记录断点时的日志输出情况,分别对v6作了记录:


    漏洞修复

        目前官方发布的 libpng 1.5.9版本已修复该漏洞,大家可以另外下载1.5.8的漏洞版本进行源码比对,看看官方是如何修复此漏洞的。下面的expanded_size就相当于v6,修复版本添加一些参数检测,防止整数上溢,进而也避免了后面memcpy复制内存时size参数过大: