Results 1 to 6 of 6

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

  1. #1
    Super Moderator
    Join Date
    Dec 2004
    Posts
    1,487
    Blog Entries
    15

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

    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



    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



    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 reggsetvalue that is highlighted
    we are interested in its stack which is show below



    so AddMruStringW is where something interesting might be available lets close procmon for now and run a debugger to check th 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


    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


    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

    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

    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
    Last edited by blabberer; January 7th, 2013 at 00:54.

  2. #2
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,084
    Blog Entries
    5
    Nice reversing, and use of Procmon.

    After reading that, I think ultimately if one wanted more than the 26 a-z entries it would be easiest to build their own ShellExec tray icon. Googling for 'RunDlg' brings up a few examples of exactly that, as well as adding MRU's to menus and such.

    Parsing the leaked Win2k source will also net the original RunDlg code too

    http://www.verysource.com/code/281236_1/rundlg.cpp.html

  3. #3
    "note: be aware in x64 the first three args are passed in registers."

    first 4 actually... rcx, rdx, r8, r9, (or floats passed via xmm)

    also, bsod risk when debugging.... kinda doubt it considering you're in userland code..

  4. #4
    Super Moderator
    Join Date
    Dec 2004
    Posts
    1,487
    Blog Entries
    15
    thanks for pointing out the error in x64 arg passing evlncrn8

    well bsod risk who knows maybe yes if sufficiently mangling some yet to be found returntolibheapnullderefappspecificdataoverwrittenheapedjitspray

  5. #5
    Wow very nice writeup I'm kinda missing these old-good-style writeups with all details so ppl can actually learn way of RCE, not just outcome

  6. #6
    local user
    Join Date
    Apr 2013
    Location
    Canada
    Posts
    7
    Fun walk-through. I wonder if the same behaviour could be done by hooking OpenRunDlgMRU(), and patching it to use more memory. It is ODD seeing a hard coded value. 26 slots, 26 letters?

    I got distracted and looked at windows 7's run list. It has a huge MRU, it is so long I wish it were possible to search it.

    ie

    Code:
    history | grep "obscure command"

Similar Threads

  1. Start function
    By jackall in forum The Newbie Forum
    Replies: 2
    Last Post: October 22nd, 2010, 10:34
  2. Where To Start
    By imb in forum The Newbie Forum
    Replies: 1
    Last Post: June 4th, 2007, 20:48
  3. HASP Driver-How to Start?!
    By zkhan123 in forum The Newbie Forum
    Replies: 3
    Last Post: March 11th, 2004, 14:12
  4. Where to Start
    By InFiNiTeX in forum The Newbie Forum
    Replies: 2
    Last Post: December 5th, 2003, 17:16
  5. Start Code
    By Tech19 in forum Malware Analysis and Unpacking Forum
    Replies: 2
    Last Post: August 24th, 2001, 18:58

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •