As estruturas que vão ser vistas aqui podem ser encontradas no header "WinNT" do seu compilador,se você quiser saber mais sobre seus campos,acesse https://msdn.microsoft.com/pt-br/library/windows/desktop/ms680198%28v=vs.85%29.aspx .
Um módulo PE é composto basicamente de :
IMAGE_XXX_HEADERS - estruturas usadas para representar cabeçalhos
IMAGE_SECTION_HEADER - estrutura geral para representar seções
IMAGE_XXX_DIRECTORY - estruturas usadas para representar diretórios,(para alguns só chamados de tabelas,para outros até dado cru),muitas vezes isso fica dentro da própria seção.
Considerados "PE HEADERS" são :
IMAGE_NT_HEADERS,IMAGE_FILE_HEADER ,IMAGE_OPTIONAL_HEADER
Veja que todas as estruturas que formam o PE HEADER estão dentro de IMAGE_NT_HEADERS
struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}
Logo após os HEADERS vem as seções :
.text ,.data,.bss ,.CRT,.rdata,.rsrc,.edata,.rdata,.idata,.reloc,.icode,.debug
Para você acessar os diretórios a primeira coisa é saber quem guarda os deslocamentos para esses diretórios,e isso fica nos headers.
Para você acessar seções basta deslocar o espaço de todos os headers juntos.
"IMAGE_NT_HEADERS" é o começo do PE HEADER,para ler e acessar esse header você usa uma estrutura IMAGE_NT_HEADERS com a função "ImageNtHeader"
IMAGE_NT_HEADERS *pheadernt = ImageNtHeader(EnderecoBasedoModulo);
Primeiro vamos o que ImageNtHeader faz :
PIMAGE_NT_HEADERS ImageNtHeader(PVOID base)
{
IMAGE_DOS_HEADER *pidh_apoio;
IMAGE_NT_HEADERS *pnt = NULL;
if(base != NULL && (int)base != -1) //Verifica a validade do ponteiro passado
{
pidh_apoio = (IMAGE_DOS_HEADER*)base;
if(pidh_apoio->e_magic == IMAGE_DOS_SIGNATURE && pidh_apoio->e_lfanew < 0x10000000)
{
pnt = (IMAGE_NT_HEADERS*)((char*)base + pidh_apoio->e_lfanew);
if(pnt->Signature != (DWORD)"PE")
{
pnt = NULL;
}
}
}
return pnt;
}
Comentários
1 - No pedaço "pidh_apoio = (IMAGE_DOS_HEADER*)base;" ,nos mostra que todo executável tem logo no começo,uma estrutura "IMAGE_DOS_HEADER"
2 - IMAGE_DOS_SIGNATURE é uma assinatura padrão "MZ" , o membro "e_lfanew" tem o endereço relativo de onde começa realmente a estrutura "IMAGE_NT_HEADERS" do módulo,
veja que ele é somado ao endereço base de onde módulo foi carregado.O membro "Signature" fica no deslocamento 0 da estrutura,logo a constante "PE" deve estar ali.
"ImageDirectoryEntryToData",é uma função que simplismente retorna o diretório desejado.
Tipos de diretórios :
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
PVOID WINAPI ImageDirectoryEntryToDataEx(
PVOID Base, //Endereço base de onde o módulo foi carregado(pego com "GetModuleHandle")
BOOLEAN MappedAsImage, //Se o módulo foi mapeado como imagem ou dado
USHORT DirectoryEntry, //Uma das constantes dos diretórios acima
PULONG Size, //Ponteiro que recebe o tamanho do diretório procurado
PIMAGE_SECTION_HEADER *FoundHeader //Ponteiro para a seção do tal diretório procurado(se existir)
)
{
PIMAGE_NT_HEADERS pnt_apoio;
if((int)Base & 1 == 0)//Testa alinhamento do endereço(verifica se é par)
{
pnt_apoio = ImageNtHeader(Base);
if(pnt_apoio != NULL)
{
if(pnt_apoio->OptionalHeader.Magic == 0x10B) //Isso testa para ver se é um executável
{
return RetornaDiretorioSecao(Base,MappedAsImage,DirectoryEntry,Size,FoundHeader,
&pnt_apoio->FileHeader,&pnt_apoio->OptionalHeader);
}
}
}
}
Comentários
A função é simples,veja que ela também chama ImageNtHeader.
Quem faz o grosso é RetornaDiretorioSecao,essa é uma função não documentada,retornando um ponteiro para o começo do diretório no módulo
O que RetornaDiretorioSecao faz:
PVOID RetornaDiretorioSecao(
PVOID Base,
BOOLEAN MappedAsImage,
USHORT DirectoryEntry,
PULONG Size,
PIMAGE_SECTION_HEADER *FoundHeader,
PIMAGE_FILE_HEADER pifh,
PIMAGE_OPTIONAL_HEADER pioh
)
{
//Checa para ver se o diretório passado é válido
if(DirectoryEntry > pioh->NumberOfRvaAndSizes)
{
*Size &= 0;
return;
}
//Checa para ver se o diretório é válido
if(pioh->DataDirectory[DirectoryEntry * 8].VirtualAddress == 0)
{
*Size = 0;
return;
}
//Põe o tamanho do diretório no argumento passado
*Size = pioh->DataDirectory[DirectoryEntry * 8].Size;
IMAGE_SECTION_HEADER *secao;
if(MappedAsImage == FALSE)
{
if(pioh->DataDirectory[DirectoryEntry * 8].VirtualAddress > pioh->SizeOfHeaders )
{
//Acessa as seções
secao_ecx = (IMAGE_SECTION_HEADER*)((char*)pioh +pifh->SizeOfOptionalHeader);
if(pifh->NumberOfSections <= 0)
{
return NULL;
}
int contador = 0;
while(true)
{ //Verifica se o rva do diretório procurado seria para a seção atual
if(pioh->DataDirectory[DirectoryEntry * 8].VirtualAddress > secao_ecx->VirtualAddress &&
pioh->DataDirectory[DirectoryEntry * 8].VirtualAddress <
secao->VirtualAddress + secao->SizeOfRawData )
{
break;
}
}
//Vai para a próxima IMAGE_SECTION_HEADER(tem 0x28 bytes essa estrutura) no array,dado em "IMAGE_NT_HEADER.FileHeader.NumberOfSections"
secao_ecx += 0x28;
contador +=1;
if(contador < pifh->NumberOfSections)
{
return NULL;
}
}
if(FoundHeader != NULL)
*FoundHeader = secao;
//Retorna o ponteiro para o diretório procurado com algumas correções de alinhamento
return (PVOID)((char*)Base + pioh->DataDirectory[DirectoryEntry * 8].VirtualAddress +
(secao->PointerToRawData - secao->VirtualAddress));
}
}
if(FoundHeader != NULL)
{
FoundHeader = NULL;
}
//Arquivo foi mapeado pelo loader do S.O, logo "VirtualAddress" tem o rva para o diretório em si
return (PVOID)((char*)Base + pioh->DataDirectory[DirectoryEntry * 8].VirtualAddress);
}
Comentários:
1 - //"IMAGE_OPTIONAL_HEADER.NumberOfRvaAndSizes" é uma constante que tem o número de diretórios possíveis.No deslocamento OptionalHeader existe o membro "DataDirectory" que é um array do tipo "IMAGE_DATA_DIRECTORY",onde o membro "VirtualAddress" tem o rva para esse diretório. "IMAGE_DATA_DIRECTORY "é uma estrutura de 8 bytes,logo "pioh->DataDirectory[DirectoryEntry * 8]".
2 - "if(MappedAsImage == FALSE)",se você mesmo carregou o módulo para o seu programa ,e esse argumento for FALSE,logo a função faz algumas checagens para ver onde estão as informações.
IMAGE_SECTION_HEADER.VirtualAddress é o rva de onde a seção seria carregada no módulo, IMAGE_SECTION_HEADER.SizeOfRawData é o tamanho da seção,
IMAGE_SECTION_HEADER.PointerToRawData tem o rva de onde essa seção fica no arquivo.
3 - As seções ficam logo após os headers no arquivo. IMAGE_FILE_HEADER.SizeOfOptionalHeader tem o tamanho da estrutura IMAGE_OPTIONAL_HEADER, e IMAGE_FILE_HEADER.NumberOfSections tem a quantidade de seções no arquivo.
Nenhum comentário:
Postar um comentário