Recently, I've taken an interest in gaining code execution on my Surface RT tablet. I have found Windows RT to be rather enticing since Microsoft has made a concerted effort to prevent the execution of unsigned code. A couple weeks ago I discovered a way to gain arbitrary shellcode execution via PowerShell. I will have a separate blog post on that topic once I get a thumbs up from Microsoft. And for the record, I am aware of the awesome public Windows RT jailbreak.
Anyway, seeing as I'm already fairly comfortable writing x86 and x86_64 shellcode, I wanted to take on the challenge of writing ARMv7-based shellcode for Windows since no one else seems to be doing it publicly. Knowing that writing shellcode from scratch would have been rather painful and prone to error, I decided to write my payload in C and then modify the resulting assembly listing slightly in order to achieve a position independent payload. Here is the result (noting that this is merely a working proof-of-concept):
You may have noticed that this shellcode is written in MASM format, therefore, it can only be assembled using armasm.exe (the ARM equivalent of ml.exe). Unfortunately, armasm doesn't provide the option of outputting to a raw bin file. It will only emit an object (.obj) file. I wrote Get-ObjDump with the intent of pulling out raw payload bytes in mind but armasm doesn't apply relocations. This means that any calls to functions present in the payload won't be fixed up and it will crash upon executing.
So rather than writing my own linker, the natural choice was to leverage Microsoft's linker, link.exe. In theory, all I would need to do is call `link bindshell.obj` and pull out the raw bytes from the '.foo' section of the resulting binary. However, I ran into a couple issues in practice:
1. link.exe requires that you specify an entry point.
Solution: Easy. Provide the '/ENTRY:"main"' switch
2. Depending on the subsystem you choose, link.exe requires certain functions in the CRT to be present. For example, the following subsystems require the following entry point functions:
/SUBSYSTEM:CONSOLE - mainCRTStartup
/DLL - _DllMainCRTStartup
/SUBSYSTEM:WINDOWS - WinMainCRTStartup
/SUBSYSTEM:NATIVE - NtProcessStartup
Solution: Obviously, I don't care about the C runtime library in my shellcode. The solution I came up with was to specify EFI_APPLICATION as the subsystem since it doesn't require the CRT. In the end, I don't care about the type of PE file I output. I just need the linker to fix up relocations for me. I can take care of pulling out the bytes from the .foo section of the resulting executable. Fortunately, Get-PEHeader can rip raw bytes from a PE file.
Wrapping things up, here is the process of obtaining fully-functioning ARM-based Windows RT shellcode from end to end: