import binascii

# Chemin du fichier d'entrée
input_file = "/var/www/html/modification_carto/ori_off"

# 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 = "4104058606609011820600102403ED00"
mcuid_bytes = bytes.fromhex(mcuid_hex)

# 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)}")

# 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
]

# 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  # Directly return the reference byte if no match

# 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)  # Make a copy of the original bytes

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

# Dictionnaire des transformations spécifiques à appliquer manuellement
transformations_specific = {
    100903: 0x6D,
    301033: 0xE1,
    400905: 0x2C,
    500995: 0x00,
    601043: 0x90,
    700916: 0x00,
    801029: 0x90,
    900905: 0x85,
    1000899: 0xD2,
    1100915: 0x04,
    1200935: 0x7B,
    1300902: 0x40,
    1386045: 0x01,
    1395070: 0xD6,
    1395071: 0x0D,
    1395074: 0xDA,
    1395075: 0x1E,
    1399726: 0xB2,
    1399727: 0x9F,
    1401136: 0xC0,
    1500899: 0xFF
}

# Appliquer les transformations manuelles
for pos, value in transformations_specific.items():
    original_bytes_final[pos] = value

# Écrire le fichier de sortie avec les transformations finales et manuelles
output_file_final = "/var/www/html/modification_carto/ori_off"
with open(output_file_final, "wb") as file:
    file.write(bytearray(original_bytes_final))

# Return the final differences found for analysis
print(f"Differences found: {differences_final}")
print(f"Total differences: {len(differences_final)}")
