-------------------------------- Anti-Sandbox utilizando Trigonometria -------------------------------- Este artigo apresenta uma técnica de anti-sandbox utilizada pelo malware LummaC2 v4.0, que utiliza trigonometria para detectar movimentos de mouse consistentes com comportamento humano, evitando assim a execução em ambientes de sandbox. A técnica consiste em capturar a posição do mouse em intervalos regulares e calcular os ângulos entre vetores formados por essas posições. Se os ângulos calculados forem menores que um limite pré-definido, o movimento é considerado como "humano", e o malware continua a execução. Caso contrário, o malware reinicia a verificação. Inicialmente, o malware verifica se houve algum movimento do cursor. O malware captura a posição inicial do mouse e, após um intervalo de 300 milissegundos, captura a nova posição. Se a nova posição for diferente da inicial, isso indica que houve um movimento do mouse. Caso não haja movimento, o processo é reiniciado.POINT initialPos; GetCursorPos(&initialPos); Sleep(300); POINT newPos; GetCursorPos(&newPos); if (newPos.x != initialPos.x || newPos.y != initialPos.y) { // Movimento detectado } else { // Sem movimento }
Quando o movimento é detectado, o malware captura cinco posições consecutivas do cursor com intervalos de 50 milissegundos entre cada captura. Essas posições serão utilizadas para análise vetorial.for (int i = 0; i < 5; i++) { GetCursorPos(&pos[i]); Sleep(50); }
Antes de prosseguir para os calculos trigonometricos, o malware garante que todas as posicoes capturadas sejam diferentes umas das outras. Isso evita que pequenos movimentos ou movimentações simuladas (como movimentos constantes e lineares) sejam considerados como "humanos".bool different = false; for (int i = 1; i < 5; i++) { if (pos[i].x != pos[i - 1].x || pos[i].y != pos[i - 1].y) { different = true; break; } } if (!different) { continue; }
Caso todas as posicoes sejam iguais, o malware reinicia o processo, aguardando novos movimentos. Uma vez confirmada a diferença entre as posicoes, o malware trata cada movimento entre duas posições consecutivas como um vetor no espaço euclidiano. Assim, os movimentos do mouse formam quatro vetores: P01, P12, P23 e P34, onde P01 é o vetor entre P0 e P1 e assim por diante. Em seguida, o malware calcula a magnitude de cada vetor, que será utilizada para calcular o ângulo entre os vetores. Para isso, o malware utiliza a distancia euclidiana entre dois pontos (P1 e P2), que é dada pela formula: No código:double euclideanDistance(POINT p1, POINT p2) { return std::sqrt(std::pow(p2.x - p1.x, 2) + std::pow(p2.y - p1.y, 2)); }
Agora com a magnitude dos vetores, o malware calcula o produto escalar entre dois vetores A e B, que é dado pela formula: E em seguida, calcula o ângulo θ entre os vetores A e B, que é dado pela formula: No código, isso é implementado da seguinte forma:double angleBetweenVectors(POINT p1, POINT p2, POINT p3) { double mag1 = euclideanDistance(p1, p2); double mag2 = euclideanDistance(p2, p3); double dotProduct = (p2.x - p1.x) * (p3.x - p2.x) + (p2.y - p1.y) * (p3.y - p2.y); double angleRad = std::acos(dotProduct / (mag1 * mag2)); // Convertendo de radianos para graus return angleRad * (180.0 / M_PI); }
Este cálculo é repetido para cada par de vetores consecutivos: P01 -> P12, P12 -> P23 e P23 -> P34. Assim que é obtido os ângulos entre os vetores, o malware verifica se todos os ângulos são menores que um limite pre-definido de 45 graus. Se forem, o movimento é considerado como "humano" e o malware continua a execução. Caso contrário, o malware reinicia a verificação.double angle1 = angleBetweenVectors(pos[0], pos[1], pos[2]); double angle2 = angleBetweenVectors(pos[1], pos[2], pos[3]); double angle3 = angleBetweenVectors(pos[2], pos[3], pos[4]); if (angle1 < 45.0 && angle2 < 45.0 && angle3 < 45.0) { std::cout << "[SUCCESS] Movimento humano detectado." << std::endl; } else { std::cout << "[INFO] Movimento humano não detectado. Reiniciando." << std::endl; }
Codigo final:#include <iostream> #include <windows.h> #include <cmath> #define SLEEP_INTERVAL 50 #define MOUSE_MOVE_CHECK 300 #define ANGLE_THRESHOLD 45.0 double euclideanDistance(POINT p1, POINT p2) { return std::sqrt(std::pow(p2.x - p1.x, 2) + std::pow(p2.y - p1.y, 2)); } double angleBetweenVectors(POINT p1, POINT p2, POINT p3) { double mag1 = euclideanDistance(p1, p2); double mag2 = euclideanDistance(p2, p3); if (mag1 == 0 || mag2 == 0) { return NAN; } double dotProduct = (p2.x - p1.x) * (p3.x - p2.x) + (p2.y - p1.y) * (p3.y - p2.y); double angleRad = std::acos(dotProduct / (mag1 * mag2)); return angleRad * (180.0 / M_PI); } int main() { POINT pos[5]; while (true) { POINT initialPos; GetCursorPos(&initialPos); Sleep(MOUSE_MOVE_CHECK); POINT newPos; GetCursorPos(&newPos); if (newPos.x != initialPos.x || newPos.y != initialPos.y) { std::cout << "[INFO] Mouse moved. Capturing positions." << std::endl; for (int i = 0; i < 5; i++) { GetCursorPos(&pos[i]); Sleep(SLEEP_INTERVAL); std::cout << "\t\\_ Position " << i << ": (" << pos[i].x << ", " << pos[i].y << ")" << std::endl; } bool different = false; for (int i = 1; i < 5; i++) { if (pos[i].x != pos[i - 1].x || pos[i].y != pos[i - 1].y) { different = true; break; } } if (!different) { std::cout << "[INFO] All positions are the same. Restarting verification." << std::endl; std::cout << std::endl; continue; } double angle1 = angleBetweenVectors(pos[0], pos[1], pos[2]); double angle2 = angleBetweenVectors(pos[1], pos[2], pos[3]); double angle3 = angleBetweenVectors(pos[2], pos[3], pos[4]); std::cout << std::endl; std::cout << "[INFO] Angles calculated between consecutive vectors:" << std::endl; std::cout << "\t\\_ Angle 1 (P0->P1->P2): " << angle1 << " degrees" << std::endl; std::cout << "\t\\_ Angle 2 (P1->P2->P3): " << angle2 << " degrees" << std::endl; std::cout << "\t\\_ Angle 3 (P2->P3->P4): " << angle3 << " degrees" << std::endl; std::cout << std::endl; if (angle1 < ANGLE_THRESHOLD && angle2 < ANGLE_THRESHOLD && angle3 < ANGLE_THRESHOLD) { std::cout << "[SUCCESS] Human movement detected (all angles < " << ANGLE_THRESHOLD << " degrees)." << std::endl; break; } else { std::cout << "[INFO] Human movement not detected. Restarting verification" << std::endl; std::cout << std::endl; } } } return 0; }
Referencias: - https://www.cuemath.com/geometry/angle-between-vectors/ - https://outpost24.com/blog/lummac2-anti-sandbox-technique-trigonometry-human-detection/