├── .gitignore ├── DInvoke.Data ├── DInvoke.Data.csproj ├── Native.cs ├── PE.cs └── Win32.cs ├── DInvoke.DynamicInvoke ├── DInvoke.DynamicInvoke.csproj ├── Generic.cs ├── Native.cs └── Utilities.cs ├── DInvoke.ManualMap ├── DInvoke.ManualMap.csproj ├── Map.cs └── Overload.cs ├── DInvoke.Tests ├── DInvoke.Tests.csproj ├── DynamicInvokeTests.cs ├── GlobalUsings.cs └── ManualMapTests.cs ├── DInvoke.sln └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Nuget personal access tokens and Credentials 210 | # nuget.config 211 | 212 | # Microsoft Azure Build Output 213 | csx/ 214 | *.build.csdef 215 | 216 | # Microsoft Azure Emulator 217 | ecf/ 218 | rcf/ 219 | 220 | # Windows Store app package directories and files 221 | AppPackages/ 222 | BundleArtifacts/ 223 | Package.StoreAssociation.xml 224 | _pkginfo.txt 225 | *.appx 226 | *.appxbundle 227 | *.appxupload 228 | 229 | # Visual Studio cache files 230 | # files ending in .cache can be ignored 231 | *.[Cc]ache 232 | # but keep track of directories ending in .cache 233 | !?*.[Cc]ache/ 234 | 235 | # Others 236 | ClientBin/ 237 | ~$* 238 | *~ 239 | *.dbmdl 240 | *.dbproj.schemaview 241 | *.jfm 242 | *.pfx 243 | *.publishsettings 244 | orleans.codegen.cs 245 | 246 | # Including strong name files can present a security risk 247 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 248 | #*.snk 249 | 250 | # Since there are multiple workflows, uncomment next line to ignore bower_components 251 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 252 | #bower_components/ 253 | 254 | # RIA/Silverlight projects 255 | Generated_Code/ 256 | 257 | # Backup & report files from converting an old project file 258 | # to a newer Visual Studio version. Backup files are not needed, 259 | # because we have git ;-) 260 | _UpgradeReport_Files/ 261 | Backup*/ 262 | UpgradeLog*.XML 263 | UpgradeLog*.htm 264 | ServiceFabricBackup/ 265 | *.rptproj.bak 266 | 267 | # SQL Server files 268 | *.mdf 269 | *.ldf 270 | *.ndf 271 | 272 | # Business Intelligence projects 273 | *.rdl.data 274 | *.bim.layout 275 | *.bim_*.settings 276 | *.rptproj.rsuser 277 | *- [Bb]ackup.rdl 278 | *- [Bb]ackup ([0-9]).rdl 279 | *- [Bb]ackup ([0-9][0-9]).rdl 280 | 281 | # Microsoft Fakes 282 | FakesAssemblies/ 283 | 284 | # GhostDoc plugin setting file 285 | *.GhostDoc.xml 286 | 287 | # Node.js Tools for Visual Studio 288 | .ntvs_analysis.dat 289 | node_modules/ 290 | 291 | # Visual Studio 6 build log 292 | *.plg 293 | 294 | # Visual Studio 6 workspace options file 295 | *.opt 296 | 297 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 298 | *.vbw 299 | 300 | # Visual Studio LightSwitch build output 301 | **/*.HTMLClient/GeneratedArtifacts 302 | **/*.DesktopClient/GeneratedArtifacts 303 | **/*.DesktopClient/ModelManifest.xml 304 | **/*.Server/GeneratedArtifacts 305 | **/*.Server/ModelManifest.xml 306 | _Pvt_Extensions 307 | 308 | # Paket dependency manager 309 | .paket/paket.exe 310 | paket-files/ 311 | 312 | # FAKE - F# Make 313 | .fake/ 314 | 315 | # CodeRush personal settings 316 | .cr/personal 317 | 318 | # Python Tools for Visual Studio (PTVS) 319 | __pycache__/ 320 | *.pyc 321 | 322 | # Cake - Uncomment if you are using it 323 | # tools/** 324 | # !tools/packages.config 325 | 326 | # Tabs Studio 327 | *.tss 328 | 329 | # Telerik's JustMock configuration file 330 | *.jmconfig 331 | 332 | # BizTalk build output 333 | *.btp.cs 334 | *.btm.cs 335 | *.odx.cs 336 | *.xsd.cs 337 | 338 | # OpenCover UI analysis results 339 | OpenCover/ 340 | 341 | # Azure Stream Analytics local run output 342 | ASALocalRun/ 343 | 344 | # MSBuild Binary and Structured Log 345 | *.binlog 346 | 347 | # NVidia Nsight GPU debugger configuration file 348 | *.nvuser 349 | 350 | # MFractors (Xamarin productivity tool) working folder 351 | .mfractor/ 352 | 353 | # Local History for Visual Studio 354 | .localhistory/ 355 | 356 | # BeatPulse healthcheck temp database 357 | healthchecksdb 358 | 359 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 360 | MigrationBackup/ 361 | 362 | # Ionide (cross platform F# VS Code tools) working folder 363 | .ionide/ 364 | 365 | # Fody - auto-generated XML schema 366 | FodyWeavers.xsd 367 | 368 | # VS Code files for those working on multiple tools 369 | .vscode/* 370 | !.vscode/settings.json 371 | !.vscode/tasks.json 372 | !.vscode/launch.json 373 | !.vscode/extensions.json 374 | *.code-workspace 375 | 376 | # Local History for Visual Studio Code 377 | .history/ 378 | 379 | # Windows Installer files from build outputs 380 | *.cab 381 | *.msi 382 | *.msix 383 | *.msm 384 | *.msp 385 | 386 | # JetBrains Rider 387 | .idea/ 388 | *.sln.iml 389 | -------------------------------------------------------------------------------- /DInvoke.Data/DInvoke.Data.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | enable 6 | disable 7 | 12 8 | true 9 | TheWover, RastaMouse 10 | Required data classes, structs and enums. 11 | 1.0.7 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /DInvoke.Data/Native.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace DInvoke.Data; 4 | 5 | /// 6 | /// Native is a library of enums and structures for Native (NtDll) API functions. 7 | /// 8 | /// 9 | /// A majority of this library is adapted from signatures found at www.pinvoke.net. 10 | /// 11 | public static class Native 12 | { 13 | [StructLayout(LayoutKind.Sequential)] 14 | public struct UNICODE_STRING 15 | { 16 | public ushort Length; 17 | public ushort MaximumLength; 18 | public IntPtr Buffer; 19 | } 20 | 21 | [StructLayout(LayoutKind.Sequential)] 22 | public struct ANSI_STRING 23 | { 24 | public ushort Length; 25 | public ushort MaximumLength; 26 | public IntPtr Buffer; 27 | } 28 | 29 | public struct PROCESS_BASIC_INFORMATION 30 | { 31 | public IntPtr ExitStatus; 32 | public IntPtr PebBaseAddress; 33 | public IntPtr AffinityMask; 34 | public IntPtr BasePriority; 35 | public UIntPtr UniqueProcessId; 36 | public int InheritedFromUniqueProcessId; 37 | 38 | public int Size => Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)); 39 | } 40 | 41 | [StructLayout(LayoutKind.Sequential, Pack = 0)] 42 | public struct OBJECT_ATTRIBUTES 43 | { 44 | public int Length; 45 | public IntPtr RootDirectory; 46 | public IntPtr ObjectName; 47 | public uint Attributes; 48 | public IntPtr SecurityDescriptor; 49 | public IntPtr SecurityQualityOfService; 50 | } 51 | 52 | [StructLayout(LayoutKind.Sequential)] 53 | public struct IO_STATUS_BLOCK 54 | { 55 | public IntPtr Status; 56 | public IntPtr Information; 57 | } 58 | 59 | [StructLayout(LayoutKind.Sequential)] 60 | public struct OSVERSIONINFOEX 61 | { 62 | public uint OSVersionInfoSize; 63 | public uint MajorVersion; 64 | public uint MinorVersion; 65 | public uint BuildNumber; 66 | public uint PlatformId; 67 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] 68 | public string CSDVersion; 69 | public ushort ServicePackMajor; 70 | public ushort ServicePackMinor; 71 | public ushort SuiteMask; 72 | public byte ProductType; 73 | public byte Reserved; 74 | } 75 | 76 | [StructLayout(LayoutKind.Sequential)] 77 | public struct LIST_ENTRY 78 | { 79 | public IntPtr Flink; 80 | public IntPtr Blink; 81 | } 82 | 83 | public enum PROCESSINFOCLASS : int 84 | { 85 | ProcessBasicInformation = 0, // 0, q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION 86 | ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX 87 | ProcessIoCounters, // q: IO_COUNTERS 88 | ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX 89 | ProcessTimes, // q: KERNEL_USER_TIMES 90 | ProcessBasePriority, // s: KPRIORITY 91 | ProcessRaisePriority, // s: ULONG 92 | ProcessDebugPort, // q: HANDLE 93 | ProcessExceptionPort, // s: HANDLE 94 | ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN 95 | ProcessLdtInformation, // 10 96 | ProcessLdtSize, 97 | ProcessDefaultHardErrorMode, // qs: ULONG 98 | ProcessIoPortHandlers, // (kernel-mode only) 99 | ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS 100 | ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void 101 | ProcessUserModeIOPL, 102 | ProcessEnableAlignmentFaultFixup, // s: BOOLEAN 103 | ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS 104 | ProcessWx86Information, 105 | ProcessHandleCount, // 20, q: ULONG, PROCESS_HANDLE_INFORMATION 106 | ProcessAffinityMask, // s: KAFFINITY 107 | ProcessPriorityBoost, // qs: ULONG 108 | ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX 109 | ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION 110 | ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND 111 | ProcessWow64Information, // q: ULONG_PTR 112 | ProcessImageFileName, // q: UNICODE_STRING 113 | ProcessLUIDDeviceMapsEnabled, // q: ULONG 114 | ProcessBreakOnTermination, // qs: ULONG 115 | ProcessDebugObjectHandle, // 30, q: HANDLE 116 | ProcessDebugFlags, // qs: ULONG 117 | ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables 118 | ProcessIoPriority, // qs: ULONG 119 | ProcessExecuteFlags, // qs: ULONG 120 | ProcessResourceManagement, 121 | ProcessCookie, // q: ULONG 122 | ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION 123 | ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION 124 | ProcessPagePriority, // q: ULONG 125 | ProcessInstrumentationCallback, // 40 126 | ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX 127 | ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[] 128 | ProcessImageFileNameWin32, // q: UNICODE_STRING 129 | ProcessImageFileMapping, // q: HANDLE (input) 130 | ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE 131 | ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE 132 | ProcessGroupInformation, // q: USHORT[] 133 | ProcessTokenVirtualizationEnabled, // s: ULONG 134 | ProcessConsoleHostProcess, // q: ULONG_PTR 135 | ProcessWindowInformation, // 50, q: PROCESS_WINDOW_INFORMATION 136 | ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8 137 | ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION 138 | ProcessDynamicFunctionTableInformation, 139 | ProcessHandleCheckingMode, 140 | ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION 141 | ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION 142 | MaxProcessInfoClass 143 | }; 144 | 145 | /// 146 | /// NTSTATUS is an undocument enum. https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 147 | /// https://www.pinvoke.net/default.aspx/Enums/NtStatus.html 148 | /// 149 | public enum NTSTATUS : uint 150 | { 151 | // Success 152 | Success = 0x00000000, 153 | Wait0 = 0x00000000, 154 | Wait1 = 0x00000001, 155 | Wait2 = 0x00000002, 156 | Wait3 = 0x00000003, 157 | Wait63 = 0x0000003f, 158 | Abandoned = 0x00000080, 159 | AbandonedWait0 = 0x00000080, 160 | AbandonedWait1 = 0x00000081, 161 | AbandonedWait2 = 0x00000082, 162 | AbandonedWait3 = 0x00000083, 163 | AbandonedWait63 = 0x000000bf, 164 | UserApc = 0x000000c0, 165 | KernelApc = 0x00000100, 166 | Alerted = 0x00000101, 167 | Timeout = 0x00000102, 168 | Pending = 0x00000103, 169 | Reparse = 0x00000104, 170 | MoreEntries = 0x00000105, 171 | NotAllAssigned = 0x00000106, 172 | SomeNotMapped = 0x00000107, 173 | OpLockBreakInProgress = 0x00000108, 174 | VolumeMounted = 0x00000109, 175 | RxActCommitted = 0x0000010a, 176 | NotifyCleanup = 0x0000010b, 177 | NotifyEnumDir = 0x0000010c, 178 | NoQuotasForAccount = 0x0000010d, 179 | PrimaryTransportConnectFailed = 0x0000010e, 180 | PageFaultTransition = 0x00000110, 181 | PageFaultDemandZero = 0x00000111, 182 | PageFaultCopyOnWrite = 0x00000112, 183 | PageFaultGuardPage = 0x00000113, 184 | PageFaultPagingFile = 0x00000114, 185 | CrashDump = 0x00000116, 186 | ReparseObject = 0x00000118, 187 | NothingToTerminate = 0x00000122, 188 | ProcessNotInJob = 0x00000123, 189 | ProcessInJob = 0x00000124, 190 | ProcessCloned = 0x00000129, 191 | FileLockedWithOnlyReaders = 0x0000012a, 192 | FileLockedWithWriters = 0x0000012b, 193 | 194 | // Informational 195 | Informational = 0x40000000, 196 | ObjectNameExists = 0x40000000, 197 | ThreadWasSuspended = 0x40000001, 198 | WorkingSetLimitRange = 0x40000002, 199 | ImageNotAtBase = 0x40000003, 200 | RegistryRecovered = 0x40000009, 201 | 202 | // Warning 203 | Warning = 0x80000000, 204 | GuardPageViolation = 0x80000001, 205 | DatatypeMisalignment = 0x80000002, 206 | Breakpoint = 0x80000003, 207 | SingleStep = 0x80000004, 208 | BufferOverflow = 0x80000005, 209 | NoMoreFiles = 0x80000006, 210 | HandlesClosed = 0x8000000a, 211 | PartialCopy = 0x8000000d, 212 | DeviceBusy = 0x80000011, 213 | InvalidEaName = 0x80000013, 214 | EaListInconsistent = 0x80000014, 215 | NoMoreEntries = 0x8000001a, 216 | LongJump = 0x80000026, 217 | DllMightBeInsecure = 0x8000002b, 218 | 219 | // Error 220 | Error = 0xc0000000, 221 | Unsuccessful = 0xc0000001, 222 | NotImplemented = 0xc0000002, 223 | InvalidInfoClass = 0xc0000003, 224 | InfoLengthMismatch = 0xc0000004, 225 | AccessViolation = 0xc0000005, 226 | InPageError = 0xc0000006, 227 | PagefileQuota = 0xc0000007, 228 | InvalidHandle = 0xc0000008, 229 | BadInitialStack = 0xc0000009, 230 | BadInitialPc = 0xc000000a, 231 | InvalidCid = 0xc000000b, 232 | TimerNotCanceled = 0xc000000c, 233 | InvalidParameter = 0xc000000d, 234 | NoSuchDevice = 0xc000000e, 235 | NoSuchFile = 0xc000000f, 236 | InvalidDeviceRequest = 0xc0000010, 237 | EndOfFile = 0xc0000011, 238 | WrongVolume = 0xc0000012, 239 | NoMediaInDevice = 0xc0000013, 240 | NoMemory = 0xc0000017, 241 | ConflictingAddresses = 0xc0000018, 242 | NotMappedView = 0xc0000019, 243 | UnableToFreeVm = 0xc000001a, 244 | UnableToDeleteSection = 0xc000001b, 245 | IllegalInstruction = 0xc000001d, 246 | AlreadyCommitted = 0xc0000021, 247 | AccessDenied = 0xc0000022, 248 | BufferTooSmall = 0xc0000023, 249 | ObjectTypeMismatch = 0xc0000024, 250 | NonContinuableException = 0xc0000025, 251 | BadStack = 0xc0000028, 252 | NotLocked = 0xc000002a, 253 | NotCommitted = 0xc000002d, 254 | InvalidParameterMix = 0xc0000030, 255 | ObjectNameInvalid = 0xc0000033, 256 | ObjectNameNotFound = 0xc0000034, 257 | ObjectNameCollision = 0xc0000035, 258 | ObjectPathInvalid = 0xc0000039, 259 | ObjectPathNotFound = 0xc000003a, 260 | ObjectPathSyntaxBad = 0xc000003b, 261 | DataOverrun = 0xc000003c, 262 | DataLate = 0xc000003d, 263 | DataError = 0xc000003e, 264 | CrcError = 0xc000003f, 265 | SectionTooBig = 0xc0000040, 266 | PortConnectionRefused = 0xc0000041, 267 | InvalidPortHandle = 0xc0000042, 268 | SharingViolation = 0xc0000043, 269 | QuotaExceeded = 0xc0000044, 270 | InvalidPageProtection = 0xc0000045, 271 | MutantNotOwned = 0xc0000046, 272 | SemaphoreLimitExceeded = 0xc0000047, 273 | PortAlreadySet = 0xc0000048, 274 | SectionNotImage = 0xc0000049, 275 | SuspendCountExceeded = 0xc000004a, 276 | ThreadIsTerminating = 0xc000004b, 277 | BadWorkingSetLimit = 0xc000004c, 278 | IncompatibleFileMap = 0xc000004d, 279 | SectionProtection = 0xc000004e, 280 | EasNotSupported = 0xc000004f, 281 | EaTooLarge = 0xc0000050, 282 | NonExistentEaEntry = 0xc0000051, 283 | NoEasOnFile = 0xc0000052, 284 | EaCorruptError = 0xc0000053, 285 | FileLockConflict = 0xc0000054, 286 | LockNotGranted = 0xc0000055, 287 | DeletePending = 0xc0000056, 288 | CtlFileNotSupported = 0xc0000057, 289 | UnknownRevision = 0xc0000058, 290 | RevisionMismatch = 0xc0000059, 291 | InvalidOwner = 0xc000005a, 292 | InvalidPrimaryGroup = 0xc000005b, 293 | NoImpersonationToken = 0xc000005c, 294 | CantDisableMandatory = 0xc000005d, 295 | NoLogonServers = 0xc000005e, 296 | NoSuchLogonSession = 0xc000005f, 297 | NoSuchPrivilege = 0xc0000060, 298 | PrivilegeNotHeld = 0xc0000061, 299 | InvalidAccountName = 0xc0000062, 300 | UserExists = 0xc0000063, 301 | NoSuchUser = 0xc0000064, 302 | GroupExists = 0xc0000065, 303 | NoSuchGroup = 0xc0000066, 304 | MemberInGroup = 0xc0000067, 305 | MemberNotInGroup = 0xc0000068, 306 | LastAdmin = 0xc0000069, 307 | WrongPassword = 0xc000006a, 308 | IllFormedPassword = 0xc000006b, 309 | PasswordRestriction = 0xc000006c, 310 | LogonFailure = 0xc000006d, 311 | AccountRestriction = 0xc000006e, 312 | InvalidLogonHours = 0xc000006f, 313 | InvalidWorkstation = 0xc0000070, 314 | PasswordExpired = 0xc0000071, 315 | AccountDisabled = 0xc0000072, 316 | NoneMapped = 0xc0000073, 317 | TooManyLuidsRequested = 0xc0000074, 318 | LuidsExhausted = 0xc0000075, 319 | InvalidSubAuthority = 0xc0000076, 320 | InvalidAcl = 0xc0000077, 321 | InvalidSid = 0xc0000078, 322 | InvalidSecurityDescr = 0xc0000079, 323 | ProcedureNotFound = 0xc000007a, 324 | InvalidImageFormat = 0xc000007b, 325 | NoToken = 0xc000007c, 326 | BadInheritanceAcl = 0xc000007d, 327 | RangeNotLocked = 0xc000007e, 328 | DiskFull = 0xc000007f, 329 | ServerDisabled = 0xc0000080, 330 | ServerNotDisabled = 0xc0000081, 331 | TooManyGuidsRequested = 0xc0000082, 332 | GuidsExhausted = 0xc0000083, 333 | InvalidIdAuthority = 0xc0000084, 334 | AgentsExhausted = 0xc0000085, 335 | InvalidVolumeLabel = 0xc0000086, 336 | SectionNotExtended = 0xc0000087, 337 | NotMappedData = 0xc0000088, 338 | ResourceDataNotFound = 0xc0000089, 339 | ResourceTypeNotFound = 0xc000008a, 340 | ResourceNameNotFound = 0xc000008b, 341 | ArrayBoundsExceeded = 0xc000008c, 342 | FloatDenormalOperand = 0xc000008d, 343 | FloatDivideByZero = 0xc000008e, 344 | FloatInexactResult = 0xc000008f, 345 | FloatInvalidOperation = 0xc0000090, 346 | FloatOverflow = 0xc0000091, 347 | FloatStackCheck = 0xc0000092, 348 | FloatUnderflow = 0xc0000093, 349 | IntegerDivideByZero = 0xc0000094, 350 | IntegerOverflow = 0xc0000095, 351 | PrivilegedInstruction = 0xc0000096, 352 | TooManyPagingFiles = 0xc0000097, 353 | FileInvalid = 0xc0000098, 354 | InsufficientResources = 0xc000009a, 355 | InstanceNotAvailable = 0xc00000ab, 356 | PipeNotAvailable = 0xc00000ac, 357 | InvalidPipeState = 0xc00000ad, 358 | PipeBusy = 0xc00000ae, 359 | IllegalFunction = 0xc00000af, 360 | PipeDisconnected = 0xc00000b0, 361 | PipeClosing = 0xc00000b1, 362 | PipeConnected = 0xc00000b2, 363 | PipeListening = 0xc00000b3, 364 | InvalidReadMode = 0xc00000b4, 365 | IoTimeout = 0xc00000b5, 366 | FileForcedClosed = 0xc00000b6, 367 | ProfilingNotStarted = 0xc00000b7, 368 | ProfilingNotStopped = 0xc00000b8, 369 | NotSameDevice = 0xc00000d4, 370 | FileRenamed = 0xc00000d5, 371 | CantWait = 0xc00000d8, 372 | PipeEmpty = 0xc00000d9, 373 | CantTerminateSelf = 0xc00000db, 374 | InternalError = 0xc00000e5, 375 | InvalidParameter1 = 0xc00000ef, 376 | InvalidParameter2 = 0xc00000f0, 377 | InvalidParameter3 = 0xc00000f1, 378 | InvalidParameter4 = 0xc00000f2, 379 | InvalidParameter5 = 0xc00000f3, 380 | InvalidParameter6 = 0xc00000f4, 381 | InvalidParameter7 = 0xc00000f5, 382 | InvalidParameter8 = 0xc00000f6, 383 | InvalidParameter9 = 0xc00000f7, 384 | InvalidParameter10 = 0xc00000f8, 385 | InvalidParameter11 = 0xc00000f9, 386 | InvalidParameter12 = 0xc00000fa, 387 | ProcessIsTerminating = 0xc000010a, 388 | MappedFileSizeZero = 0xc000011e, 389 | TooManyOpenedFiles = 0xc000011f, 390 | Cancelled = 0xc0000120, 391 | CannotDelete = 0xc0000121, 392 | InvalidComputerName = 0xc0000122, 393 | FileDeleted = 0xc0000123, 394 | SpecialAccount = 0xc0000124, 395 | SpecialGroup = 0xc0000125, 396 | SpecialUser = 0xc0000126, 397 | MembersPrimaryGroup = 0xc0000127, 398 | FileClosed = 0xc0000128, 399 | TooManyThreads = 0xc0000129, 400 | ThreadNotInProcess = 0xc000012a, 401 | TokenAlreadyInUse = 0xc000012b, 402 | PagefileQuotaExceeded = 0xc000012c, 403 | CommitmentLimit = 0xc000012d, 404 | InvalidImageLeFormat = 0xc000012e, 405 | InvalidImageNotMz = 0xc000012f, 406 | InvalidImageProtect = 0xc0000130, 407 | InvalidImageWin16 = 0xc0000131, 408 | LogonServer = 0xc0000132, 409 | DifferenceAtDc = 0xc0000133, 410 | SynchronizationRequired = 0xc0000134, 411 | DllNotFound = 0xc0000135, 412 | IoPrivilegeFailed = 0xc0000137, 413 | OrdinalNotFound = 0xc0000138, 414 | EntryPointNotFound = 0xc0000139, 415 | ControlCExit = 0xc000013a, 416 | InvalidAddress = 0xc0000141, 417 | PortNotSet = 0xc0000353, 418 | DebuggerInactive = 0xc0000354, 419 | CallbackBypass = 0xc0000503, 420 | PortClosed = 0xc0000700, 421 | MessageLost = 0xc0000701, 422 | InvalidMessage = 0xc0000702, 423 | RequestCanceled = 0xc0000703, 424 | RecursiveDispatch = 0xc0000704, 425 | LpcReceiveBufferExpected = 0xc0000705, 426 | LpcInvalidConnectionUsage = 0xc0000706, 427 | LpcRequestsNotAllowed = 0xc0000707, 428 | ResourceInUse = 0xc0000708, 429 | ProcessIsProtected = 0xc0000712, 430 | VolumeDirty = 0xc0000806, 431 | FileCheckedOut = 0xc0000901, 432 | CheckOutRequired = 0xc0000902, 433 | BadFileType = 0xc0000903, 434 | FileTooLarge = 0xc0000904, 435 | FormsAuthRequired = 0xc0000905, 436 | VirusInfected = 0xc0000906, 437 | VirusDeleted = 0xc0000907, 438 | TransactionalConflict = 0xc0190001, 439 | InvalidTransaction = 0xc0190002, 440 | TransactionNotActive = 0xc0190003, 441 | TmInitializationFailed = 0xc0190004, 442 | RmNotActive = 0xc0190005, 443 | RmMetadataCorrupt = 0xc0190006, 444 | TransactionNotJoined = 0xc0190007, 445 | DirectoryNotRm = 0xc0190008, 446 | CouldNotResizeLog = 0xc0190009, 447 | TransactionsUnsupportedRemote = 0xc019000a, 448 | LogResizeInvalidSize = 0xc019000b, 449 | RemoteFileVersionMismatch = 0xc019000c, 450 | CrmProtocolAlreadyExists = 0xc019000f, 451 | TransactionPropagationFailed = 0xc0190010, 452 | CrmProtocolNotFound = 0xc0190011, 453 | TransactionSuperiorExists = 0xc0190012, 454 | TransactionRequestNotValid = 0xc0190013, 455 | TransactionNotRequested = 0xc0190014, 456 | TransactionAlreadyAborted = 0xc0190015, 457 | TransactionAlreadyCommitted = 0xc0190016, 458 | TransactionInvalidMarshallBuffer = 0xc0190017, 459 | CurrentTransactionNotValid = 0xc0190018, 460 | LogGrowthFailed = 0xc0190019, 461 | ObjectNoLongerExists = 0xc0190021, 462 | StreamMiniversionNotFound = 0xc0190022, 463 | StreamMiniversionNotValid = 0xc0190023, 464 | MiniversionInaccessibleFromSpecifiedTransaction = 0xc0190024, 465 | CantOpenMiniversionWithModifyIntent = 0xc0190025, 466 | CantCreateMoreStreamMiniversions = 0xc0190026, 467 | HandleNoLongerValid = 0xc0190028, 468 | NoTxfMetadata = 0xc0190029, 469 | LogCorruptionDetected = 0xc0190030, 470 | CantRecoverWithHandleOpen = 0xc0190031, 471 | RmDisconnected = 0xc0190032, 472 | EnlistmentNotSuperior = 0xc0190033, 473 | RecoveryNotNeeded = 0xc0190034, 474 | RmAlreadyStarted = 0xc0190035, 475 | FileIdentityNotPersistent = 0xc0190036, 476 | CantBreakTransactionalDependency = 0xc0190037, 477 | CantCrossRmBoundary = 0xc0190038, 478 | TxfDirNotEmpty = 0xc0190039, 479 | IndoubtTransactionsExist = 0xc019003a, 480 | TmVolatile = 0xc019003b, 481 | RollbackTimerExpired = 0xc019003c, 482 | TxfAttributeCorrupt = 0xc019003d, 483 | EfsNotAllowedInTransaction = 0xc019003e, 484 | TransactionalOpenNotAllowed = 0xc019003f, 485 | TransactedMappingUnsupportedRemote = 0xc0190040, 486 | TxfMetadataAlreadyPresent = 0xc0190041, 487 | TransactionScopeCallbacksNotSet = 0xc0190042, 488 | TransactionRequiredPromotion = 0xc0190043, 489 | CannotExecuteFileInTransaction = 0xc0190044, 490 | TransactionsNotFrozen = 0xc0190045, 491 | 492 | MaximumNtStatus = 0xffffffff 493 | } 494 | } -------------------------------------------------------------------------------- /DInvoke.Data/PE.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace DInvoke.Data; 4 | 5 | /// 6 | /// Holds data structures for using PEs. 7 | /// 8 | public static class PE 9 | { 10 | public const uint DLL_PROCESS_DETACH = 0; 11 | public const uint DLL_PROCESS_ATTACH = 1; 12 | public const uint DLL_THREAD_ATTACH = 2; 13 | public const uint DLL_THREAD_DETACH = 3; 14 | 15 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 16 | public delegate bool DllMain(IntPtr hinstDll, uint fdwReason, IntPtr lpvReserved); 17 | 18 | [Flags] 19 | public enum DataSectionFlags : uint 20 | { 21 | TYPE_NO_PAD = 0x00000008, 22 | CNT_CODE = 0x00000020, 23 | CNT_INITIALIZED_DATA = 0x00000040, 24 | CNT_UNINITIALIZED_DATA = 0x00000080, 25 | LNK_INFO = 0x00000200, 26 | LNK_REMOVE = 0x00000800, 27 | LNK_COMDAT = 0x00001000, 28 | NO_DEFER_SPEC_EXC = 0x00004000, 29 | GPREL = 0x00008000, 30 | MEM_FARDATA = 0x00008000, 31 | MEM_PURGEABLE = 0x00020000, 32 | MEM_16BIT = 0x00020000, 33 | MEM_LOCKED = 0x00040000, 34 | MEM_PRELOAD = 0x00080000, 35 | ALIGN_1BYTES = 0x00100000, 36 | ALIGN_2BYTES = 0x00200000, 37 | ALIGN_4BYTES = 0x00300000, 38 | ALIGN_8BYTES = 0x00400000, 39 | ALIGN_16BYTES = 0x00500000, 40 | ALIGN_32BYTES = 0x00600000, 41 | ALIGN_64BYTES = 0x00700000, 42 | ALIGN_128BYTES = 0x00800000, 43 | ALIGN_256BYTES = 0x00900000, 44 | ALIGN_512BYTES = 0x00A00000, 45 | ALIGN_1024BYTES = 0x00B00000, 46 | ALIGN_2048BYTES = 0x00C00000, 47 | ALIGN_4096BYTES = 0x00D00000, 48 | ALIGN_8192BYTES = 0x00E00000, 49 | ALIGN_MASK = 0x00F00000, 50 | LNK_NRELOC_OVFL = 0x01000000, 51 | MEM_DISCARDABLE = 0x02000000, 52 | MEM_NOT_CACHED = 0x04000000, 53 | MEM_NOT_PAGED = 0x08000000, 54 | MEM_SHARED = 0x10000000, 55 | MEM_EXECUTE = 0x20000000, 56 | MEM_READ = 0x40000000, 57 | MEM_WRITE = 0x80000000 58 | } 59 | 60 | [StructLayout(LayoutKind.Sequential)] 61 | public struct IMAGE_DATA_DIRECTORY 62 | { 63 | public uint VirtualAddress; 64 | public uint Size; 65 | } 66 | 67 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 68 | public struct IMAGE_OPTIONAL_HEADER32 69 | { 70 | public ushort Magic; 71 | public byte MajorLinkerVersion; 72 | public byte MinorLinkerVersion; 73 | public uint SizeOfCode; 74 | public uint SizeOfInitializedData; 75 | public uint SizeOfUninitializedData; 76 | public uint AddressOfEntryPoint; 77 | public uint BaseOfCode; 78 | public uint BaseOfData; 79 | public uint ImageBase; 80 | public uint SectionAlignment; 81 | public uint FileAlignment; 82 | public ushort MajorOperatingSystemVersion; 83 | public ushort MinorOperatingSystemVersion; 84 | public ushort MajorImageVersion; 85 | public ushort MinorImageVersion; 86 | public ushort MajorSubsystemVersion; 87 | public ushort MinorSubsystemVersion; 88 | public uint Win32VersionValue; 89 | public uint SizeOfImage; 90 | public uint SizeOfHeaders; 91 | public uint CheckSum; 92 | public ushort Subsystem; 93 | public ushort DllCharacteristics; 94 | public uint SizeOfStackReserve; 95 | public uint SizeOfStackCommit; 96 | public uint SizeOfHeapReserve; 97 | public uint SizeOfHeapCommit; 98 | public uint LoaderFlags; 99 | public uint NumberOfRvaAndSizes; 100 | 101 | public IMAGE_DATA_DIRECTORY ExportTable; 102 | public IMAGE_DATA_DIRECTORY ImportTable; 103 | public IMAGE_DATA_DIRECTORY ResourceTable; 104 | public IMAGE_DATA_DIRECTORY ExceptionTable; 105 | public IMAGE_DATA_DIRECTORY CertificateTable; 106 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 107 | public IMAGE_DATA_DIRECTORY Debug; 108 | public IMAGE_DATA_DIRECTORY Architecture; 109 | public IMAGE_DATA_DIRECTORY GlobalPtr; 110 | public IMAGE_DATA_DIRECTORY TLSTable; 111 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 112 | public IMAGE_DATA_DIRECTORY BoundImport; 113 | public IMAGE_DATA_DIRECTORY IAT; 114 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 115 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 116 | public IMAGE_DATA_DIRECTORY Reserved; 117 | } 118 | 119 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 120 | public struct IMAGE_OPTIONAL_HEADER64 121 | { 122 | public ushort Magic; 123 | public byte MajorLinkerVersion; 124 | public byte MinorLinkerVersion; 125 | public uint SizeOfCode; 126 | public uint SizeOfInitializedData; 127 | public uint SizeOfUninitializedData; 128 | public uint AddressOfEntryPoint; 129 | public uint BaseOfCode; 130 | public ulong ImageBase; 131 | public uint SectionAlignment; 132 | public uint FileAlignment; 133 | public ushort MajorOperatingSystemVersion; 134 | public ushort MinorOperatingSystemVersion; 135 | public ushort MajorImageVersion; 136 | public ushort MinorImageVersion; 137 | public ushort MajorSubsystemVersion; 138 | public ushort MinorSubsystemVersion; 139 | public uint Win32VersionValue; 140 | public uint SizeOfImage; 141 | public uint SizeOfHeaders; 142 | public uint CheckSum; 143 | public ushort Subsystem; 144 | public ushort DllCharacteristics; 145 | public ulong SizeOfStackReserve; 146 | public ulong SizeOfStackCommit; 147 | public ulong SizeOfHeapReserve; 148 | public ulong SizeOfHeapCommit; 149 | public uint LoaderFlags; 150 | public uint NumberOfRvaAndSizes; 151 | 152 | public IMAGE_DATA_DIRECTORY ExportTable; 153 | public IMAGE_DATA_DIRECTORY ImportTable; 154 | public IMAGE_DATA_DIRECTORY ResourceTable; 155 | public IMAGE_DATA_DIRECTORY ExceptionTable; 156 | public IMAGE_DATA_DIRECTORY CertificateTable; 157 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 158 | public IMAGE_DATA_DIRECTORY Debug; 159 | public IMAGE_DATA_DIRECTORY Architecture; 160 | public IMAGE_DATA_DIRECTORY GlobalPtr; 161 | public IMAGE_DATA_DIRECTORY TLSTable; 162 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 163 | public IMAGE_DATA_DIRECTORY BoundImport; 164 | public IMAGE_DATA_DIRECTORY IAT; 165 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 166 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 167 | public IMAGE_DATA_DIRECTORY Reserved; 168 | } 169 | 170 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 171 | public struct IMAGE_FILE_HEADER 172 | { 173 | public ushort Machine; 174 | public ushort NumberOfSections; 175 | public uint TimeDateStamp; 176 | public uint PointerToSymbolTable; 177 | public uint NumberOfSymbols; 178 | public ushort SizeOfOptionalHeader; 179 | public ushort Characteristics; 180 | } 181 | 182 | [StructLayout(LayoutKind.Explicit)] 183 | public struct IMAGE_SECTION_HEADER 184 | { 185 | [FieldOffset(0)] 186 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 187 | public char[] Name; 188 | [FieldOffset(8)] 189 | public uint VirtualSize; 190 | [FieldOffset(12)] 191 | public uint VirtualAddress; 192 | [FieldOffset(16)] 193 | public uint SizeOfRawData; 194 | [FieldOffset(20)] 195 | public uint PointerToRawData; 196 | [FieldOffset(24)] 197 | public uint PointerToRelocations; 198 | [FieldOffset(28)] 199 | public uint PointerToLinenumbers; 200 | [FieldOffset(32)] 201 | public ushort NumberOfRelocations; 202 | [FieldOffset(34)] 203 | public ushort NumberOfLinenumbers; 204 | [FieldOffset(36)] 205 | public DataSectionFlags Characteristics; 206 | 207 | public string Section => new(Name); 208 | } 209 | 210 | [StructLayout(LayoutKind.Sequential)] 211 | public struct IMAGE_BASE_RELOCATION 212 | { 213 | public uint VirtualAdress; 214 | public uint SizeOfBlock; 215 | } 216 | 217 | [StructLayout(LayoutKind.Sequential)] 218 | public struct PE_META_DATA 219 | { 220 | public uint Pe; 221 | public bool Is32Bit; 222 | public IMAGE_FILE_HEADER ImageFileHeader; 223 | public IMAGE_OPTIONAL_HEADER32 OptHeader32; 224 | public IMAGE_OPTIONAL_HEADER64 OptHeader64; 225 | public IMAGE_SECTION_HEADER[] Sections; 226 | } 227 | 228 | [StructLayout(LayoutKind.Sequential)] 229 | public struct PE_MANUAL_MAP 230 | { 231 | public string DecoyModule; 232 | public IntPtr ModuleBase; 233 | public PE_META_DATA PEINFO; 234 | } 235 | 236 | [StructLayout(LayoutKind.Explicit)] 237 | public struct IMAGE_THUNK_DATA32 238 | { 239 | [FieldOffset(0)] 240 | public uint ForwarderString; 241 | [FieldOffset(0)] 242 | public uint Function; 243 | [FieldOffset(0)] 244 | public uint Ordinal; 245 | [FieldOffset(0)] 246 | public uint AddressOfData; 247 | } 248 | 249 | [StructLayout(LayoutKind.Explicit)] 250 | public struct IMAGE_THUNK_DATA64 251 | { 252 | [FieldOffset(0)] 253 | public ulong ForwarderString; 254 | [FieldOffset(0)] 255 | public ulong Function; 256 | [FieldOffset(0)] 257 | public ulong Ordinal; 258 | [FieldOffset(0)] 259 | public ulong AddressOfData; 260 | } 261 | 262 | [StructLayout(LayoutKind.Explicit)] 263 | public struct ApiSetNamespace 264 | { 265 | [FieldOffset(0x0C)] 266 | public int Count; 267 | 268 | [FieldOffset(0x10)] 269 | public int EntryOffset; 270 | } 271 | 272 | [StructLayout(LayoutKind.Explicit)] 273 | public struct ApiSetNamespaceEntry 274 | { 275 | [FieldOffset(0x04)] 276 | public int NameOffset; 277 | 278 | [FieldOffset(0x08)] 279 | public int NameLength; 280 | 281 | [FieldOffset(0x10)] 282 | public int ValueOffset; 283 | 284 | [FieldOffset(0x14)] 285 | public int ValueLength; 286 | } 287 | 288 | [StructLayout(LayoutKind.Explicit)] 289 | public struct ApiSetValueEntry 290 | { 291 | [FieldOffset(0x00)] 292 | public int Flags; 293 | 294 | [FieldOffset(0x04)] 295 | public int NameOffset; 296 | 297 | [FieldOffset(0x08)] 298 | public int NameCount; 299 | 300 | [FieldOffset(0x0C)] 301 | public int ValueOffset; 302 | 303 | [FieldOffset(0x10)] 304 | public int ValueCount; 305 | } 306 | 307 | [StructLayout(LayoutKind.Sequential)] 308 | public struct LDR_DATA_TABLE_ENTRY 309 | { 310 | public Native.LIST_ENTRY InLoadOrderLinks; 311 | public Native.LIST_ENTRY InMemoryOrderLinks; 312 | public Native.LIST_ENTRY InInitializationOrderLinks; 313 | public IntPtr DllBase; 314 | public IntPtr EntryPoint; 315 | public uint SizeOfImage; 316 | public Native.UNICODE_STRING FullDllName; 317 | public Native.UNICODE_STRING BaseDllName; 318 | } 319 | } -------------------------------------------------------------------------------- /DInvoke.Data/Win32.cs: -------------------------------------------------------------------------------- 1 | // Author: Ryan Cobb (@cobbr_io) 2 | // Project: SharpSploit (https://github.com/cobbr/SharpSploit) 3 | // License: BSD 3-Clause 4 | 5 | using System.Runtime.InteropServices; 6 | 7 | namespace DInvoke.Data; 8 | 9 | /// 10 | /// Win32 is a library of enums and structures for Win32 API functions. 11 | /// 12 | /// 13 | /// A majority of this library is adapted from signatures found at www.pinvoke.net. 14 | /// 15 | public static class Win32 16 | { 17 | public static class Kernel32 18 | { 19 | public const uint MEM_COMMIT = 0x1000; 20 | public const uint MEM_RESERVE = 0x2000; 21 | public const uint MEM_RELEASE = 0x8000; 22 | 23 | [StructLayout(LayoutKind.Sequential)] 24 | public struct IMAGE_IMPORT_DESCRIPTOR 25 | { 26 | public uint OriginalFirstThunk; 27 | public uint TimeDateStamp; 28 | public uint ForwarderChain; 29 | public uint Name; 30 | public uint FirstThunk; 31 | } 32 | 33 | [Flags] 34 | public enum FileAccessFlags : uint 35 | { 36 | DELETE = 0x10000, 37 | FILE_READ_DATA = 0x1, 38 | FILE_READ_ATTRIBUTES = 0x80, 39 | FILE_READ_EA = 0x8, 40 | READ_CONTROL = 0x20000, 41 | FILE_WRITE_DATA = 0x2, 42 | FILE_WRITE_ATTRIBUTES = 0x100, 43 | FILE_WRITE_EA = 0x10, 44 | FILE_APPEND_DATA = 0x4, 45 | WRITE_DAC = 0x40000, 46 | WRITE_OWNER = 0x80000, 47 | SYNCHRONIZE = 0x100000, 48 | FILE_EXECUTE = 0x20 49 | } 50 | 51 | [Flags] 52 | public enum FileShareFlags : uint 53 | { 54 | FILE_SHARE_NONE = 0x0, 55 | FILE_SHARE_READ = 0x1, 56 | FILE_SHARE_WRITE = 0x2, 57 | FILE_SHARE_DELETE = 0x4 58 | } 59 | 60 | [Flags] 61 | public enum FileOpenFlags : uint 62 | { 63 | FILE_DIRECTORY_FILE = 0x1, 64 | FILE_WRITE_THROUGH = 0x2, 65 | FILE_SEQUENTIAL_ONLY = 0x4, 66 | FILE_NO_INTERMEDIATE_BUFFERING = 0x8, 67 | FILE_SYNCHRONOUS_IO_ALERT = 0x10, 68 | FILE_SYNCHRONOUS_IO_NONALERT = 0x20, 69 | FILE_NON_DIRECTORY_FILE = 0x40, 70 | FILE_CREATE_TREE_CONNECTION = 0x80, 71 | FILE_COMPLETE_IF_OPLOCKED = 0x100, 72 | FILE_NO_EA_KNOWLEDGE = 0x200, 73 | FILE_OPEN_FOR_RECOVERY = 0x400, 74 | FILE_RANDOM_ACCESS = 0x800, 75 | FILE_DELETE_ON_CLOSE = 0x1000, 76 | FILE_OPEN_BY_FILE_ID = 0x2000, 77 | FILE_OPEN_FOR_BACKUP_INTENT = 0x4000, 78 | FILE_NO_COMPRESSION = 0x8000 79 | } 80 | } 81 | 82 | public static class WinNT 83 | { 84 | public const uint PAGE_READONLY = 0x02; 85 | public const uint PAGE_READWRITE = 0x04; 86 | public const uint PAGE_EXECUTE = 0x10; 87 | public const uint PAGE_EXECUTE_READ = 0x20; 88 | public const uint PAGE_EXECUTE_READWRITE = 0x40; 89 | 90 | public const uint SEC_IMAGE = 0x1000000; 91 | 92 | [Flags] 93 | public enum ACCESS_MASK : uint 94 | { 95 | DELETE = 0x00010000, 96 | READ_CONTROL = 0x00020000, 97 | WRITE_DAC = 0x00040000, 98 | WRITE_OWNER = 0x00080000, 99 | SYNCHRONIZE = 0x00100000, 100 | STANDARD_RIGHTS_REQUIRED = 0x000F0000, 101 | STANDARD_RIGHTS_READ = 0x00020000, 102 | STANDARD_RIGHTS_WRITE = 0x00020000, 103 | STANDARD_RIGHTS_EXECUTE = 0x00020000, 104 | STANDARD_RIGHTS_ALL = 0x001F0000, 105 | SPECIFIC_RIGHTS_ALL = 0x0000FFF, 106 | ACCESS_SYSTEM_SECURITY = 0x01000000, 107 | MAXIMUM_ALLOWED = 0x02000000, 108 | GENERIC_READ = 0x80000000, 109 | GENERIC_WRITE = 0x40000000, 110 | GENERIC_EXECUTE = 0x20000000, 111 | GENERIC_ALL = 0x10000000, 112 | DESKTOP_READOBJECTS = 0x00000001, 113 | DESKTOP_CREATEWINDOW = 0x00000002, 114 | DESKTOP_CREATEMENU = 0x00000004, 115 | DESKTOP_HOOKCONTROL = 0x00000008, 116 | DESKTOP_JOURNALRECORD = 0x00000010, 117 | DESKTOP_JOURNALPLAYBACK = 0x00000020, 118 | DESKTOP_ENUMERATE = 0x00000040, 119 | DESKTOP_WRITEOBJECTS = 0x00000080, 120 | DESKTOP_SWITCHDESKTOP = 0x00000100, 121 | WINSTA_ENUMDESKTOPS = 0x00000001, 122 | WINSTA_READATTRIBUTES = 0x00000002, 123 | WINSTA_ACCESSCLIPBOARD = 0x00000004, 124 | WINSTA_CREATEDESKTOP = 0x00000008, 125 | WINSTA_WRITEATTRIBUTES = 0x00000010, 126 | WINSTA_ACCESSGLOBALATOMS = 0x00000020, 127 | WINSTA_EXITWINDOWS = 0x00000040, 128 | WINSTA_ENUMERATE = 0x00000100, 129 | WINSTA_READSCREEN = 0x00000200, 130 | WINSTA_ALL_ACCESS = 0x0000037F, 131 | 132 | SECTION_ALL_ACCESS = 0x10000000, 133 | SECTION_QUERY = 0x0001, 134 | SECTION_MAP_WRITE = 0x0002, 135 | SECTION_MAP_READ = 0x0004, 136 | SECTION_MAP_EXECUTE = 0x0008, 137 | SECTION_EXTEND_SIZE = 0x0010 138 | }; 139 | } 140 | } -------------------------------------------------------------------------------- /DInvoke.DynamicInvoke/DInvoke.DynamicInvoke.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | enable 6 | disable 7 | 12 8 | true 9 | TheWover, RastaMouse 10 | Dynamically invoke arbitrary unmanaged code from managed code without P/Invoke. 11 | DInvoke.DynamicInvoke 12 | DInvoke.DynamicInvoke 13 | 1.0.7 14 | 15 | 16 | 17 | true 18 | 19 | 20 | 21 | true 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /DInvoke.DynamicInvoke/Generic.cs: -------------------------------------------------------------------------------- 1 | // Author: Ryan Cobb (@cobbr_io) 2 | // Project: SharpSploit (https://github.com/cobbr/SharpSploit) 3 | // License: BSD 3-Clause 4 | 5 | using System.Diagnostics; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace DInvoke.DynamicInvoke; 9 | 10 | /// 11 | /// Generic is a class for dynamically invoking arbitrary API calls from memory or disk. DynamicInvoke avoids suspicious 12 | /// P/Invoke signatures, imports, and IAT entries by loading modules and invoking their functions at runtime. 13 | /// 14 | public static class Generic 15 | { 16 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 17 | private delegate IntPtr ReadGs(); 18 | 19 | private static readonly byte[] X64SyscallStub = 20 | [ 21 | 0x49, 0x89, 0xCA, // mov r10, rcx 22 | 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, ssn 23 | 0x0F, 0x05, // syscall 24 | 0xC3 // ret 25 | ]; 26 | 27 | /// 28 | /// Dynamically invoke an arbitrary function from a DLL, providing its name, function prototype, and arguments. 29 | /// 30 | /// The Wover (@TheRealWover) 31 | /// Name of the DLL. 32 | /// Name of the function. 33 | /// Prototype for the function, represented as a Delegate object. 34 | /// Parameters to pass to the function. Can be modified if function uses call by reference. 35 | /// Whether the DLL may be loaded from disk if it is not already loaded. Default is false. 36 | /// Whether or not to resolve export forwards. Default is true. 37 | /// Object returned by the function. Must be unmarshalled by the caller. 38 | public static T DynamicApiInvoke(string dllName, string functionName, Type functionDelegateType, ref object[] parameters, bool canLoadFromDisk = false, bool resolveForwards = true) 39 | { 40 | var pFunction = GetLibraryAddress(dllName, functionName, canLoadFromDisk, resolveForwards); 41 | return DynamicFunctionInvoke(pFunction, functionDelegateType, ref parameters); 42 | } 43 | 44 | /// 45 | /// Dynamically invokes an arbitrary function from a pointer. Useful for manually mapped modules or loading/invoking unmanaged code from memory. 46 | /// 47 | /// The Wover (@TheRealWover) 48 | /// A pointer to the unmanaged function. 49 | /// Prototype for the function, represented as a Delegate object. 50 | /// Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference. 51 | /// Object returned by the function. Must be unmarshalled by the caller. 52 | public static T DynamicFunctionInvoke(IntPtr functionPointer, Type functionDelegateType, ref object[] parameters) 53 | { 54 | var funcDelegate = Marshal.GetDelegateForFunctionPointer(functionPointer, functionDelegateType); 55 | return (T)funcDelegate.DynamicInvoke(parameters); 56 | } 57 | 58 | public static T DynamicAsmInvoke(byte[] asmStub, Type functionDelegateType, ref object[] parameters) 59 | { 60 | unsafe 61 | { 62 | fixed (byte* buffer = asmStub) 63 | { 64 | var ptr = (IntPtr)buffer; 65 | var size = new IntPtr(asmStub.Length); 66 | 67 | var oldProtect = Native.NtProtectVirtualMemory(new IntPtr(-1), ref ptr, 68 | ref size, Data.Win32.WinNT.PAGE_EXECUTE_READWRITE); 69 | 70 | var result = DynamicFunctionInvoke(ptr, functionDelegateType, ref parameters); 71 | 72 | Native.NtProtectVirtualMemory(new IntPtr(-1), ref ptr, 73 | ref size, oldProtect); 74 | 75 | return result; 76 | } 77 | } 78 | } 79 | 80 | /// 81 | /// Resolves LdrLoadDll and uses that function to load a DLL from disk. 82 | /// 83 | /// Ruben Boonen (@FuzzySec) 84 | /// The path to the DLL on disk. Uses the LoadLibrary convention. 85 | /// IntPtr base address of the loaded module or IntPtr.Zero if the module was not loaded successfully. 86 | public static IntPtr LoadModuleFromDisk(string dllPath) 87 | { 88 | var uModuleName = new Data.Native.UNICODE_STRING(); 89 | Native.RtlInitUnicodeString(ref uModuleName, dllPath); 90 | 91 | var hModule = IntPtr.Zero; 92 | var callResult = Native.LdrLoadDll(IntPtr.Zero, 0, ref uModuleName, ref hModule); 93 | 94 | if (callResult != Data.Native.NTSTATUS.Success || hModule == IntPtr.Zero) 95 | return IntPtr.Zero; 96 | 97 | return hModule; 98 | } 99 | 100 | /// 101 | /// Helper for getting the pointer to a function from a DLL loaded by the process. 102 | /// 103 | /// Ruben Boonen (@FuzzySec) 104 | /// The name of the DLL (e.g. "ntdll.dll" or "C:\Windows\System32\ntdll.dll"). 105 | /// Name of the exported procedure. 106 | /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. 107 | /// Whether or not to resolve export forwards. Default is true. 108 | /// IntPtr for the desired function. 109 | public static IntPtr GetLibraryAddress(string dllName, string functionName, bool canLoadFromDisk = false, bool resolveForwards = true) 110 | { 111 | var hModule = GetLoadedModuleAddress(dllName); 112 | 113 | if (hModule == IntPtr.Zero && canLoadFromDisk) 114 | { 115 | hModule = LoadModuleFromDisk(dllName); 116 | 117 | if (hModule == IntPtr.Zero) 118 | throw new FileNotFoundException(dllName + ", unable to find the specified file."); 119 | } 120 | else if (hModule == IntPtr.Zero) 121 | { 122 | throw new DllNotFoundException(dllName + ", Dll was not found."); 123 | } 124 | 125 | return GetExportAddress(hModule, functionName, resolveForwards); 126 | } 127 | 128 | /// 129 | /// Helper for getting the pointer to a function from a DLL loaded by the process. 130 | /// 131 | /// Ruben Boonen (@FuzzySec) 132 | /// The name of the DLL (e.g. "ntdll.dll" or "C:\Windows\System32\ntdll.dll"). 133 | /// Ordinal of the exported procedure. 134 | /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. 135 | /// Whether or not to resolve export forwards. Default is true. 136 | /// IntPtr for the desired function. 137 | public static IntPtr GetLibraryAddress(string dllName, short ordinal, bool canLoadFromDisk = false, bool resolveForwards = true) 138 | { 139 | var hModule = GetLoadedModuleAddress(dllName); 140 | 141 | if (hModule == IntPtr.Zero && canLoadFromDisk) 142 | { 143 | hModule = LoadModuleFromDisk(dllName); 144 | 145 | if (hModule == IntPtr.Zero) 146 | throw new FileNotFoundException(dllName + ", unable to find the specified file."); 147 | } 148 | else if (hModule == IntPtr.Zero) 149 | { 150 | throw new DllNotFoundException(dllName + ", Dll was not found."); 151 | } 152 | 153 | return GetExportAddress(hModule, ordinal, resolveForwards); 154 | } 155 | 156 | /// 157 | /// Helper for getting the pointer to a function from a DLL loaded by the process. 158 | /// 159 | /// Ruben Boonen (@FuzzySec) 160 | /// The name of the DLL (e.g. "ntdll.dll" or "C:\Windows\System32\ntdll.dll"). 161 | /// Hash of the exported procedure. 162 | /// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788). 163 | /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. 164 | /// Whether or not to resolve export forwards. Default is true. 165 | /// IntPtr for the desired function. 166 | public static IntPtr GetLibraryAddress(string dllName, string functionHash, long key, bool canLoadFromDisk = false, bool resolveForwards = true) 167 | { 168 | var hModule = GetLoadedModuleAddress(dllName); 169 | 170 | if (hModule == IntPtr.Zero && canLoadFromDisk) 171 | { 172 | hModule = LoadModuleFromDisk(dllName); 173 | 174 | if (hModule == IntPtr.Zero) 175 | throw new FileNotFoundException(dllName + ", unable to find the specified file."); 176 | } 177 | else if (hModule == IntPtr.Zero) 178 | { 179 | throw new DllNotFoundException(dllName + ", Dll was not found."); 180 | } 181 | 182 | return GetExportAddress(hModule, functionHash, key, resolveForwards); 183 | } 184 | 185 | /// 186 | /// Helper for getting the base address of a module loaded by the current process. This base 187 | /// address could be passed to GetProcAddress/LdrGetProcedureAddress or it could be used for 188 | /// manual export parsing. This function uses the .NET System.Diagnostics.Process class. 189 | /// 190 | /// Ruben Boonen (@FuzzySec) 191 | /// The name of the DLL (e.g. "ntdll.dll"). 192 | /// IntPtr base address of the loaded module or IntPtr.Zero if the module is not found. 193 | public static IntPtr GetLoadedModuleAddress(string dllName) 194 | { 195 | using var process = Process.GetCurrentProcess(); 196 | 197 | foreach (ProcessModule module in process.Modules) 198 | { 199 | if (module.ModuleName.Equals(dllName, StringComparison.OrdinalIgnoreCase)) 200 | return module.BaseAddress; 201 | } 202 | 203 | return IntPtr.Zero; 204 | } 205 | 206 | /// 207 | /// Helper for getting the base address of a module loaded by the current process. This base 208 | /// address could be passed to GetProcAddress/LdrGetProcedureAddress or it could be used for 209 | /// manual export parsing. This function uses the .NET System.Diagnostics.Process class. 210 | /// 211 | /// Hash of the DLL name. 212 | /// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788). 213 | /// IntPtr base address of the loaded module or IntPtr.Zero if the module is not found. 214 | public static IntPtr GetLoadedModuleAddress(string hashedDllName, long key) 215 | { 216 | using var process = Process.GetCurrentProcess(); 217 | 218 | foreach (ProcessModule module in process.Modules) 219 | { 220 | var hashedName = Utilities.GetApiHash(module.ModuleName, key); 221 | 222 | if (hashedName.Equals(hashedDllName)) 223 | return module.BaseAddress; 224 | } 225 | 226 | return IntPtr.Zero; 227 | } 228 | 229 | /// 230 | /// This function uses dynamic assembly invocation to obtain a pointer to the PEB. 231 | /// __readgsqword(0x60) or __readfsdword(0x30) 232 | /// 233 | /// Base address of the PEB as an IntPtr. 234 | public static IntPtr GetPebAddress() 235 | { 236 | byte[] stub; 237 | 238 | if (IntPtr.Size == 8) 239 | { 240 | stub = 241 | [ 242 | 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, // mov rax, qword ptr gs:[0x60] 243 | 0x00, 0x00, 0x00, 244 | 0xc3 // ret 245 | ]; 246 | } 247 | else 248 | { 249 | stub = 250 | [ 251 | 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, // mov eax,dword ptr fs:[30] 252 | 0xC3 // ret 253 | ]; 254 | } 255 | 256 | var parameters = Array.Empty(); 257 | 258 | return DynamicAsmInvoke( 259 | stub, 260 | typeof(ReadGs), 261 | ref parameters); 262 | } 263 | 264 | /// 265 | /// Helper for getting the base address of a module loaded by the current process. This base 266 | /// address could be passed to GetProcAddress/LdrGetProcedureAddress or it could be used for 267 | /// manual export parsing. This function parses the _PEB_LDR_DATA structure. 268 | /// 269 | /// Ruben Boonen (@FuzzySec) 270 | /// The name of the DLL (e.g. "ntdll.dll"). 271 | /// IntPtr base address of the loaded module or IntPtr.Zero if the module is not found. 272 | public static IntPtr GetPebLdrModuleEntry(string dllName) 273 | { 274 | // Set function variables 275 | uint ldrDataOffset; 276 | uint inLoadOrderModuleListOffset; 277 | 278 | if (IntPtr.Size == 4) 279 | { 280 | ldrDataOffset = 0xc; 281 | inLoadOrderModuleListOffset = 0xC; 282 | } 283 | else 284 | { 285 | ldrDataOffset = 0x18; 286 | inLoadOrderModuleListOffset = 0x10; 287 | } 288 | 289 | // Get _PEB pointer 290 | var pPeb = GetPebAddress(); 291 | 292 | // Get module InLoadOrderModuleList -> _LIST_ENTRY 293 | var pebLdrData = Marshal.ReadIntPtr((IntPtr)((ulong)pPeb + ldrDataOffset)); 294 | var pInLoadOrderModuleList = (IntPtr)((ulong)pebLdrData + inLoadOrderModuleListOffset); 295 | var le = (Data.Native.LIST_ENTRY)Marshal.PtrToStructure(pInLoadOrderModuleList, typeof(Data.Native.LIST_ENTRY)); 296 | 297 | // Loop entries 298 | var flink = le.Flink; 299 | var hModule = IntPtr.Zero; 300 | var dte = (Data.PE.LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(flink, typeof(Data.PE.LDR_DATA_TABLE_ENTRY)); 301 | while (dte.InLoadOrderLinks.Flink != le.Blink) 302 | { 303 | // Match module name 304 | var moduleName = Marshal.PtrToStringUni(dte.BaseDllName.Buffer); 305 | if (!string.IsNullOrWhiteSpace(moduleName) && moduleName.Equals(dllName, StringComparison.OrdinalIgnoreCase)) 306 | { 307 | hModule = dte.DllBase; 308 | break; 309 | } 310 | 311 | // Move Ptr 312 | flink = dte.InLoadOrderLinks.Flink; 313 | dte = (Data.PE.LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(flink, typeof(Data.PE.LDR_DATA_TABLE_ENTRY)); 314 | } 315 | 316 | return hModule; 317 | } 318 | 319 | /// 320 | /// Get a syscall stub for the given Nt* API by walking the PEB to find the correct SSN. 321 | /// The stub can be executed using DynamicAsmInvoke. 322 | /// x64 only. 323 | /// 324 | /// A pointer to the PEB. 325 | /// The function name to get the stub for (e.g. NtOpenProcess). 326 | /// A byte[] containing the stub. 327 | public static byte[] GetSyscallStub(IntPtr pPeb, string functionName) 328 | { 329 | // x64 only 330 | if (IntPtr.Size == 4) 331 | return Array.Empty(); 332 | 333 | const uint ldrDataOffset = 0x18; 334 | const uint inLoadOrderModuleListOffset = 0x10; 335 | 336 | var pebLdrData = Marshal.ReadIntPtr((IntPtr)((ulong)pPeb + ldrDataOffset)); 337 | var pInLoadOrderModuleList = (IntPtr)((ulong)pebLdrData + inLoadOrderModuleListOffset); 338 | var le = Marshal.PtrToStructure(pInLoadOrderModuleList); 339 | 340 | // loop modules 341 | var flink = le.Flink; 342 | 343 | var dte = Marshal.PtrToStructure(flink); 344 | while (dte.InLoadOrderLinks.Flink != le.Blink) 345 | { 346 | // match module name 347 | var moduleName = Marshal.PtrToStringUni(dte.BaseDllName.Buffer); 348 | if (!string.IsNullOrWhiteSpace(moduleName) && moduleName.Equals("ntdll.dll", StringComparison.OrdinalIgnoreCase)) 349 | { 350 | var export = GetExportAddress(dte.DllBase, functionName); 351 | var ssn = Marshal.ReadByte(export + 4); 352 | 353 | var stub = X64SyscallStub; 354 | stub[4] = ssn; 355 | 356 | return stub; 357 | } 358 | 359 | // increment ptr 360 | flink = dte.InLoadOrderLinks.Flink; 361 | dte = Marshal.PtrToStructure(flink); 362 | } 363 | 364 | return Array.Empty(); 365 | } 366 | 367 | /// 368 | /// Get a syscall stub for the given Nt* API by walking the PEB to find the correct SSN. 369 | /// The stub can be executed using DynamicAsmInvoke. 370 | /// x64 only. 371 | /// 372 | /// A pointer to the PEB. 373 | /// The hashed function name to get the stub for. 374 | /// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788). 375 | /// A byte[] containing the stub. 376 | public static byte[] GetSyscallStub(IntPtr pPeb, string hashedFunctionName, long key) 377 | { 378 | // x64 only 379 | if (IntPtr.Size == 4) 380 | return Array.Empty(); 381 | 382 | const uint ldrDataOffset = 0x18; 383 | const uint inLoadOrderModuleListOffset = 0x10; 384 | 385 | var pebLdrData = Marshal.ReadIntPtr((IntPtr)((ulong)pPeb + ldrDataOffset)); 386 | var pInLoadOrderModuleList = (IntPtr)((ulong)pebLdrData + inLoadOrderModuleListOffset); 387 | var le = Marshal.PtrToStructure(pInLoadOrderModuleList); 388 | 389 | // loop modules 390 | var flink = le.Flink; 391 | 392 | var dte = Marshal.PtrToStructure(flink); 393 | while (dte.InLoadOrderLinks.Flink != le.Blink) 394 | { 395 | // match module name 396 | var moduleName = Marshal.PtrToStringUni(dte.BaseDllName.Buffer); 397 | if (!string.IsNullOrWhiteSpace(moduleName) && moduleName.Equals("ntdll.dll", StringComparison.OrdinalIgnoreCase)) 398 | { 399 | var export = GetExportAddress(dte.DllBase, hashedFunctionName, key); 400 | var ssn = Marshal.ReadByte(export + 4); 401 | 402 | var stub = X64SyscallStub; 403 | stub[4] = ssn; 404 | 405 | return stub; 406 | } 407 | 408 | // increment ptr 409 | flink = dte.InLoadOrderLinks.Flink; 410 | dte = Marshal.PtrToStructure(flink); 411 | } 412 | 413 | return Array.Empty(); 414 | } 415 | 416 | /// 417 | /// Given a module base address, resolve the address of a function by manually walking the module export table. 418 | /// 419 | /// Ruben Boonen (@FuzzySec) 420 | /// A pointer to the base address where the module is loaded in the current process. 421 | /// The name of the export to search for (e.g. "NtAlertResumeThread"). 422 | /// Whether or not to resolve export forwards. Default is true. 423 | /// IntPtr for the desired function. 424 | public static IntPtr GetExportAddress(IntPtr moduleBase, string exportName, bool resolveForwards = true) 425 | { 426 | var functionPtr = IntPtr.Zero; 427 | 428 | try 429 | { 430 | // Traverse the PE header in memory 431 | var peHeader = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + 0x3C)); 432 | var optHeader = moduleBase.ToInt64() + peHeader + 0x18; 433 | var magic = Marshal.ReadInt16((IntPtr)optHeader); 434 | long pExport; 435 | 436 | if (magic == 0x010b) pExport = optHeader + 0x60; 437 | else pExport = optHeader + 0x70; 438 | 439 | var exportRva = Marshal.ReadInt32((IntPtr)pExport); 440 | var ordinalBase = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x10)); 441 | var numberOfNames = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x18)); 442 | var functionsRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x1C)); 443 | var namesRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x20)); 444 | var ordinalsRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x24)); 445 | 446 | for (var i = 0; i < numberOfNames; i++) 447 | { 448 | var functionName = Marshal.PtrToStringAnsi((IntPtr)(moduleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + namesRva + i * 4)))); 449 | if (string.IsNullOrWhiteSpace(functionName)) continue; 450 | if (!functionName.Equals(exportName, StringComparison.OrdinalIgnoreCase)) continue; 451 | 452 | var functionOrdinal = Marshal.ReadInt16((IntPtr)(moduleBase.ToInt64() + ordinalsRva + i * 2)) + ordinalBase; 453 | 454 | var functionRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + functionsRva + 4 * (functionOrdinal - ordinalBase))); 455 | functionPtr = (IntPtr)((long)moduleBase + functionRva); 456 | 457 | if (resolveForwards) 458 | functionPtr = GetForwardAddress(functionPtr); 459 | 460 | break; 461 | } 462 | } 463 | catch 464 | { 465 | throw new InvalidOperationException("Failed to parse module exports."); 466 | } 467 | 468 | if (functionPtr == IntPtr.Zero) 469 | throw new MissingMethodException(exportName + ", export not found."); 470 | 471 | return functionPtr; 472 | } 473 | 474 | /// 475 | /// Given a module base address, resolve the address of a function by manually walking the module export table. 476 | /// 477 | /// Ruben Boonen (@FuzzySec) 478 | /// A pointer to the base address where the module is loaded in the current process. 479 | /// The ordinal number to search for (e.g. 0x136 -> ntdll!NtCreateThreadEx). 480 | /// Whether or not to resolve export forwards. Default is true. 481 | /// IntPtr for the desired function. 482 | public static IntPtr GetExportAddress(IntPtr moduleBase, short ordinal, bool resolveForwards = true) 483 | { 484 | var functionPtr = IntPtr.Zero; 485 | 486 | try 487 | { 488 | var peHeader = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + 0x3C)); 489 | var optHeader = moduleBase.ToInt64() + peHeader + 0x18; 490 | var magic = Marshal.ReadInt16((IntPtr)optHeader); 491 | long pExport; 492 | 493 | if (magic == 0x010b) pExport = optHeader + 0x60; 494 | else pExport = optHeader + 0x70; 495 | 496 | var exportRva = Marshal.ReadInt32((IntPtr)pExport); 497 | var ordinalBase = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x10)); 498 | var numberOfNames = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x18)); 499 | var functionsRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x1C)); 500 | var ordinalsRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x24)); 501 | 502 | for (var i = 0; i < numberOfNames; i++) 503 | { 504 | var functionOrdinal = Marshal.ReadInt16((IntPtr)(moduleBase.ToInt64() + ordinalsRva + i * 2)) + ordinalBase; 505 | 506 | if (functionOrdinal != ordinal) continue; 507 | 508 | var functionRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + functionsRva + 4 * (functionOrdinal - ordinalBase))); 509 | functionPtr = (IntPtr)((long)moduleBase + functionRva); 510 | 511 | if (resolveForwards) 512 | functionPtr = GetForwardAddress(functionPtr); 513 | 514 | break; 515 | } 516 | } 517 | catch 518 | { 519 | throw new InvalidOperationException("Failed to parse module exports."); 520 | } 521 | 522 | if (functionPtr == IntPtr.Zero) 523 | throw new MissingMethodException(ordinal + ", ordinal not found."); 524 | 525 | return functionPtr; 526 | } 527 | 528 | /// 529 | /// Given a module base address, resolve the address of a function by manually walking the module export table. 530 | /// 531 | /// Ruben Boonen (@FuzzySec) 532 | /// A pointer to the base address where the module is loaded in the current process. 533 | /// Hash of the exported procedure. 534 | /// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788). 535 | /// Whether or not to resolve export forwards. Default is true. 536 | /// IntPtr for the desired function. 537 | public static IntPtr GetExportAddress(IntPtr moduleBase, string functionHash, long key, bool resolveForwards = true) 538 | { 539 | var functionPtr = IntPtr.Zero; 540 | 541 | try 542 | { 543 | var peHeader = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + 0x3C)); 544 | var optHeader = moduleBase.ToInt64() + peHeader + 0x18; 545 | var magic = Marshal.ReadInt16((IntPtr)optHeader); 546 | long pExport; 547 | 548 | if (magic == 0x010b) pExport = optHeader + 0x60; 549 | else pExport = optHeader + 0x70; 550 | 551 | var exportRva = Marshal.ReadInt32((IntPtr)pExport); 552 | var ordinalBase = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x10)); 553 | var numberOfNames = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x18)); 554 | var functionsRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x1C)); 555 | var namesRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x20)); 556 | var ordinalsRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + exportRva + 0x24)); 557 | 558 | for (var i = 0; i < numberOfNames; i++) 559 | { 560 | var functionName = Marshal.PtrToStringAnsi((IntPtr)(moduleBase.ToInt64() + Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + namesRva + i * 4)))); 561 | if (string.IsNullOrWhiteSpace(functionName)) continue; 562 | if (!Utilities.GetApiHash(functionName, key).Equals(functionHash, StringComparison.OrdinalIgnoreCase)) continue; 563 | 564 | var functionOrdinal = Marshal.ReadInt16((IntPtr)(moduleBase.ToInt64() + ordinalsRva + i * 2)) + ordinalBase; 565 | 566 | var functionRva = Marshal.ReadInt32((IntPtr)(moduleBase.ToInt64() + functionsRva + 4 * (functionOrdinal - ordinalBase))); 567 | functionPtr = (IntPtr)((long)moduleBase + functionRva); 568 | 569 | if (resolveForwards) 570 | functionPtr = GetForwardAddress(functionPtr); 571 | 572 | break; 573 | } 574 | } 575 | catch 576 | { 577 | throw new InvalidOperationException("Failed to parse module exports."); 578 | } 579 | 580 | if (functionPtr == IntPtr.Zero) 581 | throw new MissingMethodException(functionHash + ", export hash not found."); 582 | 583 | return functionPtr; 584 | } 585 | 586 | /// 587 | /// Check if an address to an exported function should be resolved to a forward. If so, return the address of the forward. 588 | /// 589 | /// The Wover (@TheRealWover) 590 | /// Function of an exported address, found by parsing a PE file's export table. 591 | /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. 592 | /// IntPtr for the forward. If the function is not forwarded, return the original pointer. 593 | public static IntPtr GetForwardAddress(IntPtr exportAddress, bool canLoadFromDisk = false) 594 | { 595 | var functionPtr = exportAddress; 596 | 597 | try 598 | { 599 | var forwardNames = Marshal.PtrToStringAnsi(functionPtr); 600 | if (string.IsNullOrWhiteSpace(forwardNames)) return functionPtr; 601 | 602 | var values = forwardNames.Split('.'); 603 | 604 | if (values.Length > 1) 605 | { 606 | var forwardModuleName = values[0]; 607 | var forwardExportName = values[1]; 608 | 609 | var apiSet = GetApiSetMapping(); 610 | var lookupKey = forwardModuleName.Substring(0, forwardModuleName.Length - 2) + ".dll"; 611 | 612 | if (apiSet.ContainsKey(lookupKey)) 613 | forwardModuleName = apiSet[lookupKey]; 614 | else 615 | forwardModuleName = forwardModuleName + ".dll"; 616 | 617 | var hModule = GetPebLdrModuleEntry(forwardModuleName); 618 | 619 | if (hModule == IntPtr.Zero && canLoadFromDisk) 620 | hModule = LoadModuleFromDisk(forwardModuleName); 621 | 622 | if (hModule != IntPtr.Zero) 623 | functionPtr = GetExportAddress(hModule, forwardExportName); 624 | } 625 | } 626 | catch 627 | { 628 | // Do nothing, it was not a forward 629 | } 630 | 631 | return functionPtr; 632 | } 633 | 634 | /// 635 | /// Given a module base address, resolve the address of a function by calling LdrGetProcedureAddress. 636 | /// 637 | /// Ruben Boonen (@FuzzySec) 638 | /// A pointer to the base address where the module is loaded in the current process. 639 | /// The name of the export to search for (e.g. "NtAlertResumeThread"). 640 | /// IntPtr for the desired function. 641 | public static IntPtr GetNativeExportAddress(IntPtr moduleBase, string exportName) 642 | { 643 | var aFunc = new Data.Native.ANSI_STRING 644 | { 645 | Length = (ushort)exportName.Length, 646 | MaximumLength = (ushort)(exportName.Length + 2), 647 | Buffer = Marshal.StringToCoTaskMemAnsi(exportName) 648 | }; 649 | 650 | var pAFunc = Marshal.AllocHGlobal(Marshal.SizeOf(aFunc)); 651 | Marshal.StructureToPtr(aFunc, pAFunc, true); 652 | 653 | var pFuncAddr = IntPtr.Zero; 654 | Native.LdrGetProcedureAddress(moduleBase, pAFunc, IntPtr.Zero, ref pFuncAddr); 655 | 656 | Marshal.FreeHGlobal(pAFunc); 657 | 658 | return pFuncAddr; 659 | } 660 | 661 | /// 662 | /// Given a module base address, resolve the address of a function by calling LdrGetProcedureAddress. 663 | /// 664 | /// Ruben Boonen (@FuzzySec) 665 | /// A pointer to the base address where the module is loaded in the current process. 666 | /// The ordinal number to search for (e.g. 0x136 -> ntdll!NtCreateThreadEx). 667 | /// IntPtr for the desired function. 668 | public static IntPtr GetNativeExportAddress(IntPtr moduleBase, short ordinal) 669 | { 670 | var pFuncAddr = IntPtr.Zero; 671 | var pOrd = (IntPtr)ordinal; 672 | 673 | Native.LdrGetProcedureAddress(moduleBase, IntPtr.Zero, pOrd, ref pFuncAddr); 674 | 675 | return pFuncAddr; 676 | } 677 | 678 | /// 679 | /// Retrieve PE header information from the module base pointer. 680 | /// 681 | /// Ruben Boonen (@FuzzySec) 682 | /// Pointer to the module base. 683 | /// PE.PE_META_DATA 684 | public static Data.PE.PE_META_DATA GetPeMetaData(IntPtr pModule) 685 | { 686 | var peMetaData = new Data.PE.PE_META_DATA(); 687 | 688 | try 689 | { 690 | var e_lfanew = (uint)Marshal.ReadInt32((IntPtr)((ulong)pModule + 0x3c)); 691 | peMetaData.Pe = (uint)Marshal.ReadInt32((IntPtr)((ulong)pModule + e_lfanew)); 692 | 693 | if (peMetaData.Pe != 0x4550) 694 | throw new InvalidOperationException("Invalid PE signature."); 695 | 696 | peMetaData.ImageFileHeader = (Data.PE.IMAGE_FILE_HEADER)Marshal.PtrToStructure((IntPtr)((ulong)pModule + e_lfanew + 0x4), typeof(Data.PE.IMAGE_FILE_HEADER)); 697 | 698 | var optHeader = (IntPtr)((ulong)pModule + e_lfanew + 0x18); 699 | var peArch = (ushort)Marshal.ReadInt16(optHeader); 700 | 701 | switch (peArch) 702 | { 703 | case 0x010b: 704 | peMetaData.Is32Bit = true; 705 | peMetaData.OptHeader32 = 706 | (Data.PE.IMAGE_OPTIONAL_HEADER32)Marshal.PtrToStructure(optHeader, 707 | typeof(Data.PE.IMAGE_OPTIONAL_HEADER32)); 708 | break; 709 | 710 | case 0x020b: 711 | peMetaData.Is32Bit = false; 712 | peMetaData.OptHeader64 = 713 | (Data.PE.IMAGE_OPTIONAL_HEADER64)Marshal.PtrToStructure(optHeader, 714 | typeof(Data.PE.IMAGE_OPTIONAL_HEADER64)); 715 | break; 716 | 717 | default: 718 | throw new InvalidOperationException("Invalid magic value (PE32/PE32+)."); 719 | } 720 | 721 | var sectionArray = new Data.PE.IMAGE_SECTION_HEADER[peMetaData.ImageFileHeader.NumberOfSections]; 722 | 723 | for (var i = 0; i < peMetaData.ImageFileHeader.NumberOfSections; i++) 724 | { 725 | var sectionPtr = (IntPtr)((ulong)optHeader + peMetaData.ImageFileHeader.SizeOfOptionalHeader + (uint)(i * 0x28)); 726 | sectionArray[i] = Marshal.PtrToStructure(sectionPtr); 727 | } 728 | 729 | peMetaData.Sections = sectionArray; 730 | } 731 | catch 732 | { 733 | throw new InvalidOperationException("Invalid module base specified."); 734 | } 735 | 736 | return peMetaData; 737 | } 738 | 739 | /// 740 | /// Resolve host DLL for API Set DLL. 741 | /// 742 | /// Ruben Boonen (@FuzzySec), The Wover (@TheRealWover) 743 | /// Dictionary, a combination of Key:APISetDLL and Val:HostDLL. 744 | public static Dictionary GetApiSetMapping() 745 | { 746 | var pbi = Native.NtQueryInformationProcessBasicInformation((IntPtr)(-1)); 747 | var apiSetMapOffset = IntPtr.Size == 4 ? (uint)0x38 : 0x68; 748 | var apiSetDict = new Dictionary(); 749 | 750 | var pApiSetNamespace = Marshal.ReadIntPtr((IntPtr)((ulong)pbi.PebBaseAddress + apiSetMapOffset)); 751 | var apiSetNamespace = (Data.PE.ApiSetNamespace)Marshal.PtrToStructure(pApiSetNamespace, typeof(Data.PE.ApiSetNamespace)); 752 | 753 | for (var i = 0; i < apiSetNamespace.Count; i++) 754 | { 755 | var setEntry = new Data.PE.ApiSetNamespaceEntry(); 756 | 757 | var pSetEntry = (IntPtr)((ulong)pApiSetNamespace + (ulong)apiSetNamespace.EntryOffset + (ulong)(i * Marshal.SizeOf(setEntry))); 758 | setEntry = (Data.PE.ApiSetNamespaceEntry)Marshal.PtrToStructure(pSetEntry, typeof(Data.PE.ApiSetNamespaceEntry)); 759 | 760 | var apiSetEntryName = Marshal.PtrToStringUni((IntPtr)((ulong)pApiSetNamespace + (ulong)setEntry.NameOffset), setEntry.NameLength / 2); 761 | var apiSetEntryKey = apiSetEntryName.Substring(0, apiSetEntryName.Length - 2) + ".dll" ; // Remove the patch number and add .dll 762 | 763 | var valueEntry = new Data.PE.ApiSetValueEntry(); 764 | var pSetValue = IntPtr.Zero; 765 | 766 | switch (setEntry.ValueLength) 767 | { 768 | case 1: 769 | pSetValue = (IntPtr)((ulong)pApiSetNamespace + (ulong)setEntry.ValueOffset); 770 | break; 771 | 772 | case > 1: 773 | { 774 | for (var j = 0; j < setEntry.ValueLength; j++) 775 | { 776 | var host = (IntPtr)((ulong)pApiSetNamespace + (ulong)setEntry.ValueOffset + (ulong)Marshal.SizeOf(valueEntry) * (ulong)j); 777 | if (Marshal.PtrToStringUni(host) != apiSetEntryName) 778 | pSetValue = (IntPtr)((ulong)pApiSetNamespace + (ulong)setEntry.ValueOffset + (ulong)Marshal.SizeOf(valueEntry) * (ulong)j); 779 | } 780 | 781 | if (pSetValue == IntPtr.Zero) 782 | pSetValue = (IntPtr)((ulong)pApiSetNamespace + (ulong)setEntry.ValueOffset); 783 | 784 | break; 785 | } 786 | } 787 | 788 | valueEntry = (Data.PE.ApiSetValueEntry)Marshal.PtrToStructure(pSetValue, typeof(Data.PE.ApiSetValueEntry)); 789 | 790 | var apiSetValue = string.Empty; 791 | if (valueEntry.ValueCount != 0) 792 | { 793 | var pValue = (IntPtr)((ulong)pApiSetNamespace + (ulong)valueEntry.ValueOffset); 794 | apiSetValue = Marshal.PtrToStringUni(pValue, valueEntry.ValueCount / 2); 795 | } 796 | 797 | apiSetDict.Add(apiSetEntryKey, apiSetValue); 798 | } 799 | 800 | return apiSetDict; 801 | } 802 | 803 | /// 804 | /// Call a manually mapped PE by its EntryPoint. 805 | /// 806 | /// Ruben Boonen (@FuzzySec) 807 | /// Module meta data struct (PE.PE_META_DATA). 808 | /// Base address of the module in memory. 809 | /// void 810 | public static void CallMappedPEModule(Data.PE.PE_META_DATA peInfo, IntPtr moduleMemoryBase) 811 | { 812 | var hRemoteThread = IntPtr.Zero; 813 | var lpStartAddress = peInfo.Is32Bit ? (IntPtr)((ulong)moduleMemoryBase + peInfo.OptHeader32.AddressOfEntryPoint) : 814 | (IntPtr)((ulong)moduleMemoryBase + peInfo.OptHeader64.AddressOfEntryPoint); 815 | 816 | Native.NtCreateThreadEx( 817 | ref hRemoteThread, 818 | Data.Win32.WinNT.ACCESS_MASK.STANDARD_RIGHTS_ALL, 819 | IntPtr.Zero, (IntPtr)(-1), 820 | lpStartAddress, IntPtr.Zero, 821 | false, 0, 0, 0, IntPtr.Zero 822 | ); 823 | } 824 | 825 | /// 826 | /// Call a manually mapped DLL by DllMain -> DLL_PROCESS_ATTACH. 827 | /// 828 | /// Ruben Boonen (@FuzzySec), TheWover (@TheRealWover) 829 | /// Module meta data struct (PE.PE_META_DATA). 830 | /// Base address of the module in memory. 831 | /// void 832 | public static void CallMappedDLLModule(Data.PE.PE_META_DATA peInfo, IntPtr moduleMemoryBase) 833 | { 834 | var lpEntryPoint = peInfo.Is32Bit ? (IntPtr)((ulong)moduleMemoryBase + peInfo.OptHeader32.AddressOfEntryPoint) : 835 | (IntPtr)((ulong)moduleMemoryBase + peInfo.OptHeader64.AddressOfEntryPoint); 836 | 837 | if (lpEntryPoint == moduleMemoryBase) 838 | return; 839 | 840 | var fDllMain = (Data.PE.DllMain)Marshal.GetDelegateForFunctionPointer(lpEntryPoint, typeof(Data.PE.DllMain)); 841 | 842 | try 843 | { 844 | var result = fDllMain(moduleMemoryBase, Data.PE.DLL_PROCESS_ATTACH, IntPtr.Zero); 845 | 846 | if (!result) 847 | throw new InvalidOperationException("Call to entry point failed -> DLL_PROCESS_ATTACH"); 848 | } 849 | catch 850 | { 851 | throw new InvalidOperationException("Invalid entry point -> DLL_PROCESS_ATTACH"); 852 | } 853 | } 854 | 855 | /// 856 | /// Call a manually mapped DLL by Export. 857 | /// 858 | /// Ruben Boonen (@FuzzySec) 859 | /// Module meta data struct (PE.PE_META_DATA). 860 | /// Base address of the module in memory. 861 | /// The name of the export to search for (e.g. "NtAlertResumeThread"). 862 | /// Prototype for the function, represented as a Delegate object. 863 | /// Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference. 864 | /// Specify whether to invoke the module's entry point. 865 | /// void 866 | public static T CallMappedDLLModuleExport(Data.PE.PE_META_DATA peInfo, IntPtr moduleMemoryBase, string exportName, Type functionDelegateType, object[] parameters, bool callEntry = true) 867 | { 868 | if (callEntry) 869 | CallMappedDLLModule(peInfo, moduleMemoryBase); 870 | 871 | var pFunc = GetExportAddress(moduleMemoryBase, exportName); 872 | return DynamicFunctionInvoke(pFunc, functionDelegateType, ref parameters); 873 | } 874 | 875 | /// 876 | /// Call a manually mapped DLL by Export. 877 | /// 878 | /// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec) 879 | /// Module meta data struct (PE.PE_META_DATA). 880 | /// Base address of the module in memory. 881 | /// The number of the ordinal to search for (e.g. 0x07). 882 | /// Prototype for the function, represented as a Delegate object. 883 | /// Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference. 884 | /// Specify whether to invoke the module's entry point. 885 | /// void 886 | public static T CallMappedDLLModuleExport(Data.PE.PE_META_DATA peInfo, IntPtr moduleMemoryBase, short ordinal, Type functionDelegateType, object[] parameters, bool callEntry = true) 887 | { 888 | if (callEntry) 889 | CallMappedDLLModule(peInfo, moduleMemoryBase); 890 | 891 | var pFunc = GetExportAddress(moduleMemoryBase, ordinal); 892 | return DynamicFunctionInvoke(pFunc, functionDelegateType, ref parameters); 893 | } 894 | 895 | /// 896 | /// Call a manually mapped DLL by Export. 897 | /// 898 | /// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec) 899 | /// Module meta data struct (PE.PE_META_DATA). 900 | /// Base address of the module in memory. 901 | /// Hash of the exported procedure. 902 | /// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788). 903 | /// Prototype for the function, represented as a Delegate object. 904 | /// Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference. 905 | /// Specify whether to invoke the module's entry point. 906 | /// void 907 | public static T CallMappedDLLModuleExport(Data.PE.PE_META_DATA peInfo, IntPtr moduleMemoryBase, string functionHash, long key, Type functionDelegateType, object[] parameters, bool callEntry = true) 908 | { 909 | if (callEntry) 910 | CallMappedDLLModule(peInfo, moduleMemoryBase); 911 | 912 | var pFunc = GetExportAddress(moduleMemoryBase, functionHash, key); 913 | return DynamicFunctionInvoke(pFunc, functionDelegateType, ref parameters); 914 | } 915 | } -------------------------------------------------------------------------------- /DInvoke.DynamicInvoke/Native.cs: -------------------------------------------------------------------------------- 1 | // Author: Ryan Cobb (@cobbr_io), The Wover (@TheRealWover) 2 | // Project: SharpSploit (https://github.com/cobbr/SharpSploit) 3 | // License: BSD 3-Clause 4 | 5 | using System.Net.Http.Headers; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace DInvoke.DynamicInvoke; 9 | 10 | /// 11 | /// Contains function prototypes and wrapper functions for dynamically invoking NT API Calls. 12 | /// 13 | public static class Native 14 | { 15 | private const string NTDLL = "ntdll.dll"; 16 | 17 | public static Data.Native.NTSTATUS NtCreateThreadEx(ref IntPtr threadHandle, 18 | Data.Win32.WinNT.ACCESS_MASK desiredAccess, IntPtr objectAttributes, IntPtr processHandle, IntPtr startAddress, 19 | IntPtr parameter, bool createSuspended, int stackZeroBits, int sizeOfStack, int maximumStackSize, 20 | IntPtr attributeList) 21 | { 22 | object[] parameters = 23 | [ 24 | threadHandle, desiredAccess, objectAttributes, processHandle, startAddress, parameter, createSuspended, 25 | stackZeroBits, 26 | sizeOfStack, maximumStackSize, attributeList 27 | ]; 28 | 29 | var status = Generic.DynamicApiInvoke( 30 | NTDLL, 31 | "NtCreateThreadEx", 32 | typeof(NtCreateThreadExDelegate), 33 | ref parameters); 34 | 35 | threadHandle = (IntPtr)parameters[0]; 36 | return status; 37 | } 38 | 39 | public static Data.Native.NTSTATUS NtCreateSection(ref IntPtr sectionHandle, uint desiredAccess, 40 | IntPtr objectAttributes, ref ulong maximumSize, uint sectionPageProtection, uint allocationAttributes, 41 | IntPtr fileHandle) 42 | { 43 | object[] parameters = 44 | [ 45 | sectionHandle, desiredAccess, objectAttributes, maximumSize, 46 | sectionPageProtection, allocationAttributes, fileHandle 47 | ]; 48 | 49 | var status = Generic.DynamicApiInvoke( 50 | NTDLL, 51 | "NtCreateSection", 52 | typeof(NtCreateSectionDelegate), 53 | ref parameters); 54 | 55 | sectionHandle = (IntPtr)parameters[0]; 56 | maximumSize = (ulong)parameters[3]; 57 | 58 | return status; 59 | } 60 | 61 | public static Data.Native.NTSTATUS NtUnmapViewOfSection(IntPtr hProc, IntPtr baseAddr) 62 | { 63 | object[] parameters = [hProc, baseAddr]; 64 | 65 | return Generic.DynamicApiInvoke( 66 | NTDLL, 67 | "NtUnmapViewOfSection", 68 | typeof(NtUnmapViewOfSectionDelegate), 69 | ref parameters); 70 | } 71 | 72 | public static Data.Native.NTSTATUS NtMapViewOfSection(IntPtr sectionHandle, IntPtr processHandle, 73 | ref IntPtr baseAddress, IntPtr zeroBits, IntPtr commitSize, IntPtr sectionOffset, ref ulong viewSize, 74 | uint inheritDisposition, uint allocationType, uint win32Protect) 75 | { 76 | object[] parameters = 77 | [ 78 | sectionHandle, processHandle, baseAddress, zeroBits, commitSize, sectionOffset, viewSize, 79 | inheritDisposition, allocationType, win32Protect 80 | ]; 81 | 82 | var status = Generic.DynamicApiInvoke( 83 | "ntdll.dll", 84 | "NtMapViewOfSection", 85 | typeof(NtMapViewOfSectionDelegate), 86 | ref parameters); 87 | 88 | baseAddress = (IntPtr)parameters[2]; 89 | viewSize = (ulong)parameters[6]; 90 | 91 | return status; 92 | } 93 | 94 | public static void RtlInitUnicodeString(ref Data.Native.UNICODE_STRING destinationString, 95 | [MarshalAs(UnmanagedType.LPWStr)] string sourceString) 96 | { 97 | object[] parameters = [destinationString, sourceString]; 98 | 99 | Generic.DynamicApiInvoke( 100 | NTDLL, 101 | "RtlInitUnicodeString", 102 | typeof(RtlInitUnicodeStringDelegate), 103 | ref parameters); 104 | 105 | destinationString = (Data.Native.UNICODE_STRING)parameters[0]; 106 | } 107 | 108 | public static Data.Native.NTSTATUS LdrLoadDll(IntPtr pathToFile, uint dwFlags, 109 | ref Data.Native.UNICODE_STRING moduleFileName, ref IntPtr moduleHandle) 110 | { 111 | object[] parameters = 112 | [ 113 | pathToFile, dwFlags, moduleFileName, moduleHandle 114 | ]; 115 | 116 | var status = Generic.DynamicApiInvoke( 117 | NTDLL, 118 | "LdrLoadDll", 119 | typeof(LdrLoadDllDelegate), 120 | ref parameters); 121 | 122 | moduleHandle = (IntPtr)parameters[3]; 123 | return status; 124 | } 125 | 126 | public static void RtlZeroMemory(IntPtr destination, int length) 127 | { 128 | object[] parameters = [destination, length]; 129 | 130 | _ = Generic.DynamicApiInvoke( 131 | NTDLL, 132 | "RtlZeroMemory", 133 | typeof(RtlZeroMemoryDelegate), 134 | ref parameters); 135 | } 136 | 137 | public static Data.Native.NTSTATUS NtQueryInformationProcess(IntPtr hProcess, 138 | Data.Native.PROCESSINFOCLASS processInfoClass, out IntPtr pProcInfo) 139 | { 140 | int processInformationLength; 141 | uint retLen = 0; 142 | 143 | switch (processInfoClass) 144 | { 145 | case Data.Native.PROCESSINFOCLASS.ProcessWow64Information: 146 | pProcInfo = Marshal.AllocHGlobal(IntPtr.Size); 147 | RtlZeroMemory(pProcInfo, IntPtr.Size); 148 | processInformationLength = IntPtr.Size; 149 | break; 150 | 151 | case Data.Native.PROCESSINFOCLASS.ProcessBasicInformation: 152 | var pbi = new Data.Native.PROCESS_BASIC_INFORMATION(); 153 | pProcInfo = Marshal.AllocHGlobal(Marshal.SizeOf(pbi)); 154 | RtlZeroMemory(pProcInfo, Marshal.SizeOf(pbi)); 155 | Marshal.StructureToPtr(pbi, pProcInfo, true); 156 | processInformationLength = Marshal.SizeOf(pbi); 157 | break; 158 | 159 | default: 160 | throw new InvalidOperationException($"Invalid ProcessInfoClass: {processInfoClass}"); 161 | } 162 | 163 | object[] parameters = 164 | [ 165 | hProcess, processInfoClass, pProcInfo, processInformationLength, retLen 166 | ]; 167 | 168 | var status = Generic.DynamicApiInvoke( 169 | NTDLL, 170 | "NtQueryInformationProcess", 171 | typeof(NtQueryInformationProcessDelegate), 172 | ref parameters); 173 | 174 | pProcInfo = (IntPtr)parameters[2]; 175 | return status; 176 | } 177 | 178 | public static bool NtQueryInformationProcessWow64Information(IntPtr hProcess) 179 | { 180 | _ = NtQueryInformationProcess( 181 | hProcess, 182 | Data.Native.PROCESSINFOCLASS.ProcessWow64Information, 183 | out var pProcInfo); 184 | 185 | return Marshal.ReadIntPtr(pProcInfo) != IntPtr.Zero; 186 | } 187 | 188 | public static Data.Native.PROCESS_BASIC_INFORMATION NtQueryInformationProcessBasicInformation(IntPtr hProcess) 189 | { 190 | _ = NtQueryInformationProcess( 191 | hProcess, 192 | Data.Native.PROCESSINFOCLASS.ProcessBasicInformation, 193 | out var pProcInfo); 194 | 195 | return Marshal.PtrToStructure(pProcInfo); 196 | } 197 | 198 | public static IntPtr NtAllocateVirtualMemory(IntPtr processHandle, ref IntPtr baseAddress, IntPtr zeroBits, 199 | ref IntPtr regionSize, uint allocationType, uint protect) 200 | { 201 | object[] parameters = 202 | [ 203 | processHandle, baseAddress, zeroBits, regionSize, allocationType, protect 204 | ]; 205 | 206 | _ = Generic.DynamicApiInvoke( 207 | NTDLL, 208 | "NtAllocateVirtualMemory", 209 | typeof(NtAllocateVirtualMemoryDelegate), 210 | ref parameters); 211 | 212 | baseAddress = (IntPtr)parameters[1]; 213 | return baseAddress; 214 | } 215 | 216 | public static void NtFreeVirtualMemory(IntPtr processHandle, ref IntPtr baseAddress, ref IntPtr regionSize, 217 | uint freeType) 218 | { 219 | object[] parameters = [processHandle, baseAddress, regionSize, freeType]; 220 | 221 | _ = Generic.DynamicApiInvoke( 222 | NTDLL, 223 | "NtFreeVirtualMemory", 224 | typeof(NtFreeVirtualMemoryDelegate), 225 | ref parameters); 226 | } 227 | 228 | public static uint NtProtectVirtualMemory(IntPtr processHandle, ref IntPtr baseAddress, ref IntPtr regionSize, 229 | uint newProtect) 230 | { 231 | object[] parameters = [processHandle, baseAddress, regionSize, newProtect, (uint)0]; 232 | 233 | _ = Generic.DynamicApiInvoke( 234 | NTDLL, 235 | "NtProtectVirtualMemory", 236 | typeof(NtProtectVirtualMemoryDelegate), 237 | ref parameters); 238 | 239 | return (uint)parameters[4]; 240 | } 241 | 242 | public static uint NtWriteVirtualMemory(IntPtr processHandle, IntPtr baseAddress, IntPtr buffer, uint bufferLength) 243 | { 244 | object[] parameters = [processHandle, baseAddress, buffer, bufferLength, (uint)0]; 245 | 246 | _ = Generic.DynamicApiInvoke( 247 | NTDLL, 248 | "NtWriteVirtualMemory", 249 | typeof(NtWriteVirtualMemoryDelegate), 250 | ref parameters); 251 | 252 | return (uint)parameters[4]; 253 | } 254 | 255 | public static IntPtr LdrGetProcedureAddress(IntPtr hModule, IntPtr functionName, IntPtr ordinal, 256 | ref IntPtr functionAddress) 257 | { 258 | object[] parameters = [hModule, functionName, ordinal, functionAddress]; 259 | 260 | _ = Generic.DynamicApiInvoke( 261 | NTDLL, 262 | "LdrGetProcedureAddress", 263 | typeof(LdrGetProcedureAddressDelegate), 264 | ref parameters); 265 | 266 | functionAddress = (IntPtr)parameters[3]; 267 | return functionAddress; 268 | } 269 | 270 | public static void RtlGetVersion(ref Data.Native.OSVERSIONINFOEX versionInformation) 271 | { 272 | object[] parameters = [versionInformation]; 273 | 274 | _ = Generic.DynamicApiInvoke( 275 | NTDLL, 276 | "RtlGetVersion", 277 | typeof(RtlGetVersionDelegate), 278 | ref parameters); 279 | 280 | versionInformation = (Data.Native.OSVERSIONINFOEX)parameters[0]; 281 | } 282 | 283 | public static IntPtr NtOpenFile(ref IntPtr fileHandle, Data.Win32.Kernel32.FileAccessFlags desiredAccess, 284 | ref Data.Native.OBJECT_ATTRIBUTES objectAttributes, ref Data.Native.IO_STATUS_BLOCK ioStatusBlock, 285 | Data.Win32.Kernel32.FileShareFlags shareAccess, Data.Win32.Kernel32.FileOpenFlags openOptions) 286 | { 287 | object[] parameters = 288 | [ 289 | fileHandle, desiredAccess, objectAttributes, ioStatusBlock, shareAccess, openOptions 290 | ]; 291 | 292 | _ = Generic.DynamicApiInvoke( 293 | @"ntdll.dll", 294 | @"NtOpenFile", 295 | typeof(NtOpenFileDelegate), 296 | ref parameters); 297 | 298 | fileHandle = (IntPtr)parameters[0]; 299 | return fileHandle; 300 | } 301 | 302 | public static void NtClose(IntPtr handle) 303 | { 304 | object[] parameters = [handle]; 305 | 306 | _ = Generic.DynamicApiInvoke( 307 | NTDLL, 308 | "NtClose", 309 | typeof(NtCloseDelegate), 310 | ref parameters); 311 | } 312 | 313 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 314 | private delegate uint NtCreateThreadExDelegate( 315 | out IntPtr threadHandle, 316 | Data.Win32.WinNT.ACCESS_MASK desiredAccess, 317 | IntPtr objectAttributes, 318 | IntPtr processHandle, 319 | IntPtr startAddress, 320 | IntPtr parameter, 321 | bool createSuspended, 322 | int stackZeroBits, 323 | int sizeOfStack, 324 | int maximumStackSize, 325 | IntPtr attributeList); 326 | 327 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 328 | private delegate uint NtCreateSectionDelegate( 329 | ref IntPtr sectionHandle, 330 | uint desiredAccess, 331 | IntPtr objectAttributes, 332 | ref ulong maximumSize, 333 | uint sectionPageProtection, 334 | uint allocationAttributes, 335 | IntPtr fileHandle); 336 | 337 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 338 | private delegate uint NtUnmapViewOfSectionDelegate( 339 | IntPtr hProc, 340 | IntPtr baseAddr); 341 | 342 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 343 | private delegate uint NtMapViewOfSectionDelegate( 344 | IntPtr sectionHandle, 345 | IntPtr processHandle, 346 | out IntPtr baseAddress, 347 | IntPtr zeroBits, 348 | IntPtr commitSize, 349 | IntPtr sectionOffset, 350 | out ulong viewSize, 351 | uint inheritDisposition, 352 | uint allocationType, 353 | uint win32Protect); 354 | 355 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 356 | private delegate uint LdrLoadDllDelegate( 357 | IntPtr pathToFile, 358 | uint dwFlags, 359 | ref Data.Native.UNICODE_STRING moduleFileName, 360 | ref IntPtr moduleHandle); 361 | 362 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 363 | private delegate void RtlInitUnicodeStringDelegate( 364 | ref Data.Native.UNICODE_STRING destinationString, 365 | [MarshalAs(UnmanagedType.LPWStr)] string sourceString); 366 | 367 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 368 | private delegate void RtlZeroMemoryDelegate( 369 | IntPtr destination, 370 | int length); 371 | 372 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 373 | private delegate uint NtQueryInformationProcessDelegate( 374 | IntPtr processHandle, 375 | Data.Native.PROCESSINFOCLASS processInformationClass, 376 | IntPtr processInformation, 377 | int processInformationLength, 378 | ref uint returnLength); 379 | 380 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 381 | private delegate uint NtAllocateVirtualMemoryDelegate( 382 | IntPtr processHandle, 383 | ref IntPtr baseAddress, 384 | IntPtr zeroBits, 385 | ref IntPtr regionSize, 386 | uint allocationType, 387 | uint protect); 388 | 389 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 390 | private delegate uint NtFreeVirtualMemoryDelegate( 391 | IntPtr processHandle, 392 | ref IntPtr baseAddress, 393 | ref IntPtr regionSize, 394 | uint freeType); 395 | 396 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 397 | private delegate uint NtProtectVirtualMemoryDelegate( 398 | IntPtr processHandle, 399 | ref IntPtr baseAddress, 400 | ref IntPtr regionSize, 401 | uint newProtect, 402 | ref uint oldProtect); 403 | 404 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 405 | private delegate uint NtWriteVirtualMemoryDelegate( 406 | IntPtr processHandle, 407 | IntPtr baseAddress, 408 | IntPtr buffer, 409 | uint bufferLength, 410 | ref uint bytesWritten); 411 | 412 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 413 | private delegate uint LdrGetProcedureAddressDelegate( 414 | IntPtr hModule, 415 | IntPtr functionName, 416 | IntPtr ordinal, 417 | ref IntPtr functionAddress); 418 | 419 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 420 | private delegate uint RtlGetVersionDelegate( 421 | ref Data.Native.OSVERSIONINFOEX versionInformation); 422 | 423 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 424 | private delegate uint NtOpenFileDelegate( 425 | ref IntPtr fileHandle, 426 | Data.Win32.Kernel32.FileAccessFlags accessFlags, 427 | ref Data.Native.OBJECT_ATTRIBUTES objectAttributes, 428 | ref Data.Native.IO_STATUS_BLOCK ioStatusBlock, 429 | Data.Win32.Kernel32.FileShareFlags shareAccess, 430 | Data.Win32.Kernel32.FileOpenFlags openOptions); 431 | 432 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 433 | private delegate uint NtCloseDelegate( 434 | IntPtr handle); 435 | } -------------------------------------------------------------------------------- /DInvoke.DynamicInvoke/Utilities.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using System.Security.Cryptography.X509Certificates; 3 | using System.Text; 4 | 5 | namespace DInvoke.DynamicInvoke; 6 | 7 | public static class Utilities 8 | { 9 | /// 10 | /// Checks that a file is signed and has a valid signature. 11 | /// 12 | /// Path of file to check. 13 | /// 14 | public static bool FileHasValidSignature(string filePath) 15 | { 16 | X509Certificate2 fileCertificate; 17 | 18 | try 19 | { 20 | var signer = X509Certificate.CreateFromSignedFile(filePath); 21 | fileCertificate = new X509Certificate2(signer); 22 | } 23 | catch 24 | { 25 | return false; 26 | } 27 | 28 | var certificateChain = new X509Chain(); 29 | certificateChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; 30 | certificateChain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; 31 | certificateChain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; 32 | 33 | return certificateChain.Build(fileCertificate); 34 | } 35 | 36 | /// 37 | /// Generate an HMAC-MD5 hash of the supplied string using an Int64 as the key. This is useful for unique hash based API lookups. 38 | /// 39 | /// Ruben Boonen (@FuzzySec) 40 | /// String to hash. 41 | /// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788). 42 | /// string, the computed MD5 hash value. 43 | public static string GetApiHash(string value, long key) 44 | { 45 | var data = Encoding.UTF8.GetBytes(value.ToLower()); 46 | var bytes = BitConverter.GetBytes(key); 47 | 48 | using var hmac = new HMACMD5(bytes); 49 | var bHash = hmac.ComputeHash(data); 50 | return BitConverter.ToString(bHash).Replace("-", ""); 51 | } 52 | } -------------------------------------------------------------------------------- /DInvoke.ManualMap/DInvoke.ManualMap.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | enable 6 | disable 7 | 12 8 | true 9 | TheWover, RastaMouse 10 | Manually map PE modules from on disk or in memory. 11 | 1.0.7 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /DInvoke.ManualMap/Map.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.InteropServices; 3 | 4 | using DInvoke.DynamicInvoke; 5 | 6 | namespace DInvoke.ManualMap; 7 | 8 | /// 9 | /// Class for manually mapping PEs. 10 | /// 11 | public static class Map 12 | { 13 | /// 14 | /// Maps a DLL from disk into a Section using NtCreateSection. 15 | /// 16 | /// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec) 17 | /// Full path fo the DLL on disk. 18 | /// PE.PE_MANUAL_MAP 19 | public static Data.PE.PE_MANUAL_MAP MapModuleFromDiskToSection(string dllPath) 20 | { 21 | if (!File.Exists(dllPath)) 22 | throw new InvalidOperationException("Filepath not found."); 23 | 24 | var objectName = new Data.Native.UNICODE_STRING(); 25 | Native.RtlInitUnicodeString(ref objectName, @"\??\" + dllPath); 26 | 27 | var pObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(objectName)); 28 | Marshal.StructureToPtr(objectName, pObjectName, true); 29 | 30 | var objectAttributes = new Data.Native.OBJECT_ATTRIBUTES(); 31 | objectAttributes.Length = Marshal.SizeOf(objectAttributes); 32 | objectAttributes.ObjectName = pObjectName; 33 | objectAttributes.Attributes = 0x40; 34 | 35 | var ioStatusBlock = new Data.Native.IO_STATUS_BLOCK(); 36 | 37 | var hFile = IntPtr.Zero; 38 | 39 | Native.NtOpenFile( 40 | ref hFile, 41 | Data.Win32.Kernel32.FileAccessFlags.FILE_READ_DATA | 42 | Data.Win32.Kernel32.FileAccessFlags.FILE_EXECUTE | 43 | Data.Win32.Kernel32.FileAccessFlags.FILE_READ_ATTRIBUTES | 44 | Data.Win32.Kernel32.FileAccessFlags.SYNCHRONIZE, 45 | ref objectAttributes, ref ioStatusBlock, 46 | Data.Win32.Kernel32.FileShareFlags.FILE_SHARE_READ | 47 | Data.Win32.Kernel32.FileShareFlags.FILE_SHARE_DELETE, 48 | Data.Win32.Kernel32.FileOpenFlags.FILE_SYNCHRONOUS_IO_NONALERT | 49 | Data.Win32.Kernel32.FileOpenFlags.FILE_NON_DIRECTORY_FILE 50 | ); 51 | 52 | var hSection = IntPtr.Zero; 53 | ulong maxSize = 0; 54 | 55 | var ret = Native.NtCreateSection( 56 | ref hSection, 57 | (uint)Data.Win32.WinNT.ACCESS_MASK.SECTION_ALL_ACCESS, 58 | IntPtr.Zero, 59 | ref maxSize, 60 | Data.Win32.WinNT.PAGE_READONLY, 61 | Data.Win32.WinNT.SEC_IMAGE, 62 | hFile 63 | ); 64 | 65 | var pBaseAddress = IntPtr.Zero; 66 | 67 | Native.NtMapViewOfSection( 68 | hSection, (IntPtr)(-1), ref pBaseAddress, 69 | IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 70 | ref maxSize, 0x2, 0x0, 71 | Data.Win32.WinNT.PAGE_READWRITE 72 | ); 73 | 74 | var secMapObject = new Data.PE.PE_MANUAL_MAP 75 | { 76 | PEINFO = Generic.GetPeMetaData(pBaseAddress), 77 | ModuleBase = pBaseAddress 78 | }; 79 | 80 | Native.NtClose(hFile); 81 | 82 | return secMapObject; 83 | } 84 | 85 | /// 86 | /// Allocate file to memory from disk 87 | /// 88 | /// Ruben Boonen (@FuzzySec) 89 | /// Full path to the file to be alloacted. 90 | /// IntPtr base address of the allocated file. 91 | public static IntPtr AllocateFileToMemory(string filePath) 92 | { 93 | if (!File.Exists(filePath)) 94 | throw new InvalidOperationException("Filepath not found."); 95 | 96 | var bFile = File.ReadAllBytes(filePath); 97 | return AllocateBytesToMemory(bFile); 98 | } 99 | 100 | /// 101 | /// Allocate a byte array to memory 102 | /// 103 | /// Ruben Boonen (@FuzzySec) 104 | /// Byte array to be allocated. 105 | /// IntPtr base address of the allocated file. 106 | public static IntPtr AllocateBytesToMemory(byte[] fileBytes) 107 | { 108 | var pFile = Marshal.AllocHGlobal(fileBytes.Length); 109 | Marshal.Copy(fileBytes, 0, pFile, fileBytes.Length); 110 | return pFile; 111 | } 112 | 113 | /// 114 | /// Relocates a module in memory. 115 | /// 116 | /// Ruben Boonen (@FuzzySec) 117 | /// Module meta data struct (PE.PE_META_DATA). 118 | /// Base address of the module in memory. 119 | /// void 120 | public static void RelocateModule(Data.PE.PE_META_DATA peMetaData, IntPtr moduleMemoryBase) 121 | { 122 | var idd = peMetaData.Is32Bit ? peMetaData.OptHeader32.BaseRelocationTable : peMetaData.OptHeader64.BaseRelocationTable; 123 | var imageDelta = peMetaData.Is32Bit ? (long)((ulong)moduleMemoryBase - peMetaData.OptHeader32.ImageBase) : 124 | (long)((ulong)moduleMemoryBase - peMetaData.OptHeader64.ImageBase); 125 | 126 | var pRelocTable = (IntPtr)((ulong)moduleMemoryBase + idd.VirtualAddress); 127 | var nextRelocTableBlock = -1; 128 | 129 | while (nextRelocTableBlock != 0) 130 | { 131 | var ibr = new Data.PE.IMAGE_BASE_RELOCATION(); 132 | ibr = (Data.PE.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(pRelocTable, typeof(Data.PE.IMAGE_BASE_RELOCATION)); 133 | 134 | var relocCount = (ibr.SizeOfBlock - Marshal.SizeOf(ibr)) / 2; 135 | 136 | for (var i = 0; i < relocCount; i++) 137 | { 138 | var pRelocEntry = (IntPtr)((ulong)pRelocTable + (ulong)Marshal.SizeOf(ibr) + (ulong)(i * 2)); 139 | var relocValue = (ushort)Marshal.ReadInt16(pRelocEntry); 140 | 141 | var relocType = (ushort)(relocValue >> 12); 142 | var relocPatch = (ushort)(relocValue & 0xfff); 143 | 144 | if (relocType == 0) continue; 145 | 146 | try 147 | { 148 | var pPatch = (IntPtr)((ulong)moduleMemoryBase + ibr.VirtualAdress + relocPatch); 149 | if (relocType == 0x3) 150 | { 151 | var originalPtr = Marshal.ReadInt32(pPatch); 152 | Marshal.WriteInt32(pPatch, originalPtr + (int)imageDelta); 153 | } 154 | else 155 | { 156 | var originalPtr = Marshal.ReadInt64(pPatch); 157 | Marshal.WriteInt64(pPatch, originalPtr + imageDelta); 158 | } 159 | } 160 | catch 161 | { 162 | throw new InvalidOperationException("Memory access violation."); 163 | } 164 | } 165 | 166 | pRelocTable = (IntPtr)((ulong)pRelocTable + ibr.SizeOfBlock); 167 | nextRelocTableBlock = Marshal.ReadInt32(pRelocTable); 168 | } 169 | } 170 | 171 | /// 172 | /// Rewrite IAT for manually mapped module. 173 | /// 174 | /// Ruben Boonen (@FuzzySec) 175 | /// Module meta data struct (PE.PE_META_DATA). 176 | /// Base address of the module in memory. 177 | /// void 178 | public static void RewriteModuleIAT(Data.PE.PE_META_DATA peMetaData, IntPtr moduleMemoryBase) 179 | { 180 | var idd = peMetaData.Is32Bit ? peMetaData.OptHeader32.ImportTable : peMetaData.OptHeader64.ImportTable; 181 | 182 | if (idd.VirtualAddress == 0) 183 | return; 184 | 185 | var pImportTable = (IntPtr)((ulong)moduleMemoryBase + idd.VirtualAddress); 186 | 187 | var osVersion = new Data.Native.OSVERSIONINFOEX(); 188 | Native.RtlGetVersion(ref osVersion); 189 | 190 | var apiSetDict = new Dictionary(); 191 | 192 | if (osVersion.MajorVersion >= 10) 193 | apiSetDict = Generic.GetApiSetMapping(); 194 | 195 | var counter = 0; 196 | var iid = new Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR(); 197 | iid = (Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure( 198 | (IntPtr)((ulong)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)), 199 | typeof(Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR) 200 | ); 201 | 202 | while (iid.Name != 0) 203 | { 204 | var dllName = string.Empty; 205 | 206 | try 207 | { 208 | dllName = Marshal.PtrToStringAnsi((IntPtr)((ulong)moduleMemoryBase + iid.Name)); 209 | } 210 | catch 211 | { 212 | // ignore 213 | } 214 | 215 | if (dllName == string.Empty) 216 | throw new InvalidOperationException("Failed to read DLL name."); 217 | 218 | 219 | var lookupKey = dllName!.Substring(0, dllName.Length - 6) + ".dll"; 220 | 221 | if (osVersion.MajorVersion >= 10 && (dllName.StartsWith("api-") || dllName.StartsWith("ext-")) && 222 | apiSetDict.ContainsKey(lookupKey) && apiSetDict[lookupKey].Length > 0) 223 | { 224 | dllName = apiSetDict[lookupKey]; 225 | } 226 | 227 | var hModule = Generic.GetLoadedModuleAddress(dllName); 228 | 229 | if (hModule == IntPtr.Zero) 230 | { 231 | hModule = Generic.LoadModuleFromDisk(dllName); 232 | 233 | if (hModule == IntPtr.Zero) 234 | throw new FileNotFoundException(dllName + ", unable to find the specified file."); 235 | } 236 | 237 | if (peMetaData.Is32Bit) 238 | { 239 | var oft_itd = new Data.PE.IMAGE_THUNK_DATA32(); 240 | for (var i = 0;; i++) 241 | { 242 | oft_itd = (Data.PE.IMAGE_THUNK_DATA32)Marshal.PtrToStructure( 243 | (IntPtr)((ulong)moduleMemoryBase + iid.OriginalFirstThunk + (uint)(i * sizeof(uint))), 244 | typeof(Data.PE.IMAGE_THUNK_DATA32)); 245 | 246 | var ft_itd = (IntPtr)((ulong)moduleMemoryBase + iid.FirstThunk + (ulong)(i * sizeof(uint))); 247 | 248 | if (oft_itd.AddressOfData == 0) 249 | break; 250 | 251 | if (oft_itd.AddressOfData < 0x80000000) 252 | { 253 | var pImpByName = (IntPtr)((ulong)moduleMemoryBase + oft_itd.AddressOfData + sizeof(ushort)); 254 | var pFunc = IntPtr.Zero; 255 | 256 | pFunc = Generic.GetNativeExportAddress(hModule, 257 | Marshal.PtrToStringAnsi(pImpByName)); 258 | 259 | Marshal.WriteInt32(ft_itd, pFunc.ToInt32()); 260 | } 261 | else 262 | { 263 | ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF; 264 | 265 | var pFunc = IntPtr.Zero; 266 | pFunc = Generic.GetNativeExportAddress(hModule, (short)fOrdinal); 267 | 268 | Marshal.WriteInt32(ft_itd, pFunc.ToInt32()); 269 | } 270 | } 271 | } 272 | else 273 | { 274 | var oft_itd = new Data.PE.IMAGE_THUNK_DATA64(); 275 | 276 | for (var i = 0;; i++) 277 | { 278 | oft_itd = (Data.PE.IMAGE_THUNK_DATA64)Marshal.PtrToStructure( 279 | (IntPtr)((ulong)moduleMemoryBase + iid.OriginalFirstThunk + (ulong)(i * sizeof(ulong))), 280 | typeof(Data.PE.IMAGE_THUNK_DATA64)); 281 | 282 | var ft_itd = (IntPtr)((ulong)moduleMemoryBase + iid.FirstThunk + (ulong)(i * sizeof(ulong))); 283 | 284 | if (oft_itd.AddressOfData == 0) 285 | break; 286 | 287 | if (oft_itd.AddressOfData < 0x8000000000000000) // !IMAGE_ORDINAL_FLAG64 288 | { 289 | var pImpByName = (IntPtr)((ulong)moduleMemoryBase + oft_itd.AddressOfData + sizeof(ushort)); 290 | var pFunc = IntPtr.Zero; 291 | 292 | pFunc = Generic.GetNativeExportAddress(hModule, 293 | Marshal.PtrToStringAnsi(pImpByName)); 294 | 295 | Marshal.WriteInt64(ft_itd, pFunc.ToInt64()); 296 | } 297 | else 298 | { 299 | var fOrdinal = oft_itd.AddressOfData & 0xFFFF; 300 | 301 | var pFunc = IntPtr.Zero; 302 | pFunc = Generic.GetNativeExportAddress(hModule, (short)fOrdinal); 303 | 304 | Marshal.WriteInt64(ft_itd, pFunc.ToInt64()); 305 | } 306 | } 307 | } 308 | 309 | counter++; 310 | 311 | iid = (Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure( 312 | (IntPtr)((ulong)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)), 313 | typeof(Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR) 314 | ); 315 | } 316 | } 317 | 318 | /// 319 | /// Set correct module section permissions. 320 | /// 321 | /// Ruben Boonen (@FuzzySec) 322 | /// Module meta data struct (PE.PE_META_DATA). 323 | /// Base address of the module in memory. 324 | /// void 325 | public static void SetModuleSectionPermissions(Data.PE.PE_META_DATA peMetaData, IntPtr moduleMemoryBase) 326 | { 327 | var baseOfCode = peMetaData.Is32Bit ? (IntPtr)peMetaData.OptHeader32.BaseOfCode : (IntPtr)peMetaData.OptHeader64.BaseOfCode; 328 | Native.NtProtectVirtualMemory((IntPtr)(-1), ref moduleMemoryBase, ref baseOfCode, Data.Win32.WinNT.PAGE_READONLY); 329 | 330 | foreach (var ish in peMetaData.Sections) 331 | { 332 | var isRead = (ish.Characteristics & Data.PE.DataSectionFlags.MEM_READ) != 0; 333 | var isWrite = (ish.Characteristics & Data.PE.DataSectionFlags.MEM_WRITE) != 0; 334 | var isExecute = (ish.Characteristics & Data.PE.DataSectionFlags.MEM_EXECUTE) != 0; 335 | 336 | uint flNewProtect = 0; 337 | 338 | if (isRead & !isWrite & !isExecute) 339 | flNewProtect = Data.Win32.WinNT.PAGE_READONLY; 340 | else if (isRead & isWrite & !isExecute) 341 | flNewProtect = Data.Win32.WinNT.PAGE_READWRITE; 342 | else if (isRead & isWrite & isExecute) 343 | flNewProtect = Data.Win32.WinNT.PAGE_EXECUTE_READWRITE; 344 | else if (isRead & !isWrite & isExecute) 345 | flNewProtect = Data.Win32.WinNT.PAGE_EXECUTE_READ; 346 | else if (!isRead & !isWrite & isExecute) 347 | flNewProtect = Data.Win32.WinNT.PAGE_EXECUTE; 348 | else 349 | throw new InvalidOperationException("Unknown section flag, " + ish.Characteristics); 350 | 351 | var pVirtualSectionBase = (IntPtr)((ulong)moduleMemoryBase + ish.VirtualAddress); 352 | var protectSize = (IntPtr)ish.VirtualSize; 353 | 354 | Native.NtProtectVirtualMemory((IntPtr)(-1), ref pVirtualSectionBase, ref protectSize, flNewProtect); 355 | } 356 | } 357 | 358 | /// 359 | /// Manually map module into current process. 360 | /// 361 | /// Ruben Boonen (@FuzzySec) 362 | /// Full path to the module on disk. 363 | /// PE_MANUAL_MAP object 364 | public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(string modulePath) 365 | { 366 | var pModule = AllocateFileToMemory(modulePath); 367 | return MapModuleToMemory(pModule); 368 | } 369 | 370 | /// 371 | /// Manually map module into current process. 372 | /// 373 | /// Ruben Boonen (@FuzzySec) 374 | /// Full byte array of the module. 375 | /// PE_MANUAL_MAP object 376 | public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(byte[] module) 377 | { 378 | var pModule = AllocateBytesToMemory(module); 379 | return MapModuleToMemory(pModule); 380 | } 381 | 382 | /// 383 | /// Manually map module into current process starting at the specified base address. 384 | /// 385 | /// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec) 386 | /// Full byte array of the module. 387 | /// Address in memory to map module to. 388 | /// PE_MANUAL_MAP object 389 | public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(byte[] module, IntPtr pImage) 390 | { 391 | var pModule = AllocateBytesToMemory(module); 392 | return MapModuleToMemory(pModule, pImage); 393 | } 394 | 395 | /// 396 | /// Manually map module into current process. 397 | /// 398 | /// Ruben Boonen (@FuzzySec) 399 | /// Pointer to the module base. 400 | /// PE_MANUAL_MAP object 401 | public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(IntPtr pModule) 402 | { 403 | var peMetaData = Generic.GetPeMetaData(pModule); 404 | 405 | if (peMetaData.Is32Bit && IntPtr.Size == 8 || !peMetaData.Is32Bit && IntPtr.Size == 4) 406 | { 407 | Marshal.FreeHGlobal(pModule); 408 | throw new InvalidOperationException("The module architecture does not match the process architecture."); 409 | } 410 | 411 | var baseAddress = IntPtr.Zero; 412 | var regionSize = peMetaData.Is32Bit ? (IntPtr)peMetaData.OptHeader32.SizeOfImage : (IntPtr)peMetaData.OptHeader64.SizeOfImage; 413 | var pImage = Native.NtAllocateVirtualMemory( 414 | (IntPtr)(-1), ref baseAddress, IntPtr.Zero, ref regionSize, 415 | Data.Win32.Kernel32.MEM_COMMIT | Data.Win32.Kernel32.MEM_RESERVE, 416 | Data.Win32.WinNT.PAGE_READWRITE 417 | ); 418 | 419 | return MapModuleToMemory(pModule, pImage, peMetaData); 420 | } 421 | 422 | /// 423 | /// Manually map module into current process. 424 | /// 425 | /// Ruben Boonen (@FuzzySec) 426 | /// Pointer to the module base. 427 | /// Pointer to the PEINFO image. 428 | /// PE_MANUAL_MAP object 429 | public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(IntPtr pModule, IntPtr pImage) 430 | { 431 | var peMetaData = Generic.GetPeMetaData(pModule); 432 | return MapModuleToMemory(pModule, pImage, peMetaData); 433 | } 434 | 435 | /// 436 | /// Manually map module into current process. 437 | /// 438 | /// Ruben Boonen (@FuzzySec) 439 | /// Pointer to the module base. 440 | /// Pointer to the PEINFO image. 441 | /// PE_META_DATA of the module being mapped. 442 | /// PE_MANUAL_MAP object 443 | public static Data.PE.PE_MANUAL_MAP MapModuleToMemory(IntPtr pModule, IntPtr pImage, Data.PE.PE_META_DATA peMetaData) 444 | { 445 | if (peMetaData.Is32Bit && IntPtr.Size == 8 || !peMetaData.Is32Bit && IntPtr.Size == 4) 446 | { 447 | Marshal.FreeHGlobal(pModule); 448 | throw new InvalidOperationException("The module architecture does not match the process architecture."); 449 | } 450 | 451 | var sizeOfHeaders = peMetaData.Is32Bit ? peMetaData.OptHeader32.SizeOfHeaders : peMetaData.OptHeader64.SizeOfHeaders; 452 | var bytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pImage, pModule, sizeOfHeaders); 453 | 454 | foreach (var ish in peMetaData.Sections) 455 | { 456 | var pVirtualSectionBase = (IntPtr)((ulong)pImage + ish.VirtualAddress); 457 | var pRawSectionBase = (IntPtr)((ulong)pModule + ish.PointerToRawData); 458 | 459 | bytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pVirtualSectionBase, pRawSectionBase, ish.SizeOfRawData); 460 | 461 | if (bytesWritten != ish.SizeOfRawData) 462 | throw new InvalidOperationException("Failed to write to memory."); 463 | } 464 | 465 | RelocateModule(peMetaData, pImage); 466 | RewriteModuleIAT(peMetaData, pImage); 467 | SetModuleSectionPermissions(peMetaData, pImage); 468 | 469 | Marshal.FreeHGlobal(pModule); 470 | 471 | return new Data.PE.PE_MANUAL_MAP 472 | { 473 | ModuleBase = pImage, 474 | PEINFO = peMetaData 475 | }; 476 | } 477 | 478 | /// 479 | /// Free a module that was mapped into the current process. 480 | /// 481 | /// The Wover (@TheRealWover) 482 | /// The metadata of the manually mapped module. 483 | public static void FreeModule(Data.PE.PE_MANUAL_MAP peManualMap) 484 | { 485 | // Check if PE was mapped via module overloading 486 | if (!string.IsNullOrEmpty(peManualMap.DecoyModule)) 487 | { 488 | Native.NtUnmapViewOfSection((IntPtr)(-1), peManualMap.ModuleBase); 489 | } 490 | else 491 | { 492 | var peMetaData = peManualMap.PEINFO; 493 | 494 | var size = peMetaData.Is32Bit ? (IntPtr)peMetaData.OptHeader32.SizeOfImage : (IntPtr)peMetaData.OptHeader64.SizeOfImage; 495 | var pModule = peManualMap.ModuleBase; 496 | 497 | Native.NtFreeVirtualMemory((IntPtr)(-1), ref pModule, ref size, Data.Win32.Kernel32.MEM_RELEASE); 498 | } 499 | } 500 | 501 | /// 502 | /// Read ntdll from disk, find/copy the appropriate syscall stub and free ntdll. 503 | /// 504 | /// Ruben Boonen (@FuzzySec) 505 | /// The name of the function to search for (e.g. "NtAlertResumeThread"). 506 | /// IntPtr, Syscall stub 507 | public static IntPtr GetSyscallStub(string functionName) 508 | { 509 | var isWow64 = Native.NtQueryInformationProcessWow64Information((IntPtr)(-1)); 510 | 511 | if (IntPtr.Size == 4 && isWow64) 512 | throw new InvalidOperationException("Generating Syscall stubs is not supported for WOW64."); 513 | 514 | var ntdllPath = string.Empty; 515 | var procModules = Process.GetCurrentProcess().Modules; 516 | 517 | foreach (ProcessModule module in procModules) 518 | { 519 | if (!module.FileName.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase)) continue; 520 | 521 | ntdllPath = module.FileName; 522 | break; 523 | } 524 | 525 | var pModule = AllocateFileToMemory(ntdllPath); 526 | var peMetaData = Generic.GetPeMetaData(pModule); 527 | 528 | var baseAddress = IntPtr.Zero; 529 | var regionSize = peMetaData.Is32Bit ? (IntPtr)peMetaData.OptHeader32.SizeOfImage : (IntPtr)peMetaData.OptHeader64.SizeOfImage; 530 | var sizeOfHeaders = peMetaData.Is32Bit ? peMetaData.OptHeader32.SizeOfHeaders : peMetaData.OptHeader64.SizeOfHeaders; 531 | 532 | var pImage = Native.NtAllocateVirtualMemory( 533 | (IntPtr)(-1), ref baseAddress, IntPtr.Zero, ref regionSize, 534 | Data.Win32.Kernel32.MEM_COMMIT | Data.Win32.Kernel32.MEM_RESERVE, 535 | Data.Win32.WinNT.PAGE_READWRITE 536 | ); 537 | 538 | var bytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pImage, pModule, sizeOfHeaders); 539 | 540 | foreach (var ish in peMetaData.Sections) 541 | { 542 | var pVirtualSectionBase = (IntPtr)((ulong)pImage + ish.VirtualAddress); 543 | var pRawSectionBase = (IntPtr)((ulong)pModule + ish.PointerToRawData); 544 | 545 | bytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pVirtualSectionBase, pRawSectionBase, ish.SizeOfRawData); 546 | 547 | if (bytesWritten != ish.SizeOfRawData) 548 | throw new InvalidOperationException("Failed to write to memory."); 549 | } 550 | 551 | var pFunc = Generic.GetExportAddress(pImage, functionName); 552 | 553 | if (pFunc == IntPtr.Zero) 554 | throw new InvalidOperationException("Failed to resolve ntdll export."); 555 | 556 | baseAddress = IntPtr.Zero; 557 | regionSize = (IntPtr)0x50; 558 | 559 | var pCallStub = Native.NtAllocateVirtualMemory( 560 | (IntPtr)(-1), ref baseAddress, IntPtr.Zero, ref regionSize, 561 | Data.Win32.Kernel32.MEM_COMMIT | Data.Win32.Kernel32.MEM_RESERVE, 562 | Data.Win32.WinNT.PAGE_READWRITE 563 | ); 564 | 565 | bytesWritten = Native.NtWriteVirtualMemory((IntPtr)(-1), pCallStub, pFunc, 0x50); 566 | 567 | if (bytesWritten != 0x50) 568 | throw new InvalidOperationException("Failed to write to memory."); 569 | 570 | Native.NtProtectVirtualMemory((IntPtr)(-1), ref pCallStub, ref regionSize, Data.Win32.WinNT.PAGE_EXECUTE_READ); 571 | 572 | Marshal.FreeHGlobal(pModule); 573 | regionSize = peMetaData.Is32Bit ? (IntPtr)peMetaData.OptHeader32.SizeOfImage : (IntPtr)peMetaData.OptHeader64.SizeOfImage; 574 | 575 | Native.NtFreeVirtualMemory((IntPtr)(-1), ref pImage, ref regionSize, Data.Win32.Kernel32.MEM_RELEASE); 576 | 577 | return pCallStub; 578 | } 579 | } -------------------------------------------------------------------------------- /DInvoke.ManualMap/Overload.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | using DInvoke.DynamicInvoke; 4 | 5 | namespace DInvoke.ManualMap; 6 | 7 | public static class Overload 8 | { 9 | /// 10 | /// Locate a signed module with a minimum size which can be used for overloading. 11 | /// 12 | /// The Wover (@TheRealWover) 13 | /// Minimum module byte size. 14 | /// Whether to require that the module be legitimately signed. 15 | /// 16 | /// String, the full path for the candidate module if one is found, or an empty string if one is not found. 17 | /// 18 | public static string FindDecoyModule(long minSize, bool legitSigned = true) 19 | { 20 | var systemDirectoryPath = Environment.GetEnvironmentVariable("WINDIR") + Path.DirectorySeparatorChar + "System32"; 21 | var files = new List(Directory.GetFiles(systemDirectoryPath, "*.dll")); 22 | 23 | foreach (ProcessModule module in Process.GetCurrentProcess().Modules) 24 | { 25 | if (files.Any(s => s.Equals(module.FileName, StringComparison.OrdinalIgnoreCase))) 26 | files.RemoveAt(files.FindIndex(x => x.Equals(module.FileName, StringComparison.OrdinalIgnoreCase))); 27 | } 28 | 29 | var r = new Random(); 30 | var candidates = new List(); 31 | 32 | while (candidates.Count != files.Count) 33 | { 34 | var rInt = r.Next(0, files.Count); 35 | var currentCandidate = files[rInt]; 36 | 37 | if (candidates.Contains(rInt) == false && new FileInfo(currentCandidate).Length >= minSize) 38 | { 39 | if (legitSigned) 40 | { 41 | if (Utilities.FileHasValidSignature(currentCandidate)) 42 | return currentCandidate; 43 | 44 | candidates.Add(rInt); 45 | } 46 | else 47 | { 48 | return currentCandidate; 49 | } 50 | } 51 | 52 | candidates.Add(rInt); 53 | } 54 | 55 | return string.Empty; 56 | } 57 | 58 | /// 59 | /// Load a signed decoy module into memory, creating legitimate file-backed memory sections within the process. Afterwards overload that 60 | /// module by manually mapping a payload in it's place causing the payload to execute from what appears to be file-backed memory. 61 | /// 62 | /// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec) 63 | /// Full path to the payload module on disk. 64 | /// Optional, full path the decoy module to overload in memory. 65 | /// Whether to require that the module be legitimately signed. 66 | /// PE.PE_MANUAL_MAP 67 | public static Data.PE.PE_MANUAL_MAP OverloadModule(string payloadPath, string decoyModulePath = null, bool legitSigned = true) 68 | { 69 | if (!File.Exists(payloadPath)) 70 | throw new InvalidOperationException("Payload filepath not found."); 71 | 72 | var payload = File.ReadAllBytes(payloadPath); 73 | 74 | return OverloadModule(payload, decoyModulePath, legitSigned); 75 | } 76 | 77 | /// 78 | /// Load a signed decoy module into memory creating legitimate file-backed memory sections within the process. Afterwards overload that 79 | /// module by manually mapping a payload in it's place causing the payload to execute from what appears to be file-backed memory. 80 | /// 81 | /// The Wover (@TheRealWover), Ruben Boonen (@FuzzySec) 82 | /// Full byte array for the payload module. 83 | /// Optional, full path the decoy module to overload in memory. 84 | /// Whether to require that the module be legitimately signed. 85 | /// PE.PE_MANUAL_MAP 86 | public static Data.PE.PE_MANUAL_MAP OverloadModule(byte[] payload, string decoyModulePath = null, bool legitSigned = true) 87 | { 88 | if (!string.IsNullOrEmpty(decoyModulePath)) 89 | { 90 | if (!File.Exists(decoyModulePath)) 91 | throw new InvalidOperationException("Decoy filepath not found."); 92 | 93 | var decoyFileBytes = File.ReadAllBytes(decoyModulePath); 94 | 95 | if (decoyFileBytes.Length < payload.Length) 96 | throw new InvalidOperationException("Decoy module is too small to host the payload."); 97 | } 98 | else 99 | { 100 | decoyModulePath = FindDecoyModule(payload.Length, legitSigned); 101 | 102 | if (string.IsNullOrEmpty(decoyModulePath)) 103 | throw new InvalidOperationException("Failed to find suitable decoy module."); 104 | } 105 | 106 | var decoyMetaData = Map.MapModuleFromDiskToSection(decoyModulePath); 107 | var regionSize = decoyMetaData.PEINFO.Is32Bit ? (IntPtr)decoyMetaData.PEINFO.OptHeader32.SizeOfImage : (IntPtr)decoyMetaData.PEINFO.OptHeader64.SizeOfImage; 108 | 109 | DynamicInvoke.Native.NtProtectVirtualMemory((IntPtr)(-1), ref decoyMetaData.ModuleBase, ref regionSize, Data.Win32.WinNT.PAGE_READWRITE); 110 | DynamicInvoke.Native.RtlZeroMemory(decoyMetaData.ModuleBase, (int)regionSize); 111 | 112 | var overloadedModuleMetaData = Map.MapModuleToMemory(payload, decoyMetaData.ModuleBase); 113 | overloadedModuleMetaData.DecoyModule = decoyModulePath; 114 | 115 | return overloadedModuleMetaData; 116 | } 117 | } -------------------------------------------------------------------------------- /DInvoke.Tests/DInvoke.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | disable 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /DInvoke.Tests/DynamicInvokeTests.cs: -------------------------------------------------------------------------------- 1 | global using DInvoke.DynamicInvoke; 2 | 3 | namespace DInvoke.Tests; 4 | 5 | public sealed class DynamicInvokeTests 6 | { 7 | private const long KEY = 0xdeadbeef; 8 | 9 | [Fact] 10 | public void GetLibraryAddressByName() 11 | { 12 | var hFunction = Generic.GetLibraryAddress( 13 | "kernel32.dll", 14 | "OpenProcess"); 15 | 16 | Assert.False(hFunction == IntPtr.Zero); 17 | } 18 | 19 | [Fact] 20 | public void GetLibraryAddressByOrdinal() 21 | { 22 | var ordinal = IntPtr.Size == 8 23 | ? 0x42F 24 | : 0x42D; 25 | 26 | var hFunction = Generic.GetLibraryAddress( 27 | "kernel32.dll", 28 | (short)ordinal); 29 | 30 | Assert.False(hFunction == IntPtr.Zero); 31 | } 32 | 33 | [Fact] 34 | public void GetLibraryAddressByHash() 35 | { 36 | var hash = Utilities.GetApiHash("OpenProcess", KEY); 37 | var hFunction = Generic.GetLibraryAddress( 38 | "kernel32.dll", 39 | hash, 40 | KEY); 41 | 42 | Assert.False(hFunction == IntPtr.Zero); 43 | } 44 | 45 | [Fact] 46 | public void GetLoadedModuleAddressByHash() 47 | { 48 | var hash = Utilities.GetApiHash("kernel32.dll", KEY); 49 | var hLibrary = Generic.GetLoadedModuleAddress( 50 | hash, 51 | KEY); 52 | 53 | Assert.False(hLibrary == IntPtr.Zero); 54 | } 55 | 56 | [Fact] 57 | public void GetPebAddress() 58 | { 59 | var hPeb = Generic.GetPebAddress(); 60 | Assert.False(hPeb == IntPtr.Zero); 61 | } 62 | 63 | [Fact] 64 | public void GetPebLdrModuleEntry() 65 | { 66 | var hModule = Generic.GetPebLdrModuleEntry("kernel32.dll"); 67 | Assert.False(hModule == IntPtr.Zero); 68 | } 69 | 70 | [Fact] 71 | public void GetSyscallStubByName() 72 | { 73 | byte[] expected = 74 | [ 75 | 0x49, 0x89, 0xCA, // mov r10, rcx 76 | 0xB8, 0x26, 0x00, 0x00, 0x00, // mov eax, ssn 77 | 0x0F, 0x05, // syscall 78 | 0xC3 // ret 79 | ]; 80 | 81 | var pPeb = Generic.GetPebAddress(); 82 | var stub = Generic.GetSyscallStub(pPeb, "NtOpenProcess"); 83 | 84 | Assert.Equal(expected, stub); 85 | } 86 | 87 | [Fact] 88 | public void GetSyscallStubByHash() 89 | { 90 | byte[] expected = 91 | [ 92 | 0x49, 0x89, 0xCA, // mov r10, rcx 93 | 0xB8, 0x26, 0x00, 0x00, 0x00, // mov eax, ssn 94 | 0x0F, 0x05, // syscall 95 | 0xC3 // ret 96 | ]; 97 | 98 | var hash = Utilities.GetApiHash("NtOpenProcess", KEY); 99 | var pPeb = Generic.GetPebAddress(); 100 | var stub = Generic.GetSyscallStub(pPeb, hash, KEY); 101 | 102 | Assert.Equal(expected, stub); 103 | } 104 | 105 | [Fact] 106 | public void GetNativeExportAddress() 107 | { 108 | var hModule = Generic.GetLoadedModuleAddress("kernel32.dll"); 109 | var hExport = Generic.GetNativeExportAddress(hModule, "OpenProcess"); 110 | 111 | Assert.False(hExport == IntPtr.Zero); 112 | } 113 | } -------------------------------------------------------------------------------- /DInvoke.Tests/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; -------------------------------------------------------------------------------- /DInvoke.Tests/ManualMapTests.cs: -------------------------------------------------------------------------------- 1 | global using DInvoke.ManualMap; 2 | 3 | namespace DInvoke.Tests; 4 | 5 | public sealed class ManualMapTests 6 | { 7 | [Fact] 8 | public void MapModuleFromDiskToSection() 9 | { 10 | var map = Map.MapModuleFromDiskToSection(@"C:\Windows\System32\secur32.dll"); 11 | Assert.False(map.ModuleBase == IntPtr.Zero); 12 | } 13 | 14 | [Fact] 15 | public void FindDecoyModule() 16 | { 17 | var decoy = Overload.FindDecoyModule(666); 18 | Assert.False(string.IsNullOrWhiteSpace(decoy)); 19 | } 20 | 21 | [Fact] 22 | public void OverloadModule() 23 | { 24 | const string decoy = @"C:\Windows\System32\xpsservices.dll"; 25 | 26 | var map = Overload.OverloadModule( 27 | @"C:\Windows\System32\ntdll.dll", 28 | decoy); 29 | 30 | Assert.Equal(decoy, map.DecoyModule); 31 | Assert.False(map.ModuleBase == IntPtr.Zero); 32 | } 33 | } -------------------------------------------------------------------------------- /DInvoke.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DInvoke.DynamicInvoke", "DInvoke.DynamicInvoke\DInvoke.DynamicInvoke.csproj", "{ADE0D0BB-A2A4-4058-8E36-0EC95123C13C}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DInvoke.Data", "DInvoke.Data\DInvoke.Data.csproj", "{D233C115-243B-4BE2-A520-C4E74AD5E00E}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DInvoke.ManualMap", "DInvoke.ManualMap\DInvoke.ManualMap.csproj", "{F71F41B0-56FE-4FA0-A4D9-1F9A9C31E09C}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DInvoke.Tests", "DInvoke.Tests\DInvoke.Tests.csproj", "{4D7A58BC-CF93-4416-B095-7C83292B112A}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Any CPU = Debug|Any CPU 14 | Release|Any CPU = Release|Any CPU 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {ADE0D0BB-A2A4-4058-8E36-0EC95123C13C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {ADE0D0BB-A2A4-4058-8E36-0EC95123C13C}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {ADE0D0BB-A2A4-4058-8E36-0EC95123C13C}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {ADE0D0BB-A2A4-4058-8E36-0EC95123C13C}.Release|Any CPU.Build.0 = Release|Any CPU 21 | {D233C115-243B-4BE2-A520-C4E74AD5E00E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {D233C115-243B-4BE2-A520-C4E74AD5E00E}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {D233C115-243B-4BE2-A520-C4E74AD5E00E}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {D233C115-243B-4BE2-A520-C4E74AD5E00E}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {F71F41B0-56FE-4FA0-A4D9-1F9A9C31E09C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {F71F41B0-56FE-4FA0-A4D9-1F9A9C31E09C}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {F71F41B0-56FE-4FA0-A4D9-1F9A9C31E09C}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {F71F41B0-56FE-4FA0-A4D9-1F9A9C31E09C}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {4D7A58BC-CF93-4416-B095-7C83292B112A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {4D7A58BC-CF93-4416-B095-7C83292B112A}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {4D7A58BC-CF93-4416-B095-7C83292B112A}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {4D7A58BC-CF93-4416-B095-7C83292B112A}.Release|Any CPU.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # D/Invoke 2 | 3 | Fork of [D/Invoke by TheWover](https://github.com/TheWover/DInvoke), but refactored to .NET Standard 2.0 and split into individual NuGet packages. 4 | 5 | ## Why? 6 | 7 | The aim of this project is to provide D/Invoke in a more minimalist form. It only contains the core DynamicInvoke and ManualMap functionality, without all the additional helper methods and delegates. This help keeps the packages small and lowers the detection surface for AV. 8 | 9 | ## Examples 10 | 11 | ### DynamicApiInvoke 12 | 13 | Define the delegates and any strucs/enums that you need. Some common ones are provided in the `DInvoke.Data` namespace. 14 | 15 | ```c# 16 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] 17 | private delegate Data.Native.NTSTATUS NtOpenProcessDelegate( 18 | out SafeProcessHandle processHandle, 19 | Data.Win32.WinNT.ACCESS_MASK desiredAccess, 20 | Data.Native.OBJECT_ATTRIBUTES objectAttributes, 21 | CLIENT_ID clientId); 22 | 23 | private struct CLIENT_ID 24 | { 25 | public IntPtr UniqueProcess; 26 | public IntPtr UniqueThread; 27 | } 28 | ``` 29 | 30 | Initialise the parameters and bundle them into an `object[]`. 31 | 32 | ```c# 33 | var handle = new SafeProcessHandle(); 34 | var oa = new Data.Native.OBJECT_ATTRIBUTES(); 35 | var cid = new CLIENT_ID { UniqueProcess = 1234 }; 36 | 37 | object[] parameters = [ handle, Data.Win32.WinNT.ACCESS_MASK.MAXIMUM_ALLOWED, oa, cid ]; 38 | ``` 39 | 40 | Call `DynamicApiInvoke` specifying the DLL name, the API name, the delegate, and the function parameters. The output data type is specified as a generic, `T`. Most NT APIs return a type of `NTSTATUS`, which is a `uint`. 41 | 42 | ```c# 43 | var status = DynamicInvoke.Generic.DynamicApiInvoke( 44 | "ntdll.dll", 45 | "NtOpenProcess", 46 | typeof(NtOpenProcessDelegate), 47 | ref parameters); 48 | ``` 49 | 50 | Parameters marked as `out` need to be read out of the `parameters` array and cast back onto the original variable. 51 | 52 | ```c# 53 | handle = (SafeProcessHandle)parameters[0]; 54 | ``` 55 | 56 | ### Function Hashing 57 | 58 | Use a tool such as [CSharpRepl](https://github.com/waf/CSharpRepl) to import `DInvoke.DynamicInvoke.dll`. Call `Utilities.GetApiHash` to generate a hash for the desired DLL name and API. 59 | 60 | ``` 61 | > #r "C:\Tools\DInvoke\DInvoke.DynamicInvoke\bin\Debug\netstandard2.0\DInvoke.DynamicInvoke.dll" 62 | 63 | > DInvoke.DynamicInvoke.Utilities.GetApiHash("ntdll.dll", 0x123456789) 64 | "9BC00C9AC691986FE3CEEDA6E12F9FB0" 65 | 66 | > DInvoke.DynamicInvoke.Utilities.GetApiHash("NtOpenProcess", 0x123456789) 67 | "9713035EC6AE7BB32303F84822AB80AA" 68 | ``` 69 | 70 | Use `GetLoadedModuleAddress` to resolve the address of the DLL and `GetExportAddress` to resolve the address of the target function. 71 | 72 | ```c# 73 | var hModule = DynamicInvoke.Generic.GetLoadedModuleAddress( 74 | "9BC00C9AC691986FE3CEEDA6E12F9FB0", // ntdll.dll 75 | key); 76 | 77 | var hPointer = DynamicInvoke.Generic.GetExportAddress( 78 | hModule, 79 | "9713035EC6AE7BB32303F84822AB80AA", // NtOpenProcess 80 | key); 81 | ``` 82 | 83 | The rest of the steps are the same as above, but we call `DynamicFunctionInvoke` instead. 84 | 85 | ```c# 86 | var status = DynamicInvoke.Generic.DynamicFunctionInvoke( 87 | hPointer, 88 | typeof(NtOpenProcessDelegate), 89 | ref parameters); 90 | ``` --------------------------------------------------------------------------------