Skip to content

Commit

Permalink
0.2 (beta)
Browse files Browse the repository at this point in the history
  • Loading branch information
yarox24 committed Mar 29, 2016
1 parent 1c3cc7b commit 012cbed
Showing 1 changed file with 93 additions and 124 deletions.
217 changes: 93 additions & 124 deletions evtkit.py
Original file line number Diff line number Diff line change
@@ -1,178 +1,147 @@
#!/usr/bin/env python
import argparse, mmap, os, re, shutil, sys

VERSION = "0.1 (alpha)"
VERSION = "0.2 (beta)"
OPTION_SUFFIX = "_fixed"
PROJECT_SITE = "https://github.com/yarox24/evtkit"

# PARSER
parser = argparse.ArgumentParser(description='Fix acquired .evt - Windows Event Log files (Forensics)')
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument('-i', '--in-place', action='store_true', help='Change .evt in-place (Default)')
group.add_argument('-c', '--copy', action='store_true', help='Create copy of .evt with suffix [NAME]' + OPTION_SUFFIX + '.evt')
parser.add_argument('-o', '--out-dir', nargs=1, help='Output directory for fixed .evt files. Implies -c')
parser.add_argument('-c', '--copy_to_dir', nargs=1, help='Output directory for fixed .evt files.')
parser.add_argument('-q', '--quiet', action='store_true', help='Turn off verbosity')
parser.add_argument('sources', nargs='*', action='append', help="a.evt b.evt evt_dir/")
parser.add_argument('sources', nargs='*', action='append', help="a.evt b.evt evt_dir/ [...]")
args = parser.parse_args()


#FUNCTIONS
def qprint(text):
if not args.quiet: print text

# -o implies -c
if args.out_dir:
args.copy = True

# -i and -o
if args.in_place and args.out_dir:
qprint("--out-dir implies --copy mode")

# Determine method
method = "i"
if args.copy:
method = "c"

# Evt to work on
#MODE
CURRENT_MODE = "i" # IN-PLACE
if args.copy_to_dir:
CURRENT_MODE = "c" # COPY
OUT_DIR = args.copy_to_dir[0].rstrip("/\\")
if not os.path.isdir(OUT_DIR):
os.makedirs(OUT_DIR)
if not os.path.isdir(OUT_DIR):
qprint("Error: " + OUT_DIR + " cannot create directory")
sys.exit(-4)

# SOURCES
sources = args.sources[0]
items_number = len(sources)
COUNTER = 1

# --------------------------------------------- MAIN ---------------------------------------------
qprint("evtkit v " + VERSION + "\t-== " + PROJECT_SITE + " ==-")
first_time = True
if items_number == 0:
qprint("*** Please provide at least one .evt file or directory containing .evt files")
qprint("")
qprint("Examples:")
qprint("1. Fix in-place 2 files (Make sure you got a copy!):")
qprint(" " + sys.argv[0] + " AppEvent.Evt SysEvent.Evt")
qprint("")
qprint("2. Find all *.evt files in logs_dir/, copy them to fixed_copy/ and repair them:")
qprint(" " + sys.argv[0] + " --copy --out-dir=fixed_copy logs_dir")
sys.exit(-10)

out_dir = None
if args.out_dir:
out_dir = args.out_dir[0].rstrip("/\\")
if not os.path.isdir(out_dir):
qprint("Error: " + out_dir + " is not a valid output directory")
sys.exit(-4)

##### REBUILD STARTING FROM THIS
##### REBUILD STARTING FROM THIS
##### REBUILD STARTING FROM THIS

def check_mm_range(ptr, filesize, msg):
if ptr > filesize:
qprint(msg)
return False
return True

def check_mm_range(ptr, filesize):
return not ptr > filesize

def fixevtfile(path):
try:
filesize = os.path.getsize(path)
if filesize == 0:
qprint("* Empty evt file - 0-byte size : %s" % (path))
return
return "Empty evt file - 0-byte size"

f = open(path, "a+")
mm = mmap.mmap(f.fileno(), 0)

if not ord(mm[0]) == 0x30:
qprint("* Invalid evt file - wrong HeaderSize (first byte), should be 0x30 is 0x%x : %s" % (ord(mm[0]), path))
mm.close()
f.close()
return

if not check_mm_range(0x24, filesize, "* Invalid evt file - too short Header: %s" % path):
mm.close()
f.close()
return
#FLAG_ELF_LOGFILE_ARCHIVE_SET = 0x8
mm[0x24] = chr(0x8)
return "Invalid evt file - wrong HeaderSize (first byte), should be 0x30 is 0x%x" % (ord(mm[0]))

if not check_mm_range(0x24, filesize):
return "Invalid evt file - too short Header"

mm[0x24] = chr(0x8) #FLAG_ELF_LOGFILE_ARCHIVE_SET = 0x8

# Search for floating footer
res = re.search("\x11\x11\x11\x11\x22\x22\x22\x22\x33\x33\x33\x33\x44\x44\x44\x44", mm)

# Count events
#t = re.findall("LfLe", mm)
# print t
#print len(t) - 1

if not res:
qprint(
"* Invalid evt file - Cannot find floating footer (0x110x110x110x110x220x220x220x220x330x330x330x330x440x440x440x44) : %s" % path)
mm.close()
f.close()
return
return "Invalid evt file - Cannot find floating footer (0x110x110x110x110x220x220x220x220x330x330x330x330x440x440x440x44)"

if not check_mm_range(res.start() + 0x10, filesize):
return "Invalid evt file - floating footer too short"
ff_pointers_start = res.start() + 0x10

mm[0x10:0x20] = mm[ff_pointers_start:ff_pointers_start + 0x10]

# Count events
count_lfle = len(re.findall("LfLe", mm)) - 1
mm.close()
f.close()
except Exception as e:
qprint("* Error when fixing file: " + path)
qprint("* " + e.message)

return "Fixed, " + str(count_lfle) + " possible events"
except Exception as e:
return "Exception: " + e.message

def add_suffix(path):
filename = os.path.basename(path)
spl = filename.split(".")
filename = spl[0] + OPTION_SUFFIX
if spl[1]:
if len(spl) > 1 and spl[1]:
filename += "." + spl[1]
return os.path.dirname(path) + os.path.sep + filename


def process_single_evt(path):
global first_time
if first_time == True:
if not args.quiet:
print "Choosen method: ",
if method == "i":
qprint("[In-place] (Default)")
elif method == "c":
qprint('[Copy]')
if out_dir:
qprint("Result will be copied to - " + out_dir)
else:
qprint("Result within the same directory with suffix: [NAME]" + OPTION_SUFFIX + ".evt")
first_time = False

qprint("-> Processing: " + path)

if method == "i":
fixevtfile(path)
elif method == "c":
if not out_dir:
new_copy_path = add_suffix(path)
else:
#os.makedirs(out_dir, 0o777, True)
new_copy_path = add_suffix(out_dir + os.path.sep + os.path.basename(path))
print "Copying %s -> %s" % (path, new_copy_path)
global COUNTER
global CURRENT_MODE
global OUT_DIR

if CURRENT_MODE == "i":
result = fixevtfile(path)
elif CURRENT_MODE == "c":
new_copy_path = add_suffix(OUT_DIR + os.path.sep + os.path.basename(path))
try:
shutil.copy2(path, new_copy_path)
result = fixevtfile(new_copy_path)
except Exception as e:
qprint("* Error when copying : %s -> %s" % (path, new_copy_path))
qprint("* " + e.strerror)
return
fixevtfile(new_copy_path)

qprint("")


for path in sources:
if os.path.isdir(path):
path = path.rstrip("/\\")
files = os.listdir(path)
for file in files:
if file[-3:].lower() == "evt":
full_path = path + os.path.sep + file
process_single_evt(full_path)
elif os.path.isfile(path):
process_single_evt(path)
else:
qprint("File/directory doesn't exist: " + path)
result = "Error when copying to: " + new_copy_path + " " + e.strerror

qprint('{0: <3}'.format(str(COUNTER)+'.') + " " + path + " [" + result + "]")
COUNTER += 1


def main():
qprint("evtkit v " + VERSION + "\t-== " + PROJECT_SITE + " ==-")

if items_number == 0:
qprint("*** Please provide at least one .evt file or directory containing .evt files")
qprint("")
qprint("Examples:")
qprint("1. Fix in-place 2 files (Make sure you got a copy!):")
qprint(" " + sys.argv[0] + " AppEvent.Evt SysEvent.Evt")
qprint("")
qprint("2. Find all *.evt files in evt_dir/, copy them to fixed_copy/ and repair them:")
qprint(" " + sys.argv[0] + " --copy_to_dir=fixed_copy evt_dir")
sys.exit(-10)

if not args.quiet:
print "Choosen method: ",
if CURRENT_MODE == "i":
qprint("[In-place] (Default)")
elif CURRENT_MODE == "c":
qprint('[Copy]')
qprint("Result will be copied to - " + OUT_DIR)

# ITERATE OVER SOURCES
for path in sources:
if os.path.isdir(path):
path = path.rstrip("/\\")
try:
files = os.listdir(path)
except Exception as e:
qprint("Error when listing directory: %s" % (path) + " [" + e.strerror + "]")
continue
for file in files:
if file[-3:].lower() == "evt":
full_path = path + os.path.sep + file
process_single_evt(full_path)
elif os.path.isfile(path):
process_single_evt(path)
else:
qprint("Error: File/directory doesn't exist: " + path)

qprint("")

if __name__ == "__main__":
main()

0 comments on commit 012cbed

Please sign in to comment.