public static PeBinary Load(string filename) { filename = filename.GetFullPath().ToLower(); if (!File.Exists(filename)) { throw new FileNotFoundException("Unable to find file", filename); } if (!PEInfo.Scan(filename).IsPEBinary) { throw new ClrPlusException("File {0} does not appear to be a PE Binary".format(filename)); } PeBinary result = null; lock (_cache) { if (_cache.ContainsKey(filename)) { result = _cache[filename]; } else { // otherwise, let's load it result = new PeBinary(filename); _cache.Add(filename, result); } } // loads happen via a Task, so that no matter how we asked to get the assembly, only one copy will be ever loaded. try { result._loading.Wait(); } catch (AggregateException ae) { #if TODO Logger.Error(ae); Logger.Error(ae.InnerException); #endif var inner = ae.Flatten().InnerException; Console.WriteLine("FAIL: {0} / {1}\r\n{2}", inner.GetType(), inner.Message, inner.StackTrace); } return(result); }
private PeBinary(string filename) { _filename = filename; _info = PEInfo.Scan(filename); _loading = Task.Factory.StartNew(() => { try { using (var ri = new ResourceInfo()) { // lets pull out the relevant resources first. try { ri.Load(_filename); var manifests = ri.Resources.Keys.Where(each => each.ResourceType == ResourceTypes.RT_MANIFEST); _manifestResources = manifests.Select(each => ri.Resources[each].FirstOrDefault() as ManifestResource); var versionKey = ri.Resources.Keys.Where(each => each.ResourceType == ResourceTypes.RT_VERSION).FirstOrDefault(); var versionResource = ri.Resources[versionKey].First() as VersionResource; var versionStringTable = (versionResource["StringFileInfo"] as StringFileInfo).Strings.Values.First(); _comments = TryGetVersionString(versionStringTable, "Comments"); _companyName = TryGetVersionString(versionStringTable, "CompanyName"); _productName = TryGetVersionString(versionStringTable, "ProductName"); _assemblyVersion = TryGetVersionString(versionStringTable, "Assembly Version"); _fileVersion = TryGetVersionString(versionStringTable, "FileVersion"); _internalName = TryGetVersionString(versionStringTable, "InternalName"); _originalFilename = TryGetVersionString(versionStringTable, "OriginalFilename"); _legalCopyright = TryGetVersionString(versionStringTable, "LegalCopyright"); _legalTrademarks = TryGetVersionString(versionStringTable, "LegalTrademarks"); _fileDescription = TryGetVersionString(versionStringTable, "FileDescription"); _bugTracker = TryGetVersionString(versionStringTable, "BugTracker"); } catch { // skip it if this fails. #if TODO Logger.Warning("File {0} failed to load win32 resources", filename); #endif } } } catch (Exception) { #if TODO Logger.Warning("File {0} doesn't appear to have win32 resources", filename); #endif } if (IsManaged) { // we can read in the binary using CCI try { if (MutableAssembly != null) { // we should see if we can get assembly attributes, since sometimes they can be set, but not the native ones. foreach (var a in MutableAssembly.ContainingAssembly.AssemblyAttributes) { var attributeArgument = (a.Arguments.FirstOrDefault() as MetadataConstant); if (attributeArgument != null) { var attributeName = a.Type.ToString(); var attributeValue = attributeArgument.Value.ToString(); if (!string.IsNullOrEmpty(attributeValue)) { switch (attributeName) { case "System.Reflection.AssemblyTitleAttribute": if (string.IsNullOrEmpty(AssemblyTitle)) { AssemblyTitle = attributeValue; } break; case "System.Reflection.AssemblyCompanyAttribute": if (string.IsNullOrEmpty(AssemblyCompany)) { AssemblyCompany = attributeValue; } break; case "System.Reflection.AssemblyProductAttribute": if (string.IsNullOrEmpty(AssemblyProduct)) { AssemblyProduct = attributeValue; } break; case "System.Reflection.AssemblyVersionAttribute": if (string.IsNullOrEmpty(AssemblyVersion)) { AssemblyVersion = attributeValue; } break; case "System.Reflection.AssemblyFileVersionAttribute": if (string.IsNullOrEmpty(AssemblyFileVersion)) { AssemblyFileVersion = attributeValue; } if (string.IsNullOrEmpty(_productVersion)) { _productVersion = attributeValue; } break; case "System.Reflection.AssemblyCopyrightAttribute": if (string.IsNullOrEmpty(AssemblyCopyright)) { AssemblyCopyright = attributeValue; } break; case "System.Reflection.AssemblyTrademarkAttribute": if (string.IsNullOrEmpty(AssemblyTrademark)) { AssemblyTrademark = attributeValue; } break; case "System.Reflection.AssemblyDescriptionAttribute": if (string.IsNullOrEmpty(AssemblyDescription)) { AssemblyDescription = attributeValue; } break; case "BugTrackerAttribute": if (string.IsNullOrEmpty(BugTracker)) { BugTracker = attributeValue; } break; } } } } } _pendingChanges = false; } catch { } } }); _loading.ContinueWith((antecedent) => { // check each of the assembly references, if (IsManaged) { foreach (var ar in MutableAssembly.AssemblyReferences) { if (!ar.PublicKeyToken.Any()) { // dependent assembly isn't signed. // look for it. var dep = FindAssembly(ar.Name.Value, ar.Version.ToString()); if (dep == null) { Console.WriteLine("WARNING: Unsigned Dependent Assembly {0}-{1} not found.", ar.Name.Value, ar.Version.ToString()); } else { // we've found an unsigned dependency -- we're gonna remember this file for later. UnsignedDependentBinaries.Add(dep); } } } } }); }