public static ExecutableInfo GetExeType(string filename) { if (ExeTypeCache.ContainsKey(filename)) return ExeTypeCache[filename]; var pe = new PEInfo(filename); var result = (pe.Is32Bit ? ExecutableInfo.x86 : ExecutableInfo.none) | (pe.Is64Bit ? ExecutableInfo.x64 : ExecutableInfo.none) | (pe.IsManaged ? ExecutableInfo.managed : ExecutableInfo.native) | (pe.IsAny ? ExecutableInfo.any : ExecutableInfo.none); ExeTypeCache.Add(filename, result); return result; }
public void CopyResources(PEInfo info, IEnumerable<IntPtr> types) { foreach (var type in types) { try { var find = $"\\{type}\\"; foreach (var res in info.ResourceNames.Where(name => name.StartsWith(find))) { var id = (IntPtr)int.Parse(res.Substring(find.Length)); var data = info.GetResource(res); Native.UpdateResource(handle, type, id, 0, data, data.Length); } } catch { } } }
private ToolInfo IdentifyMicrosoftProduct(PEInfo peInfo) { var result = new ToolInfo { Vendor = ToolVendor.Microsoft, MajorVersion = peInfo.VersionInfo.ProductMajorPart, MinorVersion = peInfo.VersionInfo.ProductMinorPart }; switch (peInfo.VersionInfo.InternalName.ToLower()) { case "cl.exe": result.Type = ToolType.CCompiler; break; case "lib.exe": result.Type = ToolType.Lib; break; case "link.exe": result.Type = ToolType.Linker; break; case "masm.exe": case "ml.exe": result.Type = ToolType.Assember; break; case "ilasm.exe": result.Type = ToolType.ILAssembler; break; case "ildasm.exe": result.Type = ToolType.ILDisasembler; break; case "as.exe": result.Type = ToolType.AssemblyLinker; break; case "nmake.exe": result.Type = ToolType.Make; break; case "mc.exe": result.Type = ToolType.MessageCompiler; break; case "rc.exe": result.Type = ToolType.ResourceCompiler; break; case "midl": case "midlc": case "midl.exe": result.Type = ToolType.IDLCompiler; break; case "mt.exe": case "mt2.exe": result.Type = ToolType.ManifestTool; break; default: result.Type = ToolType.Unknown; break; } return result; }
void InstallationStep1() { ApiGroup.IsEnabled = true; SetupButton.IsEnabled = false; ApiGroup.Visibility = ApiD3D9.Visibility = ApiDXGI.Visibility = ApiOpenGL.Visibility = ApiVulkan.Visibility = Visibility.Visible; ApiVulkanGlobal.Visibility = ApiVulkanGlobalButton.Visibility = Visibility.Collapsed; var info = FileVersionInfo.GetVersionInfo(targetPath); targetName = info.FileDescription; if (targetName is null || targetName.Trim().Length == 0) { targetName = Path.GetFileNameWithoutExtension(targetPath); } UpdateStatus("Working on " + targetName + " ...", "Analyzing executable ..."); var peInfo = new PEInfo(targetPath); is64Bit = peInfo.Type == PEInfo.BinaryType.IMAGE_FILE_MACHINE_AMD64; // Check whether the API is specified in the compatibility list, in which case setup can continue right away var executableName = Path.GetFileName(targetPath); if (compatibilityIni != null && compatibilityIni.HasValue(executableName, "RenderApi")) { string api = compatibilityIni.GetString(executableName, "RenderApi"); ApiD3D9.IsChecked = api == "D3D8" || api == "D3D9"; ApiDXGI.IsChecked = api == "D3D10" || api == "D3D11" || api == "D3D12" || api == "DXGI"; ApiOpenGL.IsChecked = api == "OpenGL"; ApiVulkan.IsChecked = api == "Vulkan"; InstallationStep2(); return; } bool isApiD3D8 = peInfo.Modules.Any(s => s.StartsWith("d3d8", StringComparison.OrdinalIgnoreCase)); bool isApiD3D9 = isApiD3D8 || peInfo.Modules.Any(s => s.StartsWith("d3d9", StringComparison.OrdinalIgnoreCase)); bool isApiDXGI = peInfo.Modules.Any(s => s.StartsWith("dxgi", StringComparison.OrdinalIgnoreCase) || s.StartsWith("d3d1", StringComparison.OrdinalIgnoreCase) || s.Contains("GFSDK")); // Assume DXGI when GameWorks SDK is in use bool isApiOpenGL = peInfo.Modules.Any(s => s.StartsWith("opengl32", StringComparison.OrdinalIgnoreCase)); bool isApiVulkan = peInfo.Modules.Any(s => s.StartsWith("vulkan-1", StringComparison.OrdinalIgnoreCase)); if (isApiD3D9 && isApiDXGI) { isApiD3D9 = false; // Prefer DXGI over D3D9 } if (isApiD3D8 && !isHeadless) { MessageBox.Show(this, "It looks like the target application uses Direct3D 8. You'll have to download an additional wrapper from 'https://github.com/crosire/d3d8to9/releases' which converts all API calls to Direct3D 9 in order to use ReShade.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); } if (isApiDXGI && isApiVulkan) { isApiDXGI = false; // Prefer Vulkan over Direct3D 12 } if (isApiOpenGL && (isApiD3D8 || isApiD3D9 || isApiDXGI || isApiVulkan)) { isApiOpenGL = false; // Prefer Vulkan and Direct3D over OpenGL } Message.Text = "Which rendering API does " + targetName + " use?"; ApiD3D9.IsChecked = isApiD3D9; ApiDXGI.IsChecked = isApiDXGI; ApiOpenGL.IsChecked = isApiOpenGL; ApiVulkan.IsChecked = isApiVulkan; }
public static Resource CreateFromFile(string name, string fullPath, BitDepths bitDepth) { if ((string.IsNullOrWhiteSpace(fullPath)) || (!File.Exists(fullPath))) return null; var data = File.ReadAllBytes(fullPath); var peInfo = new PEInfo(data); var sha1 = new SHA1Managed(); return new Resource { Name = name, FileType = peInfo.FileType, WriteTime = File.GetLastWriteTimeUtc(fullPath), BitDepth = bitDepth, Version = peInfo.Version, SHA1 = BitConverter.ToString(sha1.ComputeHash(data)).Replace("-", "").ToLower(), UncompressedData = data, }; }
[SecurityCritical] // Req'd on .NET 4.0 private static unsafe IntPtr FindDebuggerRCThreadAddress(Info info) { var pid = GetCurrentProcessId(); try { var peInfo = PEInfo.GetCLR(); if (peInfo == null) { return(IntPtr.Zero); } IntPtr sectionAddr; uint sectionSize; if (!peInfo.FindSection(".data", out sectionAddr, out sectionSize)) { return(IntPtr.Zero); } // Try to find the Debugger instance location in the data section var p = (byte *)sectionAddr; var end = (byte *)sectionAddr + sectionSize; for (; p + IntPtr.Size <= end; p += IntPtr.Size) { var pDebugger = *(IntPtr *)p; if (pDebugger == IntPtr.Zero) { continue; } try { // All allocations are pointer-size aligned if (!PEInfo.IsAlignedPointer(pDebugger)) { continue; } // Make sure pid is correct var pid2 = *(uint *)((byte *)pDebugger + info.Debugger_pid); if (pid != pid2) { continue; } var pDebuggerRCThread = *(IntPtr *)((byte *)pDebugger + info.Debugger_pDebuggerRCThread); // All allocations are pointer-size aligned if (!PEInfo.IsAlignedPointer(pDebuggerRCThread)) { continue; } // Make sure it points back to Debugger var pDebugger2 = *(IntPtr *)((byte *)pDebuggerRCThread + info.DebuggerRCThread_pDebugger); if (pDebugger != pDebugger2) { continue; } return(pDebuggerRCThread); } catch { } } } catch { } return(IntPtr.Zero); }
public static void Run(Config config) { if (((!File.Exists(config.X32StartFull)) && (!File.Exists(config.X64StartFull))) || (config.Output == null) || (config.Match == null)) throw new ArgumentException("Invalid parameter"); var files = GetFiles(config.X32Path).Concat(GetFiles(config.X64Path)).Distinct(StringComparer.OrdinalIgnoreCase).Where(file => config.IsMatch(file)).ToList(); // Make sure entry points are found if (config.X32Start != null) files.Single(file => file.Equals(config.X32Start, StringComparison.OrdinalIgnoreCase)); if (config.X64Start != null) files.Single(file => file.Equals(config.X64Start, StringComparison.OrdinalIgnoreCase)); var loader = typeof(Program).Assembly.Location; var bytes = File.ReadAllBytes(loader); var loaderPeInfo = new PEInfo(bytes); if (config.X64Path == null) loaderPeInfo.CorFlags |= Native.IMAGE_COR20_HEADER_FLAGS.x32BitRequired; if (config.IsConsole) loaderPeInfo.IsConsole = true; File.WriteAllBytes(config.Output, bytes); using (var nr = new ResourceWriter(config.Output)) { var startFile = config.X64StartFull ?? config.X32StartFull; nr.CopyResources(new PEInfo(startFile), new List<IntPtr> { Native.RT_ICON, Native.RT_GROUP_ICON, Native.RT_VERSION }); var currentID = 1; foreach (var file in files) { var x32File = config.X32Path == null ? null : Path.Combine(config.X32Path, file); if ((x32File == null) || (x32File.Equals(loader, StringComparison.OrdinalIgnoreCase)) || (!File.Exists(x32File))) x32File = null; var x32Res = Resource.CreateFromFile(file, x32File, BitDepths.x32); var x64File = config.X64Path == null ? null : Path.Combine(config.X64Path, file); if ((x64File == null) || (x64File.Equals(loader, StringComparison.OrdinalIgnoreCase)) || (!File.Exists(x64File))) x64File = null; var x64Res = x64File == x32File ? x32Res : Resource.CreateFromFile(file, x64File, BitDepths.x64); if (Resource.DataMatch(x32Res, x64Res)) x64Res = x32Res; if (x32Res == x64Res) { x32Res.BitDepth = BitDepths.Any; x64Res = null; } if (x32Res != null) { x32Res.ResourceID = ++currentID; nr.AddBinary(x32Res.ResourceID, x32Res.CompressedData); x32Res.CompressedData = null; config.Resources.Add(x32Res); } if (x64Res != null) { x64Res.ResourceID = ++currentID; nr.AddBinary(x64Res.ResourceID, x64Res.CompressedData); x64Res.CompressedData = null; config.Resources.Add(x64Res); } } nr.AddBinary(1, config.SerializedData); } }
partial void BindEcmaAssemblyName(RuntimeAssemblyName refName, ref AssemblyBindResult result, ref Exception exception, ref Exception preferredException, ref bool foundMatch) { lock (s_ecmaLoadedAssemblies) { for (int i = 0; i < s_ecmaLoadedAssemblies.Count; i++) { PEInfo info = s_ecmaLoadedAssemblies[i]; if (AssemblyNameMatches(refName, info.Name, ref preferredException)) { if (foundMatch) { exception = new AmbiguousMatchException(); return; } result.EcmaMetadataReader = info.Reader; foundMatch = result.EcmaMetadataReader != null; // For failed matches, we will never be able to succeed, so return now if (!foundMatch) { return; } } } if (!foundMatch) { try { // Not found in already loaded list, attempt to source assembly from disk foreach (string filePath in FilePathsForAssembly(refName)) { FileStream ownedFileStream = null; PEReader ownedPEReader = null; try { if (!RuntimeAugments.FileExists(filePath)) { continue; } try { ownedFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); } catch (System.IO.IOException) { // Failure to open a file is not fundamentally an assembly load error, but it does indicate this file cannot be used continue; } ownedPEReader = new PEReader(ownedFileStream); // FileStream ownership transferred to ownedPEReader ownedFileStream = null; if (!ownedPEReader.HasMetadata) { continue; } MetadataReader reader = ownedPEReader.GetMetadataReader(); // Create AssemblyName from MetadataReader RuntimeAssemblyName runtimeAssemblyName = reader.GetAssemblyDefinition().ToRuntimeAssemblyName(reader).CanonicalizePublicKeyToken(); // If assembly name doesn't match, it isn't the one we're looking for. Continue to look for more assemblies if (!AssemblyNameMatches(refName, runtimeAssemblyName, ref preferredException)) { continue; } // This is the one we are looking for, add it to the list of loaded assemblies PEInfo peinfo = new PEInfo(runtimeAssemblyName, reader, ownedPEReader); s_ecmaLoadedAssemblies.Add(peinfo); // At this point the PE reader is no longer owned by this code, but is owned by the s_ecmaLoadedAssemblies list PEReader pe = ownedPEReader; ownedPEReader = null; ModuleList moduleList = ModuleList.Instance; ModuleInfo newModuleInfo = new EcmaModuleInfo(moduleList.SystemModule.Handle, pe, reader); moduleList.RegisterModule(newModuleInfo); foundMatch = true; result.EcmaMetadataReader = peinfo.Reader; break; } finally { if (ownedFileStream != null) { ownedFileStream.Dispose(); } if (ownedPEReader != null) { ownedPEReader.Dispose(); } } } } catch (System.IO.IOException) { } catch (System.ArgumentException) { } catch (System.BadImageFormatException badImageFormat) { exception = badImageFormat; } // Cache missed lookups if (!foundMatch) { PEInfo peinfo = new PEInfo(refName, null, null); s_ecmaLoadedAssemblies.Add(peinfo); } } } }
[SecurityCritical] // Req'd on .NET 4.0 private unsafe IntPtr FindAttacherThreadProc() { try { var peInfo = PEInfo.GetCLR(); if (peInfo == null) { return(IntPtr.Zero); } IntPtr sectionAddr; uint sectionSize; if (!peInfo.FindSection(".text", out sectionAddr, out sectionSize)) { return(IntPtr.Zero); } var p = (byte *)sectionAddr; var start = p; var end = (byte *)sectionAddr + sectionSize; if (IntPtr.Size == 4) { for (; p < end; p++) { // Find this code: // 50+r push reg // 50+r push reg // 50+r push reg // 68 XX XX XX XX push offset ThreadProc // 50+r push reg // 50+r push reg // FF 15 XX XX XX XX call dword ptr [mem] // CreateThread() var push = *p; if (push < 0x50 || push > 0x57) { continue; } if (p[1] != push || p[2] != push || p[8] != push || p[9] != push) { continue; } if (p[3] != 0x68) { continue; } if (p[10] != 0xFF || p[11] != 0x15) { continue; } var threadProc = new IntPtr((void *)*(uint *)(p + 4)); if (!CheckThreadProc(start, end, threadProc)) { continue; } return(threadProc); } } else { for (; p < end; p++) { // Find this code: // 45 33 C9 xor r9d,r9d // 4C 8D 05 XX XX XX XX lea r8,ThreadProc // 33 D2 xor edx,edx // 33 C9 xor ecx,ecx // FF 15 XX XX XX XX call dword ptr [mem] // CreateThread() if (*p != 0x45 && p[1] != 0x33 && p[2] != 0xC9) { continue; } if (p[3] != 0x4C && p[4] != 0x8D && p[5] != 0x05) { continue; } if (p[10] != 0x33 && p[11] != 0xD2) { continue; } if (p[12] != 0x33 && p[13] != 0xC9) { continue; } if (p[14] != 0xFF && p[15] != 0x15) { continue; } var threadProc = new IntPtr(p + 10 + *(int *)(p + 6)); if (!CheckThreadProc(start, end, threadProc)) { continue; } return(threadProc); } } } catch { } return(IntPtr.Zero); }
[SecurityCritical] // Req'd on .NET 4.0 private static unsafe IntPtr FindThreadingModeAddress() { try { // Find this code in clr!ProfilingAPIAttachServer::ExecutePipeRequests() // 83 3D XX XX XX XX 02 cmp dword ptr [mem],2 // 74 / 0F 84 XX je there // 83 E8+r 00 / 85 C0+rr sub reg,0 / test reg,reg // 74 / 0F 84 XX je there // 48+r / FF C8+r dec reg // 74 / 0F 84 XX je there // 48+r / FF C8+r dec reg var peInfo = PEInfo.GetCLR(); if (peInfo == null) { return(IntPtr.Zero); } IntPtr sectionAddr; uint sectionSize; if (!peInfo.FindSection(".text", out sectionAddr, out sectionSize)) { return(IntPtr.Zero); } var ptr = (byte *)sectionAddr; var end = (byte *)sectionAddr + sectionSize; for (; ptr < end; ptr++) { IntPtr addr; try { // 83 3D XX XX XX XX 02 cmp dword ptr [mem],2 var p = ptr; if (*p != 0x83 || p[1] != 0x3D || p[6] != 2) { continue; } if (IntPtr.Size == 4) { addr = new IntPtr((void *)*(uint *)(p + 2)); } else { addr = new IntPtr(p + 7 + *(int *)(p + 2)); } if (!PEInfo.IsAligned(addr, 4)) { continue; } if (!peInfo.IsValidImageAddress(addr)) { continue; } p += 7; // 1 = normal lazy thread creation. 2 = thread is always present if (*(uint *)addr < 1 || *(uint *)addr > 2) { continue; } *(uint *)addr = *(uint *)addr; // 74 / 0F 84 XX je there if (!NextJz(ref p)) { continue; } // 83 E8+r 00 / 85 C0+rr sub reg,0 / test reg,reg SkipRex(ref p); if (*p == 0x83 && p[2] == 0) { if ((uint)(p[1] - 0xE8) > 7) { continue; } p += 3; } else if (*p == 0x85) { var reg = (p[1] >> 3) & 7; var rm = p[1] & 7; if (reg != rm) { continue; } p += 2; } else { continue; } // 74 / 0F 84 XX je there if (!NextJz(ref p)) { continue; } // 48+r / FF C8+r dec reg if (!SkipDecReg(ref p)) { continue; } // 74 / 0F 84 XX je there if (!NextJz(ref p)) { continue; } // 48+r / FF C8+r dec reg if (!SkipDecReg(ref p)) { continue; } return(addr); } catch { } } } catch { } return(IntPtr.Zero); }
/// <summary> /// This code tries to find the CLR 2.0 profiler status flag. It searches the whole /// .text section for a certain instruction. /// </summary> /// <returns><c>true</c> if it was found, <c>false</c> otherwise</returns> private unsafe bool FindProfilerStatus() { // Record each hit here and pick the one with the most hits var addrCounts = new Dictionary <IntPtr, int>(); try { var peInfo = PEInfo.GetCLR(); if (peInfo == null) { return(false); } IntPtr sectionAddr; uint sectionSize; if (!peInfo.FindSection(".text", out sectionAddr, out sectionSize)) { return(false); } const int MAX_COUNTS = 50; var p = (byte *)sectionAddr; var end = (byte *)sectionAddr + sectionSize; for (; p < end; p++) { IntPtr addr; // F6 05 XX XX XX XX 06 test byte ptr [mem],6 if (*p == 0xF6 && p[1] == 0x05 && p[6] == 0x06) { if (IntPtr.Size == 4) { addr = new IntPtr((void *)*(uint *)(p + 2)); } else { addr = new IntPtr(p + 7 + *(int *)(p + 2)); } } else { continue; } if (!PEInfo.IsAligned(addr, 4)) { continue; } if (!peInfo.IsValidImageAddress(addr, 4)) { continue; } try { *(uint *)addr = *(uint *)addr; } catch { continue; } var count = 0; addrCounts.TryGetValue(addr, out count); count++; addrCounts[addr] = count; if (count >= MAX_COUNTS) { break; } } } catch { } var foundAddr = GetMax(addrCounts, 5); if (foundAddr == IntPtr.Zero) { return(false); } profilerStatusFlag = foundAddr; return(true); }
[SecurityCritical] // Req'd on .NET 4.0 private unsafe bool FindProfilerControlBlock() { // Record each hit here and pick the one with the most hits var addrCounts = new Dictionary <IntPtr, int>(); try { var peInfo = PEInfo.GetCLR(); if (peInfo == null) { return(false); } IntPtr sectionAddr; uint sectionSize; if (!peInfo.FindSection(".text", out sectionAddr, out sectionSize)) { return(false); } const int MAX_COUNTS = 50; var p = (byte *)sectionAddr; var end = (byte *)sectionAddr + sectionSize; for (; p < end; p++) { IntPtr addr; // A1 xx xx xx xx mov eax,[mem] // 83 F8 04 cmp eax,4 if (*p == 0xA1 && p[5] == 0x83 && p[6] == 0xF8 && p[7] == 0x04) { if (IntPtr.Size == 4) { addr = new IntPtr((void *)*(uint *)(p + 1)); } else { addr = new IntPtr(p + 5 + *(int *)(p + 1)); } } // 8B 05 xx xx xx xx mov eax,[mem] // 83 F8 04 cmp eax,4 else if (*p == 0x8B && p[1] == 0x05 && p[6] == 0x83 && p[7] == 0xF8 && p[8] == 0x04) { if (IntPtr.Size == 4) { addr = new IntPtr((void *)*(uint *)(p + 2)); } else { addr = new IntPtr(p + 6 + *(int *)(p + 2)); } } // 83 3D XX XX XX XX 04 cmp dword ptr [mem],4 else if (*p == 0x83 && p[1] == 0x3D && p[6] == 0x04) { if (IntPtr.Size == 4) { addr = new IntPtr((void *)*(uint *)(p + 2)); } else { addr = new IntPtr(p + 7 + *(int *)(p + 2)); } } else { continue; } if (!PEInfo.IsAligned(addr, 4)) { continue; } if (!peInfo.IsValidImageAddress(addr, 4)) { continue; } // Valid values are 0-4. 4 being attached. try { if (*(uint *)addr > 4) { continue; } *(uint *)addr = *(uint *)addr; } catch { continue; } var count = 0; addrCounts.TryGetValue(addr, out count); count++; addrCounts[addr] = count; if (count >= MAX_COUNTS) { break; } } } catch { } var foundAddr = GetMax(addrCounts, 5); if (foundAddr == IntPtr.Zero) { return(false); } profilerControlBlock = new IntPtr((byte *)foundAddr - (IntPtr.Size + 4)); return(true); }