【微软漏洞分析】MS10-013 Microsoft DirectShow 中的漏洞可能允许远程执行代码

MS10-013

Microsoft DirectShow 中的漏洞可能允许远程执行代码 (977935)

摘要

此安全更新解决 Microsoft DirectShow 中一个安全报告的漏洞。 如果用户打开特制 AVI 文件,这两个漏洞可能允许远程执行代码。 成功利用此漏洞的攻击者可以完全控制受影响的系统。 攻击者可随后安装程序;查看、更改或删除数据;或者创建拥有完全用户权限的新帐户。 那些帐户被配置为拥有较少系统用户权限的用户比具有管理用户权限的用户受到的影响要小。

补丁分析

我们这里以windows 7的x86的补丁分析,补丁解开之后的目录列表如下:
补丁解开之后的文件列表
重点查看补丁文件为:

  • directshow-core_6.1.7600.16490\
    • 2009/12/19 17:02 1,328,640 quartz.dll
  • video-for-windows_6.1.7600.16490\
    • 2009/07/14 09:14 65,024 avicap32.dll
    • 2009/12/19 17:02 91,648 avifil32.dll
    • 2009/12/19 17:02 84,480 mciavi32.dll
    • 2009/12/19 17:02 13,312 msrle32.dll
    • 2009/07/14 09:15 120,320 msvfw32.dll
    • 2009/12/19 17:02 31,744 msvidc32.dll

quartz.dll

主要包括三个更新函数:

  1. CheckVideoType
  2. CAviMSROutPin::ParseHeader
  3. CAviMSRFilter::ParseHeaderCreatePins

在这里插入图片描述

CheckVideoType

更新前

unsigned int __thiscall CColour::CheckVideoType(CColour *this, const struct _AMMediaType *a2)
{
  unsigned int result; // eax

  if ( !memcmp(a2, &MEDIATYPE_Video, 0x10u) && !memcmp(&a2->formattype, &FORMAT_VideoInfo, 0x10u) )
    result = a2->cbFormat < 0x58 ? 0x8004022A : 0;
  else
    result = -2147220950;
  return result;
}

更新后

int __thiscall CColour::CheckVideoType(CColour *this, const struct _AMMediaType *a2)
{
  int result; // eax
  ULONG v3; // ecx
  
  if ( !memcmp(a2, &MEDIATYPE_Video, 0x10u)
    && !memcmp(&a2->formattype, &FORMAT_VideoInfo, 0x10u)
    && (v3 = a2->cbFormat, v3 >= 0x58) )
  {
    result = ValidateBitmapInfoHeader((int *)a2->pbFormat + 12, v3 - 48) ? 0 : -2147220950;
  }
  else
  {
    result = -2147220950;
  }
  return result;
}

CAviMSROutPin::ParseHeader

更新前

int __thiscall CAviMSROutPin::ParseHeader(CAviMSROutPin *this, struct _rifflist *a2, unsigned int a3)

{
......
    CAviMSROutPin::BuildMT(this);
......
}

更新后

int __thiscall CAviMSROutPin::ParseHeader(CAviMSROutPin *this, struct _rifflist *a2, unsigned int a3)

{
......
  if ( CAviMSROutPin::BuildMT(this) < 0
    && *(_DWORD *)(*((_DWORD *)this + 84) + 8) == 1935960438
    && !ValidateBitmapInfoHeader((int *)(*((_DWORD *)this + 85) + 8), *(_DWORD *)(*((_DWORD *)this + 85) + 4)) )
  {
    return 0;
  }

......
}

CAviMSRFilter::ParseHeaderCreatePins

更新前

int __thiscall CAviMSRFilter::ParseHeaderCreatePins(CAviMSRFilter *this)
{
  int v2; // ebx
  struct _riffchunk *v3; // edi
  unsigned __int8 *v4; // ebx
  int result; // eax
  FOURCC v6; // eax
  int v7; // eax
  bool v8; // al
  struct _rifflist *v9; // edi
  unsigned int v10; // eax
  int v11; // [esp-4h] [ebp-18h]
  struct _riffchunk *v12; // [esp+Ch] [ebp-8h] BYREF
  v2 = *((_DWORD *)this + 45);
  *((_DWORD *)this + 46) = 0;
  v3 = (struct _riffchunk *)*((_DWORD *)this + 44);
  v4 = (unsigned __int8 *)v3 + v2;
  v12 = v3;
  if ( !IsValidRIFFChunk(v3, v4) )
    return -2147220945;
  while ( 1 )
  {
    if ( v3->fcc == 1414744396 )
    {
      if ( v3->cb >= 0xC )
      {
        v6 = v3[1].fcc;
        if ( v6 == 1819440243 )
        {
          ++*((_DWORD *)this + 31);
        }
        else if ( v6 == 1819108463 )
        {
          *((_DWORD *)this + 47) = v3;
        }
      }
    }
    else if ( v3->fcc == 1751742049 && v3->cb >= 0x28 )
    {
      *((_DWORD *)this + 46) = v3;
    }
    if ( *((_DWORD *)this + 31) >= 0x80u )
      goto LABEL_16;
    result = GetNextRIFFChunk(v3, v4, &v12);
    if ( result < 0 )
      goto LABEL_17;
    if ( result )
      break;
    v3 = v12;
  }
  v7 = *((_DWORD *)this + 46);
  if ( !v7 )
  {
LABEL_16:
    result = -2147220945;
LABEL_17:
    *((_DWORD *)this + 31) = 0;
    return result;
  }
  v8 = *((_DWORD *)this + 31) == 2 && (*(_DWORD *)(v7 + 20) & 0x100) != 0;
  *((_BYTE *)this + 205) = v8;
  result = CAviMSRFilter::CreatePins(this);
  if ( result < 0 )
    return result;
  v9 = (struct _rifflist *)*((_DWORD *)this + 44);
  v10 = 0;
  v12 = 0;
  while ( v9 < (struct _rifflist *)v4 )
  {
    if ( v9->fcc == 1414744396 && v9->fccListType == 1819440243 )
    {
      if ( v10 >= *((_DWORD *)this + 31) )
        return -2147220945;
      if ( CAviMSROutPin::ParseHeader(*(CAviMSROutPin **)(*((_DWORD *)this + 30) + 4 * v10), v9, v10) )
      {
        v12 = (struct _riffchunk *)((char *)v12 + 1);
      }
      else
      {
        --*((_DWORD *)this + 31);
        v11 = *(_DWORD *)(*((_DWORD *)this + 30) + 4 * *((_DWORD *)this + 31)) + 12;
        (*(void (__stdcall **)(int))(*(_DWORD *)v11 + 8))(v11);
        *(_DWORD *)(*((_DWORD *)this + 30) + 4 * *((_DWORD *)this + 31)) = 0;
      }
      v10 = (unsigned int)v12;
    }
    v9 = (struct _rifflist *)((char *)v9 + v9->cb + (v9->cb & 1) + 8);
  }
  *((_DWORD *)this + 31) = v10;
  return v10 != 0 ? 0 : -2147220945;
}

更新后

int __thiscall CAviMSRFilter::ParseHeaderCreatePins(CAviMSRFilter *this)
{
  struct _riffchunk *v2; // ebx
  int v3; // edi
  unsigned __int8 *v4; // edi
  int result; // eax
  FOURCC v6; // eax
  int v7; // eax
  bool v8; // al
  struct _rifflist *v9; // edi
  unsigned int v10; // ebx
  int v11; // eax
  unsigned int v12; // edx
  _DWORD *v13; // eax
  int v14; // ecx
  struct _riffchunk *v15; // ebx
  int v16; // eax
  unsigned __int8 *v17; // [esp+Ch] [ebp-10h]
  unsigned int v18; // [esp+10h] [ebp-Ch]
  struct _riffchunk *v19; // [esp+14h] [ebp-8h] BYREF
  v2 = (struct _riffchunk *)*((_DWORD *)this + 44);
  v3 = *((_DWORD *)this + 45);
  *((_DWORD *)this + 46) = 0;
  v4 = (unsigned __int8 *)v2 + v3;
  v19 = v2;
  v17 = v4;
  if ( !IsValidRIFFChunk(v2, v4) )
    return -2147220945;
  while ( 1 )
  {
    if ( v2->fcc == 1414744396 )
    {
      if ( v2->cb >= 0xC )
      {
        v6 = v2[1].fcc;
        if ( v6 == 1819440243 )
        {
          ++*((_DWORD *)this + 31);
        }
        else if ( v6 == 1819108463 )
        {
          *((_DWORD *)this + 47) = v2;
        }
      }
    }
    else if ( v2->fcc == 1751742049 && v2->cb >= 0x28 )
    {
      *((_DWORD *)this + 46) = v2;
    }
    if ( *((_DWORD *)this + 31) >= 0x80u )
      goto LABEL_16;
    result = GetNextRIFFChunk(v2, v4, &v19);
    if ( result < 0 )
      goto LABEL_17;
    if ( result )
      break;
    v2 = v19;
  }
  v7 = *((_DWORD *)this + 46);
  if ( !v7 )
  {
LABEL_16:
    result = -2147220945;
LABEL_17:
    *((_DWORD *)this + 31) = 0;
    return result;
  }
  v8 = *((_DWORD *)this + 31) == 2 && (*(_DWORD *)(v7 + 20) & 0x100) != 0;
  *((_BYTE *)this + 205) = v8;
  result = CAviMSRFilter::CreatePins(this);
  if ( result < 0 )
    return result;
  v9 = (struct _rifflist *)*((_DWORD *)this + 44);
  v10 = 0;
  v18 = 0;
  while ( v9 < (struct _rifflist *)v17 )
  {
    if ( v9->fcc == 1414744396 && v9->fccListType == 1819440243 )
    {
      if ( v10 >= *((_DWORD *)this + 31) )
        return -2147220945;
      if ( CAviMSROutPin::ParseHeader(*(CAviMSROutPin **)(*((_DWORD *)this + 30) + 4 * v10), v9, v10) )
      {
        v18 = ++v10;
      }
      else
      {
        --*((_DWORD *)this + 31);
        v11 = *(_DWORD *)(*((_DWORD *)this + 30) + 4 * v10);
        v19 = *(struct _riffchunk **)(v11 + 280);
        (*(void (__stdcall **)(int))(*(_DWORD *)(v11 + 12) + 8))(v11 + 12);
        v12 = v10;
        if ( v10 < *((_DWORD *)this + 31) )
        {
          do
          {
            v13 = (_DWORD *)(*((_DWORD *)this + 30) + 4 * v12);
            v14 = v13[1];
            v15 = *(struct _riffchunk **)(v14 + 280);
            *v13 = v14;
            v16 = *(_DWORD *)(*((_DWORD *)this + 30) + 4 * v12++);
            *(_DWORD *)(v16 + 280) = v19;
            v19 = v15;
          }
          while ( v12 < *((_DWORD *)this + 31) );
          v10 = v18;
        }
        *(_DWORD *)(*((_DWORD *)this + 30) + 4 * *((_DWORD *)this + 31)) = 0;
      }
    }
    v9 = (struct _rifflist *)((char *)v9 + v9->cb + (v9->cb & 1) + 8);
  }
  *((_DWORD *)this + 31) = v10;
  return v10 != 0 ? 0 : -2147220945;
}

msrle32.dll

主要包括二个更新函数:

  1. RleDecompressQuery
  2. RleDecompressGetFormat

RleDecompressQuery

更新前

int __stdcall RleDecompressQuery(int a1, int a2, int a3)
{
  __int16 v3; // dx
  int v4; // ecx
  int result; // eax
  if ( a2
    && ((v3 = *(_WORD *)(a2 + 14), v3 == 8) || *(_DWORD *)(a2 + 16) != 1)
    && ((v4 = *(_DWORD *)(a2 + 16)) == 0 || v4 == 1)
    && (!a3
     || !*(_DWORD *)(a3 + 16)
     && *(_WORD *)(a3 + 14) == v3
     && *(_DWORD *)(a3 + 4) == *(_DWORD *)(a2 + 4)
     && *(_DWORD *)(a3 + 8) == *(_DWORD *)(a2 + 8)) )
  {
    result = 0;
  }
  else
  {
    result = -2;
  }
  return result;
}

更新后

int __stdcall RleDecompressQuery(int a1, int a2, int a3)
{
  __int16 v3; // cx
  int v4; // eax
  int result; // eax
  if ( a2
    && ValidateBitmapInfoHeader((int *)a2, 0x90Cu)
    && ((v3 = *(_WORD *)(a2 + 14), v3 == 8) || *(_DWORD *)(a2 + 16) != 1)
    && ((v4 = *(_DWORD *)(a2 + 16)) == 0 || v4 == 1)
    && (!a3
     || !*(_DWORD *)(a3 + 16)
     && *(_WORD *)(a3 + 14) == v3
     && *(_DWORD *)(a3 + 4) == *(_DWORD *)(a2 + 4)
     && *(_DWORD *)(a3 + 8) == *(_DWORD *)(a2 + 8)) )
  {
    result = 0;
  }
  else
  {
    result = -2;
  }
  return result;
}

RleDecompressGetFormat

更新前

int __stdcall RleDecompressGetFormat(int a1, int a2, ULONG pulResult)
{
  int result; // eax
  int v4; // eax
  __int16 v5; // ax
  result = RleDecompressQuery(a1, a2, 0);
  if ( result )
    return result;
  v4 = *(_DWORD *)(a2 + 32);
  if ( !v4 && *(_WORD *)(a2 + 14) == 8 )
    v4 = 256;
  if ( !pulResult )
    return 4 * v4 + 40;
  qmemcpy((void *)pulResult, (const void *)a2, 0x28u);
  memcpy((void *)(pulResult + 40), (const void *)(a2 + *(_DWORD *)a2), 4 * v4);
  *(_DWORD *)pulResult = 40;
  v5 = *(_WORD *)(a2 + 14);
  *(_DWORD *)(pulResult + 16) = 0;
  *(_WORD *)(pulResult + 14) = v5;
  if ( SAFE_DIBSIZE(pulResult, pulResult + 20) >= 0 )
    result = 0;
  else
    result = -7;
  return result;
}

更新后

int __stdcall RleDecompressGetFormat(int a1, int a2, ULONG pulResult)
{
  int result; // eax
  unsigned int v4; // eax
  __int16 v5; // ax
  result = RleDecompressQuery(a1, a2, 0);
  if ( result )
    return result;
  v4 = *(_DWORD *)(a2 + 32);
  if ( !v4 )
  {
    if ( *(_WORD *)(a2 + 14) != 8 )
    {
LABEL_6:
      if ( *(_DWORD *)a2 < 0x28u )
        return -2;
      if ( !pulResult )
        return 4 * v4 + 40;
      qmemcpy((void *)pulResult, (const void *)a2, 0x28u);
      memcpy((void *)(pulResult + 40), (const void *)(a2 + *(_DWORD *)a2), 4 * v4);
      *(_DWORD *)pulResult = 40;
      v5 = *(_WORD *)(a2 + 14);
      *(_DWORD *)(pulResult + 16) = 0;
      *(_WORD *)(pulResult + 14) = v5;
      if ( SAFE_DIBSIZE(pulResult, pulResult + 20) >= 0 )
        return 0;
      return -7;
    }
    v4 = 256;
  }
  if ( v4 > 0x100 )
    return -2;
  goto LABEL_6;
}

重点分析

  1. 在多个函数中增加了文件header的验证函数ValidateBitmapInfoHeader
  2. 最后的利用点在函数RleDecompressGetFormat中的如下片段
v4 = *(_DWORD *)(a2 + 32);
......
memcpy((void *)(pulResult + 40), (const void *)(a2 + *(_DWORD *)a2), 4 * v4);

网上没找到相应的分析记录,这里把分析过程和结果记录一下,以方便大家的学习。

参考页面

  1. https://learn.microsoft.com/zh-cn/security-updates/securitybulletins/2010/ms10-013
  2. https://catalog.update.microsoft.com/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值