int32 FWindowsPlatformStackWalk::GetProcessModuleSignatures(FStackWalkModuleInfo *ModuleSignatures, const int32 ModuleSignaturesSize)
{
	FPlatformStackWalk::InitStackWalking();

	HANDLE		ProcessHandle = GetCurrentProcess(); 

	// Enumerate process modules.
	HMODULE* ModuleHandlePointer = GetProcessModules(ProcessHandle);
	if (!ModuleHandlePointer)
	{
		return 0;
	}

	// Find out how many modules we need to load modules for.
	IMAGEHLP_MODULEW64 Img = {0};
	Img.SizeOfStruct = sizeof(Img);

	int32 SignatureIndex = 0;

	// Load the modules.
	for( int32 ModuleIndex = 0; ModuleHandlePointer[ModuleIndex] && SignatureIndex < ModuleSignaturesSize; ModuleIndex++ )
	{
		MODULEINFO ModuleInfo = {0};
#if WINVER > 0x502
		WCHAR ModuleName[MAX_PATH] = {0};
		WCHAR ImageName[MAX_PATH] = {0};
#else
		ANSICHAR ModuleName[MAX_PATH] = { 0 };
		ANSICHAR ImageName[MAX_PATH] = { 0 };
#endif
#if PLATFORM_64BITS
		static_assert(sizeof( MODULEINFO ) == 24, "Broken alignment for 64bit Windows include.");
#else
		static_assert(sizeof( MODULEINFO ) == 12, "Broken alignment for 32bit Windows include.");
#endif
		FGetModuleInformation( ProcessHandle, ModuleHandlePointer[ModuleIndex], &ModuleInfo, sizeof( ModuleInfo ) );
		FGetModuleFileNameEx( ProcessHandle, ModuleHandlePointer[ModuleIndex], ImageName, MAX_PATH );
		FGetModuleBaseName( ProcessHandle, ModuleHandlePointer[ModuleIndex], ModuleName, MAX_PATH );

		// Load module.
		if(SymGetModuleInfoW64(ProcessHandle, (DWORD64)ModuleInfo.lpBaseOfDll, &Img))
		{
			FStackWalkModuleInfo Info = {0};
			Info.BaseOfImage = Img.BaseOfImage;
			FCString::Strcpy(Info.ImageName, Img.ImageName);
			Info.ImageSize = Img.ImageSize;
			FCString::Strcpy(Info.LoadedImageName, Img.LoadedImageName);
			FCString::Strcpy(Info.ModuleName, Img.ModuleName);
			Info.PdbAge = Img.PdbAge;
			Info.PdbSig = Img.PdbSig;
			FMemory::Memcpy(&Info.PdbSig70, &Img.PdbSig70, sizeof(GUID));
			Info.TimeDateStamp = Img.TimeDateStamp;

			ModuleSignatures[SignatureIndex] = Info;
			++SignatureIndex;
		}
	}

	// Free the module handle pointer allocated in case the static array was insufficient.
	FMemory::Free(ModuleHandlePointer);

	return SignatureIndex;
}
/** 
 * Upload locally built symbols to network symbol storage.
 *
 * Use case:
 *   Game designers use game from source (without prebuild game .dll-files).
 *   In this case all game .dll-files are compiled locally.
 *   For post-mortem debug programmers need .dll and .pdb files from designers.
 */
bool FWindowsPlatformStackWalk::UploadLocalSymbols()
{
	InitStackWalking();

#if WINVER > 0x502
	// Upload locally compiled files to symbol storage.
	FString SymbolStorage;
	if (!GConfig->GetString( CrashReporterSettings, TEXT( "UploadSymbolsPath" ), SymbolStorage, GEditorPerProjectIni ) || SymbolStorage.IsEmpty())
	{
		// Nothing to do.
		return true;
	}
	// Prepare string
	SymbolStorage.ReplaceInline( TEXT( "/" ), TEXT( "\\" ), ESearchCase::CaseSensitive );
	SymbolStorage = TEXT( "SRV*" ) + SymbolStorage;

	int32 ErrorCode = 0;
	HANDLE ProcessHandle = GetCurrentProcess();

	// Enumerate process modules.
	HMODULE* ModuleHandlePointer = GetProcessModules( ProcessHandle );
	if (!ModuleHandlePointer)
	{
		ErrorCode = GetLastError();
		return false;
	}

#if WITH_EDITOR
	// Get Unreal Engine Editor directory for detecting non-game editor binaries.
	FString EnginePath = FPaths::ConvertRelativePathToFull( FPaths::EngineDir() );
	FPaths::MakePlatformFilename( EnginePath );
#endif

	// Upload all locally built modules.
	for (int32 ModuleIndex = 0; ModuleHandlePointer[ModuleIndex]; ModuleIndex++)
	{
		WCHAR ImageName[MAX_PATH] = {0};
		FGetModuleFileNameEx( ProcessHandle, ModuleHandlePointer[ModuleIndex], ImageName, MAX_PATH );

#if WITH_EDITOR
		WCHAR RelativePath[MAX_PATH];
		// Skip binaries inside Unreal Engine Editor directory (non-game editor binaries)
		if (PathRelativePathTo( RelativePath, *EnginePath, FILE_ATTRIBUTE_DIRECTORY, ImageName, 0 ) && FCString::Strncmp( RelativePath, TEXT( "..\\" ), 3 ))
		{
			continue;
		}
#endif

		WCHAR DebugName[MAX_PATH];
		FCString::Strcpy( DebugName, ImageName );

		if (PathRenameExtensionW( DebugName, L".pdb" ))
		{
			// Upload only if found .pdb file
			if (PathFileExistsW( DebugName ))
			{
				// Upload original file
				UE_LOG( LogWindows, Log, TEXT( "Uploading to symbol storage: %s" ), ImageName );
				if (!SymSrvStoreFileW( ProcessHandle, *SymbolStorage, ImageName, SYMSTOREOPT_PASS_IF_EXISTS ))
				{
					UE_LOG( LogWindows, Warning, TEXT( "Uploading to symbol storage failed: %s. Error: %d" ), ImageName, GetLastError() );
				}

				// Upload debug symbols
				UE_LOG( LogWindows, Log, TEXT( "Uploading to symbol storage: %s" ), DebugName );
				if (!SymSrvStoreFileW( ProcessHandle, *SymbolStorage, DebugName, SYMSTOREOPT_PASS_IF_EXISTS ))
				{
					UE_LOG( LogWindows, Warning, TEXT( "Uploading to symbol storage failed: %s. Error: %d" ), DebugName, GetLastError() );
				}
			}
		}
	}
#else
	UE_LOG( LogWindows, Log, TEXT( "Symbol server not supported on Windows XP." ) );
#endif
	return true;
}
/**
 * Loads modules for current process.
 */ 
static void LoadProcessModules(const FString &RemoteStorage)
{
	int32 ErrorCode = 0;
	HANDLE ProcessHandle = GetCurrentProcess();

	// Enumerate process modules.
	HMODULE* ModuleHandlePointer = GetProcessModules(ProcessHandle);
	if (!ModuleHandlePointer)
	{
		ErrorCode = GetLastError();
		return;
	}

	// Load the modules.
	for( int32 ModuleIndex = 0; ModuleHandlePointer[ModuleIndex]; ModuleIndex++ )
	{
		MODULEINFO ModuleInfo = {0};
#if WINVER > 0x502
		WCHAR ModuleName[FProgramCounterSymbolInfo::MAX_NAME_LENGHT] = {0};
		WCHAR ImageName[FProgramCounterSymbolInfo::MAX_NAME_LENGHT] = {0};
#else
		ANSICHAR ModuleName[FProgramCounterSymbolInfo::MAX_NAME_LENGHT] = { 0 };
		ANSICHAR ImageName[FProgramCounterSymbolInfo::MAX_NAME_LENGHT] = { 0 };
#endif
#if PLATFORM_64BITS
		static_assert(sizeof( MODULEINFO ) == 24, "Broken alignment for 64bit Windows include.");
#else
		static_assert(sizeof( MODULEINFO ) == 12, "Broken alignment for 32bit Windows include.");
#endif
		FGetModuleInformation( ProcessHandle, ModuleHandlePointer[ModuleIndex], &ModuleInfo, sizeof( ModuleInfo ) );
		FGetModuleFileNameEx( ProcessHandle, ModuleHandlePointer[ModuleIndex], ImageName, FProgramCounterSymbolInfo::MAX_NAME_LENGHT );
		FGetModuleBaseName( ProcessHandle, ModuleHandlePointer[ModuleIndex], ModuleName, FProgramCounterSymbolInfo::MAX_NAME_LENGHT );

		// Set the search path to find PDBs in the same folder as the DLL.
#if WINVER > 0x502
		WCHAR SearchPath[MAX_PATH] = {0};
		WCHAR* FileName = NULL;
		const auto Result = GetFullPathNameW( ImageName, MAX_PATH, SearchPath, &FileName );
#else
		ANSICHAR SearchPath[MAX_PATH] = { 0 };
		ANSICHAR* FileName = NULL;
		const auto Result = GetFullPathNameA( ImageName, MAX_PATH, SearchPath, &FileName );
#endif

		FString SearchPathList;
		if (Result != 0 && Result < MAX_PATH)
		{
			*FileName = 0;
#if WINVER > 0x502
			SearchPathList = SearchPath;
#else
			SearchPathList = ANSI_TO_TCHAR(SearchPath);
#endif
		}
		if (!RemoteStorage.IsEmpty())
		{
			if (!SearchPathList.IsEmpty())
			{
				SearchPathList.AppendChar(';');
			}
			SearchPathList.Append(RemoteStorage);
		}

#if WINVER > 0x502
		SymSetSearchPathW(ProcessHandle, *SearchPathList);

		// Load module.
		const DWORD64 BaseAddress = SymLoadModuleExW( ProcessHandle, ModuleHandlePointer[ModuleIndex], ImageName, ModuleName, (DWORD64) ModuleInfo.lpBaseOfDll, (uint32) ModuleInfo.SizeOfImage, NULL, 0 );
		if( !BaseAddress )
		{
			ErrorCode = GetLastError();
			UE_LOG(LogWindows, Warning, TEXT("SymLoadModuleExW. Error: %d"), GetLastError());
		}
#else
		SymSetSearchPath(ProcessHandle, TCHAR_TO_ANSI(*SearchPathList));

		// Load module.
		const DWORD64 BaseAddress = SymLoadModuleEx( ProcessHandle, ModuleHandlePointer[ModuleIndex], ImageName, ModuleName, (DWORD64)ModuleInfo.lpBaseOfDll, (uint32)ModuleInfo.SizeOfImage, NULL, 0 );
		if (!BaseAddress)
		{
			ErrorCode = GetLastError();
			UE_LOG(LogWindows, Warning, TEXT("SymLoadModuleEx. Error: %d"), GetLastError());
		}
#endif
	} 

	// Free the module handle pointer allocated in case the static array was insufficient.
	FMemory::Free(ModuleHandlePointer);
}
Exemple #4
0
vector<EXPORT_ENTRY> Process::GetDLLExports(string p_sModule)
{
	vector<EXPORT_ENTRY> vExports;
	BYTE *pcImageBase = NULL;
	HMODULE hResult = NULL;
	
	// Make sure library is loaded 

	hResult = GetModuleHandle(p_sModule.c_str());

	if(hResult == NULL)
	{
		DebugLog::LogString("[ERROR] Cannot get DLL handle: ", p_sModule);
		
		// Forcely load DLL, ugly but we make sure the DLL functions are hooked

		LoadLibrary(p_sModule.c_str());
	}

	// Get modules 
	
	vector<MODULEENTRY32> vModules = GetProcessModules(0);
	
	if(vModules.size() == 0)
	{
		DebugLog::LogString("[ERROR] Cannot get current process modules, searching for: ", p_sModule);
		return vExports;
	}

	// Case insensitive

	p_sModule = Utils::ToLower(p_sModule);
	
	// Find requested module
	
	for(size_t i = 0; i < vModules.size(); i++)
	{
		if(p_sModule.compare(Utils::ToLower(vModules[i].szModule)) == 0)
		{
			pcImageBase = vModules[i].modBaseAddr;

			// Parse PE headers
			
			IMAGE_DOS_HEADER oDOS;
			IMAGE_NT_HEADERS oNT;
			IMAGE_DATA_DIRECTORY oExportDirEntry;
			IMAGE_EXPORT_DIRECTORY oExportDirectory;
			
			// Parse EAT
			
			DWORD *pdwAddressOfFunctions = NULL;
			DWORD *pdwAddressOfNames = NULL;
			
			CHAR *pcFunctionName = NULL;
			DWORD dwFunctionAddress = 0;
			
			DWORD dwFunctionPointerLocation = 0;
			
			// Get Export directory
			
			memcpy(&oDOS, pcImageBase, sizeof(oDOS));
			memcpy(&oNT, (BYTE *)((DWORD)pcImageBase + oDOS.e_lfanew), sizeof(oNT));
			oExportDirEntry = oNT.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
			memcpy(&oExportDirectory, (BYTE *)((DWORD)pcImageBase + oExportDirEntry.VirtualAddress), sizeof(oExportDirectory));
			
			// Parse names
			
			pdwAddressOfNames     = (DWORD *)((DWORD)pcImageBase + oExportDirectory.AddressOfNames);
			pdwAddressOfFunctions = (DWORD *)((DWORD)pcImageBase + oExportDirectory.AddressOfFunctions);
			
			for(DWORD nr = 0; nr < oExportDirectory.NumberOfFunctions; nr++)
			{
				EXPORT_ENTRY oExport;
				
				// Get function details
				
				pcFunctionName            = (CHAR *)((DWORD)pcImageBase + (DWORD)(pdwAddressOfNames[nr]));
				dwFunctionAddress         = (DWORD)pcImageBase + (DWORD)(pdwAddressOfFunctions[nr]);
				dwFunctionPointerLocation = (DWORD)pcImageBase + oExportDirectory.AddressOfFunctions + nr * sizeof(DWORD);
				
				// Save new function export
				
				oExport.dwAddress          = dwFunctionAddress;
				oExport.dwPointerOfAddress = dwFunctionPointerLocation;
				oExport.sName              = pcFunctionName;
				oExport.uOrdinal           = (USHORT)nr + 1;
				
				vExports.push_back(oExport);
			}
			
			// Do not care about other modules
			
			break;
		}
	}
	
	return vExports;
}