天天看點

詳解cve-2010-2553

我的調試環境是win7旗艦版32位+wmpalyer+windbg+IDA。

poc見: https://www.exploit-db.com/exploits/15112/ wmpalyer設定頁堆:

C:\Program Files\Debugging Tools for Windows (x86)>gflags.exe -i wmplayer.exe +h
pa +htc
Current Registry Settings for wmplayer.exe executable are: 02000010
    htc - Enable heap tail checking
    hpa - Enable page heap
           
C:\Program Files\Debugging Tools for Windows (x86)>gflags.exe -i wmplayer.exe
Current Registry Settings for wmplayer.exe executable are: 02000010
    htc - Enable heap tail checking
    hpa - Enable page heap
           

打開wmplayer,windbg附加程序,wmplayer中打開poc,windbg成功斷下:

0:015> g
(f14.efc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=113f1000 ebx=113ef000 ecx=00000040 edx=00000000 esi=113ef000 edi=113f1000
eip=76faa05b esp=1163f510 ebp=1163f518 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
msvcrt!__ascii_strnicmp+0x99:
76faa05b 660f7f07        movdqa  xmmword ptr [edi],xmm0 ds:0023:113f1000=????????????????????????????????
           

此時檢視棧回溯及113f1000所在堆的資訊:

0:027> kvn
 # ChildEBP RetAddr  Args to Child              
00 1163f518 76faa00b 113f1000 113ef000 00002000 msvcrt!__ascii_strnicmp+0x99 (FPO: [3,0,0])
01 1163f548 70ae3ba2 113f1000 113ef000 00002000 msvcrt!_VEC_memcpy+0x52 (FPO: [3,0,0])
02 1163f588 70aeeeda 00000004 00000000 00000068 iccvid!CVDecompress+0x141 (FPO: [Non-Fpo])
03 1163f5b8 70ae80f8 0ddd0f60 00000000 10ed2fd8 iccvid!Decompress+0x128 (FPO: [Non-Fpo])
04 1163f604 71f01759 0ddd0f60 00000001 0000400d iccvid!DriverProc+0x1bf (FPO: [Non-Fpo])
05 1163f628 6ce78639 71f1c7c0 0000400d 1163f640 MSVFW32!ICSendMessage+0x31 (FPO: [Non-Fpo])
06 1163f658 6ce789c4 71f1c7c0 00000000 10ed2fd8 quartz!CVFWDynLink::ICDecompress+0x3e (FPO: [Non-Fpo])
07 1163f710 6cf26cbe 1107cfa8 111bafb8 00000000 quartz!CAVIDec::Transform+0x2b0 (FPO: [Non-Fpo])
08 1163f73c 6cf26910 1107cfa8 00000000 0e956ee0 quartz!CVideoTransformFilter::Receive+0x120 (FPO: [Non-Fpo])
09 1163f750 6ce60472 0e9aef44 1107cfa8 1163f790 quartz!CTransformInputPin::Receive+0x33 (FPO: [Non-Fpo])
0a 1163f760 6cf2d61e 1107cfa8 00040103 0e956ee0 quartz!CBaseOutputPin::Deliver+0x22 (FPO: [Non-Fpo])
0b 1163f790 6cf2d830 1163f7c0 1163f7bc 00000000 quartz!CBaseMSRWorker::TryDeliverSample+0x102 (FPO: [Non-Fpo])
0c 1163f7d4 6cf2deba 00000000 0e956ee0 0e956ee0 quartz!CBaseMSRWorker::PushLoop+0x15b (FPO: [Non-Fpo])
0d 1163f7ec 6cf2e46a 00000000 6ce35735 00000000 quartz!CBaseMSRWorker::DoRunLoop+0x44 (FPO: [Non-Fpo])
0e 1163f7f4 6ce35735 00000000 00000000 1163f810 quartz!CBaseMSRWorker::ThreadProc+0x39 (FPO: [0,0,4])
0f 1163f804 76811174 0e956ee0 1163f850 7720b3f5 quartz!CAMThread::InitialThreadProc+0x15 (FPO: [Non-Fpo])
10 1163f810 7720b3f5 0e956ee0 6779fde2 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
11 1163f850 7720b3c8 6ce35720 0e956ee0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
12 1163f868 00000000 6ce35720 0e956ee0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
0:027> !heap -p -a 113f1000
    address 113f1000 found in
    _DPH_HEAP_ROOT @ b1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                10e53c64:         113eb000             6000 -         113ea000             8000
    6fe58e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77274ea6 ntdll!RtlDebugAllocateHeap+0x00000030
    77237d96 ntdll!RtlpAllocateHeap+0x000000c4
    772034ca ntdll!RtlAllocateHeap+0x0000023a
    754a7589 KERNELBASE!LocalAlloc+0x0000005f
    70ae3d93 iccvid!CVDecompressBegin+0x00000092
    70aee2a2 iccvid!DecompressBegin+0x000002cf
    70ae80d1 iccvid!DriverProc+0x00000198
    71f01759 MSVFW32!ICSendMessage+0x00000031
    6ce79925 quartz!CAVIDec::StartStreaming+0x0000027a
    6cf266fb quartz!CTransformFilter::Pause+0x00000060
    6ce782a4 quartz!CAVIDec::Pause+0x0000002f
    6ce29e03 quartz!CFilterGraph::Pause+0x00000223
    6ce2c8b1 quartz!CFGControl::Cue+0x00000032
    6ce35c40 quartz!CFGControl::CImplMediaControl::StepPause+0x0000004c
    6ce35be9 quartz!CFGControl::CImplMediaControl::Pause+0x0000002d
    6d4aaac6 qedit!CMediaDet::EnterBitmapGrabMode+0x00000114
    6d4aa64b qedit!CMediaDet::GetBitmapBits+0x000000ac
    6893d32a wmp!SelectPoster+0x000000c3
    6893d585 wmp!EhGetVideoThumbnail+0x000000c5
    68601358 wmp!CWMPThumbnailRetriever::ComputeAndCacheThumbnail+0x00000449
    6891026c wmp!CArtHandler::_RunMLSJob+0x000002a7
    689115ef wmp!CArtHandler::_RunJob+0x00000038
    68911693 wmp!CArtHandler::_BackgroundArtThreadLoop+0x00000044
    68911899 wmp!BackgroundArtWorkProc+0x00000050
    771c6cf5 ntdll!TppWorkpExecuteCallback+0x0000010f
    771de8d1 ntdll!TppWorkerThread+0x00000572
    76811174 kernel32!BaseThreadInitThunk+0x0000000e
    7720b3f5 ntdll!__RtlUserThreadStart+0x00000070
    7720b3c8 ntdll!_RtlUserThreadStart+0x0000001b
           

看到棧回溯中msvcrt!_VEC_memcpy+0x52 我們應該猜到是複制資料的時候出現了問題。

繼續往上看函數的調用,檢視iccvid!CVDecompress+0x141處函數調用:

0:027> ub iccvid!CVDecompress+0x141
iccvid!CVDecompress+0x127:
70ae3b88 8b461c          mov     eax,dword ptr [esi+1Ch]
70ae3b8b 8b4dfc          mov     ecx,dword ptr [ebp-4]
70ae3b8e 03c1            add     eax,ecx
70ae3b90 6800200000      push    2000h
70ae3b95 8d8800e0ffff    lea     ecx,[eax-2000h]
70ae3b9b 51              push    ecx
70ae3b9c 50              push    eax
70ae3b9d e834d60000      call    iccvid!memcpy (70af11d6)
           

可以看到問題出現在iccvid!CVDecompress函數中,其中調用了 iccvid!memcpy引發了異常,那麼就重點分析一下函數iccvid!CVDecompress吧 我們在函數iccvid!CVDecompress上斷點,重新加載,運作并檢視此時函數的參數情況:

0:005> t
eax=00000001 ebx=119bfcf0 ecx=fffb95f0 edx=00000120 esi=112c7f60 edi=10086a10
eip=70d4eed5 esp=119bfca0 ebp=119bfcc8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
iccvid!Decompress+0x123:
70d4eed5 e8874bffff      call    iccvid!CVDecompress (70d43a61)
0:005> dd esp
119bfca0  11306fc0 11148af8 00000068 10040000
119bfcb0  00046e00 10086a10 fffffc10 00000001
119bfcc0  112c7f60 112c7f60 119bfd14 70d480f8
119bfcd0  112c7f60 00000000 112eafd8 11148af8
119bfce0  00000000 00000000 ffffffff ffffffff
119bfcf0  00046e00 10040000 00000068 00000000
119bfd00  ffffffff ffffffff 119bfd50 733ec7dc
119bfd10  0ff80fa8 119bfd38 733d1759 112c7f60
0:005> dd 11148af8
11148af8  68000000 20016001 00101000 00001000
11148b08  60000000 00206001 00110000 41411000
11148b18  41414141 41414141 00114141 41411000
11148b28  41414141 41414141 00114141 41411000
11148b38  41414141 41414141 00114141 00411000
11148b48  31786469 00000010 63643030 00000010
11148b58  00000004 00000068 c0c0c0c0 c0c0c0c0
11148b68  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
           

我們可以看到第二個參數就是poc中cinepak_codec_data1開始的資料。 用IDA打開 iccvid.dll檢視函數iccvid!CVDecompress的僞c代碼(詳見附表): 可以看到當滿足v26 && !BYTE3(a3) && *(_BYTE *)v14 == 17時進行記憶體資料的複制 每次複制v26+1 a3即函數的第三個參數,00000068取一個位元組是以等于0,v14=a2+10 v14+=*(_BYTE *)(v14 + 3) | ((*(_BYTE *)(v14 + 2) | (*(_BYTE *)(v14 + 1) << 8)) << 8) 在未進入循環前,我們看下此時的v14布局:

0:005> dd 0x11148af8+0x0a
11148b02  10000010 00000000 60016000 00000020
11148b12  10000011 41414141 41414141 41414141
11148b22  10000011 41414141 41414141 41414141
11148b32  10000011 41414141 41414141 41414141
11148b42  10000011 64690041 00103178 30300000
11148b52  00106364 00040000 00680000 c0c00000
11148b62  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
           

第一次時,*(byte*)v14=0x10=16!=17是以不會進行複制資料操作 然後v14=v14+*(_BYTE *)(v14 + 3) | ((*(_BYTE *)(v14 + 2) | (*(_BYTE *)(v14 + 1) << 8)) << 8) 此處*(byte*)(v14+3)=0x10 *(byte*)(v14+2)=0x0 *(byte*)(v14+1)=0x0 是以進行操作後v14=v14+0x10 根據記憶體布局 後續的幾次循環其實都是加上0x10 此時*v14=0x10000011,*(byte*)v14=0x11 符合複制資料的條件,進行記憶體資料複制操作。

而且記憶體複制還包含在一個大的循環裡邊,即當v26<v13時進行循環: v26從0開始,每次循環加一,v13等于*(_BYTE *)(a2 + 9) | (*(_BYTE *)(a2 + 8) << 8)這是一個固定值0x10

iccvid!CVDecompress+0x7b:
70d43adc c1e008          shl     eax,8
70d43adf 895df4          mov     dword ptr [ebp-0Ch],ebx
70d43ae2 0bc1            or      eax,ecx
70d43ae4 8d5f0a          lea     ebx,[edi+0Ah]
70d43ae7 8945e0          mov     dword ptr [ebp-20h],eax
70d43aea 895df0          mov     dword ptr [ebp-10h],ebx
70d43aed 0f8ed2010000    jle     iccvid!CVDecompress+0x264 (70d43cc5)
70d43af3 8365fc00        and     dword ptr [ebp-4],0
0:005> bp 70d43ae4
0:005> g
Breakpoint 2 hit
eax=00000010 ebx=00000000 ecx=00000010 edx=00000120 esi=11306fc0 edi=11148af8
eip=70d43ae4 esp=119bfc6c ebp=119bfc98 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
iccvid!CVDecompress+0x83:
70d43ae4 8d5f0a          lea     ebx,[edi+0Ah]
           

最近在步入函數iccvid!CVDecompress時做個虛拟機快照,這樣友善以後調試,也可以避免每次啟動帶來的資料變化。

我們在函數70ae3b9d e834d60000 call iccvid!memcpy處下斷,看他執行幾次出現異常:

0:005> u
iccvid!CVDecompress+0x12a:
70d43b8b 8b4dfc          mov     ecx,dword ptr [ebp-4]
70d43b8e 03c1            add     eax,ecx
70d43b90 6800200000      push    2000h
70d43b95 8d8800e0ffff    lea     ecx,[eax-2000h]
70d43b9b 51              push    ecx
70d43b9c 50              push    eax
70d43b9d e834d60000      call    iccvid!memcpy (70d511d6)
70d43ba2 83c40c          add     esp,0Ch
0:005> bp 70d43b9d
0:005> bl
 0 e 70d4eeda     0001 (0001)  0:**** iccvid!Decompress+0x128
 1 e 70d4eebf     0001 (0001)  0:**** iccvid!Decompress+0x10d
 2 e 70d43ae4     0001 (0001)  0:**** iccvid!CVDecompress+0x83
 3 e 70d43b9d     0001 (0001)  0:**** iccvid!CVDecompress+0x13c
0:005> bd 0,1,2
0:005> bl
 0 d 70d4eeda     0001 (0001)  0:**** iccvid!Decompress+0x128
 1 d 70d4eebf     0001 (0001)  0:**** iccvid!Decompress+0x10d
 2 d 70d43ae4     0001 (0001)  0:**** iccvid!CVDecompress+0x83
 3 e 70d43b9d     0001 (0001)  0:**** iccvid!CVDecompress+0x13c
0:005> g
Breakpoint 2 hit
eax=115e0000 ebx=11148b12 ecx=115de000 edx=00000041 esi=11306fc0 edi=00000010
eip=70d43b9d esp=119bfc60 ebp=119bfc98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
iccvid!CVDecompress+0x13c:
70d43b9d e834d60000      call    iccvid!memcpy (70d511d6)
0:005> dd esp l4
119bfc60  115e0000 115de000 00002000 10086a10
0:005> g
Breakpoint 3 hit
eax=115e2000 ebx=11148b22 ecx=115e0000 edx=00000041 esi=11306fc0 edi=00000010
eip=70d43b9d esp=119bfc60 ebp=119bfc98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
iccvid!CVDecompress+0x13c:
70d43b9d e834d60000      call    iccvid!memcpy (70d511d6)
0:005> dd esp l4
119bfc60  115e2000 115e0000 00002000 10086a10
0:005> g
Breakpoint 3 hit
eax=115e4000 ebx=11148b32 ecx=115e2000 edx=00000041 esi=11306fc0 edi=00000010
eip=70d43b9d esp=119bfc60 ebp=119bfc98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
iccvid!CVDecompress+0x13c:
70d43b9d e834d60000      call    iccvid!memcpy (70d511d6)
0:005> dd esp l4
119bfc60  115e4000 115e2000 00002000 10086a10
0:005> g
(f2c.a3c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=115e4000 ebx=115e2000 ecx=00000040 edx=00000000 esi=115e2000 edi=115e4000
eip=76faa05b esp=119bfc20 ebp=119bfc28 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
msvcrt!__ascii_strnicmp+0x99:
76faa05b 660f7f07        movdqa  xmmword ptr [edi],xmm0 ds:0023:115e4000=????????????????????????????????
           

可以看到當執行第三次記憶體複制時出現異常 通過異常處堆的資訊我們可以看到,此處堆起始于115de000,大小為0x6000,也就是115de000-115e4000 而每次複制的記憶體大小為0x2000,第三次複制時記憶體的起始位址已經是115e4000,複制資料時肯定導緻堆溢出了。

再來分析一下函數iccvid!memcpy吧 IDA的部分僞代碼如下:

memcpy((void *)(v28 + *(_DWORD *)(v7 + 28)), (const void *)(v28 + *(_DWORD *)(v7 + 28) - 0x2000), 0x2000u);
           

先看一下這個函數,第一次參數是目的位址,第二個參數是原位址,第三個參數是複制長度。 一開始v28=0 *(_DWORD *)(v7 + 28)= *(_DWORD *)(a1 + 28) 也就是函數iccvid!CVDecompress第一個參數偏移0x1c處儲存的位址就是函數memcpy要複制到的位址。 每次複制後v28+0x2000.

0:005> t
eax=00000001 ebx=119bfcf0 ecx=fffb95f0 edx=00000120 esi=112c7f60 edi=10086a10
eip=70d43a61 esp=119bfc9c ebp=119bfcc8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
iccvid!CVDecompress:
70d43a61 8bff            mov     edi,edi
0:005> dd esp
119bfc9c  70d4eeda 11306fc0 11148af8 00000068
119bfcac  10040000 00046e00 10086a10 fffffc10
119bfcbc  00000001 112c7f60 112c7f60 119bfd14
119bfccc  70d480f8 112c7f60 00000000 112eafd8
119bfcdc  11148af8 00000000 00000000 ffffffff
119bfcec  ffffffff 00046e00 10040000 00000068
119bfcfc  00000000 ffffffff ffffffff 119bfd50
119bfd0c  733ec7dc 0ff80fa8 119bfd38 733d1759
0:005> dd 11306fdc l4
11306fdc  115de000 115de000 00000000 01200150
           

位址0x115de000 就是memcpy複制的目的位址 原位址為0x115de000向前0x2000處儲存的資料,但是由于第一次的時候if語句沒有成立(v14不等于0x11),是以真正的複制是以0x115e0000 為目的位址,0x115de000 為原位址開始的。

而且這三次複制每次的資料都是一樣的 都是來自位址0x115de000的複制

真正的堆溢出利用需要控制0x115de000中的資料,正好覆寫115e4000開始處記憶體中的虛表指針等重要結構,可以達到任意代碼執行的效果。

signed int __stdcall CVDecompress(unsigned int a1, int a2, unsigned int a3, int a4, int a5, int a6, int a7)
{
  unsigned int v7; // [email protected]
  int v8; // [email protected]
  int v9; // [email protected]
  signed int result; // [email protected]
  int v11; // [email protected]
  int v12; // [email protected]
  int v13; // [email protected]
  int v14; // [email protected]
  int v15; // [email protected]
  __int16 v16; // [email protected]
  int v17; // [email protected]
  bool v18; // [email protected]
  int v19; // [email protected]
  int v20; // [email protected]
  int v21; // [sp+Ch] [bp-20h]@7
  int v22; // [sp+10h] [bp-1Ch]@10
  int v23; // [sp+14h] [bp-18h]@18
  int v24; // [sp+18h] [bp-14h]@18
  int v25; // [sp+1Ch] [bp-10h]@7
  int v26; // [sp+20h] [bp-Ch]@7
  unsigned int v27; // [sp+24h] [bp-8h]@6
  int v28; // [sp+28h] [bp-4h]@8

  v7 = a1;
  v8 = *(_DWORD *)(a1 + 36);
  if ( v8 )
  {
    v9 = a7;
    *(_DWORD *)(a1 + 36) = 0;
    CVDecompress(v7, v8, 0x2446u, 0, 0, 0, v9);
    LocalFree((HLOCAL)v8);
  }
  if ( a3 < 0x20
    || (v11 = a2,
        v12 = *(_BYTE *)(a2 + 3) | ((*(_BYTE *)(a2 + 2) | (*(_BYTE *)(a2 + 1) << 8)) << 8),
        (signed int)a3 < v12)
    || (BYTE3(a3) = *(_BYTE *)a2, ULongSub(v12, 0xAu, (int)&v27) < 0) )
  {
LABEL_4:
    result = 0;
  }
  else
  {
    v26 = 0;
    v13 = *(_BYTE *)(v11 + 9) | (*(_BYTE *)(v11 + 8) << 8);
    v14 = v11 + 10;
    v21 = v13;
    v25 = v11 + 10;
    if ( v13 > 0 )
    {
      v28 = 0;
      do
      {
        if ( v27 < 0x16 )
          break;
        v15 = *(_BYTE *)(v14 + 3) | ((*(_BYTE *)(v14 + 2) | (*(_BYTE *)(v14 + 1) << 8)) << 8);
        v22 = v15;
        if ( v27 < v15 )
          break;
        if ( *(_BYTE *)v14 == 16 || *(_BYTE *)v14 == 17 )
        {
          if ( ULongSub(v15, 0xCu, (int)&a1) < 0 )
            goto LABEL_4;
          v16 = *(_BYTE *)(v14 + 5);
          a2 = (unsigned __int16)(*(_WORD *)(v7 + 46)
                                * (_byteswap_ushort(*(_WORD *)(v14 + 8)) - _byteswap_ushort(*(_WORD *)(v14 + 4))));
          if ( v26 && !BYTE3(a3) && *(_BYTE *)v14 == 17 )
            memcpy((void *)(v28 + *(_DWORD *)(v7 + 28)), (const void *)(v28 + *(_DWORD *)(v7 + 28) - 0x2000), 0x2000u);
          v17 = v25 + 12;
          v18 = a1 < 4;
          *(_DWORD *)(v7 + 56) = v28 + *(_DWORD *)(v7 + 32);
          v19 = v14 + 12;
          v24 = v14 + 12;
          v23 = v25 + 12;
          *(_DWORD *)(v7 + 60) = a7;
          if ( !v18 )
          {
            do
            {
              v20 = *(_BYTE *)(v19 + 3) | ((*(_BYTE *)(v19 + 2) | (*(_BYTE *)(v19 + 1) << 8)) << 8);
              if ( a1 < v20 )
                break;
              switch ( *(_BYTE *)v19 )
              {
                case 0x20:
                case 0x21:
                case 0x24:
                case 0x25:
                  (*(void (__stdcall **)(int, _DWORD, _DWORD, _DWORD))v7)(
                    v17,
                    *(_DWORD *)(v7 + 56),
                    *(_DWORD *)(v7 + 52),
                    *(_DWORD *)(v7 + 48));
                  break;
                case 0x22:
                case 0x23:
                case 0x26:
                case 0x27:
                  (*(void (__stdcall **)(int, int, _DWORD, _DWORD))(v7 + 4))(
                    v17,
                    *(_DWORD *)(v7 + 56) + 4096,
                    *(_DWORD *)(v7 + 52),
                    *(_DWORD *)(v7 + 48));
                  break;
                case 0x30:
                  (*(void (__stdcall **)(unsigned int, int, int, int, int, int, int))(v7 + 8))(
                    v7,
                    v17 + 4,
                    v20 - 4,
                    a4,
                    a5,
                    a6,
                    a2);
                  break;
                case 0x31:
                  (*(void (__stdcall **)(unsigned int, int, int, int, int, int, int))(v7 + 16))(
                    v7,
                    v17 + 4,
                    v20 - 4,
                    a4,
                    a5,
                    a6,
                    a2);
                  break;
                case 0x32:
                  (*(void (__stdcall **)(unsigned int, int, int, int, int, int, int))(v7 + 12))(
                    v7,
                    v17 + 4,
                    v20 - 4,
                    a4,
                    a5,
                    a6,
                    a2);
                  break;
                default:
                  break;
              }
              v19 = v20 + v24;
              v17 = v20 + v23;
              v24 += v20;
              v23 += v20;
              if ( (unsigned int)v20 <= 1 )
                v20 = 1;
              a1 -= v20;
            }
            while ( a1 >= 4 );
            v15 = v22;
          }
          a6 += a7 * (signed __int16)a2;
          ++v26;
          v28 += 0x2000;
          v13 = v21;
        }
        v25 += v15;
        v27 -= v15;
        v14 += v15;
      }
      while ( v26 < v13 );
    }
    result = 1;
  }
  return result;
}