Ir para o conteúdo
AZ Tools

Inspetor PE: visualizador de EXE e DLL

Lê uma imagem PE do Windows como o dumpbin ou o pefile fariam, direto dos bytes e sem enviar nada. O cabeçalho MS-DOS do início é um fóssil: o único campo que ainda importa é o e_lfanew, no deslocamento 0x3C, que diz onde começam a assinatura "PE\0\0" de verdade e o cabeçalho COFF. Dali em diante você tem a máquina (x86, x86-64, ARM64, ARM64EC, Itanium, RISC-V e as demais), se o cabeçalho opcional é PE32 ou PE32+, se o cabeçalho de arquivo carrega a característica de DLL, e sob qual subsistema o carregador vai iniciá-lo: console do Windows, GUI do Windows, nativo ou uma das variantes EFI. A linha de proteções é o equivalente do checksec no Windows e sai de DllCharacteristics: ASLR (DYNAMIC_BASE), ASLR de alta entropia, que é o que leva uma imagem de 64 bits de oito bits de aleatoriedade na realocação para dezessete ou mais, DEP/NX (NX_COMPAT), Control Flow Guard (GUARD_CF), se o tratamento estruturado de exceções foi suprimido (NO_SEH), a verificação de integridade forçada e se existe alguma tabela de certificados. As seções aparecem com endereço virtual, tamanho virtual e em disco, e características decodificadas; a que for ao mesmo tempo gravável e executável é sinalizada, porque fora de um empacotador, um instalador ou código automodificável quase nunca há motivo para isso. As importações são agrupadas por DLL com o nome de cada função, ou mostradas como #ordinal quando o arquivo importou por ordinal e portanto nunca registrou um nome: essa tabela é a resposta honesta para o que este binário realmente precisa. As exportações dão o nome sob o qual a biblioteca se publica, a base ordinal (muitas vezes diferente de 1) e todos os nomes exportados. Dois limites ditos com clareza. Um diretório de certificados não vazio significa que o arquivo carrega uma assinatura, não que a assinatura seja válida, atual ou de alguém em quem você confie; verificar o Authenticode exige a cadeia de certificados e uma autoridade de carimbo de tempo, e está fora do escopo. E o carimbo de ligação é apenas um campo que o linker escreve, então uma compilação reprodutível o terá fixado numa constante ou num hash. Arquivos malformados são recusados em vez de lidos pela metade: um magic MZ errado, um cabeçalho DOS que não aponta para uma assinatura PE, um magic de cabeçalho opcional desconhecido e uma seção que declara mais dados do que o arquivo contém geram cada um um erro com nome.

Como usar

  1. Solte o arquivo na caixa. Um .exe, uma .dll, um driver .sys, um controle .ocx ou um binário .efi são analisados do mesmo jeito: não é a extensão que decide.
  2. Leia os cartões de cabeçalho para arquitetura, PE32 contra PE32+, EXE contra DLL e o subsistema. A build de console e a de GUI do mesmo programa só diferem aqui.
  3. Confira as etiquetas de proteção. ASLR, DEP e CFG são o que uma cadeia de ferramentas atual do Windows liga por padrão, então uma etiqueta âmbar num binário recente merece explicação antes da distribuição.
  4. Procure nas importações a capacidade que interessa: WS2_32 é socket, WININET ou WINHTTP indicam conversa com a web, ADVAPI32 registro ou serviços, CRYPT32 certificados.
  5. Veja na tabela de seções se alguma é gravável e executável, e nos diretórios de dados se há certificado, entrada de depuração ou cabeçalho do runtime CLR, que muda como o resto deve ser lido.

Perguntas frequentes

O arquivo mostra a etiqueta de assinatura. Isso quer dizer que ele é seguro?
Não, e a diferença importa. A etiqueta diz apenas que o diretório de dados de certificados não está vazio, ou seja, que há um blob Authenticode anexado depois da última seção. Ela não diz que esse blob corresponde aos bytes anteriores, que o certificado de assinatura encadeia até uma raiz em que o Windows confia, que o certificado era válido no momento da assinatura, nem que quem assinou é quem o arquivo afirma. Qualquer uma dessas coisas pode ser falsa com o diretório igualmente preenchido: dá para reassinar com um certificado autoemitido, ou alterar o conteúdo depois de assinar para que o hash deixe de bater. Verificar de verdade exige a cadeia completa, dados de revogação e normalmente um carimbo de tempo confiável, e isso é operação de rede, deliberadamente fora do escopo de uma ferramenta que promete nunca enviar o seu arquivo.
O que o ASLR de alta entropia acrescenta ao ASLR comum?
O ASLR comum move a imagem para uma base aleatória na carga, mas no Windows de 32 bits só cerca de oito bits do endereço são realmente aleatórios, poucos o bastante para serem quebrados por tentativa em laço. O HIGH_ENTROPY_VA avisa ao carregador que a imagem pode ser colocada em qualquer ponto do espaço de endereços de 64 bits, o que eleva os bits aleatórios para dezessete ou mais e torna o chute impraticável. Ele só significa algo numa imagem PE32+ que também tenha DYNAMIC_BASE, e ainda exige que o programa nunca trunque um ponteiro para 32 bits: por isso os linkers o deixam atrás de /HIGHENTROPYVA e por isso um binário de 64 bits herdado de código da era dos 32 bits pode deixá-lo desligado de propósito.
Por que algumas funções importadas aparecem como #12 em vez de um nome?
Porque o arquivo as importou por ordinal. Cada entrada de um vetor de thunks é uma palavra de máquina cujo bit mais alto é uma bandeira: quando ele está ligado, os 16 bits baixos são o ordinal a procurar na tabela de endereços da DLL exportadora, e nenhum nome fica guardado no arquivo importador. Quando está desligado, o resto da palavra é um RVA que aponta para um par dica/nome e o nome está ali. Importar por ordinal resolve um pouco mais rápido e era comum em código antigo; também é o que se vê quando alguém quer esconder qual API está sendo chamada. Esta ferramenta mostra o ordinal cru em vez de adivinhar, porque o mapeamento de ordinal para nome mora na DLL exportadora e depende da versão instalada.
A tabela mostra uma seção gravável e executável. Isso é grave?
É incomum o bastante para merecer atenção, mas sozinho não prova nada. Um compilador e um linker normais emitem .text como leitura mais execução e .data como leitura mais escrita, nunca as duas juntas, porque o DEP existe justamente para fazer essa combinação falhar. Seções com IMAGE_SCN_MEM_WRITE e IMAGE_SCN_MEM_EXECUTE ao mesmo tempo geralmente vêm de um empacotador em tempo de execução que descomprime código na própria seção antes de saltar para ela — o UPX chama a sua de UPX1 — ou de um instalador antigo, um esquema de proteção automodificável, ou um JIT que aloca dentro da imagem. Se você não esperava nada disso, vale entender o que o binário faz antes de executá-lo.
A hora de ligação diz 1970, ou uma data no futuro. O arquivo está corrompido?
Quase certamente não. TimeDateStamp é um campo de 32 bits com segundos desde 1970 que o linker preenche, e as cadeias de ferramentas modernas deixaram de tratá-lo como data. Uma compilação reprodutível o zera ou o fixa numa constante para que o mesmo código-fonte produza sempre a mesma saída byte a byte, e o MSVC com /Brepro escreve ali um hash das entradas, que cai num ponto arbitrário do calendário e muitas vezes bem no futuro. O cabeçalho Rich e o diretório de depuração costumam ser evidência melhor sobre a cadeia de ferramentas do que esse campo, e nada disso prova quando o arquivo foi de fato distribuído. Trate-o como metadado com formato de data.
É um assembly .NET. Por que as importações e o ponto de entrada parecem quase vazios?
Porque num assembly gerenciado a parte PE é uma casca. Quando o diretório de dados do runtime CLR (índice 14, o descritor COM) não está vazio, o programa de verdade é IL guardado em metadados do .NET, e os cabeçalhos nativos existem sobretudo para satisfazer o carregador do Windows. Um executável C# clássico tem exatamente uma importação, _CorExeMain de mscoree.dll, um ponto de entrada que é um salto de duas instruções até ela, e uma seção .text que é mais metadado do que código de máquina. Por isso o campo de arquitetura pode dizer Intel 386 num programa que roda tranquilamente em 64 bits, e os tamanhos de seção não dizem nada sobre o tamanho do programa. Ler direito exige um desmontador de IL como ildasm ou ILSpy.

Ferramentas relacionadas