Package de.pdf_scrutinizer.emulation

Source Code of de.pdf_scrutinizer.emulation.InterpreterEmulation

/*
* PDF Scrutinizer, a library for detecting and analyzing malicious PDF documents.
* Copyright 2013  Florian Schmitt <florian@florianschmitt.de>, Fraunhofer FKIE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package de.pdf_scrutinizer.emulation;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.NDC;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextAction;
import org.mozilla.javascript.EcmaError;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableNativeJavaObject;
import org.mozilla.javascript.ScriptableObject;

import de.pdf_scrutinizer.Scrutinizer;
import de.pdf_scrutinizer.Scrutinizer.Intensity;
import de.pdf_scrutinizer.data.AnalysisResult.Classification;
import de.pdf_scrutinizer.API.App;
import de.pdf_scrutinizer.API.Collab;
import de.pdf_scrutinizer.API.Event;
import de.pdf_scrutinizer.API.Spell;
import de.pdf_scrutinizer.API.Timeout;
import de.pdf_scrutinizer.API.Util;
import de.pdf_scrutinizer.API.XMLData;
import de.pdf_scrutinizer.API.display;
import de.pdf_scrutinizer.API.app.Doc;
import de.pdf_scrutinizer.API.app.plugIn;
import de.pdf_scrutinizer.API.app.doc.Media;

public abstract class InterpreterEmulation {
    protected Log log = LogFactory.getLog(InterpreterEmulation.class);
    protected Doc document;
    protected Scrutinizer scrutinizer;
    String viewerversions[] = {"8", "9"};

    public void execute(final String code) {
        List<String> codes = new ArrayList<String>();
        codes.add(code);
        execute(codes);
    }

    // ScriptableNativeJavaObject is needed for app object (and any JavaToJS-converted object) to accept dynamically added properties
    public void execute(final List<String> code) {
        if (document == null) {
            log.error("doc object of InterpreterEmulation is not initialized");
            return;
        }

        for (String x : viewerversions) {
            new ScriptableNativeJavaObject.ScriptableNativeContextFactory().call(generateContextAction(x, "5.13", code));
            if (scrutinizer.getAnalysisResult().getClassification() == Classification.malicious) return;
        }

        // if the document is not detected as malicious
        // try another version of the first plugin
        if (!(scrutinizer.getAnalysisResult().getClassification() == Classification.malicious)) {
            for (String x : viewerversions) {
                new ScriptableNativeJavaObject.ScriptableNativeContextFactory().call(generateContextAction(x, "8.13", code));
                if (scrutinizer.getAnalysisResult().getClassification() == Classification.malicious) return;
            }
        }
    }

    protected ContextAction generateContextAction(final String viewerVersion, final String pluginVersion, final List<String> codes) {
        ContextAction action = new ContextAction() {
            public Object run(Context cx) {
                log.info("initializing Rhino JavaScript engine...");
                cx.setOptimizationLevel(-1); // Interpreter mode

                Doc doc = document; //global 'this'-object

                //define methods of doc object
                String[] names = {
                        "getPageNumWords",
                        "getPageNthWord",
                        "selectPageNthWord",
                        "syncAnnotScan",
                        "getAnnots",
                        "getAnnot",
                        "getField",
                        "getURL",
                        "isBoxChecked",
                        "printSeps",
                        "breakpoint", //dummy
                };
                //TODO: problem: no overloading allowed

                doc.defineFunctionProperties(names, Doc.class, ScriptableObject.DONTENUM);

                Scriptable scope = cx.initStandardObjects(doc);
                cx.putThreadLocal("topscope", scope);
                cx.putThreadLocal("scrutinizer", scrutinizer);

                //set up API
                App app = new App(scrutinizer, doc);

                ScriptableObject.putProperty(scope, "app", Context.javaToJS(app, scope));
                ScriptableObject.putProperty(scope, "Collab", Context.javaToJS(new Collab(scrutinizer), scope));
                ScriptableObject.putProperty(scope, "util", Context.javaToJS(new Util(scrutinizer), scope));
                ScriptableObject.putProperty(scope, "event", Context.javaToJS(new Event(scrutinizer, doc), scope));
                ScriptableObject.putProperty(scope, "media", Context.javaToJS(new Media(scrutinizer), scope));
                ScriptableObject.putProperty(scope, "XMLData", Context.javaToJS(new XMLData(scrutinizer), scope));
                ScriptableObject.putProperty(scope, "display", Context.javaToJS(new display(), scope));
                ScriptableObject.putProperty(scope, "console", Context.javaToJS(doc.console, scope));
                ScriptableObject.putProperty(scope, "info", Context.javaToJS(doc.info, scope));
                ScriptableObject.putProperty(scope, "spell", Context.javaToJS(new Spell(scrutinizer), scope));

                // redirect String.eval() and app.eval() to eval()
                ScriptableObject.putProperty((Scriptable) scope.get("String", scope), "eval", (Scriptable) scope.get("eval", scope));
                ScriptableObject.putProperty((Scriptable) scope.get("app", scope), "eval", (Scriptable) scope.get("eval", scope));

                /* these are deprecated but still used in malicious samples */
                ScriptableObject.putProperty(scope, "subject", Context.javaToJS(doc.info.Subject, scope));
                ScriptableObject.putProperty(scope, "producer", Context.javaToJS(doc.info.Producer, scope));
                ScriptableObject.putProperty(scope, "creator", Context.javaToJS(doc.info.Creator, scope));
                ScriptableObject.putProperty(scope, "author", Context.javaToJS(doc.info.Author, scope));
                ScriptableObject.putProperty(scope, "keywords", Context.javaToJS(doc.info.Keywords, scope));
                ScriptableObject.putProperty(scope, "creationDate", Context.javaToJS(doc.info.CreationDate, scope));
                ScriptableObject.putProperty(scope, "modDate", Context.javaToJS(doc.info.ModDate, scope));
                ScriptableObject.putProperty(scope, "title", Context.javaToJS(doc.info.Title, scope));

                ScriptableObject.putProperty(scope, "zoom", Context.javaToJS(doc.zoom, scope));
                ScriptableObject.putProperty(scope, "URL", Context.javaToJS(doc.URL, scope));
                ScriptableObject.putProperty(scope, "numPages", Context.javaToJS(doc.numPages, scope));

                // if document catalog contains custom metadata we have to put them into the context.
                if (scrutinizer.getDocumentAdapter() != null) {
                    PDDocumentInformation info = scrutinizer.getDocumentAdapter().getDocument().getDocumentInformation();
                    if (info != null) {
                        String[] docinfokeys = {"Author", "Creator", "CreationDate", "Subject", "Title", "Keywords", "ModDate", "Producer", "Trapped"};
                        Set<String> metadataKeys = info.getMetadataKeys();
                        metadataKeys.removeAll(Arrays.asList(docinfokeys)); // remove non-custom keys

                        for (String metadataKey : metadataKeys) {
                            log.debug(String.format("adding custom info metadata: %s value: %s", "info." + metadataKey, info.getCustomMetadataValue(metadataKey)));
                            ScriptableObject.putProperty((Scriptable) scope.get("info", scope), metadataKey, Context.javaToJS(info.getCustomMetadataValue(metadataKey), scope));
                        }
                    }
                }

                app.viewerVersion = Double.parseDouble(viewerVersion);
                plugIn plugin = app.getPlugin();
                plugin.version = Double.parseDouble(pluginVersion);
                app.setPlugin(plugin);
                log.info("using viewerVersion " + app.viewerVersion);
                for (String str : codes) {
                    doExecute(str, cx, scope);
                }

                List<Timeout> timeouts = app.getTimeouts();
                synchronized (timeouts) {
                    for (Timeout timeout : timeouts) {
                        timeout.stop();
                    }
                }

                return null;
            }
        };

        return action;
    }

    private void doExecute(final String code, final Context cx, final Scriptable scope) {
        String oneLineCode = code.trim().replace("\\s", " ").replace("\r\n", " ").replace("\n", " ");
        if (oneLineCode.length() > 50) {
            log.info("code peek: \"" + oneLineCode.substring(0, 50) + "...\"");
        } else {
            log.info("code peek: \"" + oneLineCode + "\"");
        }

        scrutinizer.getStaticAnalysis().doit(code);

        if (scrutinizer.getIntensity() == Intensity.lousy) {
            // if already classified as malicious do not execute the code.
            if (scrutinizer.getAnalysisResult().getClassification() == Classification.malicious) {
                return;
            }
        }

        log.info("starting execution");
        NDC.push("[EXE]");

        try {
            cx.evaluateString(scope, code, "InterpreterEmulation.doExecute", 0, null);
        } catch (EvaluatorException e) {
            scrutinizer.getAnalysisResult().addException(e);
        } catch (EcmaError e) {
            scrutinizer.getAnalysisResult().addException(e);
        } finally {
            NDC.pop();
        }
    }
}
TOP

Related Classes of de.pdf_scrutinizer.emulation.InterpreterEmulation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.