From 3e05d95bfcdd727ee50a61c65e3bb661661c63c0 Mon Sep 17 00:00:00 2001 From: Hubert Jasudowicz Date: Wed, 19 Aug 2020 11:58:11 +0200 Subject: [PATCH] wip --- drakcore/drakcore/frontend/package-lock.json | 24 +++ drakcore/drakcore/frontend/package.json | 5 +- .../drakcore/frontend/src/AnalysisApicall.js | 140 +++++++++++++----- .../drakcore/frontend/src/AnalysisMain.js | 2 +- drakcore/drakcore/frontend/src/index.js | 1 + drakrun/drakrun/main.py | 43 ++++++ 6 files changed, 175 insertions(+), 40 deletions(-) diff --git a/drakcore/drakcore/frontend/package-lock.json b/drakcore/drakcore/frontend/package-lock.json index 8714382be..e43fd686b 100644 --- a/drakcore/drakcore/frontend/package-lock.json +++ b/drakcore/drakcore/frontend/package-lock.json @@ -8463,6 +8463,11 @@ "p-is-promise": "^2.0.0" } }, + "memoize-one": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", + "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -11230,6 +11235,25 @@ "warning": "^3.0.0" } }, + "react-virtualized-auto-sizer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz", + "integrity": "sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==" + }, + "react-window": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.5.tgz", + "integrity": "sha512-HeTwlNa37AFa8MDZFZOKcNEkuF2YflA0hpGPiTT9vR7OawEt+GZbfM6wqkBahD3D3pUjIabQYzsnY/BSJbgq6Q==", + "requires": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + } + }, + "react-window-infinite-loader": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/react-window-infinite-loader/-/react-window-infinite-loader-1.0.5.tgz", + "integrity": "sha512-IcPIq8lADK3zsAcqoLqQGyduicqR6jWkiK2VUX5sKSI9X/rou6OWlOEexnGyujdNTG7hSG8OVBFEhLSDs4qrxg==" + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", diff --git a/drakcore/drakcore/frontend/package.json b/drakcore/drakcore/frontend/package.json index 78fc0f991..8110f0d7c 100644 --- a/drakcore/drakcore/frontend/package.json +++ b/drakcore/drakcore/frontend/package.json @@ -14,7 +14,10 @@ "react-d3-tree": "^1.16.1", "react-dom": "^16.13.1", "react-router-dom": "^5.2.0", - "react-scripts": "^3.4.1" + "react-scripts": "^3.4.1", + "react-virtualized-auto-sizer": "^1.0.2", + "react-window": "^1.8.5", + "react-window-infinite-loader": "^1.0.5" }, "scripts": { "start": "react-scripts start", diff --git a/drakcore/drakcore/frontend/src/AnalysisApicall.js b/drakcore/drakcore/frontend/src/AnalysisApicall.js index b067f4104..55e4325d9 100644 --- a/drakcore/drakcore/frontend/src/AnalysisApicall.js +++ b/drakcore/drakcore/frontend/src/AnalysisApicall.js @@ -1,8 +1,10 @@ import React from "react"; import { Component } from "react"; +import { FixedSizeList as List } from "react-window"; +import OptionPicker from "./OptionPicker"; +import AutoSizer from "react-virtualized-auto-sizer"; import "./App.css"; import api from "./api"; -import OptionPicker from "./OptionPicker"; class AnalysisApicall extends Component { constructor(props) { @@ -13,9 +15,13 @@ class AnalysisApicall extends Component { this.state = { calls: null, processList: [], + filter: '', + filteredResults: [], }; this.pidChanged = this.pidChanged.bind(this); + this.filterChanged = this.filterChanged.bind(this); + this.computeFiltered = this.computeFiltered.bind(this); } async pidChanged(new_pid) { @@ -24,11 +30,33 @@ class AnalysisApicall extends Component { const res = await api.getApiCalls(this.analysis_id, new_pid); const calls = res.data.split("\n").map(JSON.parse); this.setState({ calls }); + this.computeFiltered(this.state.filter); } catch (e) { this.setState({ calls: [] }); } } + computeFiltered(filter) { + if (filter === '') { + this.setState({ filteredResults: this.state.calls }); + return; + } + try { + let regex = new RegExp(filter, 'gi'); + this.setState({ + filteredResults: this.state.calls.filter((elem) => + regex.test(elem.method) + ), + }); + } catch { } + } + + filterChanged(event) { + const newFilter = event.target.value; + this.setState({filter: newFilter}); + this.computeFiltered(newFilter); + } + async componentDidMount() { const analysis = this.props.match.params.analysis; const process_tree = await api.getProcessTree(analysis); @@ -37,14 +65,11 @@ class AnalysisApicall extends Component { let result = []; process_tree.forEach((proc) => { - result.push({ - key: proc.pid, - value: `${proc.pid} – ${proc.procname || "unnamed process"}`, - }); + result.push({ key: proc.pid, value: `${proc.pid} – ${proc.procname || "unnamed process"}` }); result.push(...treeFlatten(proc.children)); }); - result.sort((a, b) => a.pid - b.pid); + result.sort((a, b) => a.key - b.key); return result; } @@ -82,33 +107,62 @@ class AnalysisApicall extends Component { ); } else { - let tableContent = this.state.calls.map((entry, i) => ( - - {entry.timestamp} - - {entry.method} - - - {entry.arguments.map((arg, i) => ( -
- {arg} -
- ))} - - - )); - content = ( - - - - - - - - - {tableContent} -
TimestampMethodArguments
+ // let tableContent = this.state.calls.map((entry, i) => ( + // + // {entry.timestamp} + // + // {entry.method} + // + // + // {entry.arguments.map((arg, i) => ( + //
+ // {arg} + //
+ // ))} + // + // + // )); + + const Row = ({ data, index, style }) => { + const entry = data[index]; + const args = entry.arguments.join(", "); + return ( +
+
{entry.timestamp}
+
+ + {entry.method}({args}) = ? + +
+
+ ); + }; + + let tableContent = ( + + {Row} + ); + + content = tableContent; + + // content = ( + // + // + // + // + // + // + // + // + // {tableContent} + //
TimestampMethodArguments
+ // ); } return ( @@ -119,12 +173,22 @@ class AnalysisApicall extends Component {
- +
+
+ this.pidChanged(parseInt(pid))} + /> +
+ +
{content}
diff --git a/drakcore/drakcore/frontend/src/AnalysisMain.js b/drakcore/drakcore/frontend/src/AnalysisMain.js index 361d6dc5c..2d2c33d09 100644 --- a/drakcore/drakcore/frontend/src/AnalysisMain.js +++ b/drakcore/drakcore/frontend/src/AnalysisMain.js @@ -163,7 +163,7 @@ class AnalysisMain extends Component { try { const res_graph = await api.getGraph(this.analysisID); if (res_graph.data) { - this.setState({ graphState: "loaded", graph: res_graph.data }); + //this.setState({ graphState: "loaded", graph: res_graph.data }); } else { this.setState({ graphState: "missing" }); } diff --git a/drakcore/drakcore/frontend/src/index.js b/drakcore/drakcore/frontend/src/index.js index c24e9d807..a85313303 100644 --- a/drakcore/drakcore/frontend/src/index.js +++ b/drakcore/drakcore/frontend/src/index.js @@ -2,4 +2,5 @@ import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; + ReactDOM.render(, document.getElementById("root")); diff --git a/drakrun/drakrun/main.py b/drakrun/drakrun/main.py index 102779222..e5f348ea1 100644 --- a/drakrun/drakrun/main.py +++ b/drakrun/drakrun/main.py @@ -11,6 +11,7 @@ import zipfile import json import re +import functools from typing import Optional, List from stat import S_ISREG, ST_CTIME, ST_MODE, ST_SIZE @@ -78,6 +79,47 @@ def start_dnsmasq(vm_id: int, dns_server: str) -> Optional[subprocess.Popen]: ]) +def local_logs(method): + class LocalBuffer(logging.Handler): + FIELDS = ( + "levelname", + "message", + "created", + ) + + def __init__(self): + super().__init__() + self.buffer = [] + + def emit(self, record): + entry = {k: v for (k, v) in record.__dict__.items() if k in self.FIELDS} + self.buffer.append(entry) + + @functools.wraps(method) + def wrapper(self: Karton, *args, **kwargs): + handler = LocalBuffer() + try: + # Register new log handler + self.log.addHandler(handler) + method(self, *args, **kwargs) + except Exception: + self.log.exception("Analysis failed") + finally: + # Unregister local handler + self.log.removeHandler(handler) + try: + res = LocalResource("analysis_log.json", + json.dumps(handler.buffer), + bucket="drakrun") + task_uid = self.current_task.payload.get('override_uid') or self.current_task.uid + res._uid = f"{task_uid}/{res.name}" + res.upload(self.minio) + except Exception: + self.log.exception("Failed to upload analysis logs") + + return wrapper + + class DrakrunKarton(Karton): identity = "karton.drakrun-prod" filters = [ @@ -269,6 +311,7 @@ def get_profile_list() -> List[str]: return out + @local_logs def process(self): sample = self.current_task.get_resource("sample") self.log.info("hostname: {}".format(socket.gethostname()))