blabberer

Reversing RunDialog (Start+Run or Winkey+R) to Add a 27th entry to RunMRU list

Rate this Entry
Mint77 posted in the forum asking how to increase the run dialog
(Start => Run / Winkey + R) MRU (Most Recently Used ) contents

It is aptly named MRU which implies it holds only a few entries and not all the entries from times immemorial

It seems he had earlier been told by someone at MSDN that the max limit was 26 entries and the older entries drop out on FIFO (First In First Out) basis

So if the MRU list is full the and we have a new contender the oldest entry drops out and the latest entry is dropped in

Logically right and practically right

But logic and practicality never works when it comes to reversing

He posted that he was told there was no way to increase the limit and was looking for some ideas to realize his fantasy

So I tossed in a some time and took a look.

A few minutes in procmon / windbg and the 27th entry is overloaded into RunMruList

Name:  runmrubiggerthan_26.JPG
Views: 6747
Size:  142.7 KB

WARNING:

do not mimic the methods shown. Without understanding the implications of various locks held like spinlocks , critical sections, , interlocked cmpexchg in critical system processes it may crash and may cause BSOD


RUN Dialog is handled by explorer.exe
Lets fire procmon and capture pertinent events in explorer.exe

(be sure to configure symbols in procmon prior to capturing events so that stack is properly displayed you can point it to your _NT_SYMBOL_PATH cache )

a default procmon captures too much events

procmon monitors file events , registry events network event and profiling events
apart from process / thread events

an enormous amount of spew ensues as a result

we need to set a filter

we know we are interested in explore.exe events only

we also are interested in MRU so set a filter for MRU in path

click filter menu and select filter submenu (ctrl + L hotkey)

process monitor filter will popup



1st time 2nd time
in the 1st drop down select process path
in the 2nd drop down select is contains
in the 3rd drop down type in explorer.exe MRU
in the 4th drop down select include include



click add after each time if all went well the pane should look like this

Name:  procmon filter.PNG
Views: 6680
Size:  80.6 KB

click apply and let procmon roll

goto start => hit run or do Winkey+R and execute a program

preferably one which is not available in MRU

or clear the MRU via taskbar and start menu properties and type in a new program
so that we have a complete log

a fresh run will see the following entries notice RegSetValue that is highlighted
we are interested in its stack which is shown below

Name:  procmonstk.jpg
Views: 6673
Size:  125.0 KB

so AddMruStringW is where something interesting might be available lets close procmon for now and run a debugger to check the AddMruStringW function in explorer.exe

Code:

windbg -pn explorer.exe -c "bp Shell32!AddMruStringW;g"
-pn attaches to a running process by specifying the process name

-c Specifies the initial debugger command to run at start-up.



In the initial command we are setting breakpoint on the api we saw in procmon and ask windbg to continue its execution

We now go to start=>run and enter any program to execute so that we shall break in windbg and we can examine the state

Code:
Breakpoint 0 hit
eax=0274ee20 ebx=00000000 ecx=7c9c95ba edx=000000fb esi=01c73ff8 edi=00000009 eip=7ca2b28d esp=0274ebf8 ebp=0274f0b0 iopl=0         nv up ei pl zr na pe nc cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000 efl=00000246
SHELL32!AddMRUStringW:
7ca2b28d 8bff            mov     edi,edi
lets check the stack

Code:
0:017> kb
ChildEBP RetAddr  Args to Child              
039bebf4 7ca408e2 00139220 039bee20 00150202 SHELL32!AddMRUStringW
039bf0b0 7ca4073f 039bf128 7ca40091 039bf0ec SHELL32!CRunDlg::OKPushed+0x1ce
039bf0c0 7e418734 00150202 00000111 00000001 SHELL32!RunDlgProc+0x121
039bf0ec 7e423ce4 7ca40091 00150202 00000111 USER32!InternalCallWinProc+0x28
039bf158 7e423b30 0009e158 7ca40091 00150202 USER32!UserCallDlgProcCheckWow+0x146
039bf1a0 7e423d5c 00000000 00000111 00000001 USER32!DefDlgProcWorker+0xa8
039bf1bc 7e418734 00150202 00000111 00000001 USER32!DefDlgProcW+0x22
039bf1e8 7e418816 7e423d3a 00150202 00000111 USER32!InternalCallWinProc+0x28
039bf250 7e42927b 0009e158 7e423d3a 00150202 USER32!UserCallWinProcCheckWow+0x150
039bf28c 7e4292e3 005aa750 00566d80 00000001 USER32!SendMessageWorker+0x4a5
039bf2ac 7e431cde 00150202 00000111 00000001 USER32!SendMessageW+0x7f
039bf2dc 7e42763c 00150202 0057edc0 00170222 USER32!IsDialogMessageW+0x41f
039bf318 7e4249c4 00150202 00170222 00000001 USER32!DialogBox2+0x144
039bf340 7e424a06 7c9c0000 7cc26c50 00170222 USER32!InternalDialogBox+0xd0
039bf360 7e4247ea 7c9c0000 7cc26c50 00170222 USER32!DialogBoxIndirectParamAorW+0x37
039bf384 7ca4033c 7c9c0000 000003eb 00170222 USER32!DialogBoxParamW+0x3f
039bf3cc 7ca402c8 7c9c0000 000003eb 00170222 SHELL32!SHFusionDialogBoxParam+0x3b
039bf400 0102129f 00170222 00000000 039bf834 SHELL32!RunFileDlg+0xc4
039bfa40 010210f3 00170222 00000000 01be80c0 Explorer!_RunFileDlg+0x12f
039bfee0 77f69598 000003b8 01be71e0 77f6957b Explorer!CTray::_RunDlgThreadProc+0x29a
039bfef8 7c927ac2 01be71e0 7c97e440 00160a70 SHLWAPI!ExecuteWorkItem+0x1d
039bff40 7c927b03 77f6957b 01be71e0 0009f298 ntdll!RtlpWorkerCallout+0x70
039bff60 7c927bc5 00000000 01be71e0 00160a70 ntdll!RtlpExecuteWorkerRequest+0x1a
039bff74 7c927b9c 7c927ae9 00000000 01be71e0 ntdll!RtlpApcCallout+0x11
039bffb4 7c80b729 00000000 0274ec60 0274ec60 ntdll!RtlpWorkerThread+0x87
039bffec 00000000 7c910250 00000000 00000000 kernel32!BaseThreadStart+0x37
it looks the same as in procmon

lets check the arguments to the function

since this is x86 32bit three arguments are shown in stack if we want more we need to play with esp register

note: be aware in x64 the first three four args are passed in registers thanks for the comment by evlncrn8


the first three args as per kb

Code:
ChildEBP RetAddr  Args to Child              
039bebf4 7ca408e2  00139220 039bee20 00150202 SHELL32!AddMRUStringW
what is the first argument

0:017> dd poi(esp+4) l4
00139220 00000002 0000001a 7c80aa36 00000828

you should recognize the 0x1a

0:017> .formats 1a
Evaluate expression:
Hex: 0000001a
Decimal: 26 <--------------------

0:017> du poi(esp+8)
039bee20 "cmd\1" <------------- yes this is our input

so since this is an argument check who pushed it

ub return address in stack viz

Code:
0:017> ub 7ca408e2

7ca408c2 68b4959c7c     	push    offset SHELL32!`string' (7c9c95b4)
7ca408c7 8d8570fdffff    	lea     eax,[ebp-290h]
7ca408cd 50              	push    eax
7ca408ce ff15341c9c7c	call    dword ptr [SHELL32!_imp__StrCatBuffW (7c9c1c34)]
7ca408d4 8d8570fdffff    	lea     eax,[ebp-290h]
7ca408da 50            	push    eax
7ca408db 56              	push    esi <-------------------
7ca408dc ff1584b2a27c    call    dword ptr [SHELL32!_imp__AddMRUStringW (7ca2b284)]
what is in esi

0:017> r esi
esi=00139220

where did esi get that value

ub retn_address length > default on trial and error till we locate esi
or use ida
or ollydbg register highlighting functionality


we see esi got the value from the return value of a Function

Code:
0:017> ub 7ca408e2 l40 

7ca408b2 e8b2faffff      call    SHELL32!OpenRunDlgMRU (7ca40369)
7ca408b7 8bf0            mov     esi,eax <------------------------
7ca408b9 3bf3            cmp     esi,ebx
7ca408bb 742b            je      SHELL32!CRunDlg::OKPushed+0x1d4 (7ca408e8)
7ca408bd 6806010000      push    106h
7ca408c2 68b4959c7c      push    offset SHELL32!`string' (7c9c95b4)
7ca408c7 8d8570fdffff    lea     eax,[ebp-290h]
7ca408cd 50              push    eax
7ca408ce ff15341c9c7c    call    dword ptr [SHELL32!_imp__StrCatBuffW (7c9c1c34)]
7ca408d4 8d8570fdffff    lea     eax,[ebp-290h]
7ca408da 50              push    eax
7ca408db 56              push    esi
7ca408dc ff1584b2a27c    call    dword ptr [SHELL32!_imp__AddMRUStringW (7ca2b284)]
so we would need to check this function

Code:
0:016> uf SHELL32!OpenRunDlgMRU
SHELL32!OpenRunDlgMRU+0x19:
7ca4002f 2145fc          and     dword ptr [ebp-4],eax
7ca40032 8d45e8          lea     eax,[ebp-18h]
7ca40035 50              push    eax
7ca40036 c745e818000000  mov     dword ptr [ebp-18h],18h
7ca4003d c745ec1a000000  mov     dword ptr [ebp-14h],1Ah
7ca40044 c745f002000000  mov     dword ptr [ebp-10h],2
7ca4004b c745f401000080  mov     dword ptr [ebp-0Ch],80000001h
7ca40052 c745f810109d7c  mov     dword ptr [ebp-8],offset SHELL32!`string'+0x10 (7c9d1010)
7ca40059 ff15b0b2a27c    call    dword ptr [SHELL32!_imp__CreateMRUListW (7ca2b2b0)]
7ca4005f e922030000      jmp     SHELL32!OpenRunDlgMRU+0x49 (7ca40386)

SHELL32!OpenRunDlgMRU:
7ca40369 8bff            mov     edi,edi
7ca4036b 55              push    ebp
7ca4036c 8bec            mov     ebp,esp
7ca4036e 83ec18          sub     esp,18h
7ca40371 6a00            push    0
7ca40373 6894f6bc7c      push    offset SHELL32!g_hMRURunDlg (7cbcf694)
7ca40378 ff15b4139c7c    call    dword ptr [SHELL32!_imp__InterlockedExchange (7c9c13b4)] 
7ca4037e 85c0            test    eax,eax
7ca40380 0f84a9fcffff    je      SHELL32!OpenRunDlgMRU+0x19 (7ca4002f)

SHELL32!OpenRunDlgMRU+0x49:
7ca40386 c9              leave
7ca40387 c3              ret
so either InterlockedExchange return or


0:016> ln poi(SHELL32!_imp__CreateMRUListW)
(7ca2b2b9) SHELL32!CreateMRUListW | (7ca2b320) SHELL32!CFSFolder::_CreatePerClassDefExtIcon
Exact matches:
SHELL32!CreateMRUListW (<no parameter info>) return Is passed into esi



Remember the warnings about lock synchronization

This structure is protected by lock is what we can understand

Something like

Code:
void somecrapfunct(void)
{
             If  ( (intcmpexch(global_) ) == 0) 
             {
                      CreateMruListW(.........);
             }
            return ;
}
I leave the CreateMruList() analysis to readers

Hint it makes an indirect call and goes on to set a reg key see the args

Code:
7ca4004b c745f401000080  mov     dword ptr [ebp-0Ch],80000001h
7ca40052 c745f810109d7c  mov     dword ptr [ebp-8],offset SHELL32!`string'+0x10 (7c9d1010)

0:016> du /c 40 7c9d1010
7c9d1010  "Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU"


C:\WinDDK\7600.16385.1\inc\api>grep -ir "#define HKEY_current_user" *

WINREG.H:#define HKEY_CURRENT_USER                   (( HKEY ) (ULONG_PTR)((LONG
)0x80000001) )
WINREG.H:#define HKEY_CURRENT_USER_LOCAL_SETTINGS    (( HKEY ) (ULONG_PTR)((LONG
)0x80000007) )

C:\WinDDK\7600.16385.1\inc\api>
Lets see what this global contains

Code:
0:016> dd poi(SHELL32!g_hMRURunDlg) l4
xxxxxxxx  00000002 0000001a 7c80aa36 000008fc

i removed the address coz i wrote this blog over several days so the address might confuse reader 
for a single session the allocated address will remain same here xxxxxxxxx will be   00139220 
in a single session output
there lies our esi to AddStringMruW

lets memory modify it (you need to break into OpenRunDialog and modify it before the lock is taken)

Code:
read warning in last paragraph about address assume  00139220 instead of 02522df4 for a single uninterrupted 
session (it will be whatever it was in [esp+4] when you broke into windbg) 

0:016> dd poi(SHELL32!g_hMRURunDlg)+4 L1
02522df4  0000001a

0:016> ed poi(SHELL32!g_hMRURunDlg)+4 0x1b < lets add one more string

0:016> dd poi(SHELL32!g_hMRURunDlg)+4 L1
02522df4  0000001b
lets detach windbg from explorer and keep adding strings to runmru
and check was it successful did we get our 27th string in runmru ?

yes we got it

warning again
please do not mimic this in system critical process

also this is not a full reverse it doesn't mean that you can set the value to 0xffffffff
and have the full liberty of 2^32 - 1 strings in runmru

think before hand
what may happen to alloc memory
how the buffers are allocated why is it a protected global
can increasing beyond 26 corrupt further structures
where did the RunMRULIST get its next character from apart from abcdef............xyz

Code:
0:016> .formats 61+0n26
Chars:   ...{   +1 from z 
what happens when this runs out of byte limit 0xff recycle or crash ? is it bytelimit or wordlimit ? or omg INT64
who else uses this set ba r4 breaks

happy runmruing

Submit "Reversing RunDialog (Start+Run or Winkey+R) to Add a 27th entry to RunMRU list" to Digg Submit "Reversing RunDialog (Start+Run or Winkey+R) to Add a 27th entry to RunMRU list" to del.icio.us Submit "Reversing RunDialog (Start+Run or Winkey+R) to Add a 27th entry to RunMRU list" to StumbleUpon Submit "Reversing RunDialog (Start+Run or Winkey+R) to Add a 27th entry to RunMRU list" to Google

Updated January 7th, 2013 at 00:56 by blabberer

Categories
Uncategorized

Comments