Microsoft Windows FastFAT.sys Sectors per FAT Denial of Service Vulnerability

Do You remember story about MS14-063 from last year ? It turns out there is continuation of it, but this time inside FAT12 partition.

[VIDEO] Time to stick the magic stick


Affected systems
From Windows NT to Windows 7 SP1
I personally tested it on :

* Windows XP SP3 x86
* Windows 7 SP1 x86/x64

Bug reconstruction
1. Create FAT12 partition and set WORD at offset 0x16 (Sectors per FAT) to e.g. 0x3000.

Do NOT exceed 0x3FFF value.
How to do this and suggested parameters bs=512 count=32067.
Image can be empty.

Malformed value of field “Sectors per FAT” in FAT12 Boot sector, leads to attempt to read of unallocated memory region during FAT 1 mapping into cache.

My malformed partition presents in the following way:

Crash dump
Windows 7 SP1 x86

kd> !analyze -v
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *

Invalid system memory was referenced.  This cannot be protected by try-except,
it must be protected by a Probe.  Typically the address is just plain bad or it
is pointing at freed memory.
Arg1: a3f00000, memory referenced.
Arg2: 00000000, value 0 = read operation, 1 = write operation.
Arg3: 82a6a05e, If non-zero, the instruction address which referenced the bad memory
Arg4: 00000000, (reserved)

Debugging Details:

READ_ADDRESS:  a3f00000 

82a6a05e 8a0e            mov     cl,byte ptr [esi]

PROCESS_NAME:  explorer.exe

TRAP_FRAME:  a2447414 -- (.trap 0xffffffffa2447414)
ErrCode = 00000000
eax=000006e2 ebx=86eb8b98 ecx=a2447400 edx=00000011 esi=a3f00000 edi=0000000f
eip=82a6a05e esp=a2447488 ebp=a24474c8 iopl=0         nv up ei pl nz ac po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010212
82a6a05e 8a0e            mov     cl,byte ptr [esi]          ds:0023:a3f00000=??
Resetting default scope

LAST_CONTROL_TRANSFER:  from 82916d5f to 828b27b8

a2446f64 82916d5f 00000003 6641e18b 00000065 nt!RtlpBreakWithStatusInstruction
a2446fb4 8291785d 00000003 00000000 00082982 nt!KiBugCheckDebugBreak+0x1c
a2447378 828c5879 00000050 a3f00000 00000000 nt!KeBugCheck2+0x68b
a24473fc 82878aa8 00000000 a3f00000 00000000 nt!MmAccessFault+0x104
a24473fc 82a6a05e 00000000 a3f00000 00000000 nt!KiTrap0E+0xdc
a24474c8 975dbb32 86e819c0 004474ec 00721e00 nt!CcMapData+0xae
a24474f4 975d9e1d a2b52fb8 85dad920 00001000 fastfat!FatReadVolumeFile+0x3a
a2447580 975da534 a2b52fb8 a2447524 00000002 fastfat!FatExamineFatEntries+0x11f
a24475e8 975ecd64 a2b52fb8 85dad920 3519a638 fastfat!FatSetupAllocationSupport+0x38a
a2447774 975ee3cf a2b52fb8 8a9b0da8 a3392fa8 fastfat!FatMountVolume+0x418
a2447794 975ee478 a2b52fb8 93528e90 3519a6ac fastfat!FatCommonFileSystemControl+0x3f
a24477e0 82b696c3 82275620 93528e90 93528e90 fastfat!FatFsdFileSystemControl+0x82
a2447804 8286ebd5 00000001 93528ff4 82275620 nt!IovCallDriver+0x258
a2447818 85499a56 270d61d5 8229bde8 93528e90 nt!IofCallDriver+0x1b
a2447878 85499c5b 8229bde8 93528e90 86f2c678 fltmgr!FltpFsControlMountVolume+0x180
a24478a8 82b696c3 8229bde8 93528e90 93528e90 fltmgr!FltpFsControl+0x5b
a24478cc 8286ebd5 00000001 8296fb88 8229bde8 nt!IovCallDriver+0x258
a24478e0 829d1dd9 82804870 8a9b0da8 82804900 nt!IofCallDriver+0x1b
a2447944 828df92e 8a9b0da8 85dac000 00000000 nt!IopMountVolume+0x1d8
a244797c 82a7ddfb 85dac008 a2447aa8 a2447a40 nt!IopCheckVpbMounted+0x64
a2447a60 82a5dd1e 8a9b0da8 851cfde8 85d66750 nt!IopParseDevice+0x7db
a2447adc 82a6e147 00000000 a2447b30 00000040 nt!ObpLookupObjectName+0x4fa
a2447b38 82a64c25 02effc44 851cfde8 828b1d01 nt!ObOpenObjectByName+0x165
a2447bb4 82a884a4 02effca0 00100081 02effc44 nt!IopCreateFile+0x673
a2447c00 828758c6 02effca0 00100081 02effc44 nt!NtCreateFile+0x34
a2447c00 776170f4 02effca0 00100081 02effc44 nt!KiSystemServicePostCall
02effc00 77615614 7573a9d9 02effca0 00100081 ntdll!KiFastSystemCallRet
02effc04 7573a9d9 02effca0 00100081 02effc44 ntdll!ZwCreateFile+0xc
02effca8 772ce99f 00004000 00100081 00000007 KERNELBASE!CreateFileW+0x35e
02effcd4 761a2fc5 03cc0038 00000001 00000007 kernel32!CreateFileWImplementation+0x69
02effd38 761a2bc9 03cc0038 00000001 00000000 SHELL32!CLocalInterruptSource::v_CreateEvent+0x41
02effd5c 761aac0f 0368f598 00000000 02effd94 SHELL32!CFSInterruptSource::GetEvent+0x7b
02effd9c 761aa92a 02effdc0 00000000 006e7a90 SHELL32!CChangeNotify::_GetInterruptEvents+0x93
02effdc8 7611561b 00000000 00000000 00000067 SHELL32!CChangeNotify::_MessagePump+0x67
02effde0 75fd43c0 006e7a90 00000000 00000000 SHELL32!CChangeNotify::s_ThreadProc+0x4f
02effe68 772cee1c 0201ed74 02effeb4 776337eb SHLWAPI!WrapperThreadProc+0x1b5
02effe74 776337eb 0201ed74 758640f9 00000000 kernel32!BaseThreadInitThunk+0xe
02effeb4 776337be 75fd42ed 0201ed74 00000000 ntdll!__RtlUserThreadStart+0x70
02effecc 00000000 75fd42ed 0201ed74 00000000 ntdll!_RtlUserThreadStart+0x1b


82a6a05e 8a0e            mov     cl,byte ptr [esi]

SYMBOL_NAME:  nt!CcMapData+ae
FOLLOWUP_NAME:  MachineOwner
IMAGE_NAME:  ntkrpamp.exe
FAILURE_BUCKET_ID:  0x50_VRF_nt!CcMapData+ae
BUCKET_ID:  0x50_VRF_nt!CcMapData+ae
Followup: MachineOwner

Vulnerable code:

Line 72:
CcMapData (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG Flags,
    __out PVOID *Bcb,
    __deref_out_bcount(Length) PVOID *Buffer

Line 155:
    ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES((ULongToPtr(FileOffset->LowPart)), Length);
    PETHREAD Thread = PsGetCurrentThread();
    BOOLEAN ReturnStatus;

    DebugTrace(+1, me, "CcMapData\n", 0 );

    MmSavePageFaultReadAhead( Thread, &SavedState );

    ReturnStatus = CcMapDataCommon( FileObject,
                                    Buffer );
Line 193
            //  Loop to touch each page

            BaseAddress = *Buffer;

            while (PageCount != 0) {

                MmSetPageFaultReadAhead( Thread, PageCount - 1 );

                ch = *((volatile UCHAR *)(BaseAddress));   // <----------   CRASH!!!!

                BaseAddress = (PCHAR) BaseAddress + PAGE_SIZE;
                PageCount -= 1;

PageCount is calculated based on controlled Length value, which in this case (read of FATx) consists of:
Sectors per FAT * Bytes per sector

kd> . frame /c 5
kd> dd ebp+10 L1 //get Length value
f53e1510  00721e00
kd> ?00721e00 / 0x200(= Bytes per sector)
Evaluate expression: 14607 = 0000390f (= Sectors per FAT) 

FileOffset equals:

kd> dt _LARGE_INTEGER poi(ebp+c)
   +0x000 LowPart          : 0x200
   +0x004 HighPart         : 0
   +0x000 u                : __unnamed
   +0x000 QuadPart         : 512

PageCount for these values equals:

Evaluate expression: 1826 = 00000722

Each While-Loop iteration, BaseAddress pointer is increased by PAGE_SIZE, so in this scenario memory region which will be “cover” by this loop is:

kd> ?(0x722 * 0x1000) / 0x400
PageCount     PAGE_SIZE     1KB

Evaluate expression: 7304 = 00001c88
kd> ?00001c88 / 0x400
Evaluate expression: 7 = 00000007   ~   7MB

Let’s check how many bytes we are really able to cache:


Line 241:
CcMapDataCommon (
    IN PFILE_OBJECT FileObject,
    IN ULONG Length,
    IN ULONG Flags,
    OUT PVOID *Bcb,
    OUT PVOID *Buffer

Line 350:
    //  Get pointer to SharedCacheMap.

    SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;

    //  Call local routine to Map or Access the file data.  If we cannot map
    //  the data because of a Wait condition, return FALSE.

    if (FlagOn(Flags, MAP_WAIT)) {

        *Buffer = CcGetVirtualAddress( SharedCacheMap,
                                       (PVACB *)&TempBcb,
                                       &ReceivedLength );

        ASSERT( ReceivedLength >= Length ); // maybe convert it to IF ?


checking ReceiveLength in CcGetVirtualAddress:


Line 388:
ULONG VacbOffset = FileOffset.LowPart & (VACB_MAPPING_GRANULARITY - 1);
Line  449:
*ReceivedLength = VACB_MAPPING_GRANULARITY - VacbOffset;



Line 31:
#define VACB_MAPPING_GRANULARITY         (0x40000)

Fragments of code suggest us that ReceiveLength should at least be equal Lenght and maximum value of ReceiveLength can be 0x40000 bytes which is 256KB.

MSDN CcMapData

CcMapData cannot map data across view boundaries in the cache manager. The cache manager manages files in the system in 256 KB-aligned views. (The cache manager’s view size is specified by the system-defined constant VACB_MAPPING_GRANULARITY, which is set to 256 KB in ntifs.h.) Mapped regions cannot span more than one 256 KB view. Therefore, the largest region that can be mapped is 256 KB, beginning at a 256 KB-aligned offset in the file.

Code and documentation clearly points that mapped region of file data can’t exceed 256KB.
In our case kernel will act like there is ~7MB of available space what leads to crash after iteration over available 256KB’s.

Why bug exists?
Lack of verification Length value, leads to iteration in this loop:

Line 198

            while (PageCount != 0) {

                MmSetPageFaultReadAhead( Thread, PageCount - 1 );

                ch = *((volatile UCHAR *)(BaseAddress));   // <----------   CRASH!!!!

                BaseAddress = (PCHAR) BaseAddress + PAGE_SIZE;
                PageCount -= 1;

over available mapped/allocated region.

Not always triggerable

During my research I observed that not each value of Sectors per FAT bigger than 0x0200 will cause crash. E.g. Sectors per FAT set to 0x4000 causes exception in Fastfat!FatCommonRead:

Stack trace when Sectors per FAT == 40 00

Windows XP SP3
ChildEBP RetAddr  Args to Child              
bad46fc0 b7e0d505 86a69e50 bad46fec 804e24f1 Fastfat!FatExceptionFilter+0x5
bad46fcc 804e24f1 bad46ff4 00000000 bad46ff4 Fastfat!FatFsdRead+0x12b
bad46ff4 804db49a bad470d8 bad47518 bad47128 nt!_except_handler3+0x61
bad47018 804db46b bad470d8 bad47518 bad47128 nt!ExecuteHandler2+0x26
bad470c8 804dc6a1 bad470d8 bad47128 c000000d nt!ExecuteHandler+0x24
bad473fc b7e12fc4 c000000d 86a69e50 8667b888 nt!ExRaiseStatus+0xb5
bad474b8 b7e0d69a 86a69e50 8667b888 86a501e8 Fastfat!FatCommonRead+0x66b
bad47528 804e37f7 8686ba98 8667b888 00000000 Fastfat!FatFsdRead+0x13d
bad47538 804f95d8 00000000 86b01ad0 86b01ae0 nt!IopfCallDriver+0x31
bad4754c 804f95ff 8686ba98 86b01b08 86b01ae8 nt!IopPageReadInternal+0xf4
bad4756c 804f9264 86a501e8 86b01b08 86b01ae8 nt!IoPageRead+0x1b
bad475e0 804eba6a 0dead8c0 c7fc0000 c031ff00 nt!MiDispatchFault+0x274
bad47630 804e1718 00000000 c7fc0000 00000000 nt!MmAccessFault+0x5bc
bad47630 8056d716 00000000 c7fc0000 00000000 nt!KiTrap0E+0xcc
bad47708 b7e15b25 86a501e8 bad47734 00001000 nt!CcMapData+0xef
bad4773c b7e1e8b6 86a84e28 8698b3a8 00000000 Fastfat!FatReadDirectoryFile+0x92
bad47770 b7e137b7 86a84e28 8686bb90 bad47880 Fastfat!FatLocateVolumeLabel+0x7f
bad4790c b7e10a93 86a84e28 86b6a718 86bd3af0 Fastfat!FatMountVolume+0x49b
bad4792c b7e10a38 86a84e28 8690eaf0 8690ec78 Fastfat!FatCommonFileSystemControl+0x49
bad47978 804e37f7 86a2d928 8690eaf0 8690ec9c Fastfat!FatFsdFileSystemControl+0x85

b7e0d485 53              push    ebx
kd> .exr poi(poi(ebp+c))
ExceptionAddress: b7e12fc4 (Fastfat!FatCommonRead+0x0000066b)
   ExceptionCode: c000000d  // STATUS_INVALID_PARAMETER
   ExceptionFlags: 00000001
NumberParameters: 0

I did not dig deeper, so I cannot point place in code where validation on probably FileObject->Length is made and cause this exception. But it looks like there is already some kind of Length value validation but NOT sufficiently accurate.

Posted in Bez kategorii, Bugs, Security | Tagged , , , , , , , | Leave a comment

Story about MS14-063

Last week Microsoft released patch for reported by me vulnerability in FastFat driver marking it as:
MS14-063 – Vulnerability in FAT32 Disk Partition Driver Could Allow Elevation of Privilege (2998579)

Let me present some of the most interesting parts of advisory and add couple details/comments.

[VIDEO]When the bug kicks in…
Microsoft informs that the following OS’s are vulnerable:

• Microsoft Windows Server 2003 SP2
• Vista SP2
• Server 2008 SP2

BUT… as you can imagine “forgotten” in this year Windows XP and its FastFAT driver also contains this vulnerability but bug in it will stay there forever…Let we see Windows XP SP3 reaction on evil usb stick with malformed FAT32 partition.

[+]General description
Vulnerable code existing in FastFAT.sys driver can be exploited via intentionally malformed FAT32 Boot sector delivered with usb stick. All values of field “Number of FATs” greater than 2 will lead to not enough memory allocation for further actions made by FastFAT.sys driver and in consequences to pool overflow.

[+]How that thing happens ? – code analysis

First of all view of my malformed FAT32 Boot Sector:

Member	"Value (dec)"	"Value (hex)"	Size
"00000000 struct BOOTSECTOR_FAT32"	{...}		00000200
"  00000000 int8 jmp[00000003]"			00000003
"  00000003 char OemName[00000008]"	MSDOS5.0		00000008
"  0000000B struct BPB_FAT32"	{...}		00000035
"    0000000B uint16 BytesPerSector"	512	0200	00000002
"    0000000D int8 SectorsPerCluster"	1	01	00000001
"    0000000E uint16 ReservedSectors"	36	0024	00000002
"    00000010 int8 NumberOfFATs"	119	77	00000001
"    00000011 uint16 RootEntries"	0	0000	00000002
"    00000013 uint16 TotalSectors"	0	0000	00000002
"    00000015 int8 Media"	-8	F8	00000001
"    00000016 uint16 SectorsPerFAT"	0	0000	00000002
"    00000018 uint16 SectorsPerTrack"	63	003F	00000002
"    0000001A uint16 HeadsPerCylinder"	255	00FF	00000002
"    0000001C uint32 HiddenSectors"	63	0000003F	00000004
"    00000020 uint32 TotalSectorsBig"	80262	00013986	00000004
"++ FAT32 Section
"    00000024 uint32 SectorsPerFAT"	618	0000026A	00000004
"    00000028 uint16 Flags"	0	0000	00000002
"    0000002A uint16 Version"	0	0000	00000002
"    0000002C uint32 RootCluster"	2	00000002	00000004
"    00000030 uint16 InfoSector"	1	0001	00000002
"    00000032 uint16 BootBackupStart"	6	0006	00000002
"    00000034 int8 Reserved[0000000C]"			0000000C
"  00000040 int8 DriveNumber"	-128	80	00000001
"  00000041 int8 Unused"	1	01	00000001
"  00000042 int8 ExtBootSignature"	41	29	00000001
"  00000043 uint32 SerialNumber"	3896654535	E8423AC7	00000004
"  00000047 char VolumeLabel[0000000B]"	"NO NAME    "		0000000B
"  00000052 char FileSystem[00000008]"	"FAT32   "		00000008
"  0000005A blob BootCode[000001A6]"			000001A6

I will reference to some fields and their values in further analysis.

Activation of special pool will help us to locate moment when a pool overflow starts to appear

verifier /volatile /flags 0x1 /adddriver fastfat.sys

After insertion of usb stick…
[+]Crash dump info

kd> !analyze -v
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *

N bytes of memory was allocated and more than N bytes are being referenced.
This cannot be protected by try-except.
When possible, the guilty driver's name (Unicode string) is printed on
the bugcheck screen and saved in KiBugCheckDriver.
Arg1: 8a011008, memory referenced
Arg2: 00000001, value 0 = read operation, 1 = write operation
Arg3: b7ae63da, if non-zero, the address which referenced memory.
Arg4: 00000000, (reserved)

Debugging Details:
WRITE_ADDRESS:  8a011008 Special pool

b7ae63da 8978fc          mov     dword ptr [eax-4],edi

FAULTING_MODULE: b7ada000 Fastfat

TRAP_FRAME:  bacdf8c0 -- (.trap 0xffffffffbacdf8c0)
ErrCode = 00000002
eax=8a01100c ebx=8a7ece90 ecx=00186c00 edx=00000800 esi=89a14b18 edi=00004800
eip=b7ae63da esp=bacdf934 ebp=bacdfab4 iopl=0         nv up ei ng nz ac pe cy
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010297
b7ae63da 8978fc          mov     dword ptr [eax-4],edi ds:0023:8a011008=????????
Resetting default scope

LAST_CONTROL_TRANSFER:  from 8051cc4f to 804f8cb5

bacdf848 8051cc4f 00000050 8a011008 00000001 nt!KeBugCheckEx+0x1b
bacdf8a8 8054051c 00000001 8a011008 00000000 nt!MmAccessFault+0x8e7
bacdf8a8 b7ae63da 00000001 8a011008 00000000 nt!KiTrap0E+0xcc
bacdfab4 b7adab9a 89a14b18 8a7ece90 89c59020 Fastfat!FatCommonWrite+0x444
bacdfaf8 804ee119 89c59020 8a7ece90 806d12a4 Fastfat!FatFsdWrite+0xad
bacdfb08 8064d628 89ada170 00004000 89c59020 nt!IopfCallDriver+0x31
bacdfb2c 804ef411 bacdfb68 bacdfd40 00000000 nt!IovCallDriver+0xa0
bacdfb40 8050c497 89ada107 bacdfb68 bacdfbfc nt!IoSynchronousPageWrite+0xaf
bacdfc24 8050ce3d e10ec820 e10ec828 e10ec828 nt!MiFlushSectionInternal+0x3bf
bacdfc60 804e38a2 89c33d70 e10ec820 00000004 nt!MmFlushSection+0x1b5
bacdfce8 804e3bc4 00001000 00000000 00000001 nt!CcFlushCache+0x386
bacdfd2c 804e61ee 89da0290 8055b0c0 89da1da8 nt!CcWriteBehind+0xdc
bacdfd74 80534c02 89da0290 00000000 89da1da8 nt!CcWorkerThread+0x126
bacdfdac 805c6160 89da0290 00000000 00000000 nt!ExpWorkerThread+0x100
bacdfddc 80541dd2 80534b02 00000000 00000000 nt!PspSystemThreadStartup+0x34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16


b7ae63da 8978fc          mov     dword ptr [eax-4],edi

SYMBOL_NAME:  Fastfat!FatCommonWrite+444
FOLLOWUP_NAME:  MachineOwner
FAILURE_BUCKET_ID:  0xD6_VRF_Fastfat!FatCommonWrite+444
BUCKET_ID:  0xD6_VRF_Fastfat!FatCommonWrite+444
Followup: MachineOwner

[+]Detailed analysis

With active special pool for fastfat.sys You should land in below area when the bug kicks in:

PAGE:0001C37A                 movzx   edx, word ptr [eax+90h]
PAGE:0001C381                 movzx   ecx, cx
PAGE:0001C384                 imul    edx, ecx
PAGE:0001C387                 mov     [ebp+BytesPerFat], edx
PAGE:0001C38D loc_1C38D:                              
PAGE:0001C38D                 mov     cl, [eax+96h]
PAGE:0001C393                 cmp     cl, 2           ; cl = Number of FATs
PAGE:0001C396                 jbe     short RegularFATsAmount
PAGE:0001C398                 push    'itaF'          ; Tag
PAGE:0001C39D                 movzx   eax, cl
PAGE:0001C3A0                 push    eax             ; Number of FATs used as pool size
PAGE:0001C3A1                 push    11h             ; PoolType
PAGE:0001C3A3                 call    ds:__imp__ExAllocatePoolWithTag
PAGE:0001C3A9                 mov     edi, eax
PAGE:0001C3AB                 mov     eax, [ebp+VCB]
PAGE:0001C3AE                 jmp     short loc_1C3B6
PAGE:0001C3B0 ; ---------------------------------------------------------------------------
PAGE:0001C3B0 RegularFATsAmount:                     
PAGE:0001C3B0                 lea     edi, [ebp+var_174]
PAGE:0001C3B6 loc_1C3B6:                              
PAGE:0001C3B6                 mov     [ebp+unknow], edi
PAGE:0001C3BC                 and     [ebp+counter], 0
PAGE:0001C3C3                 cmp     byte ptr [eax+96h], 0
PAGE:0001C3CA                 jbe     short loc_1C410
PAGE:0001C3CC                 mov     ecx, [ebp+offsetToFirstFAT]
PAGE:0001C3CF                 mov     edx, ecx
PAGE:0001C3D1                 sub     edx, [ebp+StartingVbo]
PAGE:0001C3D4                 lea     eax, [edi+0Ch]
PAGE:0001C3D7 fillArrayLoop:                         
PAGE:0001C3D7                 mov     edi, [ebp+offsetToFirstFAT] 
PAGE:0001C3DA                 mov     [eax-4], edi    
PAGE:0001C3DD                 mov     [eax-0Ch], ecx  
PAGE:0001C3E0                 and     dword ptr [eax-8], 0
PAGE:0001C3E4                 mov     [eax], edx      
PAGE:0001C3E6                 mov     edi, [ebp+unknow3]
PAGE:0001C3EC                 mov     [eax+4], edi   
PAGE:0001C3EF                 inc     [ebp+counter]
PAGE:0001C3F5                 add     ecx, [ebp+BytesPerFat]
PAGE:0001C3FB                 add     eax, 18h
PAGE:0001C3FE                 mov     edi, [ebp+VCB]
PAGE:0001C401                 movzx   edi, byte ptr [edi+96h] ; to EDI goes Number of FATs
PAGE:0001C408                 cmp     [ebp+counter], edi
PAGE:0001C40E                 jb      short fillArrayLoop

as You can see above, when number of FATs is bigger than 2 it’s amount is used to allocate pool of that size.

PAGE:0001C39D                 movzx   eax, cl
PAGE:0001C3A0                 push    eax             ; Number of FATs used as pool size
PAGE:0001C3A1                 push    11h             ; PoolType
PAGE:0001C3A3                 call    ds:__imp__ExAllocatePoolWithTag

Next loop appears and it iterates amount of times indicated by number of FATs. In this loop ( fillArrayLoop ), pool allocated by code describe above is filled by array of structures
where size of structure equals 24 bytes (structure consists of 6 DWORD’s). Is easy to deduce that iteration will lead to pool overflow because during pool allocation number of FATs was taken in count without size of structure element. It’s even easier to understand on pseudo code:

        NumberOfFATs = *(_BYTE *)(VCB + 150);
        if ( NumberOfFATs <= 2u )
          ptrPool = &v100;
          ptrPool = ExAllocatePoolWithTag((POOL_TYPE)17, NumberOfFATs, 'itaF'); [BUG]//NumberOfFATs !!! instead of NumberOfFATs * sizeof(SomeStructure)=24
          v14 = VCB;
        counter = 0;
        if ( *(_BYTE *)(v14 + 0x96) )
          v18 = offsetToFirstFAT;
          unknow1 = offsetToFirstFAT - unknow2;
          v20 = (int)((char *)ptrPool + 12);
            *(_DWORD *)(v20 - 4) = offsetToFirstFAT;
            *(_DWORD *)(v20 - 12) = v18;
            *(_DWORD *)(v20 - 8) = 0;
            *(_DWORD *)v20 = unknow1;
            *(_DWORD *)(v20 + 4) = unknow3;
            v18 += BytesPerFat;
            v20 += 24;
          while ( counter < NumberOfFATs );


Taking glance at how this array looks in memory after couple iterations:
FOR 3 loops cycle :

00 48 00 00
00 00 00 00
00 48 00 00
00 08 00 00 
00 02 00 00
ef ef ef ef <- not initialized

00 1c 05 00 
00 00 00 00 
00 48 00 00 
00 08 00 00 
00 02 00 00 
ef ef ef ef <- not initialized

00 f0 09 00 
00 00 00 00 
00 48 00 00 
00 08 00 00 
00 02 00 00 
ef ef ef ef <- not initialized

Which values at particular offset we are able to control ?

Offset +0: (v20 – 12)
For first iteration it’s value equals offsetToFirstFAT and further it’s result of adding: (v20 – 12) = (v20 – 12) + BytesPerFat.
Where BytesPerFAT equals : Bytes per sector = 512 * Sectors per fat = 618 == 0x4D400 (316416)

Offset +4: (v20 – 8)
Constant 0

Offset + 8: (v20 – 4)
Value of this field always equals offsetToFirstFAT.
Where offsetToFirstFAT : Bytes per sector * Reserved sectors == (0x4800)

Taking in count information’s about how this bug is triggered and what portion of date we are able to control during page overflow….how do you think, it’s exploitable or not ? I will leave the answer for the reader. But…
the most lucrative scenario for attacker would be to create malformed FAT32 partition which contains .exe file and gives possibility (not causes crash after usb stick insertion) to victim to run it.
Exe for e.g would be responsible of kernel pool spraying. After that it would write any random date to malformed partition triggering in the same time bug in FatCommonWrite. Ohh yeah….my observations shows that when you create nearly empty malformed partition containing couple files, bug only triggers when you open one of these file and try to save(write) modifications.

For sure we should not disregard this vulnerability because history and e.g recently Chris Evans write-up about off-by-one shows that any kind of scenario can become real in some circumstances.

Microsoft why so long ????!!!!
There is a lot of complaints on Microsoft because this particular vulnerability is patched in newer system version like Windows 7/8/8.1 so it implicates that it was good know vuln for MS for a long time and they did not patch it…I gonna leave it without comment, but also process of patching affected systems mentioned at the beginning of this post took a while because this vulnerability was submitted by me to MS at the beginning of March this year (2014) and currently we have October 2014….well 😉

Posted in Bugs, Security | Tagged , , , , | Leave a comment

Fake “Police Trojan” analysis

For some time the “virus of the police” has become an epidemic across Europe. Currently a variant of the first sample, found during summer of 2011, is infecting
Windows operating system users. It blocked the system on startup, with a screen that prevented access to the desktop…

Read entire analysis: police_trojan.pdf

Posted in Analiza, Malware, RE | Leave a comment

Few vulnerabilities in <= VLC media player 2.0.1 demuxers

After two mails to VLC security team and lack of answer I decided to public this research before any patch. Presented here vulns are not too evil (Local DoS) so making them public will not cause any damage for VLC users.

==[ Details ]==
<= VLC media player 2.0.1 contains vulnerabilities in few Demuxers:

1.	voc.c – DoS via Divison by 0
2.	smf.c – DoS via Infinite loop
3.	au.c  – DoS via Division by 0

1. Details voc.c – DoS via Divison by 0:
First scenario:
ReadBlockHeader function to handle block data type 0x9 contains the following code:

Line 304:
        case 9: /* newer data block with channel number and bits resolution */
            if( i_block_size < 12 )
                goto corrupt;
            i_block_size -= 12;

            if( ( stream_Read( p_demux->s, buf, 8 ) < 8 )
             || ( stream_Read( p_demux->s, NULL, 4 ) < 4 ) )
                goto corrupt;

   = GetDWLE( buf );
   = buf[4];
   = buf[5];

If block header at offset 0x5 will be set to 0 then = 0, what causes:

Line 360: =
                * ( / 8);

that will be set to 0 and after exit from ReadBlockHeader the following code:

Line 428:
    while( ( i_offset >= p_sys->i_block_end )
         && ( p_sys->i_silence_countdown == 0 ) )
        if( ReadBlockHeader( p_demux ) != VLC_SUCCESS )
            return 0;

    if( p_sys->i_silence_countdown == 0 )
        i = ( p_sys->i_block_end - i_offset )
            / p_sys->; // <- div by 0

in Demux function leads to division by zero and as an end result VLC crash.

Second scenario:
Because at the beginning in ReadBlockHeader function, structure new_fmt (es_format_t) is initialized by zero:

Line 175:
es_format_Init( &new_fmt, AUDIO_ES, 0 );

therefore if type of first block will be set to different one where “normal” new_fmt structure initialization occurs e.g 0x6 then at the end of
ReadBlockHeader ,

Line 399:
        if( p_sys->p_es == NULL )
            memcpy( &p_sys->fmt, &new_fmt, sizeof( p_sys->fmt ) );

new_fmt structure initialized by 0 will be copied to p_sys->fmt which leads to division by zero after return to Demux function like in above scenario.

2. smf.c – DoS via Infinite loop
In Open function we see the following code:

Line 210:
        for (;;)
            stream_Read (stream, head, 8);
            if (memcmp (head, "MTrk", 4) == 0)

            msg_Dbg (p_this, "skipping unknown SMF chunk");
            stream_Read (stream, NULL, GetDWBE (head + 4));

it aim is to find „MTrk” ID chunk. But like we can also notice there is lack of checks for stream_Read function indicating that end of stream occurred.
File with malformed or without “MTrk” ID chunk will cause infinite loop and as a result VLC DoS.

3 au.c – DoS via Division by 0

Line 144:    
	/* init fmt */
    es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
    p_sys->     = GetDWBE( &hdr[12] );
    p_sys-> = GetDWBE( &hdr[16] );

setting 0(DWORD) at file offset len(“.snd”)+12 => 16 we set 0 value for i_rate field. Lack of any inspection of this field and its value leads to division by zero at

Line 278:
    p_sys->i_frame_length = (mtime_t)1000000 *
                            (mtime_t)i_samples /

and as an end result to VLC crash.

==[ Proof of Concept ]==

1. voc.c - DoS via Divison by 0:
File sample:
First scenario:
Change offset 0x23 value from 0x02 to 0x0

Second scenario:
Change offset  0x1A value from 0x060C842E to 0x06020000

2. smf.c - DoS via Infinite loop

File sample:
Malform “MTrk” chunk ID anyhow e.g “ATrk”.

3. au.c - DoS via Division by 0

File sample:
Change offset 0x10  value from 0x00001F40  to 0x00000000
Posted in Bugs, Security | Tagged , , , | Leave a comment

BHO Reversing

From a long time for those days (BHO is supported since IE 4.0) malware writers exploit BHO functionality to bully on IE users.
Mostly evil BHO has two functionality ( for sure if we talk about bankers):

- monitoring/logging requests sending by browser
    POST dump - password stealing
- HTML page code dynamic modification
   HTML code injection - used for e.g - adding additional form fields intended to obtain, more amount of TAN codes or generally some extra data.

=] BHO creation [=
Dll implementation is possible in couple manners:
Pure COM/WinApi
Is easy to predict that in this case entire implementation of all COM interfaces will belong to us, but it’s a great exercise to get know all details about BHO mechanism hidden under the hood.
Detailed tutorial about how to write an BHO without the use of MFC/ATL and with basic infromation about COM technology you can find here:


In case when you take advantages of ATL library, to implementation will remain only one method plus an events handlers. Tutorial about creating BHO based on ATL library you can find here:

BHO mechanism call stack
In a nutshell:
Ole32.dll in IE
@export DllGetClassObject – pass pointer on IClassFactory coclass.
IClassFactory->CreateInstance – pass pointer on IObjectWithSite coclass.
IObjectWithSite->SetSite – obtain pointer to IWebBrowser2 interface.
IWebBrowser2->QueryInterface for IConnectionPointContainer
IConnectionPointContainer-> FindConnectionPoint for DWebBrowserEvents2 dispatcher.
IConnectionPointContainer->Advise – registration of coclass implementing DWebBrowserEvents2 (events handler) dispatcher.

=] Interfaces [=
We (and also malware writers) will be especially interested in two interfaces:
=] Events handling [=
As you might guess, major malware code responsible of that action like HTLM code injection or POST dump will be located in class implements DWebBrowserEvents2 interface.
Delving into the details, HTML Code injection we can expect in event handler for event:
„DocumentComplete – Fires when a document is completely loaded and initialized.”

POST Dump ( credentials theft)
„BeforeNavigate2 – Fires before navigation occurs in the given object (on either a window element or a frameset element).”

Lets we take a glance on residual implementation of that class in CPP:

class CEvents : public DWebBrowserEvents2 {
STDMETHODIMP Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr);
void OnBeforeNavigate2(...);
void OnDocumentComplete(...);

STDMETHODIMP CEvents::Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)



	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CCBHO, &CLSID_CBHO>,
	public IObjectWithSiteImpl<CCBHO>,
	public IDispatchImpl<ICBHO, &IID_ICBHO, &LIBID_firstBHOLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
	public IDispEventImpl<1, CCBHO, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>

	BEGIN_SINK_MAP(CCBHO) //initialize _ATL_EVENT_ENTRY structure 
		SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
		SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2, OnBeforeNavigate)

    // DWebBrowserEvents2
    void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL);
	void STDMETHODCALLTYPE OnBeforeNavigate(IDispatch *pDisp,    
											VARIANT *url,
											VARIANT *Flags,
											VARIANT *TargetFrameName,
											VARIANT *PostData,
											VARIANT *Headers,
											VARIANT_BOOL *Cancel);

Like I mentioned above, key role in BHO malware functionality plays code located in event handlers related with events BEFORENAVIGATE2 and DOCUMENTCOMPLETE. But before we gonna examine real malware lets we check example implementation of HTML Code injection and POST dump in CPP.

HTML Code injection (ATL)

void STDMETHODCALLTYPE CCBHO::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
    // Retrieve the top-level window from the site.
	CComQIPtr<IWebBrowser2> tmpBrowser = pDisp;
	if(tmpBrowser && m_webBrowser && m_webBrowser.IsEqualObject(tmpBrowser))
		CComPtr<IDispatch> doc;
		hr = m_webBrowser->get_Document(&doc);
			CComQIPtr<IHTMLDocument2> html = doc;
			if( html != NULL)
				//check target url
					debug("[+] Target URL detected");
					CComPtr<IHTMLElement> body;
					hr = html->get_body(&body);
					if(!SUCCEEDED(hr) || body == NULL)
					debug("[+] Make simple html code injection, right after <body> tag");
					body->insertAdjacentHTML(L"afterBegin",L"<h1 style=\"text-align:center;color:red;\">Injected Code</h1>");
					debug("[+] Find login form");
					CComPtr<IHTMLElementCollection> forms;
					hr = html->get_forms(&forms);
					if(!SUCCEEDED(hr) || forms == NULL)
					long amount = 0;
					CComVariant name;
					CComPtr<IDispatch> pDisp;
					for(int i =0; i < amount;i++)
						CComVariant index(i);
						CComQIPtr<IHTMLElement> form = pDisp;
						debug("[+] Injecting additional form field");
							L"<label>Phone number<br /><input type=\"text\" name=\"phone\" class=\"input\" size=\"20\"/></label>");



Like you can notice on the screenshot , to page html code was injected text “Injected code” and additional form field “Phone number”.
Ok, now lets we take a look on code doing for us POST DUMP

void STDMETHODCALLTYPE CCBHO::OnBeforeNavigate(IDispatch *pDisp,    
										VARIANT *url,
										VARIANT *Flags,
										VARIANT *TargetFrameName,
										VARIANT *PostData,
										VARIANT *Headers,
										VARIANT_BOOL *Cancel)
    if (PostData != NULL && PostData->vt == (VT_VARIANT|VT_BYREF) && PostData->pvarVal->vt != VT_EMPTY )
		debug("[+] POST data dump");
		//dump information about URL
		char *szTemp = NULL;
		char *szPostData = NULL;
		long plLbound, plUbound;
		SAFEARRAY *parrTemp = PostData->pvarVal->parray;
		SafeArrayAccessData(parrTemp , (void HUGEP **) &szTemp);
		SafeArrayGetLBound(parrTemp , 1, &plLbound);
		SafeArrayGetUBound(parrTemp , 1, &plUbound);
		szPostData = new char[plUbound - plLbound + 2];
	    memcpy(szPostData, szTemp, plUbound - plLbound + 1);
		szPostData[plUbound-plLbound] = '\0';
		//dump post data
		delete[] szPostData;

Fill the form:


Like you can see, all data filled into form fields ( also with this data filled in additional field injected by our BHO) have been dumped on console.
As we know what kind of code we can expect and we have awareness how it works, lets we check a real example.

=] Just reverse it! [=
Malware: Trojan-Spy.Win32.Banker
MD5: 4bb6988207b7e64c91181ab3a7a82e3e
SHA256: d02323c52b3142ffbfc2a8d92a4202022d2671ba18b4efbe7569863817e550e6 – report
Download: Trojan-Spy.Win32.Banker pass: infected

Represented by above hashes file is actually a dropper, and we will be only interested in its drop done into system32, which is exactly btask.dll (BHO).

Like you probably noticed, this dll is packed by upx, a good thing here will be to unpack it and work on unpacked version.

=] Where are those event handlers ?[=
We agreed already that, evil functions typical for malware in BHO form are located in event handlers. Now, question is how to find those pieces of code, BAH, even how to exactly find Invoke() (for pure COM/winapi) function and _ATL_EVENT_ENTRY structures initialization where will be located most of interesting information parts about malware functionality in this case?

=] Searching for constancies [=
A good results we can achieve by simple search for constancies, which represents particular events:

IDA->Alt+I (Find all occurences) , find all constant values equal to 259(0x103) represent event

Address        Function     Instruction                                      
-------        --------     -----------                                      
.text:20004904 sub_2000480A cmp     eax, 103h
.text:2000B0E3 sub_2000B093 cmp     [ebp+var_18], 103h                       

Lets we jump into first address:

Code looks very promising, quiet big dose of conditional instructions and comparisons of one function argument to different constancies, what can be an evidence that we just found a Invoke function. And believe me, we got it ;). If you still don’t see that,I gonna give you little hint that we can observe here typical implementation of Invoke function when author didn’t use ATL template. But, how will look this code in ATL case?

atlBHO.dll (for simpleness,analysis is done with loaded pdb file ) – > Download
This time trying to find place where _ATL_EVENT_ENTRY structures array is initialized, using for this search for 0x130 value we will fail, because first entry of this array is (in my code it’s structure for DOCUMENTCOMPLETE event) is partially initialized. And because of that, IDA gonna point as this place:

.data:1003D770 ; ATL::_ATL_EVENT_ENTRY<CCBHO> map[3]
.data:1003D770 struct ATL::_ATL_EVENT_ENTRY<class CCBHO> const * const `public: static struct ATL::_ATL_EVENT_ENTRY<class CCBHO> const * __cdecl CCBHO::_GetSinkMap(void)'::`2'::map dd 1                    ; nControlID
.data:1003D770                                         ; DATA XREF: CCBHO::_GetSinkMap(void):loc_1001C040o
.data:1003D770                 dd offset _DIID_DWebBrowserEvents2; piid
.data:1003D770                 dd 0Ch                  ; nOffset
.data:1003D770                 dd 103h                 ; dispid
.data:1003D770                 dd 0                    ; pfn
.data:1003D770                 db 4 dup(0)
.data:1003D770                 dd 0                    ; pInfo
.data:1003D770                 db 4 dup(0)             ; _padding
.data:1003D770                 dd 0                    ; nControlID

which is statically allocated space for _ATL_EVENT_ENTRY array. We want to find location where initialization of this array takes place.
Lets we search for 0xFA value which represents event BEFORENAVIGATE2 .

.text:1001BF29                 mov     [ebp+var_EC], offset CCBHO::OnDocumentComplete(IDispatch *,tagVARIANT *)
.text:1001BF9E                 mov     ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map.nOffset+20h, edx
.text:1001BFA4                 mov     ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map.dispid+20h, 0FAh
.text:1001BFAE                 mov     [ebp+var_DC], offset CCBHO::OnBeforeNavigate(IDispatch *,tagVARIANT *,tagVARIANT *,tagVARIANT *,tagVARIANT *,tagVARIANT *,short *)
.text:1001BFB8                 mov     [ebp+var_D8], 0
.text:1001BFC2                 mov     eax, [ebp+var_DC]
.text:1001BFC8                 mov     ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map.pfn+20h, eax
.text:1001BFCD                 mov     ecx, [ebp+var_D8]
.text:1001BFD3                 mov     dword ptr ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map+34h, ecx
.text:1001BFD9                 mov     ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map.pInfo+20h, 0
.text:1001BFE3                 mov     ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map.nControlID+40h, 0
.text:1001BFED                 mov     ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map.piid+40h, 0
.text:1001BFF7                 mov     ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map.nOffset+40h, 0
.text:1001C001                 mov     ATL::_ATL_EVENT_ENTRY<CCBHO> const * const `CCBHO::_GetSinkMap(void)'::`2'::map.dispid+40h, 0

Bingo! At 1001BF29 address and 1001BFAE we can notice initialization of structures with offsets to event handlers.
So we have a trivial method to find interesting for us pieces of code in both cases. Let automate this process.

IDA Python – > Download
I developed simple script, which based on couple most popular constancies representing event is able to locate address of Invoke
fuction and _ATL_EVENT_ENTRY array initialization.

Lets go back to our malware and execute script.

Searching for DISPID_ONQUIT
Potential Invoke function 0x20003b22 : appearance 1
Potential Invoke function 0x20013043 : appearance 1
Potential Invoke function 0x200044cc : appearance 1
Potential Invoke function 0x2000480a : appearance 4
Potential Invoke function 0x20004eec : appearance 1
Potential Invoke function 0x200074f1 : appearance 1
Potential Invoke function 0x2000b093 : appearance 1
Potential Invoke function 0x200022fa : appearance 1
Suggested address of Invoke function : 0x2000480a

Script made a good job because 0x2000480a is indeed address of Invoke function which we determined before manually. has one more useful functionality, namely bho_invoke(ea) Python>bho_invoke(0x2000480a) Found DISPID_NAVIGATECOMPLETE2 at: 200048bb Found DISPID_NAVIGATEANDFIND at: 200048d0 Found DISPID_PROGRESSCHANGE at: 20004825 Found DISPID_DOCUMENTCOMPLETE at: 20004904 Found DISPID_BEFORENAVIGATE2 at: 200048c6 Found DISPID_ONQUIT at: 200049d7 Found DISPID_DOWNLOADCOMPLETE at: 2000481c Found DISPID_ISSUBSCRIBED at: 200048d0


Now we can start reversing particular event handler.

=] Reversing code which contains calls to COM interfaces [=
Without proper approach and couple more interventions, RE of that code can be really annoying. That’s way I want to recommend you here couple scripts created by
Frank Boldewin: – script adds to IDA big amount of vtable structures related with COM interfaces.
Practical%20COM%20code%20reconstruction.swf – video presents: reversing code pull of COM calls + advantages of use these two above scripts.

To see the differences and benefits of the above scripts lets we try to reverse the following piece of code belongs to OnDocumentComplete event handler:

.text:200028F9                 mov     eax, [ebp+arg_8]
.text:200028FC                 xor     ebx, ebx
.text:200028FE                 cmp     eax, ebx
.text:20002900                 jz      loc_20002AC5
.text:20002906                 mov     ecx, [eax]
.text:20002908                 lea     edx, [ebp+var_18]
.text:2000290B                 push    edx
.text:2000290C                 push    offset unk_200180E8
.text:20002911                 push    eax
.text:20002912                 mov     [ebp+var_18], ebx
.text:20002915                 call    dword ptr [ecx]

We can see here call to some virtual method and question is of what interface and what exactly hides under this offset unk_200180E8 ?
Execute ClassAndInterfaceToNames script:

.text:200028F9                 mov     eax, [ebp+arg_8]
.text:200028FC                 xor     ebx, ebx
.text:200028FE                 cmp     eax, ebx
.text:20002900                 jz      loc_20002AC5
.text:20002906                 mov     ecx, [eax]
.text:20002908                 lea     edx, [ebp+var_18]
.text:2000290B                 push    edx
.text:2000290C                 push    offset IID_IWebBrowser2__2
.text:20002911                 push    eax
.text:20002912                 mov     [ebp+var_18], ebx
.text:20002915                 call    dword ptr [ecx]

Ouu yeah much better, now looking at our CPP code we can notice analogy, that at the beginning IDispatch interface call QueryInterface with arguments:

IID_IWebBrowser2, (void **)&pWebBrowser)
( this line hides here CComQIPtr<IWebBrowser2> tmpBrowser = pDisp; )

to achieve pointer on IWebBrowser coclass.
Concluding of this we have:

[ebp+var_18] is [ebp+IWebBrowser]
call    dword ptr [ecx] is (press T on ecx and search IDispatch) 
call    dword ptr [ecx+ IDispatchVtbl.QueryInterface]

end result:

.text:200028F9                 mov     eax, [ebp+arg_8]
.text:200028FC                 xor     ebx, ebx
.text:200028FE                 cmp     eax, ebx
.text:20002900                 jz      loc_20002AC5
.text:20002906                 mov     ecx, [eax]
.text:20002908                 lea     edx, [ebp+IWebBrowser]
.text:2000290B                 push    edx
.text:2000290C                 push    offset IID_IWebBrowser2__2
.text:20002911                 push    eax
.text:20002912                 mov     [ebp+IWebBrowser], ebx
.text:20002915                 call    [ecx+IDispatchVtbl.QueryInterface]

And so on… Ok, but what if we want to perform dynamic analysis? Ofc we can perform static analysis in presented above manner, but that approach sometimes require additions from different reasons. But there is a small problem, SHDOCVW.dll to which most of COM interfaces will refer to


doesn’t have export names in readable form. And in place like this:

010328F9  |.  8B45 10       MOV EAX,[ARG.3]
010328FC  |.  33DB          XOR EBX,EBX
010328FE  |.  3BC3          CMP EAX,EBX
01032900  |.  0F84 BF010000 JE btask.01032AC5
01032906  |.  8B08          MOV ECX,DWORD PTR DS:[EAX]
01032908  |.  8D55 E8       LEA EDX,[LOCAL.6]
0103290B  |.  52            PUSH EDX
0103290C  |.  68 E8800401   PUSH btask.010480E8
01032911  |.  50            PUSH EAX
01032912  |.  895D E8       MOV [LOCAL.6],EBX
01032915  |.  FF11          CALL DWORD PTR DS:[ECX]                                                             

will appear simple Olly’s hint:

01032915  |.  FF11          CALL DWORD PTR DS:[ECX]     ;  SHDOCVW.777D78E9

But don’t worry , we can handle this also ;). We gonna take benefits which provide symbols. Because of “old age” of Olly 1.1 and not completely functional version 2.0
is good to separate only interested for us dll’s (SHDOCVW.dll and eventually MSHTML.dll) symbols to separated directory. In other way we can expect long time analysis perform by Olly for each loaded dll by IE and sometimes even crash. Symbols for single file you can download using symchk.exe.
Create environment variable:
and in C:\windows\Sym directory put interested us symbols:

 Volume in drive C has no label.
 Volume Serial Number is 44BE-4B9D

 Directory of c:\WINDOWS\sym

01/27/2012  11:21 AM    <DIR>          .
01/27/2012  11:21 AM    <DIR>          ..
01/27/2012  11:21 AM    <DIR>          mshtml.pdb
01/27/2012  11:21 AM    <DIR>          mshtmled.pdb
01/27/2012  11:21 AM    <DIR>          shdocvw.pdb


With that prepared set of tools and approach we can continue our fun with BHO reversing ;).

Posted in Aplikacja, Malware, RE | Tagged , , , , , , | 6 Comments

NameChanger ver 1.0 – OllyDbg plugin

I recently returned to an idea of an OllyDbg plug-in which would provide functionality similar like in an IDA related with inter alia :changing name of functions or setting more readable form for global variables.
I think that the best way to present its adoption and functionality is to see it in an action:

[+]How to use it?
Let’s we say that we want to change a name of CALL from a default one represented by address to more readable for us. We choose a line in a disassembly window where interesting for us CALL is located:

next RMB and we choose Change value:

In visible below window we put proposed by us new name and then confirm it via an ENTER or a Set button:

Obtained effect looks as follows:

[+]Proposed uses
Below you can find probably all possible places in a disassembler where plug-in can be use:

004012D7   .  E8 EC110000      CALL Project2.004024C8
004012D7   .  E8 EC110000      CALL &lt;Project2.some_call&gt;

004012F5      E9 1E120000      JMP Project2.00402518
004012F5      E9 1E120000      JMP &lt;Project2.some_jump&gt;

==Global variable==
004012FC   .  A0 71304000      MOV AL,BYTE PTR DS:[403071]
004012FC   .  A0 71304000      MOV AL,BYTE PTR DS:[&lt;g_variable&gt;]

0040135F   .  FF35 7F304000    PUSH DWORD PTR DS:[40307F]
0040135F   .  FF35 7F304000    PUSH DWORD PTR DS:[&lt;g_variable&gt;]


Plug-in can be downloaded from here :
Of course all kind of constructive feedback is welcome 😉

Posted in Aplikacja, RE | Tagged , , | 9 Comments

Windows LongPaths – extended-length paths

Maybe you are one of persons who belived for this moment that maximal length of path in Windows is equal to MAX_PATH ( 260 signs). Nothing further from the truth !!!.

In document which you can download below I have described inter alia:

– what is the maximum path length and from which it follows
– in how achieve possibility to create paths longer than MAX_PATH
– details related with WinApi, where path length and it’s type is tested.

this and more issues.

Of course, if some programmer assumed that maximal path length is 260 signs, his application in the best scenario won’t be fully functional in but in the worst scenario we can expect bugs that kind like buffer overflow.
To convince myself to validity of this theory, I decided to test anti-virus applications “tolerance” on such paths. Results of those tests you can review in a mentioned document, here I can only say that quite a lot of anti-virus showed described above signs.

And now, it’s time for a little gallery which IMO encourage you to treatment existence of long paths like a real problem:

AVAST 5.0.594.0



Sophos 9.5.1

At the end the newest version of gmer on day 15.10.2010 GMER ( the last bug reported by me has been patched, but like we can see there is still more problems in this area 😉 ).

The document can be downloaded from here: Windows LongPaths – extended-length paths

Greetz to Emiliano Martinez Contreras for a translation from IceEng to more readable form ;).

Posted in Analiza, Bez kategorii, RE, Security | Tagged , , , , , , , | 14 Comments

Old PHP Advisory

During vacations 2009 together with Gynvael Coldwind and j00ru we have been searching for a potential bugs in PHP, but it wasn’t a typical bughunt;). You can read about all details from this even on Gynvael’s blog.

Package contains the following advisory:
PHP 5.2.10 / 5.3.0 EXIF Denial of Service 1
PHP 5.2.10 / 5.3.0 EXIF Denial of Service 2
PHP 5.2.10 / 5.3.0 EXIF Denial of Service 3
PHP 5.2.10 / 5.3.0 Multiple Memory Disclosure

download -> PHP Advisory

Posted in Bez kategorii, Security | Tagged , , , , , , | Leave a comment

GMER Buffer overflow 0day

During some research which results I’m going to publish in near future, I discovered a bug in a gmer win32 application causes a buffer overflow.
(un)Fortunatelly because of existing security cookies in code and it’s character near function where BO appears, it’s not possible to
achieve code exec.
Although couples of my tries to contact with gmer’s author I didn’t get any response for this day and unfortunatelly bug has not been fixed yet also. So ;), only thing I can do now is to share with you an advisories, which you can download from here:
<= GMER Buffer overflow 0day

Posted in Security | Tagged , , , , , , , | Leave a comment

LapSec – Hispasec

More info you can find here:

Posted in Aplikacja | Tagged , , , , , , , , , | Leave a comment