/// <exception cref="T:System.ArgumentException">The <paramref name="path" /> parameter contains invalid characters, is empty, or contains only white spaces.</exception> /// <exception cref="T:System.IO.PathTooLongException">In the .NET for Windows Store apps or the Portable Class Library, catch the base class exception, <see cref="T:System.IO.IOException" />, instead.The <paramref name="path" /> parameter is longer than the system-defined maximum length.</exception> public static string TryRunPeVerify(this AssemblyPatcher patcher, AppInfo appInfo, string targetFile) { var peSettings = new PEVerifyInput { AssemblyResolutionFolder = Path.GetDirectoryName(targetFile), IgnoreErrors = appInfo.IgnorePEVerifyErrors.ToList() }; PEVerifyOutput peOutput = patcher.RunPeVerify(peSettings); return(peOutput.Output); }
/// <summary> /// Executes the bundled PEVerify executable on the specified assembly by first serializing it to file. PEVerify is an unmanaged, Windows-only application. /// </summary> /// <param name="targetAssembly">The assembly on which to run PEVerify.</param> /// <param name="input">The arguments with which to run PEVerify and process its output.</param> /// <returns></returns> public static PEVerifyOutput RunPeVerify(AssemblyDefinition targetAssembly, PEVerifyInput input) { var matchMdTokens = new Regex(@"\[(mdToken=|token:)0x(?<token> [0-9a-f]* ) \]", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); var tempName = Guid.NewGuid().ToString(); var tempPath = Path.Combine(input.AssemblyResolutionFolder, tempName); var matchErrorCount = new Regex($@"(?<count>\d+) Error\(s\) Verifying {tempName}", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); try { //PEVerify is in the same folder as Patchwork, not the directory. targetAssembly.Write(tempPath); var info = new ProcessStartInfo() { UseShellExecute = false, FileName = PEVerifyLocation, RedirectStandardOutput = true, CreateNoWindow = true, WorkingDirectory = input.AssemblyResolutionFolder ?? Environment.CurrentDirectory, Arguments = $"{input.Switches} /ignore={input.IgnoreErrors.Select(x => x.ToString("X")).Join(",")} \"{tempPath}\"" }; string ret; using (var process = Process.Start(info)) { ret= process.StandardOutput.ReadToEnd().Replace(tempPath, targetAssembly.Name.Name); } var ass = AssemblyCache.Default.ReadAssembly(tempPath); if (input.ExpandMetadataTokens) { ret = matchMdTokens.Replace(ret, match => { var token = match.Groups["token"].Value; var tokenNumber = Convert.ToUInt32(token, 16); var tk = new MetadataToken(tokenNumber); var provider = (MemberReference) ass.MainModule.LookupTokenExtended(tk); var providerName = provider?.UserFriendlyName() ?? ""; var informativeFormat = $@"[{providerName}, 0x{token}]"; return informativeFormat; //return match.Value; }); } var countCapture = matchErrorCount.Match(ret).Groups["count"]; int errorCount; if (countCapture.Success) { if (!int.TryParse(countCapture.Value, out errorCount)) { errorCount = -1; } } else { errorCount = 0; } return new PEVerifyOutput() { Output = ret, ErrorCount = errorCount }; } finally { File.Delete(tempPath); } }
/// <summary> /// This method runs the PEVerify command-line tool on the patched assembly. It does this by first writing it to a temporary file.<br/> /// PEVerify is a tool that verifies IL. It goes over it and looks for various issues.<br/> /// Some of the errors it reports are relatively harmless but others mean the assembly cannot be loaded.<br/> /// Ideally, it should report no errors.<br/> /// This operation returns an extended and user-friendly form of the output, translating metadata tokens into user-readable names. /// </summary> /// <returns></returns> public PEVerifyOutput RunPeVerify(PEVerifyInput input) { return(PeVerifyRunner.RunPeVerify(TargetAssembly, input)); }