#!/usr/bin/env python3
# inspect_and_send_smb.py
# Usage: python3 inspect_and_send_smb.py <target-ip> <negotiate.bin> <session_setup.bin>

import sys, binascii, socket, os

def hexdump(b, n=64):
    print(binascii.hexlify(b[:n]).decode())

def read_file(path):
    with open(path, 'rb') as f:
        return f.read()

def has_netbios_header(data):
    if len(data) < 4:
        return False
    first = data[0]
    length = int.from_bytes(data[1:4], 'big')
    return (first == 0x00) and (0 < length <= len(data)-4 + 1000) # loose upper bound

def ensure_netbios_header(data):
    if has_netbios_header(data):
        length = int.from_bytes(data[1:4], 'big')
        if length == len(data)-4:
            return data  # already correct
    payload = data
    length = len(payload)
    if length >= (1 << 24):
        raise ValueError("payload too large for NetBIOS 3-byte length")
    header = b'\x00' + length.to_bytes(3, 'big')
    return header + payload

def send_one(target, data, port=445, timeout=5):
    with socket.create_connection((target, port), timeout=timeout) as s:
        s.settimeout(timeout)
        print(f"[+] sending {len(data)} bytes to {target}:{port} ...")
        s.sendall(data)
        try:
            r = s.recv(8192)
            print(f"[+] received {len(r)} bytes (first 200 bytes shown):")
            hexdump(r, 200)
        except socket.timeout:
            print("[!] recv timed out (no/late response).")

if __name__ == "__main__":
    if len(sys.argv) < 4:
        print("Usage: python3 inspect_and_send_smb.py <target-ip> <negotiate.bin> <session_setup.bin>")
        sys.exit(1)
    target = sys.argv[1]
    negotiate_path = sys.argv[2]
    session_path = sys.argv[3]

    if not os.path.exists(negotiate_path) or not os.path.exists(session_path):
        print("Files not found.")
        sys.exit(2)

    neg_data = read_file(negotiate_path)
    sess_data = read_file(session_path)

    print("----- negotiate.bin first 32 bytes -----")
    hexdump(neg_data, 32)
    print("has_netbios_header(negotiate):", has_netbios_header(neg_data))
    print("negotiated length (file):", len(neg_data))

    print("\n----- session_setup.bin first 32 bytes -----")
    hexdump(sess_data, 32)
    print("has_netbios_header(session):", has_netbios_header(sess_data))
    print("session_setup length (file):", len(sess_data))

    # Fix headers if necessary
    neg_packet = ensure_netbios_header(neg_data)
    sess_packet = ensure_netbios_header(sess_data)

    print("\nAfter ensuring NetBIOS header:")
    print("neg packet len:", len(neg_packet), " first bytes:")
    hexdump(neg_packet, 16)
    print("session packet len:", len(sess_packet), " first bytes:")
    hexdump(sess_packet, 16)

    # Send: negotiate then session setup (adjust as you need)
    print("\n[+] Connecting and sending packets (will read small replies)...")
    with socket.create_connection((target, 445), timeout=5) as s:
        s.settimeout(5)
        print("[+] Sending Negotiate...")
        s.sendall(neg_packet)
        try:
            r = s.recv(8192)
            print("[+] Negotiate response length:", len(r))
            hexdump(r, 200)
        except socket.timeout:
            print("[!] No Negotiate response (timed out)")

        print("[+] Sending Session Setup...")
        s.sendall(sess_packet)
        try:
            r2 = s.recv(8192)
            print("[+] Session Setup response length:", len(r2))
            hexdump(r2, 200)
        except socket.timeout:
            #print("[!] No Session Setup response (timed out)")
            pass

    print("[+] Done. Capture in Wireshark to verify.")
