All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.owasp.dependencycheck.analyzer.PEAnalyzer Maven / Gradle / Ivy

/*
 * This file is part of dependency-check-core.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright (c) 2020 Jeremy Long. All Rights Reserved.
 */
package org.owasp.dependencycheck.analyzer;

import com.github.packageurl.MalformedPackageURLException;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;

import org.boris.pecoff4j.PE;
import org.boris.pecoff4j.ResourceDirectory;
import org.boris.pecoff4j.ResourceEntry;
import org.boris.pecoff4j.constant.ResourceType;
import org.owasp.dependencycheck.utils.PEParser;
import org.boris.pecoff4j.io.ResourceParser;
import org.boris.pecoff4j.resources.StringFileInfo;
import org.boris.pecoff4j.resources.StringTable;
import org.boris.pecoff4j.resources.VersionInfo;
import org.boris.pecoff4j.util.ResourceHelper;

import javax.annotation.concurrent.ThreadSafe;
import org.apache.commons.lang3.StringUtils;

import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.dependency.EvidenceType;
import org.owasp.dependencycheck.dependency.naming.GenericIdentifier;
import org.owasp.dependencycheck.dependency.naming.PurlIdentifier;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.DependencyVersion;
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Takes a dependency and analyze the PE header for meta data that can be used
 * to identify the library.
 *
 * @author Amodio Pesce
 */
@ThreadSafe
@Experimental
public class PEAnalyzer extends AbstractFileTypeAnalyzer {

    //
    /**
     * Logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(AssemblyAnalyzer.class);
    /**
     * The name of the analyzer.
     */
    private static final String ANALYZER_NAME = "PE Analyzer";

    /**
     * The phase that this analyzer is intended to run in.
     */
    private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION2;
    /**
     * The set of file extensions supported by this analyzer.
     */
    private static final String[] EXTENSIONS = {"exe", "dll"};

    /**
     * The file filter used to determine which files this analyzer supports.
     */
    private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
    /**
     * A descriptor for the type of dependencies processed or added by this
     * analyzer.
     */
    public static final String DEPENDENCY_ECOSYSTEM = Ecosystem.NATIVE;

    /**
     * Returns the name of the analyzer.
     *
     * @return the name of the analyzer.
     */
    @Override
    public String getName() {
        return ANALYZER_NAME;
    }

    /**
     * Returns the phase that the analyzer is intended to run in.
     *
     * @return the phase that the analyzer is intended to run in.
     */
    @Override
    public AnalysisPhase getAnalysisPhase() {
        return ANALYSIS_PHASE;
    }

    /**
     * 

* Returns the setting key to determine if the analyzer is enabled.

* * @return the key for the analyzer's enabled property */ @Override protected String getAnalyzerEnabledSettingKey() { return Settings.KEYS.ANALYZER_PE_ENABLED; } /** * Returns the FileFilter. * * @return the FileFilter */ @Override protected FileFilter getFileFilter() { return FILTER; } @Override protected void prepareFileTypeAnalyzer(Engine engine) throws InitializationException { //nothing to prepare } /** * Collects information about the file name. * * @param dependency the dependency to analyze. * @param engine the engine that is scanning the dependencies * @throws AnalysisException is thrown if there is an error analyzing the PE * file. */ @Override protected void analyzeDependency(final Dependency dependency, final Engine engine) throws AnalysisException { for (Evidence e : dependency.getEvidence()) { if ("grokassembly".equals(e.getSource())) { LOGGER.debug("Skipping {} because it was already analyzed by the Assembly Analyzer", dependency.getFileName()); return; } } try { final File fileToCheck = dependency.getActualFile(); final PE pe = PEParser.parse(fileToCheck.getPath()); final ResourceDirectory rd = pe.getImageData().getResourceTable(); final ResourceEntry[] entries = ResourceHelper.findResources(rd, ResourceType.VERSION_INFO); for (ResourceEntry entrie : entries) { final byte[] data = entrie.getData(); final VersionInfo version = ResourceParser.readVersionInfo(data); final StringFileInfo strings = version.getStringFileInfo(); final StringTable table = strings.getTable(0); String pVersion = null; String fVersion = null; for (int j = 0; j < table.getCount(); j++) { final String key = table.getString(j).getKey(); final String value = table.getString(j).getValue(); switch (key) { case "ProductVersion": dependency.addEvidence(EvidenceType.VERSION, "PE Header", "ProductVersion", value, Confidence.HIGHEST); pVersion = value; break; case "CompanyName": dependency.addEvidence(EvidenceType.VENDOR, "PE Header", "CompanyName", value, Confidence.HIGHEST); break; case "FileVersion": dependency.addEvidence(EvidenceType.VERSION, "PE Header", "FileVersion", value, Confidence.HIGH); fVersion = value; break; case "InternalName": dependency.addEvidence(EvidenceType.PRODUCT, "PE Header", "InternalName", value, Confidence.MEDIUM); determineDependencyName(dependency, value); break; case "LegalCopyright": dependency.addEvidence(EvidenceType.VENDOR, "PE Header", "LegalCopyright", value, Confidence.HIGHEST); if (dependency.getLicense() != null && dependency.getLicense().length() > 0) { dependency.setLicense(dependency.getLicense() + "/n/nLegal Copyright: " + value); } else { dependency.setLicense("Legal Copyright: " + value); } break; case "OriginalFilename": dependency.addEvidence(EvidenceType.VERSION, "PE Header", "OriginalFilename", value, Confidence.MEDIUM); determineDependencyName(dependency, value); break; case "ProductName": dependency.addEvidence(EvidenceType.PRODUCT, "PE Header", "ProductName", value, Confidence.HIGHEST); determineDependencyName(dependency, value); break; default: LOGGER.debug("PE Analyzer found `" + key + "` with a value:" + value); } if (fVersion != null && pVersion != null) { final int max = Math.min(fVersion.length(), pVersion.length()); int pos; for (pos = 0; pos < max; pos++) { if (fVersion.charAt(pos) != pVersion.charAt(pos)) { break; } } final DependencyVersion fileVersion = DependencyVersionUtil.parseVersion(fVersion, true); final DependencyVersion productVersion = DependencyVersionUtil.parseVersion(pVersion, true); if (pos > 0) { final DependencyVersion matchingVersion = DependencyVersionUtil.parseVersion(fVersion.substring(0, pos), true); if (fileVersion != null && fileVersion.toString().length() == fVersion.length()) { if (matchingVersion != null && matchingVersion.getVersionParts().size() > 2) { dependency.addEvidence(EvidenceType.VERSION, "PE Header", "FilteredVersion", matchingVersion.toString(), Confidence.HIGHEST); dependency.setVersion(matchingVersion.toString()); } } } if (dependency.getVersion() == null) { if (fVersion.length() >= pVersion.length()) { if (fileVersion != null && fileVersion.toString().length() == fVersion.length()) { dependency.setVersion(fileVersion.toString()); } else if (productVersion != null && productVersion.toString().length() == pVersion.length()) { dependency.setVersion(productVersion.toString()); } } else { if (productVersion != null && productVersion.toString().length() == pVersion.length()) { dependency.setVersion(productVersion.toString()); } else if (fileVersion != null && fileVersion.toString().length() == fVersion.length()) { dependency.setVersion(fileVersion.toString()); } } } } else if (pVersion != null) { final DependencyVersion productVersion = DependencyVersionUtil.parseVersion(pVersion, true); if (productVersion != null && dependency.getActualFile().getName().contains(productVersion.toString())) { dependency.setVersion(productVersion.toString()); } } else if (fVersion != null) { final DependencyVersion fileVersion = DependencyVersionUtil.parseVersion(fVersion, true); if (fileVersion != null && dependency.getActualFile().getName().contains(fileVersion.toString())) { dependency.setVersion(fileVersion.toString()); } } if (dependency.getName() != null && dependency.getVersion() != null) { try { dependency.addSoftwareIdentifier(new PurlIdentifier("generic", dependency.getName(), dependency.getVersion(), Confidence.MEDIUM)); } catch (MalformedPackageURLException ex) { LOGGER.debug("Unable to create Package URL Identifier for " + dependency.getName(), ex); dependency.addSoftwareIdentifier(new GenericIdentifier( String.format("%s@%s", dependency.getName(), dependency.getVersion()), Confidence.MEDIUM)); } } if (dependency.getEcosystem() == null) { //this could be an assembly dependency.setEcosystem(DEPENDENCY_ECOSYSTEM); } } } } catch (IOException ex) { throw new AnalysisException(ex); } } private void determineDependencyName(final Dependency dependency, final String value) { if (dependency.getName() == null && StringUtils.containsIgnoreCase(dependency.getActualFile().getName(), value)) { final String ext = FileUtils.getFileExtension(value); if (ext != null) { dependency.setName(value.substring(0, value.length() - ext.length() - 1)); } else { dependency.setName(value); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy