Files
BSI-PSA-95160/main.py
2025-02-03 03:24:46 -08:00

163 lines
6.7 KiB
Python

import tkinter as tk
from tkinter import filedialog, ttk, messagebox
import re
from typing import Tuple, List
from collections import Counter
class PSADecoder:
def __init__(self):
# Tabela de decodificação exata do PDF (Table 1)
self.decode_table = {
0xCF: '0', 0xCE: '1', 0xCD: '2', 0xCC: '3', 0xCB: '4',
0xCA: '5', 0xC9: '6', 0xC8: '7', 0xC7: '8', 0xC6: '9',
0xBE: 'A', 0xBD: 'B', 0xBC: 'C', 0xBB: 'D', 0xBA: 'E',
0xB9: 'F', 0xB8: 'G', 0xB7: 'H', 0xB6: 'I', 0xB5: 'J',
0xB4: 'K', 0xB3: 'L', 0xB2: 'M', 0xB1: 'N', 0xB0: 'O',
0xAF: 'P', 0xAE: 'Q', 0xAD: 'R', 0xAC: 'S', 0xAB: 'T',
0xAA: 'U', 0xA9: 'V', 0xA8: 'W', 0xA7: 'X', 0xA6: 'Y',
0xA5: 'Z'
}
def decode_bytes(self, data: bytes) -> str:
decoded = ''
for byte in data:
if byte in self.decode_table:
decoded += self.decode_table[byte]
else:
decoded += ' ' # Substitui caracteres não encontrados na tabela por espaço
return decoded
class VINPINFinder(tk.Tk):
def __init__(self):
super().__init__()
self.decoder = PSADecoder()
self.title("Decodificador BSI PSA - VIN/PIN Finder")
self.geometry("800x600")
# Criar o frame principal
main_frame = ttk.Frame(self, padding="10")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Botão para selecionar arquivo
self.select_button = ttk.Button(
main_frame,
text="Selecionar Arquivo BSI",
command=self.select_file
)
self.select_button.grid(row=0, column=0, pady=10, sticky=tk.W)
self.select_buttonb = ttk.Button(main_frame, text="About", command=self.show_about)
self.select_buttonb.grid(row=0, column=1, pady=10, sticky=tk.W)
# Label para mostrar o arquivo selecionado
self.file_label = ttk.Label(main_frame, text="Nenhum arquivo selecionado")
self.file_label.grid(row=1, column=0, pady=5, sticky=tk.W)
# Frame para resultados
results_frame = ttk.LabelFrame(main_frame, text="Resultados da Decodificação", padding="5")
results_frame.grid(row=2, column=0, pady=10, sticky=(tk.W, tk.E, tk.N, tk.S))
# Texto para mostrar resultados
self.results_text = tk.Text(results_frame, height=20, width=80)
self.results_text.grid(row=0, column=0, pady=5)
# Scrollbar para resultados
scrollbar = ttk.Scrollbar(results_frame, orient=tk.VERTICAL, command=self.results_text.yview)
scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
self.results_text.configure(yscrollcommand=scrollbar.set)
def validate_vin_occurrences(self, vins: List[str]) -> List[str]:
"""Valida VINs que aparecem entre 2 e 3 vezes"""
counter = Counter(vins)
valid_vins = [vin for vin, count in counter.items() if 2 <= count <= 3]
return valid_vins
def find_isolated_pin(self, decoded_content: str) -> str:
"""
Procura por um PIN isolado (4 caracteres alfanuméricos com não-alfanuméricos ao redor)
Usa lookbehind e lookahead para garantir que o PIN está isolado
"""
# Padrão modificado:
# (?<![A-Z0-9]) - lookbehind negativo para garantir que não há alfanumérico antes
# [A-Z0-9]{4} - quatro caracteres alfanuméricos
# (?![A-Z0-9]) - lookahead negativo para garantir que não há alfanumérico depois
pin_pattern = r'(?<![A-Z0-9])([A-Z0-9]{4})(?![A-Z0-9])'
matches = re.finditer(pin_pattern, decoded_content)
for match in matches:
return match.group(1) # Retorna o primeiro PIN isolado encontrado
return ''
def select_file(self):
filename = filedialog.askopenfilename(
title="Selecione o arquivo BSI",
filetypes=[
("Arquivos binários", "*.bin"),
("Todos os arquivos", "*.*")
]
)
if filename:
self.file_label.config(text=f"Arquivo selecionado: {filename}")
self.process_file(filename)
def process_file(self, filename: str):
try:
# Ler o arquivo em modo binário
with open(filename, 'rb') as file:
content = file.read()
# Decodificar o conteúdo usando apenas a tabela PSA BSI
decoded_content = self.decoder.decode_bytes(content)
# Procurar por VINs (17 caracteres alfanuméricos)
all_vins = re.findall(r'[A-Z0-9]{17}', decoded_content)
valid_vins = self.validate_vin_occurrences(all_vins)
# Procurar por um PIN isolado
pin = self.find_isolated_pin(decoded_content)
# Limpar resultados anteriores
self.results_text.delete(1.0, tk.END)
# Mostrar resultados
self.results_text.insert(tk.END, "=== Resultados da Decodificação BSI ===\n\n")
# Mostrar VINs válidos (que aparecem 2-3 vezes)
self.results_text.insert(tk.END, "VIN encontrado:\n")
if valid_vins:
for vin in valid_vins:
count = all_vins.count(vin)
self.results_text.insert(tk.END, f"VIN: {vin} (encontrado {count} vezes)\n")
else:
self.results_text.insert(tk.END, "Nenhum VIN válido encontrado (deve aparecer 2-3 vezes)\n")
# Mostrar PIN (se encontrado)
self.results_text.insert(tk.END, "\nPIN encontrado:\n")
if pin:
self.results_text.insert(tk.END, f"PIN: {pin}\n")
else:
self.results_text.insert(tk.END, "Nenhum PIN isolado encontrado\n")
# Informações adicionais
self.results_text.insert(tk.END, f"\nTamanho do arquivo: {len(content)} bytes\n")
self.results_text.insert(tk.END, "\nNota: VINs são validados apenas se aparecem 2-3 vezes no arquivo.\n")
self.results_text.insert(tk.END, " PIN deve ser exatamente 4 caracteres isolados.\n")
except Exception as e:
self.results_text.delete(1.0, tk.END)
self.results_text.insert(tk.END, f"Erro ao processar arquivo: {str(e)}")
def show_about(self):
messagebox.showinfo(
"Sobre",
"BSI VALEO 24C128 PIN Decoder\n"
"Versão 1.0\n\n"
"Programa para decodificar PINs de BSI VALEO 24C128 E2PROM\n"
"Created by: @Godax"
)
if __name__ == "__main__":
app = VINPINFinder()
app.mainloop()