#Author: Emanuel Durmaz

import os,re, utils, logHelpers, logFormats, traceback
from enum import Enum

class LogType(Enum):
    WalletProtectionMiniFilter = 1
    ClipboardHijackingProtectionMainThread = 2
    ClipboardHijackingProtectionPollThread = 3
    ClipboardMonitor = 4
    FilesystemMon = 5
    Simulation = 6
    HttpTraffic = 7
    WindowInteraction = 8


MAIN_DIR = "/media/user/HDD2/SampleLogs_Normal/" # ANALYSIS SYSTEM
#MAIN_DIR = "/media/user/HDD2/SampTest/"
#MAIN_DIR = "/home/user/SampleLogsTesting/" #LAPTOP

OUT_DIR = "/home/user/EvalLogs/"



class Family:
    def __init__(self, familyDirPath):
        print(familyDirPath)
        self.familyDirPath = familyDirPath
        self.familyName = os.path.basename(familyDirPath[:-1]) # skip slash
        self.sampleRunList = objListFactory(familyDirPath, SampleRun)
        self.cntSampleRuns = len(self.sampleRunList)

        self.parse()

        self.cntFailedSamplesToRun = len(self.failedSamplesToRun)
        self.cntSamples = len(self.filenameSet) #assuming that inputSampleSet has no duplicate filenames

    def parse(self):

        self.cntExecutedSamples = 0
        self.failedSamplesToRun = set()
        self.filenameSet = set()

        self.cntWalletStealerDetected = 0
        self.cntClipboardHijackerDetected = 0

        #self.cntSampleCrashed = 0
        self.cntSampleWithWalletIrpOpen = 0
        self.cntSampleWithWalletIrpRead = 0
        self.cntSampleWithWalletIrpWrite = 0

        self.cntSampleWithHttpResponses = 0
        self.cntSampleWithPostRequests = 0
        self.cntSampleWithGetRequests = 0
        self.cntSampleWithBigRequests = 0

        self.cntSampleWithWalletBytesInHttpRequest = 0

        for sample in self.sampleRunList:
            try:

                self.filenameSet.add(sample.filename)
                if sample.initialPid != "" and sample.initialPid != "0":
                    self.cntExecutedSamples += 1
                else:
                    self.failedSamplesToRun.add(sample.filename)
                    continue

                try:
                    if sample.logFileObjects[LogType.HttpTraffic].hasWalletBytesInHttpRequest:
                        f = open("leakedWalletBytes", "a") #save path of sample in my logfile
                        f.write(OUT_DIR + self.familyName + "/" + sample.filename + "\n")
                        f.close()
                except KeyError as e:
                    pass

                try:
                    if sample.logFileObjects[LogType.WalletProtectionMiniFilter].isAccessingWallet:
                        self.cntWalletStealerDetected += 1
                except KeyError as e: # could mean that this logfile didnt exist
                    pass

                try:
                    if sample.logFileObjects[LogType.ClipboardHijackingProtectionMainThread].detectedClipboardHijacker:
                        self.cntClipboardHijackerDetected += 1

                        # save addresses
                        f = open(OUT_DIR + self.familyName + "_addresses", "a")
                        addresses = sample.logFileObjects[
                            LogType.ClipboardHijackingProtectionMainThread].detectedHijackerAddresses

                        for address in addresses:
                            f.write(address + " | " + sample.filename + "\n")
                        f.close()

                        # save occurrences
                        fOpenFailures = open(OUT_DIR + self.familyName + "_Detected_OpenClipboardFailures", "a")
                    else:
                        fOpenFailures = open(OUT_DIR + self.familyName + "_NotDetected_OpenClipboardFailures", "a")

                    cntOpenClipboardFailures = sample.logFileObjects[
                        LogType.ClipboardHijackingProtectionMainThread].cntOpenClipboardFailures
                    fOpenFailures.write(str(cntOpenClipboardFailures) + " | " + sample.filename + "\n")
                    fOpenFailures.close()
                except KeyError as e:
                    pass
                except FileNotFoundError as e:
                    print("IGNORE: " + traceback.format_exc())

                try:
                    if sample.logFileObjects[LogType.FilesystemMon].cntWalletsIrpOpenLines > 0:
                        self.cntSampleWithWalletIrpOpen += 1
                except KeyError as e:
                    pass

                try:
                    if sample.logFileObjects[LogType.FilesystemMon].cntWalletsIrpReadLines > 0:
                        self.cntSampleWithWalletIrpRead += 1
                except KeyError as e:
                    pass

                try:
                    if sample.logFileObjects[LogType.FilesystemMon].cntWalletsIrpWriteLines > 0:
                        self.cntSampleWithWalletIrpWrite += 1
                except KeyError as e:
                    pass

                try:
                    if sample.logFileObjects[LogType.HttpTraffic].hasHttpResponses:
                        self.cntSampleWithHttpResponses += 1
                except KeyError as e:
                    pass

                try:
                    if sample.logFileObjects[LogType.HttpTraffic].hasPostRequests:
                        self.cntSampleWithPostRequests += 1
                except KeyError as e:
                    pass

                try:
                    if sample.logFileObjects[LogType.HttpTraffic].hasGetRequests:
                        self.cntSampleWithGetRequests += 1
                except KeyError as e:
                    pass

                try:
                    if sample.logFileObjects[LogType.HttpTraffic].hasBigRequests:
                        self.cntSampleWithBigRequests += 1
                except KeyError as e:
                    pass

                try:
                    if sample.logFileObjects[LogType.HttpTraffic].hasWalletBytesInHttpRequest:
                        self.cntSampleWithWalletBytesInHttpRequest += 1
                except KeyError as e:
                    pass

            except Exception as e:
                print(traceback.format_exc())

    def print(self):
        print("-> " + self.familyDirPath)
        print("--> cntSampleRuns: " + str(self.cntSampleRuns))
        print("--> cntSamples: " + str(self.cntSamples))  
        print("--> cntExecutedSamples: " + str(self.cntExecutedSamples))
        print("--> cntFailedSamplesToRun: " + str(self.cntFailedSamplesToRun))
        print("--> cntWalletStealerDetected: " + str(self.cntWalletStealerDetected))
        print("--> cntClipboardHijackerDetected: " + str(self.cntClipboardHijackerDetected))
        print("--> cntSampleWithWalletIrpOpen: " + str(self.cntSampleWithWalletIrpOpen))
        print("--> cntSampleWithWalletIrpRead: " + str(self.cntSampleWithWalletIrpRead))
        print("--> cntSampleWithWalletIrpWrite: " + str(self.cntSampleWithWalletIrpWrite))
        print("--> cntSampleWithHttpResponses: " + str(self.cntSampleWithHttpResponses))
        print("--> cntSampleWithPostRequests: " + str(self.cntSampleWithPostRequests))
        print("--> cntSampleWithGetRequests: " + str(self.cntSampleWithGetRequests))
        print("--> cntSampleWithBigRequests: " + str(self.cntSampleWithBigRequests))
        print("--> cntSampleWithWalletBytesInHttpRequest: " + str(self.cntSampleWithWalletBytesInHttpRequest)) 



#######################################################################
class SampleRun:
    def __init__(self, sampleLogDirPath):
        self.sampleLogDirPath = sampleLogDirPath
        self.filename = self.extractSampleFilename()

        self.initialPid = ""

        try:
            self.initialPid = self.extractInitialPid()

            self.logPaths = self.findLogPaths()
            self.parseLogFiles()
        except:
            print("Exception: " + traceback.format_exc() + " | sampleLogDirPath: " + sampleLogDirPath)

    def parseLogFiles(self):

        self.logFileObjects = dict()

        try:
            self.walletProtectionMiniFilterLog = logFormats.WalletProtectionMiniFilterLog(
                self.logPaths[LogType.WalletProtectionMiniFilter])
            self.logFileObjects[LogType.WalletProtectionMiniFilter] = self.walletProtectionMiniFilterLog
        except KeyError as e:
            self.walletProtectionMiniFilterLog = 0

        try:
            self.clipboardHijackingProtectionMainThreadLog = logFormats.ClipboardHijackingProtectionMainThreadLog(
                self.logPaths[LogType.ClipboardHijackingProtectionMainThread])
            self.logFileObjects[LogType.ClipboardHijackingProtectionMainThread] = self.clipboardHijackingProtectionMainThreadLog
        except KeyError as e:
            self.clipboardHijackingProtectionMainThreadLog = 0

        try:
            self.clipboardHijackingProtectionPollThreadLog = logFormats.ClipboardHijackingProtectionPollThreadLog(
                self.logPaths[LogType.ClipboardHijackingProtectionPollThread])
            self.logFileObjects[LogType.ClipboardHijackingProtectionPollThread] = self.clipboardHijackingProtectionPollThreadLog
        except KeyError as e:
            self.clipboardHijackingProtectionPollThreadLog = 0

        try:
            self.clipboardMonitorLog = logFormats.ClipboardMonitorLog(self.logPaths[LogType.ClipboardMonitor])
            self.logFileObjects[LogType.ClipboardMonitor] = self.clipboardMonitorLog
        except KeyError as e:
            self.clipboardMonitorLog = 0

        try:
            self.filesystemMonLog = logFormats.FilesystemMonLog(self.logPaths[LogType.FilesystemMon])
            self.logFileObjects[LogType.FilesystemMon] = self.filesystemMonLog
        except KeyError as e:
            self.filesystemMonLog = 0

        try:
            self.simulationLog = logFormats.SimulationLog(self.logPaths[LogType.Simulation])
            self.logFileObjects[LogType.Simulation] = self.simulationLog
        except KeyError as e:
            self.simulationLog = 0

        try:
            self.httpTrafficLog = logFormats.HttpTrafficLog(self.logPaths[LogType.HttpTraffic])
            self.logFileObjects[LogType.HttpTraffic] = self.httpTrafficLog
        except KeyError as e:
            self.httpTrafficLog = 0

        try:
            self.windowInteractionLog = logFormats.WindowInteractionLog(self.logPaths[LogType.WindowInteraction])
            self.logFileObjects[LogType.WindowInteraction] = self.windowInteractionLog
        except KeyError as e:
            self.windowInteractionLog = 0

    #######################################################################
    def findLogPaths(self):
        logPaths = dict()
        for name in os.listdir(self.sampleLogDirPath):
            path = self.sampleLogDirPath + name
            if os.path.isfile(path):
                if name == "WalletProtectionMiniFilter.txt":
                    logPaths[LogType.WalletProtectionMiniFilter] = path
                if name == "FilesystemMon.txt":
                    logPaths[LogType.FilesystemMon] = path
                if name.find("httpLog") != -1:
                    logPaths[LogType.HttpTraffic] = path
                if name.find("simLog") != -1:
                    logPaths[LogType.Simulation] = path
                if name.find("WindowInteraction") != -1:
                    logPaths[LogType.WindowInteraction] = path
                if name.find("ClipboardHijackingProtection_MainThread") != -1:
                    logPaths[LogType.ClipboardHijackingProtectionMainThread] = path
                if name.find("ClipboardHijackingProtection_PollThread") != -1:
                    logPaths[LogType.ClipboardHijackingProtectionPollThread] = path
                if name.find("ClipboardMonitor") != -1:
                    logPaths[LogType.ClipboardMonitor] = path
        return logPaths


    #######################################################################

    def extractInitialPid(self):
        f = open(self.sampleLogDirPath + "pslog.txt","rb")

        pid = ""

        for line in f.readlines():
            line = str(line) #force string conversion (opened in binary mode, to avoid encoding errors)


            if line.find("process ID") != -1:
                pid = utils.extractStringBetween(line, "process ID ", ".")
                break

            if line.find("Win32-Anwendung") != -1:
                pid = "0"
                break

        f.close()
        return pid

    def extractSampleFilename(self):
        sampleDirName = os.path.basename(self.sampleLogDirPath[:-1])  # cut slash at end, and get directory name
        filename = sampleDirName[:-20]
        return filename


    def print(self):
        print("--> " + self.filename)
        print("---> initialPid: " + self.initialPid)
        print("---> sampleLogDirPath: " + self.sampleLogDirPath)

        for key, logFileObject in self.logFileObjects.items():
            logFileObject.print()




################################################################################

def filterLogsByPids(sampleLogDir, pidArray):
    logfile = open(sampleLogDir + "FilesystemMon.txt", "r", errors='ignore') #ignore utf8 decode errors
    filteredLogFile = open(sampleLogDir + "FilesystemMon_filtered.txt", "w")

    for line in logfile.readlines():
        for pid in pidArray:
            if line.find("processId: " + str(pid) + " |") != -1:
                filteredLogFile.write(line)

    logfile.close()
    filteredLogFile.close()



def objListFactory(rootDir, createObjRoutine):
    objList =  []
    for name in os.listdir(rootDir):
        if os.path.isdir(rootDir + name):
            obj = createObjRoutine(rootDir + name + "/")
            objList.append(obj)
    return objList




######################################################################################




familyList = objListFactory(MAIN_DIR, Family)
for family in familyList:
    family.print()

