diff --git a/Scylla/DeviceNameResolver.cpp b/Scylla/DeviceNameResolver.cpp index b51b497..58c94f1 100644 --- a/Scylla/DeviceNameResolver.cpp +++ b/Scylla/DeviceNameResolver.cpp @@ -1,56 +1,98 @@ #include "DeviceNameResolver.h" +#include "NativeWinApi.h" DeviceNameResolver::DeviceNameResolver() { + NativeWinApi::initialize(); initDeviceNameList(); } DeviceNameResolver::~DeviceNameResolver() { deviceNameList.clear(); } void DeviceNameResolver::initDeviceNameList() { TCHAR shortName[3] = {0}; TCHAR longName[MAX_PATH] = {0}; HardDisk hardDisk; - shortName[1] = L':'; + shortName[1] = TEXT(':'); deviceNameList.reserve(3); for ( TCHAR shortD = TEXT('a'); shortD < TEXT('z'); shortD++ ) { shortName[0] = shortD; if (QueryDosDevice( shortName, longName, MAX_PATH ) > 0) { hardDisk.shortName[0] = _totupper(shortD); hardDisk.shortName[1] = TEXT(':'); hardDisk.shortName[2] = 0; hardDisk.longNameLength = _tcslen(longName); _tcscpy_s(hardDisk.longName, longName); deviceNameList.push_back(hardDisk); } } + + fixVirtualDevices(); } -bool DeviceNameResolver::resolveDeviceLongNameToShort( WCHAR * sourcePath, WCHAR * targetPath ) +bool DeviceNameResolver::resolveDeviceLongNameToShort(const TCHAR * sourcePath, TCHAR * targetPath) { for (unsigned int i = 0; i < deviceNameList.size(); i++) { if (!_tcsnicmp(deviceNameList[i].longName, sourcePath, deviceNameList[i].longNameLength)) { _tcscpy_s(targetPath, MAX_PATH, deviceNameList[i].shortName); _tcscat_s(targetPath, MAX_PATH, sourcePath + deviceNameList[i].longNameLength); return true; } } return false; } +void DeviceNameResolver::fixVirtualDevices() +{ + WCHAR longCopy[MAX_PATH] = {0}; + OBJECT_ATTRIBUTES oa = {0}; + UNICODE_STRING unicodeInput = {0}; + UNICODE_STRING unicodeOutput = {0}; + HANDLE hFile = 0; + ULONG retLen = 0; + HardDisk hardDisk; + + unicodeOutput.Length = MAX_PATH * 2 * sizeof(WCHAR); + unicodeOutput.MaximumLength = unicodeOutput.Length; + unicodeOutput.Buffer = (PWSTR)calloc(unicodeOutput.Length, 1); + + for (unsigned int i = 0; i < deviceNameList.size(); i++) + { + wcscpy_s(longCopy, deviceNameList[i].longName); + + NativeWinApi::RtlInitUnicodeString(&unicodeInput, longCopy); + InitializeObjectAttributes(&oa, &unicodeInput, 0, 0, 0); + + if(NT_SUCCESS(NativeWinApi::NtOpenSymbolicLinkObject(&hFile, SYMBOLIC_LINK_QUERY, &oa))) + { + if (NT_SUCCESS(NativeWinApi::NtQuerySymbolicLinkObject(hFile, &unicodeOutput, &retLen))) + { + hardDisk.longNameLength = wcslen(unicodeOutput.Buffer); + wcscpy_s(hardDisk.shortName, deviceNameList[i].shortName); + wcscpy_s(hardDisk.longName, unicodeOutput.Buffer); + deviceNameList.push_back(hardDisk); + } + + NativeWinApi::NtClose(hFile); + } + } + + free(unicodeOutput.Buffer); +} + diff --git a/Scylla/DeviceNameResolver.h b/Scylla/DeviceNameResolver.h index 8eb2801..c46623a 100644 --- a/Scylla/DeviceNameResolver.h +++ b/Scylla/DeviceNameResolver.h @@ -1,28 +1,29 @@ #include #pragma once #include #include #include class HardDisk { public: - WCHAR shortName[3]; - WCHAR longName[MAX_PATH]; + TCHAR shortName[3]; + TCHAR longName[MAX_PATH]; size_t longNameLength; }; class DeviceNameResolver { public: DeviceNameResolver(); ~DeviceNameResolver(); - bool resolveDeviceLongNameToShort( WCHAR * sourcePath, WCHAR * targetPath ); + bool resolveDeviceLongNameToShort(const TCHAR * sourcePath, TCHAR * targetPath); private: std::vector deviceNameList; void initDeviceNameList(); + void fixVirtualDevices(); }; diff --git a/Scylla/NativeWinApi.cpp b/Scylla/NativeWinApi.cpp index 7077c4d..2e38758 100644 --- a/Scylla/NativeWinApi.cpp +++ b/Scylla/NativeWinApi.cpp @@ -1,72 +1,83 @@ #include "NativeWinApi.h" def_NtCreateThreadEx NativeWinApi::NtCreateThreadEx = 0; def_NtDuplicateObject NativeWinApi::NtDuplicateObject = 0; def_NtOpenProcess NativeWinApi::NtOpenProcess = 0; def_NtOpenThread NativeWinApi::NtOpenThread = 0; def_NtQueryObject NativeWinApi::NtQueryObject = 0; def_NtQueryInformationFile NativeWinApi::NtQueryInformationFile = 0; def_NtQueryInformationProcess NativeWinApi::NtQueryInformationProcess = 0; def_NtQueryInformationThread NativeWinApi::NtQueryInformationThread = 0; def_NtQuerySystemInformation NativeWinApi::NtQuerySystemInformation = 0; def_NtQueryVirtualMemory NativeWinApi::NtQueryVirtualMemory = 0; def_NtResumeProcess NativeWinApi::NtResumeProcess = 0; def_NtResumeThread NativeWinApi::NtResumeThread = 0; def_NtSetInformationThread NativeWinApi::NtSetInformationThread = 0; def_NtSuspendProcess NativeWinApi::NtSuspendProcess = 0; def_NtTerminateProcess NativeWinApi::NtTerminateProcess = 0; +def_NtOpenSymbolicLinkObject NativeWinApi::NtOpenSymbolicLinkObject = 0; +def_NtQuerySymbolicLinkObject NativeWinApi::NtQuerySymbolicLinkObject = 0; + def_RtlNtStatusToDosError NativeWinApi::RtlNtStatusToDosError = 0; +def_NtClose NativeWinApi::NtClose = 0; void NativeWinApi::initialize() { + if (RtlNtStatusToDosError) + { + return; + } + HMODULE hModuleNtdll = GetModuleHandle(L"ntdll.dll"); if (!hModuleNtdll) { return; } NtCreateThreadEx = (def_NtCreateThreadEx)GetProcAddress(hModuleNtdll, "NtCreateThreadEx"); NtDuplicateObject = (def_NtDuplicateObject)GetProcAddress(hModuleNtdll, "NtDuplicateObject"); NtOpenProcess = (def_NtOpenProcess)GetProcAddress(hModuleNtdll, "NtOpenProcess"); NtOpenThread = (def_NtOpenThread)GetProcAddress(hModuleNtdll, "NtOpenThread"); NtQueryObject = (def_NtQueryObject)GetProcAddress(hModuleNtdll, "NtQueryObject"); NtQueryInformationFile = (def_NtQueryInformationFile)GetProcAddress(hModuleNtdll, "NtQueryInformationFile"); NtQueryInformationProcess = (def_NtQueryInformationProcess)GetProcAddress(hModuleNtdll, "NtQueryInformationProcess"); NtQueryInformationThread = (def_NtQueryInformationThread)GetProcAddress(hModuleNtdll, "NtQueryInformationThread"); NtQuerySystemInformation = (def_NtQuerySystemInformation)GetProcAddress(hModuleNtdll, "NtQuerySystemInformation"); NtQueryVirtualMemory = (def_NtQueryVirtualMemory)GetProcAddress(hModuleNtdll, "NtQueryVirtualMemory"); NtResumeProcess = (def_NtResumeProcess)GetProcAddress(hModuleNtdll, "NtResumeProcess"); NtResumeThread = (def_NtResumeThread)GetProcAddress(hModuleNtdll, "NtResumeThread"); NtSetInformationThread = (def_NtSetInformationThread)GetProcAddress(hModuleNtdll, "NtSetInformationThread"); NtSuspendProcess = (def_NtSuspendProcess)GetProcAddress(hModuleNtdll, "NtSuspendProcess"); NtTerminateProcess = (def_NtTerminateProcess)GetProcAddress(hModuleNtdll, "NtTerminateProcess"); + NtOpenSymbolicLinkObject = (def_NtOpenSymbolicLinkObject)GetProcAddress(hModuleNtdll, "NtOpenSymbolicLinkObject"); + NtQuerySymbolicLinkObject = (def_NtQuerySymbolicLinkObject)GetProcAddress(hModuleNtdll, "NtQuerySymbolicLinkObject"); RtlNtStatusToDosError = (def_RtlNtStatusToDosError)GetProcAddress(hModuleNtdll, "RtlNtStatusToDosError"); - + NtClose = (def_NtClose)GetProcAddress(hModuleNtdll, "NtClose"); } PPEB NativeWinApi::getCurrentProcessEnvironmentBlock() { return getProcessEnvironmentBlockAddress(GetCurrentProcess()); } PPEB NativeWinApi::getProcessEnvironmentBlockAddress(HANDLE processHandle) { ULONG lReturnLength = 0; PROCESS_BASIC_INFORMATION processBasicInformation; if ((NtQueryInformationProcess(processHandle,ProcessBasicInformation,&processBasicInformation,sizeof(PROCESS_BASIC_INFORMATION),&lReturnLength) >= 0) && (lReturnLength == sizeof(PROCESS_BASIC_INFORMATION))) { //printf("NtQueryInformationProcess success %d\n",sizeof(PROCESS_BASIC_INFORMATION)); return processBasicInformation.PebBaseAddress; } else { //printf("NtQueryInformationProcess failed %d vs %d\n",lReturnLength,sizeof(PROCESS_BASIC_INFORMATION)); return 0; } } \ No newline at end of file diff --git a/Scylla/NativeWinApi.h b/Scylla/NativeWinApi.h index c041b87..d5a66f8 100644 --- a/Scylla/NativeWinApi.h +++ b/Scylla/NativeWinApi.h @@ -1,472 +1,486 @@ #pragma once #include #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #define DUPLICATE_SAME_ATTRIBUTES 0x00000004 #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) typedef LONG KPRIORITY; typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation, SystemPathInformation, SystemProcessInformation, SystemCallCountInformation, SystemDeviceInformation, SystemProcessorPerformanceInformation, SystemFlagsInformation, SystemCallTimeInformation, SystemModuleInformation, SystemLocksInformation, SystemStackTraceInformation, SystemPagedPoolInformation, SystemNonPagedPoolInformation, SystemHandleInformation, SystemObjectInformation, SystemPageFileInformation, SystemVdmInstemulInformation, SystemVdmBopInformation, SystemFileCacheInformation, SystemPoolTagInformation, SystemInterruptInformation, SystemDpcBehaviorInformation, SystemFullMemoryInformation, SystemLoadGdiDriverInformation, SystemUnloadGdiDriverInformation, SystemTimeAdjustmentInformation, SystemSummaryMemoryInformation, SystemNextEventIdInformation, SystemEventIdsInformation, SystemCrashDumpInformation, SystemExceptionInformation, SystemCrashDumpStateInformation, SystemKernelDebuggerInformation, SystemContextSwitchInformation, SystemRegistryQuotaInformation, SystemExtendServiceTableInformation, SystemPrioritySeperation, SystemPlugPlayBusInformation, SystemDockInformation, SystemPowerInformation2, SystemProcessorSpeedInformation, SystemCurrentTimeZoneInformation, SystemLookasideInformation } SYSTEM_INFORMATION_CLASS; typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef struct _FILE_NAME_INFORMATION { // Information Classes 9 and 21 ULONG FileNameLength; WCHAR FileName[1]; } FILE_NAME_INFORMATION; typedef enum _FILE_INFORMATION_CLASS { FileNameInformation=9, } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef struct _CLIENT_ID{ HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID, *PCLIENT_ID; #define InitializeObjectAttributes(p,n,a,r,s) \ { \ (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ (p)->ObjectName = n; \ (p)->Attributes = a; \ (p)->RootDirectory = r; \ (p)->SecurityDescriptor = s; \ (p)->SecurityQualityOfService = NULL; \ } typedef struct _OBJECT_ATTRIBUTES { ULONG Length; PVOID RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; typedef struct _MEMORY_REGION_INFORMATION { PVOID AllocationBase; //Imagebase ULONG AllocationProtect; ULONG RegionType; SIZE_T RegionSize; //Size of image } MEMORY_REGION_INFORMATION, *PMEMORY_REGION_INFORMATION; typedef enum _OBJECT_INFORMATION_CLASS { ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllInformation, ObjectDataInformation } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; typedef enum _THREADINFOCLASS { ThreadBasicInformation, ThreadTimes, ThreadPriority, ThreadBasePriority, ThreadAffinityMask, ThreadImpersonationToken, ThreadDescriptorTableEntry, ThreadEnableAlignmentFaultFixup, ThreadEventPair_Reusable, ThreadQuerySetWin32StartAddress, ThreadZeroTlsCell, ThreadPerformanceCount, ThreadAmILastThread, ThreadIdealProcessor, ThreadPriorityBoost, ThreadSetTlsArrayAddress, ThreadIsIoPending, ThreadHideFromDebugger, ThreadBreakOnTermination, MaxThreadInfoClass } THREADINFOCLASS; // // Memory Information Classes for NtQueryVirtualMemory // typedef enum _MEMORY_INFORMATION_CLASS { MemoryBasicInformation, MemoryWorkingSetInformation, MemoryMappedFilenameInformation, //MemorySectionName, UNICODE_STRING, Wrapper: GetMappedFileNameW MemoryRegionInformation, //MemoryBasicVlmInformation, MEMORY_REGION_INFORMATION MemoryWorkingSetExInformation } MEMORY_INFORMATION_CLASS; typedef enum _PROCESSINFOCLASS { ProcessBasicInformation, ProcessQuotaLimits, ProcessIoCounters, ProcessVmCounters, ProcessTimes, ProcessBasePriority, ProcessRaisePriority, ProcessDebugPort, ProcessExceptionPort, ProcessAccessToken, ProcessLdtInformation, ProcessLdtSize, ProcessDefaultHardErrorMode, ProcessIoPortHandlers, ProcessPooledUsageAndLimits, ProcessWorkingSetWatch, ProcessUserModeIOPL, ProcessEnableAlignmentFaultFixup, ProcessPriorityClass, ProcessWx86Information, ProcessHandleCount, ProcessAffinityMask, ProcessPriorityBoost, ProcessDeviceMap, ProcessSessionInformation, ProcessForegroundInformation, ProcessWow64Information, ProcessImageFileName, ProcessLUIDDeviceMapsEnabled, ProcessBreakOnTermination, ProcessDebugObjectHandle, ProcessDebugFlags, ProcessHandleTracing, ProcessIoPriority, ProcessExecuteFlags, ProcessResourceManagement, ProcessCookie, ProcessImageInformation, MaxProcessInfoClass } PROCESSINFOCLASS; typedef struct _PEB_LDR_DATA { BYTE Reserved1[8]; PVOID Reserved2[3]; LIST_ENTRY InMemoryOrderModuleList; } PEB_LDR_DATA, *PPEB_LDR_DATA; typedef struct _RTL_USER_PROCESS_PARAMETERS { BYTE Reserved1[16]; PVOID Reserved2[10]; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PVOID PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId; } PEB, *PPEB; typedef struct _PROCESS_BASIC_INFORMATION { PVOID Reserved1; PPEB PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; } PROCESS_BASIC_INFORMATION; typedef struct _MEMORY_WORKING_SET_LIST { ULONG NumberOfPages; ULONG WorkingSetList[1]; } MEMORY_WORKING_SET_LIST, *PMEMORY_WORKING_SET_LIST; typedef struct _MEMORY_SECTION_NAME { UNICODE_STRING SectionFileName; } MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME; typedef struct _SYSTEM_SESSION_PROCESS_INFORMATION { ULONG SessionId; ULONG SizeOfBuf; PVOID Buffer; } SYSTEM_SESSION_PROCESS_INFORMATION, *PSYSTEM_SESSION_PROCESS_INFORMATION; typedef struct _SYSTEM_THREAD_INFORMATION { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientId; KPRIORITY Priority; LONG BasePriority; ULONG ContextSwitches; ULONG ThreadState; ULONG WaitReason; } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION { SYSTEM_THREAD_INFORMATION ThreadInfo; PVOID StackBase; PVOID StackLimit; PVOID Win32StartAddress; PVOID TebAddress; /* This is only filled in on Vista and above */ ULONG_PTR Reserved2; ULONG_PTR Reserved3; ULONG_PTR Reserved4; } SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION; typedef struct _SYSTEM_PROCESS_INFORMATION { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER SpareLi1; LARGE_INTEGER SpareLi2; LARGE_INTEGER SpareLi3; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ImageName; KPRIORITY BasePriority; HANDLE UniqueProcessId; HANDLE InheritedFromUniqueProcessId; ULONG HandleCount; ULONG SessionId; ULONG_PTR PageDirectoryBase; SIZE_T PeakVirtualSize; SIZE_T VirtualSize; ULONG PageFaultCount; SIZE_T PeakWorkingSetSize; SIZE_T WorkingSetSize; SIZE_T QuotaPeakPagedPoolUsage; SIZE_T QuotaPagedPoolUsage; SIZE_T QuotaPeakNonPagedPoolUsage; SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; SIZE_T PrivatePageCount; LARGE_INTEGER ReadOperationCount; LARGE_INTEGER WriteOperationCount; LARGE_INTEGER OtherOperationCount; LARGE_INTEGER ReadTransferCount; LARGE_INTEGER WriteTransferCount; LARGE_INTEGER OtherTransferCount; SYSTEM_THREAD_INFORMATION Threads[1]; } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; /////////////////////////////////////////////////////////////////////////////////////// //Evolution of Process Environment Block (PEB) http://blog.rewolf.pl/blog/?p=573 //March 2, 2013 / ReWolf posted in programming, reverse engineering, source code, x64 / #pragma pack(push) #pragma pack(1) template struct LIST_ENTRY_T { T Flink; T Blink; }; template struct UNICODE_STRING_T { union { struct { WORD Length; WORD MaximumLength; }; T dummy; }; T _Buffer; }; template struct _PEB_T { union { struct { BYTE InheritedAddressSpace; BYTE ReadImageFileExecOptions; BYTE BeingDebugged; BYTE _SYSTEM_DEPENDENT_01; }; T dummy01; }; T Mutant; T ImageBaseAddress; T Ldr; T ProcessParameters; T SubSystemData; T ProcessHeap; T FastPebLock; T _SYSTEM_DEPENDENT_02; T _SYSTEM_DEPENDENT_03; T _SYSTEM_DEPENDENT_04; union { T KernelCallbackTable; T UserSharedInfoPtr; }; DWORD SystemReserved; DWORD _SYSTEM_DEPENDENT_05; T _SYSTEM_DEPENDENT_06; T TlsExpansionCounter; T TlsBitmap; DWORD TlsBitmapBits[2]; T ReadOnlySharedMemoryBase; T _SYSTEM_DEPENDENT_07; T ReadOnlyStaticServerData; T AnsiCodePageData; T OemCodePageData; T UnicodeCaseTableData; DWORD NumberOfProcessors; union { DWORD NtGlobalFlag; NGF dummy02; }; LARGE_INTEGER CriticalSectionTimeout; T HeapSegmentReserve; T HeapSegmentCommit; T HeapDeCommitTotalFreeThreshold; T HeapDeCommitFreeBlockThreshold; DWORD NumberOfHeaps; DWORD MaximumNumberOfHeaps; T ProcessHeaps; }; typedef _PEB_T PEB32; typedef _PEB_T PEB64; #ifdef _WIN64 typedef PEB64 PEB_CURRENT; #else typedef PEB32 PEB_CURRENT; #endif #pragma pack(pop) typedef NTSTATUS (WINAPI *def_NtTerminateProcess)(HANDLE ProcessHandle, NTSTATUS ExitStatus); typedef NTSTATUS (WINAPI *def_NtQueryObject)(HANDLE Handle,OBJECT_INFORMATION_CLASS ObjectInformationClass,PVOID ObjectInformation,ULONG ObjectInformationLength,PULONG ReturnLength); typedef NTSTATUS (WINAPI *def_NtDuplicateObject)(HANDLE SourceProcessHandle, HANDLE SourceHandle, HANDLE TargetProcessHandle, PHANDLE TargetHandle, ACCESS_MASK DesiredAccess, BOOLEAN InheritHandle, ULONG Options ); typedef NTSTATUS (WINAPI *def_NtQueryInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); typedef NTSTATUS (WINAPI *def_NtQueryInformationThread)(HANDLE ThreadHandle,THREADINFOCLASS ThreadInformationClass,PVOID ThreadInformation,ULONG ThreadInformationLength,PULONG ReturnLength); typedef NTSTATUS (WINAPI *def_NtQueryInformationProcess)(HANDLE ProcessHandle,PROCESSINFOCLASS ProcessInformationClass,PVOID ProcessInformation,ULONG ProcessInformationLength,PULONG ReturnLength); typedef NTSTATUS (WINAPI *def_NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass,PVOID SystemInformation,ULONG SystemInformationLength, PULONG ReturnLength); typedef NTSTATUS (WINAPI *def_NtQueryVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength); typedef NTSTATUS (WINAPI *def_NtOpenProcess)(PHANDLE ProcessHandle, ACCESS_MASK AccessMask, PVOID ObjectAttributes, PCLIENT_ID ClientId ); typedef NTSTATUS (WINAPI *def_NtOpenThread)(PHANDLE ThreadHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PCLIENT_ID ClientId); typedef NTSTATUS (WINAPI *def_NtResumeThread)(HANDLE ThreadHandle, PULONG SuspendCount); typedef NTSTATUS (WINAPI *def_NtSetInformationThread)(HANDLE ThreadHandle,THREADINFOCLASS ThreadInformationClass,PVOID ThreadInformation,ULONG ThreadInformationLength); typedef NTSTATUS (WINAPI *def_NtCreateThreadEx)(PHANDLE hThread,ACCESS_MASK DesiredAccess,LPVOID ObjectAttributes,HANDLE ProcessHandle,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,int CreateFlags,ULONG StackZeroBits,LPVOID SizeOfStackCommit,LPVOID SizeOfStackReserve,LPVOID lpBytesBuffer); typedef NTSTATUS (WINAPI *def_NtSuspendProcess)(HANDLE ProcessHandle); typedef NTSTATUS (WINAPI *def_NtResumeProcess)(HANDLE ProcessHandle); +typedef NTSTATUS (WINAPI *def_NtOpenSymbolicLinkObject)(PHANDLE LinkHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes); +typedef NTSTATUS (WINAPI *def_NtQuerySymbolicLinkObject)(HANDLE LinkHandle,PUNICODE_STRING LinkTarget,PULONG ReturnedLength); + typedef ULONG (WINAPI *def_RtlNtStatusToDosError)(NTSTATUS Status); +typedef NTSTATUS (WINAPI *def_NtClose)(HANDLE Handle); //Flags from waliedassar #define NtCreateThreadExFlagCreateSuspended 0x1 #define NtCreateThreadExFlagSuppressDllMains 0x2 #define NtCreateThreadExFlagHideFromDebugger 0x4 +#define SYMBOLIC_LINK_QUERY (0x0001) + class NativeWinApi { public: static def_NtCreateThreadEx NtCreateThreadEx; static def_NtDuplicateObject NtDuplicateObject; static def_NtOpenProcess NtOpenProcess; static def_NtOpenThread NtOpenThread; static def_NtQueryObject NtQueryObject; static def_NtQueryInformationFile NtQueryInformationFile; static def_NtQueryInformationProcess NtQueryInformationProcess; static def_NtQueryInformationThread NtQueryInformationThread; static def_NtQuerySystemInformation NtQuerySystemInformation; static def_NtQueryVirtualMemory NtQueryVirtualMemory; static def_NtResumeProcess NtResumeProcess; static def_NtResumeThread NtResumeThread; static def_NtSetInformationThread NtSetInformationThread; static def_NtSuspendProcess NtSuspendProcess; static def_NtTerminateProcess NtTerminateProcess; + static def_NtOpenSymbolicLinkObject NtOpenSymbolicLinkObject; + static def_NtQuerySymbolicLinkObject NtQuerySymbolicLinkObject; - + static def_NtClose NtClose; static def_RtlNtStatusToDosError RtlNtStatusToDosError; + static void RtlInitUnicodeString(PUNICODE_STRING DestinationString, PWSTR SourceString) + { + DestinationString->Buffer = SourceString; + DestinationString->MaximumLength = DestinationString->Length = (USHORT)wcslen(SourceString) * sizeof(WCHAR); + } + static void initialize(); static PPEB getCurrentProcessEnvironmentBlock(); static PPEB getProcessEnvironmentBlockAddress(HANDLE processHandle); }; diff --git a/Scylla/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp index baaef34..a11048b 100644 --- a/Scylla/ProcessAccessHelp.cpp +++ b/Scylla/ProcessAccessHelp.cpp @@ -1,930 +1,935 @@ #include "ProcessAccessHelp.h" #include "Scylla.h" #include "NativeWinApi.h" #include "PeParser.h" HANDLE ProcessAccessHelp::hProcess = 0; ModuleInfo * ProcessAccessHelp::selectedModule; DWORD_PTR ProcessAccessHelp::targetImageBase = 0; DWORD_PTR ProcessAccessHelp::targetSizeOfImage = 0; DWORD_PTR ProcessAccessHelp::maxValidAddress = 0; std::vector ProcessAccessHelp::moduleList; //target process module list std::vector ProcessAccessHelp::ownModuleList; //own module list _DInst ProcessAccessHelp::decomposerResult[MAX_INSTRUCTIONS]; unsigned int ProcessAccessHelp::decomposerInstructionsCount = 0; _CodeInfo ProcessAccessHelp::decomposerCi = {0}; _DecodedInst ProcessAccessHelp::decodedInstructions[MAX_INSTRUCTIONS]; unsigned int ProcessAccessHelp::decodedInstructionsCount = 0; BYTE ProcessAccessHelp::fileHeaderFromDisk[PE_HEADER_BYTES_COUNT]; //#define DEBUG_COMMENTS bool ProcessAccessHelp::openProcessHandle(DWORD dwPID) { if (dwPID > 0) { if (hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: There is already a process handle, HANDLE %X", hProcess); #endif return false; } else { //hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, dwPID); //if (!NT_SUCCESS(NativeWinApi::NtOpenProcess(&hProcess,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE,&ObjectAttributes, &cid))) hProcess = NativeOpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_SUSPEND_RESUME|PROCESS_TERMINATE, dwPID); if (hProcess) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: Failed to open handle, PID %X", dwPID); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"openProcessHandle :: Wrong PID, PID %X", dwPID); #endif return false; } } HANDLE ProcessAccessHelp::NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId) { HANDLE hProcess = 0; CLIENT_ID cid = {0}; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS ntStatus = 0; InitializeObjectAttributes(&ObjectAttributes, 0, 0, 0, 0); cid.UniqueProcess = (HANDLE)dwProcessId; ntStatus = NativeWinApi::NtOpenProcess(&hProcess,dwDesiredAccess,&ObjectAttributes, &cid); if (NT_SUCCESS(ntStatus)) { return hProcess; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X", dwProcessId, NativeWinApi::RtlNtStatusToDosError(ntStatus)); #endif return 0; } } void ProcessAccessHelp::closeProcessHandle() { if (hProcess) { CloseHandle(hProcess); hProcess = 0; } moduleList.clear(); targetImageBase = 0; selectedModule = 0; } bool ProcessAccessHelp::readMemoryPartlyFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) { DWORD_PTR addressPart = 0; DWORD_PTR readBytes = 0; DWORD_PTR bytesToRead = 0; MEMORY_BASIC_INFORMATION memBasic = {0}; bool returnValue = false; if (!hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: hProcess == NULL"); #endif return returnValue; } if (!readMemoryFromProcess(address, size, dataBuffer)) { addressPart = address; do { if (!VirtualQueryEx(ProcessAccessHelp::hProcess,(LPCVOID)addressPart,&memBasic,sizeof(memBasic))) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: Error VirtualQueryEx %X %X err: %u", addressPart,size, GetLastError()); #endif break; } bytesToRead = memBasic.RegionSize; if ( (readBytes+bytesToRead) > size) { bytesToRead = size - readBytes; } if (memBasic.State == MEM_COMMIT) { if (!readMemoryFromProcess(addressPart, bytesToRead, (LPVOID)((DWORD_PTR)dataBuffer + readBytes))) { break; } } else { ZeroMemory((LPVOID)((DWORD_PTR)dataBuffer + readBytes),bytesToRead); } readBytes += bytesToRead; addressPart += memBasic.RegionSize; } while (readBytes < size); if (readBytes == size) { returnValue = true; } } else { returnValue = true; } return returnValue; } bool ProcessAccessHelp::writeMemoryToProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) { SIZE_T lpNumberOfBytesWritten = 0; if (!hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL"); #endif return false; } return (WriteProcessMemory(hProcess,(LPVOID)address, dataBuffer, size,&lpNumberOfBytesWritten) != FALSE); } bool ProcessAccessHelp::readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer) { SIZE_T lpNumberOfBytesRead = 0; DWORD dwProtect = 0; bool returnValue = false; if (!hProcess) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL"); #endif return returnValue; } if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError()); #endif if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u", address,size, GetLastError()); #endif returnValue = false; } else { if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError()); #endif returnValue = false; } else { returnValue = true; } VirtualProtectEx(hProcess, (LPVOID)address, size, dwProtect, &dwProtect); } } else { returnValue = true; } if (returnValue) { if (size != lpNumberOfBytesRead) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes", lpNumberOfBytesRead, size); #endif returnValue = false; } else { returnValue = true; } } return returnValue; } bool ProcessAccessHelp::decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress) { ZeroMemory(&decomposerCi, sizeof(_CodeInfo)); decomposerCi.code = dataBuffer; decomposerCi.codeLen = (int)bufferSize; decomposerCi.dt = dt; decomposerCi.codeOffset = startAddress; decomposerInstructionsCount = 0; if (distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult)/sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR"); #endif return false; } else { return true; } } bool ProcessAccessHelp::disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset) { // Holds the result of the decoding. _DecodeResult res; // next is used for instruction's offset synchronization. // decodedInstructionsCount holds the count of filled instructions' array by the decoder. decodedInstructionsCount = 0; _OffsetType offset = startOffset; res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount); /* for (unsigned int i = 0; i < decodedInstructionsCount; i++) { #ifdef SUPPORT_64BIT_OFFSET printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #else printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p); #endif }*/ if (res == DECRES_INPUTERR) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR"); #endif return false; } else if (res == DECRES_SUCCESS) { //printf("disassembleMemory :: res == DECRES_SUCCESS\n"); return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"disassembleMemory :: res == %d", res); #endif return true; //not all instructions fit in buffer } } DWORD_PTR ProcessAccessHelp::findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask) { DWORD pos = 0; size_t searchLen = strlen(mask) - 1; for(DWORD_PTR retAddress = startOffset; retAddress < startOffset + size; retAddress++) { if( *(BYTE*)retAddress == pattern[pos] || mask[pos] == '?' ) { if(mask[pos+1] == 0x00) { return (retAddress - searchLen); } pos++; } else { pos = 0; } } return 0; } bool ProcessAccessHelp::readHeaderFromCurrentFile(const WCHAR * filePath) { return readHeaderFromFile(fileHeaderFromDisk, sizeof(fileHeaderFromDisk), filePath); } LONGLONG ProcessAccessHelp::getFileSize(const WCHAR * filePath) { LONGLONG fileSize = 0; HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { fileSize = getFileSize(hFile); CloseHandle(hFile); } return fileSize; } LONGLONG ProcessAccessHelp::getFileSize(HANDLE hFile) { LARGE_INTEGER lpFileSize = {0}; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { if (!GetFileSizeEx(hFile, &lpFileSize)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u", GetLastError()); #endif return 0; } else { return lpFileSize.QuadPart; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize hFile invalid"); #endif return 0; } } bool ProcessAccessHelp::readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer) { DWORD lpNumberOfBytesRead = 0; DWORD retValue = 0; DWORD dwError = 0; if (hFile != INVALID_HANDLE_VALUE) { retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN); dwError = GetLastError(); if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: SetFilePointer failed error %u", dwError); #endif return false; } else { if (ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: ReadFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readMemoryFromFile :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer) { HANDLE hFile = CreateFile(file, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { bool resultValue = writeMemoryToFile(hFile,0,size,dataBuffer); CloseHandle(hFile); return resultValue; } else { return false; } } bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer) { DWORD lpNumberOfBytesWritten = 0; DWORD retValue = 0; DWORD dwError = 0; if ((hFile != INVALID_HANDLE_VALUE) && dataBuffer) { retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN); dwError = GetLastError(); if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: SetFilePointer failed error %u", dwError); #endif return false; } else { if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: WriteFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFile :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer) { DWORD lpNumberOfBytesWritten = 0; DWORD retValue = 0; if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0)) { SetFilePointer(hFile, 0, 0, FILE_END); if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0)) { return true; } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFileEnd :: WriteFile failed - size %d - error %u", size, GetLastError()); #endif return false; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"writeMemoryToFileEnd :: hFile invalid"); #endif return false; } } bool ProcessAccessHelp::readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath) { DWORD lpNumberOfBytesRead = 0; LONGLONG fileSize = 0; DWORD dwSize = 0; bool returnValue = 0; HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( hFile == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"readHeaderFromFile :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif returnValue = false; } else { fileSize = getFileSize(hFile); if (fileSize > 0) { if (fileSize > bufferSize) { dwSize = bufferSize; } else { dwSize = (DWORD)(fileSize - 1); } returnValue = readMemoryFromFile(hFile, 0, dwSize, buffer); } CloseHandle(hFile); } return returnValue; } LPVOID ProcessAccessHelp::createFileMappingViewRead(const WCHAR * filePath) { return createFileMappingView(filePath, GENERIC_READ, PAGE_READONLY | SEC_IMAGE, FILE_MAP_READ); } LPVOID ProcessAccessHelp::createFileMappingViewFull(const WCHAR * filePath) { return createFileMappingView(filePath, GENERIC_ALL, PAGE_EXECUTE_READWRITE, FILE_MAP_ALL_ACCESS); } LPVOID ProcessAccessHelp::createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap) { HANDLE hFile = CreateFile(filePath, accessFile, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if( hFile == INVALID_HANDLE_VALUE ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError()); #endif return NULL; } HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL); CloseHandle(hFile); if( hMappedFile == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: hMappedFile == NULL"); #endif return NULL; } if (GetLastError() == ERROR_ALREADY_EXISTS) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS"); #endif return NULL; } LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0); if( addrMappedDll == NULL ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL"); #endif CloseHandle(hMappedFile); return NULL; } CloseHandle(hMappedFile); return addrMappedDll; } DWORD ProcessAccessHelp::getProcessByName(const WCHAR * processName) { DWORD dwPID = 0; HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32W pe32; pe32.dwSize = sizeof(PROCESSENTRY32W); if( !Process32FirstW( hProcessSnap, &pe32 ) ) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getProcessByName :: Error getting first Process"); #endif CloseHandle( hProcessSnap ); return 0; } do { if(!_wcsicmp(pe32.szExeFile, processName)) { dwPID = pe32.th32ProcessID; break; } } while(Process32NextW(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); return dwPID; } bool ProcessAccessHelp::getProcessModules(HANDLE hProcess, std::vector &moduleList) { ModuleInfo module; WCHAR filename[MAX_PATH*2] = {0}; DWORD cbNeeded = 0; bool retVal = false; DeviceNameResolver deviceNameResolver; moduleList.reserve(20); EnumProcessModules(hProcess, 0, 0, &cbNeeded); HMODULE* hMods=(HMODULE*)malloc(cbNeeded*sizeof(HMODULE)); if (hMods) { if(EnumProcessModules(hProcess, hMods, cbNeeded, &cbNeeded)) { for(unsigned int i = 1; i < (cbNeeded/sizeof(HMODULE)); i++) //skip first module! { module.modBaseAddr = (DWORD_PTR)hMods[i]; module.modBaseSize = (DWORD)getSizeOfImageProcess(hProcess, module.modBaseAddr); module.isAlreadyParsed = false; module.parsing = false; filename[0] = 0; + module.fullPath[0] = 0; + if (GetMappedFileNameW(hProcess, (LPVOID)module.modBaseAddr, filename, _countof(filename)) > 0) { - deviceNameResolver.resolveDeviceLongNameToShort(filename, module.fullPath); + if (!deviceNameResolver.resolveDeviceLongNameToShort(filename, module.fullPath)) + { + MessageBoxW(0, filename, L"Cannot resolve this path!", MB_ICONERROR); + } } moduleList.push_back(module); } retVal = true; } free(hMods); } return retVal; } bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize) { MEMORY_BASIC_INFORMATION memBasic; if (VirtualQueryEx(hProcess,(LPCVOID)address,&memBasic,sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getMemoryRegionFromAddress :: VirtualQueryEx error %u", GetLastError()); #endif return false; } else { *memoryRegionBase = (DWORD_PTR)memBasic.BaseAddress; *memoryRegionSize = memBasic.RegionSize; return true; } } bool ProcessAccessHelp::getSizeOfImageCurrentProcess() { DWORD_PTR newSizeOfImage = getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase); if (newSizeOfImage != 0) { ProcessAccessHelp::targetSizeOfImage = newSizeOfImage; return true; } else { return false; } } SIZE_T ProcessAccessHelp::getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase) { SIZE_T sizeOfImage = 0, sizeOfImageNative = 0; MEMORY_BASIC_INFORMATION lpBuffer = {0}; sizeOfImageNative = getSizeOfImageProcessNative(processHandle, moduleBase); if (sizeOfImageNative) { return sizeOfImageNative; } WCHAR filenameOriginal[MAX_PATH*2] = {0}; WCHAR filenameTest[MAX_PATH*2] = {0}; GetMappedFileNameW(processHandle, (LPVOID)moduleBase, filenameOriginal, _countof(filenameOriginal)); do { moduleBase = (DWORD_PTR)((SIZE_T)moduleBase + lpBuffer.RegionSize); sizeOfImage += lpBuffer.RegionSize; if (!VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &lpBuffer, sizeof(MEMORY_BASIC_INFORMATION))) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getSizeOfImageProcess :: VirtualQuery failed %X", GetLastError()); #endif lpBuffer.Type = 0; sizeOfImage = 0; } GetMappedFileNameW(processHandle, (LPVOID)moduleBase, filenameTest, _countof(filenameTest)); if (_wcsicmp(filenameOriginal,filenameTest) != 0)//problem: 2 modules without free space { break; } } while (lpBuffer.Type == MEM_IMAGE); //if (sizeOfImage != sizeOfImageNative) //{ // WCHAR temp[1000] = {0}; // wsprintfW(temp, L"0x%X sizeofimage\n0x%X sizeOfImageNative", sizeOfImage, sizeOfImageNative); // MessageBoxW(0, temp, L"Test", 0); //} return sizeOfImage; } DWORD ProcessAccessHelp::getEntryPointFromFile(const WCHAR * filePath) { PeParser peFile(filePath, false); return peFile.getEntryPoint(); } bool ProcessAccessHelp::createBackupFile(const WCHAR * filePath) { size_t fileNameLength = wcslen(filePath) + 5; //.bak + null BOOL retValue = 0; WCHAR * backupFile = new WCHAR[fileNameLength]; wcscpy_s(backupFile, fileNameLength, filePath); wcscat_s(backupFile, fileNameLength, L".bak"); retValue = CopyFile(filePath, backupFile, FALSE); if (!retValue) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"createBackupFile :: CopyFile failed with error 0x%X", GetLastError()); #endif } delete [] backupFile; return retValue != 0; } DWORD ProcessAccessHelp::getModuleHandlesFromProcess(const HANDLE hProcess, HMODULE ** hMods) { DWORD count = 30; DWORD cbNeeded = 0; bool notEnough = true; *hMods = new HMODULE[count]; do { if (!EnumProcessModules(hProcess, *hMods, count * sizeof(HMODULE), &cbNeeded)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getModuleHandlesFromProcess :: EnumProcessModules failed count %d", count); #endif delete [] *hMods; return 0; } if ((count * sizeof(HMODULE)) < cbNeeded) { delete [] *hMods; count = cbNeeded / sizeof(HMODULE); *hMods = new HMODULE[count]; } else { notEnough = false; } } while (notEnough); return cbNeeded / sizeof(HMODULE); } void ProcessAccessHelp::setCurrentProcessAsTarget() { ProcessAccessHelp::hProcess = GetCurrentProcess(); } bool ProcessAccessHelp::suspendProcess() { if (NativeWinApi::NtSuspendProcess) { if (NT_SUCCESS( NativeWinApi::NtSuspendProcess(ProcessAccessHelp::hProcess) )) { return true; } } return false; } bool ProcessAccessHelp::resumeProcess() { if (NativeWinApi::NtResumeProcess) { if (NT_SUCCESS( NativeWinApi::NtResumeProcess(ProcessAccessHelp::hProcess) )) { return true; } } return false; } bool ProcessAccessHelp::terminateProcess() { if (NativeWinApi::NtTerminateProcess) { if (NT_SUCCESS( NativeWinApi::NtTerminateProcess(ProcessAccessHelp::hProcess, 0) )) { return true; } } return false; } bool ProcessAccessHelp::isPageExecutable( DWORD Protect ) { if (Protect & PAGE_NOCACHE) Protect ^= PAGE_NOCACHE; if (Protect & PAGE_GUARD) Protect ^= PAGE_GUARD; if (Protect & PAGE_WRITECOMBINE) Protect ^= PAGE_WRITECOMBINE; switch(Protect) { case PAGE_EXECUTE: { return true; } case PAGE_EXECUTE_READ: { return true; } case PAGE_EXECUTE_READWRITE: { return true; } case PAGE_EXECUTE_WRITECOPY: { return true; } default: return false; } } SIZE_T ProcessAccessHelp::getSizeOfImageProcessNative( HANDLE processHandle, DWORD_PTR moduleBase ) { MEMORY_REGION_INFORMATION memRegion = {0}; SIZE_T retLen = 0; if (NativeWinApi::NtQueryVirtualMemory(processHandle, (PVOID)moduleBase, MemoryRegionInformation, &memRegion, sizeof(MEMORY_REGION_INFORMATION), &retLen) == STATUS_SUCCESS) { return memRegion.RegionSize; } return 0; } diff --git a/Scylla/ProcessLister.cpp b/Scylla/ProcessLister.cpp index bbfb64d..223c4fb 100644 --- a/Scylla/ProcessLister.cpp +++ b/Scylla/ProcessLister.cpp @@ -1,292 +1,292 @@ #include "ProcessLister.h" #include "SystemInformation.h" #include "Logger.h" #include "ProcessAccessHelp.h" #include //#define DEBUG_COMMENTS def_IsWow64Process ProcessLister::_IsWow64Process = 0; std::vector& ProcessLister::getProcessList() { return processList; } bool ProcessLister::isWindows64() { #ifdef _WIN64 //compiled 64bit application return true; #else //32bit exe, check wow64 BOOL bIsWow64 = FALSE; //not available in all windows operating systems //Minimum supported client: Windows Vista, Windows XP with SP2 //Minimum supported server: Windows Server 2008, Windows Server 2003 with SP1 if (_IsWow64Process) { _IsWow64Process(GetCurrentProcess(), &bIsWow64); - if (bIsWow64 == TRUE) + if (bIsWow64 != FALSE) { return true; } else { return false; } } else { return false; } #endif } //only needed in windows xp DWORD ProcessLister::setDebugPrivileges() { DWORD err = 0; HANDLE hToken = 0; TOKEN_PRIVILEGES Debug_Privileges = {0}; if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Debug_Privileges.Privileges[0].Luid)) { return GetLastError(); } if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { err = GetLastError(); if(hToken) CloseHandle(hToken); return err; } Debug_Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; Debug_Privileges.PrivilegeCount = 1; AdjustTokenPrivileges(hToken, false, &Debug_Privileges, 0, NULL, NULL); CloseHandle(hToken); return GetLastError(); } /************************************************************************/ /* Check if a process is 32 or 64bit */ /************************************************************************/ ProcessType ProcessLister::checkIsProcess64(HANDLE hProcess) { BOOL bIsWow64 = FALSE; if (!hProcess) { return PROCESS_MISSING_RIGHTS; } if (!isWindows64()) { //32bit win can only run 32bit process return PROCESS_32; } _IsWow64Process(hProcess, &bIsWow64); if (bIsWow64 == FALSE) { //process not running under wow return PROCESS_64; } else { //process running under wow -> 32bit return PROCESS_32; } } bool ProcessLister::getAbsoluteFilePath(HANDLE hProcess, Process * process) { WCHAR processPath[MAX_PATH]; bool retVal = false; wcscpy_s(process->fullPath, L"Unknown path"); if(!hProcess) { //missing rights return false; } + + if (GetProcessImageFileNameW(hProcess, processPath, _countof(processPath)) > 0) { if (!deviceNameResolver->resolveDeviceLongNameToShort(processPath, process->fullPath)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getAbsoluteFilePath :: resolveDeviceLongNameToShort failed with path %s", processPath); #endif //some virtual volumes - if (GetModuleFileNameExW(hProcess, 0, process->fullPath, _countof(process->fullPath)) != 0) - { - retVal = true; - } + + MessageBoxW(0, processPath, L"Cannot resolve this path!", MB_ICONERROR); } else { retVal = true; } } else { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"getAbsoluteFilePath :: GetProcessImageFileName failed %u", GetLastError()); #endif if (GetModuleFileNameExW(hProcess, 0, process->fullPath, _countof(process->fullPath)) != 0) { retVal = true; } } return retVal; } std::vector& ProcessLister::getProcessListSnapshotNative() { ULONG retLength = 0; ULONG bufferLength = 1; PSYSTEM_PROCESS_INFORMATION pBuffer = (PSYSTEM_PROCESS_INFORMATION)malloc(bufferLength); PSYSTEM_PROCESS_INFORMATION pIter; if (!processList.empty()) { //clear elements, but keep reversed memory processList.clear(); } else { //first time, reserve memory processList.reserve(34); } if (NativeWinApi::NtQuerySystemInformation(SystemProcessInformation, pBuffer, bufferLength, &retLength) == STATUS_INFO_LENGTH_MISMATCH) { free(pBuffer); bufferLength = retLength + sizeof(SYSTEM_PROCESS_INFORMATION); pBuffer = (PSYSTEM_PROCESS_INFORMATION)malloc(bufferLength); if (!pBuffer) return processList; if (NativeWinApi::NtQuerySystemInformation(SystemProcessInformation, pBuffer, bufferLength, &retLength) != STATUS_SUCCESS) { return processList; } } else { return processList; } pIter = pBuffer; while(TRUE) { if (pIter->UniqueProcessId > (HANDLE)4) //small filter { handleProcessInformationAndAddToList(pIter); } if (pIter->NextEntryOffset == 0) { break; } else { pIter = (PSYSTEM_PROCESS_INFORMATION)((DWORD_PTR)pIter + (DWORD_PTR)pIter->NextEntryOffset); } } std::reverse(processList.begin(), processList.end()); //reverse process list free(pBuffer); return processList; } void ProcessLister::handleProcessInformationAndAddToList( PSYSTEM_PROCESS_INFORMATION pProcess ) { Process process; WCHAR tempProcessName[MAX_PATH*2] = {0}; process.PID = (DWORD)pProcess->UniqueProcessId; HANDLE hProcess = ProcessAccessHelp::NativeOpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, process.PID); if (hProcess) { ProcessType processType = checkIsProcess64(hProcess); #ifdef _WIN64 if (processType == PROCESS_64) #else if (processType == PROCESS_32) #endif { process.sessionId = pProcess->SessionId; memcpy(tempProcessName, pProcess->ImageName.Buffer, pProcess->ImageName.Length); wcscpy_s(process.filename, tempProcessName); getAbsoluteFilePath(hProcess, &process); process.pebAddress = getPebAddressFromProcess(hProcess); getProcessImageInformation(hProcess, &process); processList.push_back(process); } CloseHandle(hProcess); } } void ProcessLister::getProcessImageInformation( HANDLE hProcess, Process* process ) { DWORD_PTR readImagebase = 0; process->imageBase = 0; process->imageSize = 0; if (hProcess && process->pebAddress) { PEB_CURRENT * peb = (PEB_CURRENT *)process->pebAddress; if (ReadProcessMemory(hProcess, &peb->ImageBaseAddress, &readImagebase, sizeof(DWORD_PTR), 0)) { process->imageBase = readImagebase; process->imageSize = (DWORD)ProcessAccessHelp::getSizeOfImageProcess(hProcess, process->imageBase); } } } DWORD_PTR ProcessLister::getPebAddressFromProcess( HANDLE hProcess ) { if (hProcess) { ULONG RequiredLen = 0; void * PebAddress = 0; PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = {0}; if(NativeWinApi::NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == STATUS_SUCCESS) { PebAddress = (void*)myProcessBasicInformation->PebBaseAddress; } else { if(NativeWinApi::NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == STATUS_SUCCESS) { PebAddress = (void*)myProcessBasicInformation->PebBaseAddress; } } return (DWORD_PTR)PebAddress; } return 0; }