Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WOW64 Stub for D/Invoke #50

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

WOW64 Stub for D/Invoke #50

wants to merge 1 commit into from

Conversation

am0nsec
Copy link

@am0nsec am0nsec commented Jun 11, 2020

Abstract

Two days ago I discussed with @TheWover and @FuzzySecurity about contributing to this project, and they both mentioned that D/Invoke wasn't supporting Windows on Windows x64 (hereby as "WOW64"). I therefore made a custom stub to implement this feature.

WOW64 is a feature that was introduced with Windows XP and that allow the execution of x86 applications on x64 systems. This is done via three main DLLs (hereby as "module"):

  • wow64.dll for non-GUI-related API calls translation;
  • wow64win.dll for GUI-related API translation; and
  • wow64cpu.dll for x86 emulation.

I don't know the inner mechanisms and how all of that work; however I know that there is an insane number of things that happen for each system calls and re-implementing everything would be a huge piece of work.

Implementation

A normal WOW64 stub from NTDLL is as follows:

0:000> u NtCreateMutant
ntdll!NtCreateMutant:
773b1be0 b8b3000000      mov     eax,0B3h
773b1be5 bad0603c77      mov     edx,offset ntdll!Wow64SystemServiceCall (773c60d0)
773b1bea ffd2            call    edx
773b1bec c21000          ret     10h
773b1bef 90              nop

As shown, there is no system call executed from here, instead the stub call ntdll!Wow64SystemServiceCall. The problem is that this is a private (i.e. not exported) function and I still did not find a reliable way to retrieve the address of the function.

But this is not a big deal because this is only pointing to a JMP instruction to an exported function: Wow64Transition. This function is responsible for switching the segment register (i.e. CPU long mode) to transition from x86 to x64 and therefore to the whNt* functions.

0:000> u ntdll!Wow64SystemServiceCall L 1
ntdll!Wow64SystemServiceCall:
773c60d0 ff2528824677    jmp     dword ptr [ntdll!Wow64Transition (77468228)]

The address of the Wow64Transition exported function can be easily found by using GetExportAddress() from SharpSploit.Execution.DynamicInvoke class. With the address, a custom stub can be created:

0:006> u 04d90000
04d90000 b8b3000000      mov     eax,0B3h
04d90005 ff1528824677    call    dword ptr [ntdll!Wow64Transition (77468228)]
04d9000b c21000          ret     10h
04d9000e 90              nop
04d9000f 90              nop

If you are executig NtAllocateVirtualMemory, this should look like that:

  1. .NET delegate from function pointer (x86)
  2. Custom stub (x86)
  3. ntdll!Wow64Transition (x86)
  4. wow64!whNNtAllocateVirtualMemory (x64)
  5. ntdll!NtAllocateVirtualMemory (x64)
  6. syscall (x64)

Final Notes

Target Framework: .NET Framework 4.7.1
Build and Run: Dubug, Release, Release with optimisation
Test Program: https://gist.github.com/am0nsec/dc81efa478b7d6c8d948177bcb5a276d

@FuzzySecurity
Copy link
Collaborator

As a solution on Win10 currently this probably works (I haven't tested yet), my issue is compat. One of the reasons to copy the callstub is because they change across Windows versions. See for example WOW64 on Win7:

image

On 7 neither Wow64SystemServiceCall or Wow64Transition are exported functions. Let me check this out over the weekend and add my comments below 👍

@Dewera
Copy link

Dewera commented Jun 17, 2020

@FuzzySecurity A manual reimplementation shouldn't be as complicated as mentioned above. If you follow Wow64SystemServiceCall you will notice it's just a chain of calls into an eventual transition back into x64 mode (in wow64cpu.dll) after which a normal x64 syscall is performed before the switch back to WOW64 mode. Furthermore, x64 mode is held in cs:33h and WOW64 mode is held in cs:23h which I believe remains static throughout all Windows versions.

Unfortunately lost my C# code to do this (otherwise would offer it as reference) but maybe this could help?

@am0nsec
Copy link
Author

am0nsec commented Jun 17, 2020

Re-implementing the whole process would be indeed an insane amount of work.

You can transition between x64 and x86 by switching the execution context, this is actually what the Heaven's Gate technique do. However, this is now mitigated by CFG.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants