# === StraightArc Technologies Open Toolset : banner & disclaimer =============
def _sta_accept():
    import sys, os
    line = "=" * 68
    print(line)
    print("               StraightArc Technologies Open Toolset")
    print(line)
    print('DISCLAIMER: This tool is provided on an "AS IS" basis. StraightArc')
    print("Technologies or any of its associates shall not be responsible for")
    print("the consequences of its use. Always operate on a COPY of the media,")
    print("never the original evidence.")
    print(line)
    if os.environ.get("STRAIGHTARC_ACCEPT") == "1":
        return
    if not sys.stdin.isatty():
        sys.exit("Non-interactive run: set STRAIGHTARC_ACCEPT=1 to proceed.")
    try:
        ans = input("Type 'accept' to acknowledge and continue: ").strip().lower()
    except (EOFError, KeyboardInterrupt):
        sys.exit("\nDisclaimer not accepted. Exiting.")
    if ans not in ("accept", "y", "yes"):
        sys.exit("Disclaimer not accepted. Exiting.")
_sta_accept()
# ============================================================================

import struct, datetime
A="/mnt/d/MS/_case/artifacts/"
J=A+"_Extend__UsnJrnl__J"
import glob,os
cands=[p for p in glob.glob(A+"*") if "UsnJrnl" in p]
J=cands[0] if cands else J
print("parsing:",os.path.basename(J), f"{os.path.getsize(J):,} bytes")
def ft(v):
    try: return datetime.datetime(1601,1,1)+datetime.timedelta(microseconds=v//10)
    except: return None
REASON={0x1:"DataOverwrite",0x2:"DataExtend",0x100:"FileCreate",0x200:"FileDelete",0x400:"Rename",0x800:"IndexableChange",0x8000:"RenameOld",0x1000:"RenameNew",0x80000000:"Close",0x10:"NamedDataExtend"}
def rflags(r):
    return "|".join(v for k,v in REASON.items() if r&k) or hex(r)
KW=("anydesk","hfssd","funder","avremove","ip_scan","advanced_ip","psexec","passview","webbrowser","mimikatz","netscan","softperfect","rclone","winscp","megasync",".rdp","cobalt","nssm","gmer","procdump","lazagne")
f=open(J,"rb"); data=f.read()
n=len(data); i=0; hits=[]; earliest=None; latest=None; total=0
# scan for USN v2 records
while i < n-60:
    rl=struct.unpack_from("<I",data,i)[0]
    if rl<0x38 or rl>0x400 or (i+rl)>n or rl%8!=0:
        i+=8; continue
    maj=struct.unpack_from("<H",data,i+4)[0]; mnr=struct.unpack_from("<H",data,i+6)[0]
    if maj!=2 or mnr!=0:
        i+=8; continue
    ts=ft(struct.unpack_from("<Q",data,i+0x20)[0])
    reason=struct.unpack_from("<I",data,i+0x28)[0]
    fnl=struct.unpack_from("<H",data,i+0x38)[0]; fno=struct.unpack_from("<H",data,i+0x3A)[0]
    if fnl==0 or fnl>510 or i+fno+fnl>n:
        i+=8; continue
    try: name=data[i+fno:i+fno+fnl].decode("utf-16le","ignore")
    except: name=""
    if ts and 2024<=ts.year<=2025:
        total+=1
        if earliest is None or ts<earliest: earliest=ts
        if latest is None or ts>latest: latest=ts
        low=name.lower()
        if any(k in low for k in KW):
            hits.append((ts,name,rflags(reason)))
    i+=rl
print(f"valid USN records (2024-25): {total:,}   range {earliest} .. {latest} UTC")
hits.sort()
# dedup consecutive same (name,reason within same second)
seen=set(); out=[]
for ts,name,rf in hits:
    k=(ts.replace(microsecond=0),name,rf)
    if k in seen: continue
    seen.add(k); out.append((ts,name,rf))
print(f"\n=== attacker-tool filesystem events ({len(out)}) chronological (UTC; IST=+5:30) ===")
for ts,name,rf in out:
    ist=ts+datetime.timedelta(hours=5,minutes=30)
    print(f"  {ts}  (IST {ist.strftime('%H:%M:%S')})  {name:42} [{rf}]")


# ============================================================================
# DISCLAIMER
# This script is provided on an "AS IS" basis. StraightArc Technologies or any
# of its associates shall not be responsible for the consequences of its use.
#
# A Contribution from StraightArc Technologies (info@straightarc.com)
# ============================================================================
