Gaining access to the full Windows APIs from Windows 8 apps (including VirtualAlloc)


Note: this is not a security bug, it is a direct consequence of allowing native and unsafe code in Windows Store apps. This is not a way to escape the AppContainer protection (you still can't access the user's files without the appropriate permissions).

As many of you already know, Windows Store apps (aka. Metro style apps) are restricted to a limited set of APIs:

  • WinRT APIs (Windows.winmd)
  • Some portions of the .NET Framework (.NET Core)
  • A small set of Win32 APIs

In particular, .NET reflection is only allowed on public methods and properties (when it is used on framework DLLs). This restriction does not apply to your own code. In addition, restricted .NET types are not accessible, even if they are public.

Two important APIs that are not allowed on Store apps are VirtualAlloc and VirtualProtect, which can be used create executable regions of memory, and are necessary in order to implement jitters (on the fly compilation).

The following unsafe C# library makes it possible to gain access to all these APIs. It is composed of 100% pure C# code (although unsafe), but something similar could also be achieved using C++. No DLLs have been modified after the compilation, and the sample app passes the Store certification tests.

This workaround could be used to implement third-party virtual machines for Java, Python, etc. in addition to Microsoft’s .NET and Chakra.

How it works.

First, we need a GetObjectAddress function that returns an unsafe pointer to a managed object. This is done by saving a reference to the object inside a field of a custom class, ManagedReferenceHolder. Then, we take the address of (&) a marker field inside the same class. By incrementing the pointer, we get the address which contains the address to the managed object.

Now, we get the unsafe address of our assembly (GetObjectAddress(typeof(Example).Assembly)) and start scanning for the RuntimeAssembly.m_flags field. Once we find it, we set its value to ASSEMBLY_FLAGS_SAFE_REFLECTION (again, via unsafe byte manipulations, not via reflection). Now we can (almost) access private and internal members of the .NET Framework classes, provided that we unset the INVOCATION_FLAGS_NEED_SECURITY and INVOCATION_FLAGS_NON_W8P_FX_API values from the m_invocationFlags field of every MemberInfo (eg. FieldInfo, MethodInfo) that we want to invoke.

Another useful thing we can do is unsetting the APPX_FLAGS_API_CHECK and APPX_FLAGS_APPX_MODEL values of the AppDomain.s_flags. In this way, we can also load custom assemblies from a file.

Once we gain full access to the reflection, we can invoke the internal P/Invoke methods Microsoft.Win32.Win32Native.GetModuleHandle and GetProcAddress, which make it possible to get access to any Win32 function, including VirtualAlloc and VirtualProtect.

The example application allocates a portion of memory using VirtualAlloc with the PAGE_EXECUTE_READWRITE flag. Then it writes some x86 instructions, and generates a delegate for that code, using Marshal.GetDelegateForFunctionPointer.


Source code:


Note: although what has been described is technically feasible and cannot be statically detected by the Windows Store certification process, the terms of the Windows Store don't allow execution of code which was not already packaged inside the app, "in the context of the app itself". This would probably also apply to simple interpreters without native machine code generation.


Remco said...

The big problem here of course is when your app is in the store, you will get errors on ARM devices which only support the WinRT. Maybe worth to mention.

antiufo said...

Win32 APIs are also available on Windows RT. This is how the old desktop features of Windows keep working (everything has been recompiled for ARM, of course). The difference here is that the kernel refuses to launch desktop executables which have not been signed by Microsoft.
this sample app has been developed and tested for x86 (since I don't
have any ARM tablets to work on), I don't see any reason why it couldn't
be adjusted to work on ARM.

Programmdude said...

Not entirely certain it would be against the terms and conditions, if you were executing scripts locally and not downloading them. If you package lua files in your app, they are "in the context of the app", at least in my opinion.
In this case I am referring to luajit, not the standard lua interpreter.

WAN Optimization said...

Thanks for sharing. nice. Telemedicine

Post a Comment

Copyright (c) 2009-2013 Andrea Martinelli