From 166d343849731198b06280ed8af339a051bac629 Mon Sep 17 00:00:00 2001 From: stuartjash Date: Tue, 6 Sep 2022 15:32:48 -0700 Subject: [PATCH 1/7] addition of new process parser for parsing process dump --- analysis/ProcessParser.swift | 67 ++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 analysis/ProcessParser.swift diff --git a/analysis/ProcessParser.swift b/analysis/ProcessParser.swift new file mode 100644 index 0000000..03cfb89 --- /dev/null +++ b/analysis/ProcessParser.swift @@ -0,0 +1,67 @@ +// +// ProcessParser.swift +// aftermath +// +// Created by Stuart Ashenbrenner on 9/6/22. +// + +import Foundation + +class ProcessParser: AftermathModule { + + let collectionDir: String + let storylineFile: URL + + init(collectionDir: String, storylineFile: URL) { + self.collectionDir = collectionDir + self.storylineFile = storylineFile + } + + func parseProcessDump() { + + let procPathRaw = "\(self.collectionDir)/Processes/process_dump.txt" + do { + + let data = try String(contentsOf: URL(fileURLWithPath: procPathRaw), encoding: .utf8) + let line = data.components(separatedBy: "\n") + + for ind in 1...line.count - 1 { + let splitLine = line[ind].components(separatedBy: " ") + + guard let date = splitLine[safe: 0] else { continue } + guard let time = splitLine[safe: 1] else { continue } + guard let zone = splitLine[safe: 2] else { continue } + let unformattedDate = date + "T" + time + zone // 2022-09-02T17:16:58 +0000 + let dateFormatter = DateFormatter() + dateFormatter.locale = Locale(identifier: "en_US") + dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" // 2022-09-02T17:16:58+0000 + dateFormatter.timeZone = TimeZone(secondsFromGMT: 0) + + var info = "" + for i in 3...splitLine.count - 1 { + info = info.appending(" " + splitLine[i]) + } + + sanatizeInfo(&info) + + guard let dateZone = dateFormatter.date(from: unformattedDate) else { continue } + dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" + let formattedDate = dateFormatter.string(from: dateZone) + let text = "\(formattedDate), PROCESS, \(info)" + self.addTextToFile(atUrl: self.storylineFile, text: text) + } + } catch { + print("Error parsing process dump raw file: \(error)") + } + } + + fileprivate func sanatizeInfo(_ info: inout String) { + info = info.replacingOccurrences(of: ",", with: "") + info = info.replacingOccurrences(of: "\"", with: "") + } + + func run() { + self.log("Parsing process collection...") + parseProcessDump() + } +} From 011a737de6cfb03d9bae783ee782b5fbc2cd1b8a Mon Sep 17 00:00:00 2001 From: stuartjash Date: Tue, 6 Sep 2022 15:33:05 -0700 Subject: [PATCH 2/7] minor tweaks --- aftermath/CaseFiles.swift | 6 +++--- analysis/AnalysisModule.swift | 6 +++--- analysis/DatabaseParser.swift | 6 +----- analysis/Storyline.swift | 1 - analysis/Timeline.swift | 5 ----- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/aftermath/CaseFiles.swift b/aftermath/CaseFiles.swift index 98eda58..5f62610 100644 --- a/aftermath/CaseFiles.swift +++ b/aftermath/CaseFiles.swift @@ -9,9 +9,9 @@ import Foundation import ZIPFoundation struct CaseFiles { - static let caseDir = FileManager.default.temporaryDirectory.appendingPathComponent("Aftermath_\(Host.current().localizedName ?? "")_\(Date().ISO8601Format())") + static let caseDir = FileManager.default.temporaryDirectory.appendingPathComponent("Aftermath_\(Host.current().localizedName ?? "")_\(Date().ISO8601Format().replacingOccurrences(of: ":", with: "_"))") static let logFile = caseDir.appendingPathComponent("aftermath.log") - static let analysisCaseDir = FileManager.default.temporaryDirectory.appendingPathComponent("Aftermath_Analysis_\(Host.current().localizedName ?? "")_\(Date().ISO8601Format())") + static let analysisCaseDir = FileManager.default.temporaryDirectory.appendingPathComponent("Aftermath_Analysis_\(Host.current().localizedName ?? "")_\(Date().ISO8601Format().replacingOccurrences(of: ":", with: "_"))") static let analysisLogFile = analysisCaseDir.appendingPathComponent("aftermath_analysis.log") static let metadataFile = caseDir.appendingPathComponent("metadata.csv") static let fm = FileManager.default @@ -36,7 +36,7 @@ struct CaseFiles { static func MoveTemporaryCaseDir(outputDir: String, isAnalysis: Bool) { - print("Moving the aftermath direcotry from its tempoarary location. This may take some time. Please wait...") + print("Moving the aftermath directory from its tempoarary location. This may take some time. Please wait...") var localCaseDir: URL diff --git a/analysis/AnalysisModule.swift b/analysis/AnalysisModule.swift index bc2ba2b..1b95972 100644 --- a/analysis/AnalysisModule.swift +++ b/analysis/AnalysisModule.swift @@ -19,10 +19,7 @@ class AnalysisModule: AftermathModule, AMProto { init(collectionDir: String) { - self.collectionDir = collectionDir - - } func run() { @@ -38,6 +35,9 @@ class AnalysisModule: AftermathModule, AMProto { let logParser = LogParser(collectionDir: collectionDir, storylineFile: storylineFile) logParser.run() + let processParser = ProcessParser(collectionDir: collectionDir, storylineFile: storylineFile) + processParser.run() + let timeline = Timeline(collectionDir: collectionDir, timelineFile: timelineFile, storylineFile: storylineFile) timeline.run() diff --git a/analysis/DatabaseParser.swift b/analysis/DatabaseParser.swift index a45d2d7..2d353cf 100644 --- a/analysis/DatabaseParser.swift +++ b/analysis/DatabaseParser.swift @@ -31,6 +31,7 @@ class DatabaseParser: AftermathModule { tccFiles.append(f) } } + for tcc_path in tccFiles { var db : OpaquePointer? @@ -88,7 +89,6 @@ class DatabaseParser: AftermathModule { } self.addTextToFile(atUrl: tccWriteFile, text: "\(client),\(service),\(authValue),\(authReason),\(last_modified)") - self.addTextToFile(atUrl: storylineFile , text: "\(last_modified),tcc,\(authValue),\(service),\(client)") } } @@ -162,7 +162,6 @@ class DatabaseParser: AftermathModule { if LSQuarantineDataURLString != "" || LSQuarantineOriginURLString != "" { self.addTextToFile(atUrl: storylineFile, text: "\(LSQuarantineTimeStamp),lsquarantine,\(LSQuarantineAgentName),\(LSQuarantineDataURLString),\(LSQuarantineOriginURLString)") } - } } } else { @@ -180,8 +179,6 @@ class DatabaseParser: AftermathModule { parseTCC() } - - enum TCCAuthValue: String, CaseIterable { case denied = "0" case unknown = "1" @@ -255,7 +252,6 @@ class DatabaseParser: AftermathModule { case siri = "kTCCServiceSiri" case speechRecognition = "kTCCServiceSpeechRecognition" } - } extension Collection where Indices.Iterator.Element == Index { diff --git a/analysis/Storyline.swift b/analysis/Storyline.swift index af4d599..f7bacc1 100644 --- a/analysis/Storyline.swift +++ b/analysis/Storyline.swift @@ -53,7 +53,6 @@ class Storyline: AftermathModule { } func addFirefoxData() { - let chromePaths = ["history":"\(collectionDir)/Browser/Firefox/history_output.csv","downloads":"\(collectionDir)/Browser/Firefox/downloads_output.csv"] for (title,p) in chromePaths { diff --git a/analysis/Timeline.swift b/analysis/Timeline.swift index 73bdcae..0ed993e 100644 --- a/analysis/Timeline.swift +++ b/analysis/Timeline.swift @@ -28,7 +28,6 @@ class Timeline: AftermathModule { let headerOptions = ["birth", "accessed", "modified"] - for r in metadataFileContents.rows { var file: String = "" @@ -58,9 +57,7 @@ class Timeline: AftermathModule { } } - func sortTimeline() { - self.log("Creating a file timeline...") let sortedTimeline = self.createNewCaseFile(dirUrl: CaseFiles.analysisCaseDir, filename: "file_timeline.csv") @@ -82,7 +79,6 @@ class Timeline: AftermathModule { } func removeUnsorted() { - do { if filemanager.fileExists(atPath: self.timelineFile.path) { try filemanager.removeItem(at: self.timelineFile) @@ -93,7 +89,6 @@ class Timeline: AftermathModule { } func run() { - organizeMetadata() //timestamp, type(download,birth,access,etc), path sortTimeline() removeUnsorted() From 7bdf5560c5a03f44de7b7e2a92f5ac440b18537c Mon Sep 17 00:00:00 2001 From: stuartjash Date: Tue, 6 Sep 2022 15:33:39 -0700 Subject: [PATCH 3/7] new proc parser --- aftermath.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aftermath.xcodeproj/project.pbxproj b/aftermath.xcodeproj/project.pbxproj index 0cc7eac..8a0e7f4 100644 --- a/aftermath.xcodeproj/project.pbxproj +++ b/aftermath.xcodeproj/project.pbxproj @@ -46,6 +46,7 @@ A0E1E3F8275ED35D008D0DC6 /* NetworkConnections.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0E1E3F7275ED35D008D0DC6 /* NetworkConnections.swift */; }; A0E22EF2285CD60A003A411A /* CommonDirectories.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0E22EF1285CD60A003A411A /* CommonDirectories.swift */; }; A0FAEEFE28B94B2C00AC655F /* LogParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0FAEEFD28B94B2C00AC655F /* LogParser.swift */; }; + A0FD80F628C7F82400E91584 /* ProcessParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0FD80F528C7F82400E91584 /* ProcessParser.swift */; }; A190FFD328B8094600B9EF9A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A190FFD228B8094600B9EF9A /* XCTest.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; A190FFE228B8151F00B9EF9A /* MockFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A190FFD528B80C3900B9EF9A /* MockFileManager.swift */; }; A190FFE328B8168400B9EF9A /* AftermathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A190FFCF28B8084F00B9EF9A /* AftermathTests.swift */; }; @@ -113,6 +114,7 @@ A0E1E3F7275ED35D008D0DC6 /* NetworkConnections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConnections.swift; sourceTree = ""; }; A0E22EF1285CD60A003A411A /* CommonDirectories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonDirectories.swift; sourceTree = ""; }; A0FAEEFD28B94B2C00AC655F /* LogParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogParser.swift; sourceTree = ""; }; + A0FD80F528C7F82400E91584 /* ProcessParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessParser.swift; sourceTree = ""; }; A190FFCF28B8084F00B9EF9A /* AftermathTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AftermathTests.swift; sourceTree = ""; }; A190FFD228B8094600B9EF9A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; A190FFD528B80C3900B9EF9A /* MockFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFileManager.swift; sourceTree = ""; }; @@ -249,6 +251,7 @@ A0C930D328A4318F0011FB87 /* Timeline.swift */, A02509F028AD93DA0030D6A7 /* Storyline.swift */, A0FAEEFD28B94B2C00AC655F /* LogParser.swift */, + A0FD80F528C7F82400E91584 /* ProcessParser.swift */, ); path = analysis; sourceTree = ""; @@ -519,6 +522,7 @@ A3046F8E27627DAC0069AA21 /* Module.swift in Sources */, 8ABB9E2B27568EB700C0ADD7 /* UnifiedLogModule.swift in Sources */, A0879957275AD2DC00E885BC /* SystemConfig.swift in Sources */, + A0FD80F628C7F82400E91584 /* ProcessParser.swift in Sources */, A05BF3BF284FF8CF009E197B /* Slack.swift in Sources */, A007834E28947D71008489EA /* Emond.swift in Sources */, A076742F2755798F00ED7066 /* ArtifactsModule.swift in Sources */, From 9c2456668aef4e48e774e48b548d26cf0bf97f11 Mon Sep 17 00:00:00 2001 From: stuartjash Date: Tue, 6 Sep 2022 15:54:44 -0700 Subject: [PATCH 4/7] fixed spelling issues --- aftermath/CaseFiles.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aftermath/CaseFiles.swift b/aftermath/CaseFiles.swift index 5f62610..e34cee9 100644 --- a/aftermath/CaseFiles.swift +++ b/aftermath/CaseFiles.swift @@ -34,9 +34,8 @@ struct CaseFiles { } } - static func MoveTemporaryCaseDir(outputDir: String, isAnalysis: Bool) { - print("Moving the aftermath directory from its tempoarary location. This may take some time. Please wait...") + print("Moving the aftermath directory from its temporary location. This may take some time. Please wait...") var localCaseDir: URL From b4b04dd5cd18cb93a47c29c0e6c5987d86330722 Mon Sep 17 00:00:00 2001 From: stuartjash Date: Thu, 8 Sep 2022 13:59:03 -0700 Subject: [PATCH 5/7] added step to check if arg begins with - but is not valid --- aftermath/Command.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aftermath/Command.swift b/aftermath/Command.swift index 7ebe110..b8362c7 100644 --- a/aftermath/Command.swift +++ b/aftermath/Command.swift @@ -24,6 +24,7 @@ class Command { static var analysisDir: String? = nil static var outputDir: String = "/tmp" static var collectDirs: [String] = [] + static var availableArgs: [String] = ["-h", "--help", "--cleanup", "-d", "--deep", "--pretty", "-o", "--output", "--analyze", "--collect-dirs"] static func main() { setup(with: CommandLine.arguments) @@ -61,8 +62,13 @@ class Command { } default: if !arg.starts(with: "-") { + if !availableArgs.contains(arg) { + print("Unidentified argument: \(arg)") + exit(9) + } } else { print("Unidentified argument: \(arg)") + exit(9) } } } From 7783fa5fc861d33cdb2aa1d31d5b36ceee45c79d Mon Sep 17 00:00:00 2001 From: stuartjash Date: Thu, 8 Sep 2022 14:10:30 -0700 Subject: [PATCH 6/7] updated readme with uninstaller info --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 483d31f..d8ef38e 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,9 @@ There is an Aftermath.pkg available under [Releases](https://github.com/jamf/aft sudo aftermath [option1] [option2] ``` +## Uninstall +To uninstall the aftermath binary, run the `Aftermath Uninstaller.pkg` from the Releases [Releases](https://github.com/jamf/aftermath/releases). This will uninstall the binary and also run `aftermath --cleanup` to remove aftermath directories. If any aftermath directories elsewhere, using the `--output` command, it is the responsibility of the user/admin to remove said directories. + ## Help Menu ``` @@ -77,7 +80,7 @@ sudo aftermath [option1] [option2] -o or --output -> specify an output location for Aftermath collection results (defaults to /tmp) usage: -o Users/user/Desktop --pretty -> colorize Terminal output ---cleanup -> remove Aftermath Response Folders +--cleanup -> remove Aftermath folders from default locations ("/tmp", "/var/folders/zz/) ``` ## Contributors From c99fb869bf98e3b001ce698ce5eb6b4e284b8f96 Mon Sep 17 00:00:00 2001 From: stuartjash Date: Thu, 8 Sep 2022 14:12:57 -0700 Subject: [PATCH 7/7] fixed grammar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d8ef38e..f07202b 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ sudo aftermath [option1] [option2] ``` ## Uninstall -To uninstall the aftermath binary, run the `Aftermath Uninstaller.pkg` from the Releases [Releases](https://github.com/jamf/aftermath/releases). This will uninstall the binary and also run `aftermath --cleanup` to remove aftermath directories. If any aftermath directories elsewhere, using the `--output` command, it is the responsibility of the user/admin to remove said directories. +To uninstall the aftermath binary, run the `Aftermath Uninstaller.pkg` from the Releases [Releases](https://github.com/jamf/aftermath/releases). This will uninstall the binary and also run `aftermath --cleanup` to remove aftermath directories. If any aftermath directories reside elsewhere, from using the `--output` command, it is the responsibility of the user/admin to remove said directories. ## Help Menu