CyberChef/src/core/operations/YARARules.mjs

115 lines
4.4 KiB
JavaScript
Raw Normal View History

2019-01-08 17:19:58 +01:00
/**
* @author Matt C [matt@artemisbot.uk]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import Yara from "libyara-wasm";
/**
2019-01-09 16:28:50 +01:00
* YARA Rules operation
2019-01-08 17:19:58 +01:00
*/
2019-01-09 16:28:50 +01:00
class YARARules extends Operation {
2019-01-08 17:19:58 +01:00
/**
2019-01-09 16:28:50 +01:00
* YARARules constructor
2019-01-08 17:19:58 +01:00
*/
constructor() {
super();
2019-01-09 16:28:50 +01:00
this.name = "YARA Rules";
2019-01-08 17:19:58 +01:00
this.module = "Yara";
2019-01-09 16:28:50 +01:00
this.description = "YARA is a tool developed at VirusTotal, primarily aimed at helping malware researchers to identify and classify malware samples. It matches based on rules specified by the user containing textual or binary patterns and a boolean expression. For help on writing rules, see the <a href='https://yara.readthedocs.io/en/latest/writingrules.html'>YARA documentation.</a>";
this.infoURL = "https://wikipedia.org/wiki/YARA";
this.inputType = "ArrayBuffer";
2019-01-08 17:19:58 +01:00
this.outputType = "string";
this.args = [
{
name: "Rules",
2019-01-09 16:28:50 +01:00
type: "text",
value: "",
rows: 5
},
{
name: "Show strings",
type: "boolean",
2019-01-09 16:28:50 +01:00
hint: "Show each match's data",
value: false
},
{
name: "Show string lengths",
type: "boolean",
2019-01-09 16:28:50 +01:00
hint: "Show the length of each match's data",
value: false
},
{
name: "Show metadata",
type: "boolean",
2019-01-09 16:28:50 +01:00
hint: "Show the metadata of each rule",
value: false
}
];
2019-01-08 17:19:58 +01:00
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [rules, showStrings, showLengths, showMeta] = args;
2019-01-08 17:19:58 +01:00
return new Promise((resolve, reject) => {
Yara().then(yara => {
2019-01-09 00:26:14 +01:00
let matchString = "";
2019-01-09 16:28:50 +01:00
const inpArr = new Uint8Array(input);
const inpVec = new yara.vectorChar();
for (let i = 0; i < inpArr.length; i++) {
inpVec.push_back(inpArr[i]);
}
const resp = yara.run(inpVec, rules);
2019-01-08 17:19:58 +01:00
if (resp.compileErrors.size() > 0) {
for (let i = 0; i < resp.compileErrors.size(); i++) {
const compileError = resp.compileErrors.get(i);
2019-01-09 00:26:14 +01:00
if (!compileError.warning) {
reject(new OperationError(`Error on line ${compileError.lineNumber}: ${compileError.message}`));
} else {
matchString += `Warning on line ${compileError.lineNumber}: ${compileError.message}`;
}
2019-01-08 17:19:58 +01:00
}
}
const matchedRules = resp.matchedRules;
for (let i = 0; i < matchedRules.size(); i++) {
const rule = matchedRules.get(i);
const matches = rule.resolvedMatches;
let meta = "";
if (showMeta && rule.metadata.size() > 0) {
meta += " [";
for (let j = 0; j < rule.metadata.size(); j++) {
meta += `${rule.metadata.get(j).identifier}: ${rule.metadata.get(j).data}, `;
}
meta = meta.slice(0, -2) + "]";
}
if (matches.size() === 0 || !(showStrings || showLengths)) {
matchString += `Input matches rule "${rule.ruleName}"${meta}.\n`;
2019-01-09 00:26:14 +01:00
} else {
matchString += `Rule "${rule.ruleName}"${meta} matches:\n`;
for (let j = 0; j < matches.size(); j++) {
const match = matches.get(j);
if (showStrings || showLengths) {
matchString += `Pos ${match.location}, ${showLengths ? `length ${match.matchLength}, ` : ""}identifier ${match.stringIdentifier}${showStrings ? `, data: "${match.data}"` : ""}\n`;
}
2019-01-09 00:26:14 +01:00
}
2019-01-08 17:19:58 +01:00
}
2019-01-09 00:26:14 +01:00
2019-01-08 17:19:58 +01:00
}
resolve(matchString);
});
});
}
}
2019-01-09 16:28:50 +01:00
export default YARARules;