import binascii
import re
from collections import defaultdict, Counter

# Fonction pour lire le fichier binaire et convertir le contenu en hexadécimal
def read_file(file_path):
    with open(file_path, 'rb') as file:
        file_content = file.read()
    return binascii.hexlify(file_content).decode('utf-8')

# Fonction pour extraire les segments du contenu du fichier
def extract_segments(file_content, segment_size):
    num_segments = len(file_content) // (segment_size * 2)
    segments = []

    for i in range(num_segments):
        segment = file_content[i * segment_size * 2: (i + 1) * segment_size * 2]
        if segment.count('0') > segment_size:
            continue
        if len(segment) == segment_size * 2:  # Assurez-vous que le segment a la bonne longueur
            segments.append((i, segment))
    
    return segments

# Fonction pour appliquer des transformations spécifiques
def apply_specific_transformations(segment, mcuid_bytes):
    transformations = []
    for i in range(len(mcuid_bytes)):
        original_byte = int(segment[i * 2:(i + 1) * 2], 16)
        mcuid_byte = mcuid_bytes[i]
        results = {
            "addition_mod": (original_byte + mcuid_byte) % 256,
            "xor": original_byte ^ mcuid_byte,
            "subtraction_mod": (original_byte - mcuid_byte) % 256
        }
        transformations.append(results)
        if mcuid_byte in results.values():
            return True, transformations
    return False, transformations

# Fonction pour appliquer des transformations inversées
def invert_transformations(segment, transformations, mcuid_bytes):
    inverted_bytes = []
    for i, trans in enumerate(transformations):
        original_byte = int(segment[i * 2:(i + 1) * 2], 16)
        mcuid_byte = None
        if trans["addition_mod"] == (original_byte + mcuid_bytes[i]) % 256:
            mcuid_byte = (trans["addition_mod"] - original_byte) % 256
        elif trans["xor"] == (original_byte ^ mcuid_bytes[i]):
            mcuid_byte = original_byte ^ trans["xor"]
        elif trans["subtraction_mod"] == (original_byte - mcuid_bytes[i]) % 256:
            mcuid_byte = (trans["subtraction_mod"] + original_byte) % 256
        inverted_bytes.append(mcuid_byte)
    return inverted_bytes

# Fonction pour combiner les octets inversés en tenant compte de l'ordre des segments
def combine_inverted_bytes(segments, mcuid_bytes):
    combined_bytes = defaultdict(list)
    for index, segment in segments:
        match, transformations = apply_specific_transformations(segment, mcuid_bytes)
        if match:
            inverted_bytes = invert_transformations(segment, transformations, mcuid_bytes)
            for i, byte in enumerate(inverted_bytes):
                position = index * len(inverted_bytes) + i
                combined_bytes[position].append(byte)
    
    # Trier les octets combinés par position et sélectionner les octets les plus fréquents
    sorted_indices = sorted(combined_bytes.keys())
    sorted_bytes = [Counter(combined_bytes[i]).most_common(1)[0][0] for i in sorted_indices]
    
    return sorted_bytes

# Fonction principale pour trouver le MCUID dans un fichier
def find_mcuid(file_path, mcuid_hex):
    mcuid_bytes = bytes.fromhex(mcuid_hex)
    segment_size = len(mcuid_bytes)
    
    file_content = read_file(file_path)
    segments = extract_segments(file_content, segment_size)
    combined_inverted_bytes = combine_inverted_bytes(segments, mcuid_bytes)
    
    # Extraire les MCUIDs possibles et vérifier celui qui est correct
    possible_mcuid = None
    for i in range(len(combined_inverted_bytes) - segment_size + 1):
        possible_mcuid = combined_inverted_bytes[i:i + segment_size]
        possible_mcuid_hex = ''.join(f'{byte:02X}' for byte in possible_mcuid)
        if len(possible_mcuid_hex) == len(mcuid_hex):  # Vérifiez la longueur du MCUID
            if possible_mcuid_hex.startswith(mcuid_hex[:4]) and possible_mcuid_hex.endswith(mcuid_hex[-8:]):
                break

    return possible_mcuid_hex

# Exemple d'utilisation
file_path = '/var/www/html/modification_carto/ori ocas pcr 2.1'
mcuid_hex = "410482850C80A82F830600102417E000"
mcuid = find_mcuid(file_path, mcuid_hex)
print(f"Extracted MCUID: {mcuid}")
