import gradio as gr import torch from torchvision import transforms from transformers import ViTForImageClassification from PIL import Image import torch.nn.functional as F import numpy as np import math import io # --- CONFIGURAÇÃO --- MODEL_PATH = "./malware_vit_model" # 0. Configurar Dispositivo (Correção do Erro) # Detecta se há GPU disponível. Se houver, usa CUDA, senão usa CPU. device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"Usando dispositivo para inferência: {device}") # 1. Carregar o Modelo print("Carregando modelo...") try: model = ViTForImageClassification.from_pretrained(MODEL_PATH) model.to(device) # Move o modelo para o dispositivo correto (GPU ou CPU) model.eval() labels = model.config.id2label print("Modelo carregado com sucesso!") except Exception as e: print(f"Erro ao carregar o modelo: {e}") labels = {0: "Erro", 1: "Modelo não encontrado"} # 2. Definir as Transformações transform_pipeline = transforms.Compose([ transforms.Resize((224, 224)), transforms.Grayscale(num_output_channels=3), transforms.ToTensor(), transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) ]) # 3. Função Auxiliar: Converter Binário para Imagem def binary_to_image(binary_data): """ Converte bytes brutos de malware em uma imagem em escala de cinza. A largura é fixa baseada no tamanho do arquivo (heurística de Nataraj et al.). " Image Representation of Malware: To extract image-based features, a malware binary has to be transformed to an image. A given malware binary is read as a 1D array (vector) of 8 bit unsigned integers and then organized into a 2D array (matrix). The width of the matrix is fixed depending on the file size and the height varies according to the file size". """ try: # Converte bytes para array numpy data = np.frombuffer(binary_data, dtype=np.uint8) # Se o arquivo estiver vazio, retorna None if len(data) == 0: return None # 2. Definir a largura (Width) baseada no tamanho do arquivo # Tabela empírica padrão usada na literatura acadêmica file_len = len(data) if file_len < 10 * 1024: # < 10 kB width = 32 elif file_len < 30 * 1024: # 10 kB - 30 kB width = 64 elif file_len < 60 * 1024: # 30 kB - 60 kB width = 128 elif file_len < 100 * 1024: # 60 kB - 100 kB width = 256 elif file_len < 200 * 1024: # 100 kB - 200 kB width = 384 elif file_len < 500 * 1024: # 200 kB - 500 kB width = 512 elif file_len < 1000 * 1024: # 500 kB - 1 MB width = 768 else: # > 1 MB width = 1024 # 3. Calcular a altura (Height) # Altura = Total de Bytes / Largura (arredondado para cima) height = math.ceil(file_len / width) # 4. Padding (Preenchimento) # O array 1D precisa ter exatamente width * height elementos para virar matriz. # Se faltar bytes para completar a última linha, preenchemos com 0 (preto). required_size = width * height pad_len = required_size - file_len if pad_len > 0: data = np.pad(data, (0, pad_len), 'constant', constant_values=0) # 5. Transformar em Matriz 2D e depois em Imagem img_array = data.reshape((height, width)) img = Image.fromarray(img_array, 'L') # 'L' = Grayscale (8-bit pixels) return img except Exception as e: print(f"Erro ao converter {file_path}: {e}") return None # 4. Função Principal de Predição def predict(file_bytes): if file_bytes is None: return None, None # Converter binário para imagem image = binary_to_image(file_bytes) if image is None: return {"Erro": 0.0}, None try: input_tensor = transform_pipeline(image) input_tensor = input_tensor.unsqueeze(0) # CORREÇÃO CRÍTICA: Mover a entrada para o mesmo dispositivo do modelo input_tensor = input_tensor.to(device) with torch.no_grad(): outputs = model(input_tensor) logits = outputs.logits probabilities = F.softmax(logits, dim=1)[0] confidences = {labels[i]: float(probabilities[i]) for i in range(len(labels))} image = image.resize((224, 224)) return confidences, image except Exception as e: return {f"Erro no processamento: {str(e)}": 0.0}, None # --- INTERFACE GRADIO --- title = "🦠 Classificador de Malware (Binário -> ViT)" description = "Faça upload de qualquer arquivo (.exe, .bin, .dll). O sistema converte para imagem e classifica a família." interface = gr.Interface( fn=predict, inputs=gr.File(type="binary", label="Upload do Arquivo"), outputs=[ gr.Label(num_top_classes=5, label="Famílias Prováveis"), gr.Image(type="pil", label="Representação Visual") ], title=title, description=description ) if __name__ == "__main__": interface.launch()