Results 1 to 4 of 4

Thread: Weird export forwarding thanks to Vista x64 SP1

  1. #1
    Registered User
    Join Date
    Jul 2007
    Posts
    107
    Blog Entries
    6

    Weird export forwarding thanks to Vista x64 SP1

    After installing the SP1 for Vista x64, I noticed that ImpREC stopped working properly on some files using DefWindowProcA and DefWindowProcW from user32.dll.
    These 2 APIs are forwarded as usual respectively to NtdllDefWindowProc_A and NtdllDefWindowProc_W from ntdll.dll but cannot be "unforwarded" back to user32.dll using the traditional method.

    I'll explain how the loader usually resolves forwarded exports, the unforwarding method used by ImpREC and why it fails on those 2 particular cases.

    Using the information provided by the Import Directory of the executable, the loader looks for a matching name or ordinal in the specified dll.
    After a match is found, the corresponding entry from the AddressOfFunctions array is retrieved from the Export Directory and augmented by the ImageBase of the dll.
    That value is then written to the IAT.

    Sometimes, for compatibility reasons, an import can be forwarded to another one from a different module.
    In that case, the AddressOfFunctions entry does not lead to code but to an ASCII string composed of the module name and the import name or ordinal.
    Code:
    .text:7DCA751E ; LRESULT __stdcall DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
    .text:7DCA751E DefWindowProcA  db 'NTDLL.NtdllDefWindowProc_A',0
    .text:7DCA7539 ; Exported entry 151. DefWindowProcW
    .text:7DCA7539                 public DefWindowProcW
    .text:7DCA7539 ; LRESULT __stdcall DefWindowProcW(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
    .text:7DCA7539 DefWindowProcW  db 'NTDLL.NtdllDefWindowProc_W',0
    The loader then restarts the whole process from the beginning, using the info from the forwarding string rather than the original info from the Import Directory of the executable.
    The Entry Point of the newly-found function is written to the IAT instead.

    ImpREC finds the IAT and goes through it to identify all the imports that it contains.
    Some entries belong to ntdll.dll and need to be "unforwarded" to their original location.
    DefWindowProcA should be unforwarded from NtdllDefWindowProc_A.


    http://img510.imageshack.us/my.php?image=presp1zr0.png

    If everything goes well, the original import is found by "bruteforcing" the Entry Point of every function until a forwarding string is found: NTDLL.DefWindowProc_A at the Entry Point of DefWindowProcA in user32.dll and then comes in some guesswork.

    Because an import could have been forwarded from another module, doesn't mean that it really was, there are some false-positives.
    The guesswork is based on a very crude probability analysis based on the module name of the previous import and the module name of the next import.
    EndDialog from user32.dll is almost never forwarded from shlwapi32.dll.

    Something changed with Vista x64 SP1 through some modifications of wow64.dll since the content of the \SysWOW64 directory should be the same as the standard Vista 32-bit SP1.
    Some hotfix is applied only during run-time by WoW64.


    http://img177.imageshack.us/my.php?image=postsp11vz2.png


    http://img177.imageshack.us/my.php?image=postsp12vf6.png

    During execution, the AddressOfFunctions entries of DefWindowProcA and DefWindowProcW from user32.dll are modified.
    The RVA based at the ImageBase becomes greater than the SizeOfImage and leads into the memory area of ntdll.dll rather than the usual forwarding string.
    Instead of 0x0001751E, the AddressOfFunctions becomes 0x015C3D42 or 0x01793D42 or 0x01B83D42 for DefWindowProcA.

    The same result is achieved but this method prevents the unforwarding of some imports through the traditional method since there is no forwarding string anymore.
    It leads into code now:
    Code:
    ntdll.dll:77C43D42 ntdll_NtdllDefWindowProc_A:
    ntdll.dll:77C43D42 jmp     ds:off_77CB6020
    ...
    ntdll.dll:77CB6020 off_77CB6020 dd offset loc_7669C0E7     ; DATA XREF: ntdll.dll:ntdll_NtdllDefWindowProc_Ar
    And jumps back to user32.dll:
    Code:
    user32.dll:7669C0E7 loc_7669C0E7:                           ; DATA XREF: ntdll.dll:off_77CB6020o
    user32.dll:7669C0E7 push    10h
    user32.dll:7669C0E9 push    offset unk_7669C158
    user32.dll:7669C0EE call    near ptr unk_766BC240
    user32.dll:7669C0F3 call    near ptr unk_766980D7
    ...
    Unforwarding is still possible anyway since a side-effect could be identified: the Entry Point of both imports become identical.
    GetProcAddress(DefWindowProcA) == GetProcAddress(NtdllDefWindowProc_A)
    GetProcAddress(DefWindowProcW) == GetProcAddress(NtdllDefWindowProc_W)

    To sum everything up:
    It doesn't really matter, the average user of Vista x64 SP1 would never notice the difference.
    Unpacking in a 32-bit VM instead is still more reliable than under WoW64.

    This will be a part of my proposed upcoming ReCon talk.

  2. #2
    Administrator dELTA's Avatar
    Join Date
    Oct 2000
    Location
    Ring -1
    Posts
    4,206
    Blog Entries
    5
    Nice to see your finding becoming an informative blog post. Maybe an ImpREC plugin that handles this situation would add an extra spice to your RECon talk?
    "Give a man a quote from the FAQ, and he'll ignore it. Print the FAQ, shove it up his ass, kick him in the balls, DDoS his ass and kick/ban him, and the point usually gets through eventually."

  3. #3
    Quote Originally Posted by TiGa View Post
    The guesswork is based on a very crude probability analysis based on the module name of the previous import and the module name of the next import.
    But remember that this trick won't work in a shuffled IAT, like some Armadillo ones...

    Anyway, nice work, mate

    Good luck at your congress.

    Cheers

    Nacho_dj

  4. #4
    Registered User
    Join Date
    Jul 2007
    Posts
    107
    Blog Entries
    6
    Maybe "guessing" was not the best possible choice of word.
    I'd say "predict the most probable outcome" but it sounds like guessing again.
    "Analysing the context" sounds less random.
    But Nacho_dj is right anyway.

    Sometimes there is no context:
    Code:
    <dword 0x0 separator>
    EndDialog
    ptr:blah
    <dword 0x0 separator>
    It could either be forwarded from shlwapi or really be EndDialog.
    Flip a coin or do nothing.
    That's what ImpREC does in that case, it does nothing.

    @Delta: Check your PM box
    On Vista x64, ImpREC already holds together with duct tape and ty-wraps.
    Plugins and AutoTrace crash miserably 9 times out of 10.

    TiGa
    Programming today is a race between software engineers to build bigger and better idiot-proof programs and the Universe trying to produce bigger and better idiots.
    So far, the Universe is winning.

Similar Threads

  1. A problem with forwarding an exported function in a DLL
    By mehdi311ggg in forum Advanced Reversing and Programming
    Replies: 1
    Last Post: December 18th, 2010, 14:34
  2. CTcpFwd cross-platform stdin/out to socket forwarding class
    By j00ru vx tech blog in forum Blogs Forum
    Replies: 0
    Last Post: April 20th, 2010, 02:20
  3. Weird dll hook thanks to Vista SP1
    By TiGa in forum Advanced Reversing and Programming
    Replies: 2
    Last Post: March 28th, 2008, 15:23
  4. Weird...
    By ancev in forum Off Topic
    Replies: 1
    Last Post: March 17th, 2007, 20:05
  5. Weird Request
    By naides in forum Off Topic
    Replies: 2
    Last Post: May 20th, 2005, 04:57

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
  •