import binascii

# Chemin du fichier d'entrée
input_file = "/var/www/html/modification_carto/volkswagensimospcr2.1_bench_fullbackup_41048480128019348206001024fade00_20230407173439_int_flash.bin"

# Lire le fichier en mode binaire
with open(input_file, 'rb') as file:
    file_content = file.read()

# Convertir le contenu binaire en hexadécimal pour une meilleure lisibilité
hex_content = binascii.hexlify(file_content).decode('utf-8')

# Afficher les 1000 premiers caractères pour analyse initiale
print("First 1000 characters of the file in hex:")
print(hex_content[:1000])

# Définir le MCUID connu
mcuid_hex = "4104848012801934"
mcuid_bytes = bytes.fromhex(mcuid_hex)

# Définir les octets de référence
reference_bytes = [
    0x00, 0x6d, 0x05, 0xe1, 0x2c, 0x00, 0x90, 0x00, 0x90, 0x85, 0xd2, 0x04, 0x7b,
    0x40, 0xe8, 0xff, 0x1b, 0x6f, 0x63, 0xf3, 0xc6, 0xf2, 0x7b, 0x70, 0xf6, 0x1b,
    0x5f, 0x60, 0xf8, 0xc6, 0xf2, 0x7b, 0x30, 0xf1, 0xf8, 0x1b, 0x3f, 0x0e, 0xfd,
    0xc6, 0xf2, 0x90, 0x23,
    # Ajout des transformations manuelles
    0x00, 0x01, 0x6d, 0x05, 0xe1, 0x2c, 0x00, 0x90,
    0x7e, 0x08, 0x00, 0x00, 0x6d, 0xff, 0x00, 0x90,
    0xd9, 0x0f, 0x70, 0x00, 0xf6, 0x5f, 0x60, 0x30,
    0xf1, 0xf8, 0x3f, 0x0e, 0xfd
]

# Diviser le fichier en segments plus petits pour gérer la charge de calcul
segment_size = len(mcuid_bytes)
num_segments = len(file_content) // segment_size

matching_segments = []

# Fonction pour appliquer des transformations spécifiques
def apply_specific_transformations(segment, mcuid_bytes):
    transformations = []
    for i in range(len(segment)):
        original_byte = segment[i]
        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

# Analyser des segments spécifiques
for i in range(num_segments):
    segment = file_content[i * segment_size: (i + 1) * segment_size]
    
    # Exclure les segments contenant principalement des zéros
    if segment.count(0) > segment_size / 2:
        continue
    
    match, transformations = apply_specific_transformations(segment, mcuid_bytes)
    if match:
        matching_segments.append((i, segment, transformations))

# Fonction pour appliquer des transformations inversées
def invert_transformations(segment, transformations):
    inverted_bytes = []
    for i, trans in enumerate(transformations):
        mcuid_byte = None
        if trans["addition_mod"] == (segment[i] + mcuid_bytes[i]) % 256:
            mcuid_byte = (trans["addition_mod"] - segment[i]) % 256
        elif trans["xor"] == (segment[i] ^ mcuid_bytes[i]):
            mcuid_byte = segment[i] ^ trans["xor"]
        elif trans["subtraction_mod"] == (segment[i] - mcuid_bytes[i]) % 256:
            mcuid_byte = (trans["subtraction_mod"] + segment[i]) % 256
        inverted_bytes.append(mcuid_byte)
    return inverted_bytes

# Appliquer les transformations inversées sur les segments correspondants
print("Matching segments in the file:")
for index, segment, transformations in matching_segments[:10]:  # Afficher seulement les 10 premiers pour éviter de surcharger
    inverted_bytes = invert_transformations(segment, transformations)
    print(f"Index: {index}, Segment: {segment}")
    for i, (orig, trans, inv) in enumerate(zip(segment, transformations, inverted_bytes)):
        print(f"  Byte {i}: Original: {orig}, Transformations: {trans}, Inverted Byte: {inv}")

# Afficher le nombre total de segments correspondants
print(f"Total matching segments: {len(matching_segments)}")

# Fonction de transformation finale
def apply_transformations_v3_final(original_byte, mcuid_byte, reference_byte):
    if (original_byte + mcuid_byte) % 256 == reference_byte:
        return (original_byte + mcuid_byte) % 256
    elif (original_byte ^ mcuid_byte) == reference_byte:
        return original_byte ^ mcuid_byte
    elif (original_byte - mcuid_byte) % 256 == reference_byte:
        return (original_byte - mcuid_byte) % 256
    elif (original_byte + 2 * mcuid_byte) % 256 == reference_byte:
        return (original_byte + 2 * mcuid_byte) % 256
    elif (original_byte - 2 * mcuid_byte) % 256 == reference_byte:
        return (original_byte - 2 * mcuid_byte) % 256
    else:
        return reference_byte  # Directement retourner l'octet de référence si aucune correspondance

# Calculer les positions spécifiques par rapport au MCUID
def calculate_positions_from_mcuid(mcuid_bytes, data_length, step=100000):
    positions = []
    mcuid_length = len(mcuid_bytes)
    base_position = sum(mcuid_bytes)
    for i in range(mcuid_length):
        position = (base_position + i * step + mcuid_bytes[i % mcuid_length]) % data_length
        positions.append(position)
    return positions

data_length = len(file_content)

# Calculer toutes les positions spécifiques par rapport au MCUID
positions_from_mcuid = calculate_positions_from_mcuid(mcuid_bytes, data_length)

# Appliquer les transformations finales aux octets pertinents
differences_final = []
original_bytes_final = list(file_content)  # Faire une copie des octets originaux

for i, pos in enumerate(positions_from_mcuid):
    original_byte = original_bytes_final[pos]
    mcuid_byte = mcuid_bytes[i % len(mcuid_bytes)]
    reference_byte = reference_bytes[i % len(reference_bytes)]
    transformed_byte = apply_transformations_v3_final(original_byte, mcuid_byte, reference_byte)
    if original_bytes_final[pos] != transformed_byte:
        differences_final.append((pos, original_bytes_final[pos], transformed_byte))
    original_bytes_final[pos] = transformed_byte

# Vérifier les différences restantes après les corrections
differences_remaining = [(pos, original_bytes_final[pos]) for pos in range(len(original_bytes_final)) if original_bytes_final[pos] != file_content[pos]]

# Afficher les différences restantes
print(f"Differences found: {differences_remaining}")
print(f"Total differences: {len(differences_remaining)}")

# Écrire le fichier de sortie avec les transformations finales
output_file_final = "/var/www/html/modification_carto/ori_off_corrected.bin"
with open(output_file_final, "wb") as file:
    file.write(bytearray(original_bytes_final))
