mirror of
https://github.com/hasherezade/bearparser
synced 2026-06-08 14:32:38 +00:00
214 lines
6.1 KiB
C++
214 lines
6.1 KiB
C++
#include "PEFile.h"
|
|
|
|
bool PEFileBuilder::signatureMatches(AbstractByteBuffer *buf)
|
|
{
|
|
if (buf == NULL) return false;
|
|
|
|
offset_t dosOffset = 0;
|
|
WORD *magic = (WORD*) buf->getContentAt(dosOffset, sizeof(WORD));
|
|
if (magic == NULL) return false;
|
|
|
|
if ((*magic) != S_DOS) {
|
|
return false;
|
|
}
|
|
offset_t newOffset = dosOffset + (sizeof(IMAGE_DOS_HEADER) - sizeof(LONG));
|
|
LONG* lfnew = (LONG*) buf->getContentAt(newOffset, sizeof(LONG));
|
|
if (lfnew == NULL) {
|
|
return false;
|
|
}
|
|
offset_t peOffset = static_cast<offset_t>(*lfnew);
|
|
DWORD *peMagic = (DWORD*) buf->getContentAt(peOffset, sizeof(DWORD));
|
|
if (peMagic == NULL) {
|
|
return false;
|
|
}
|
|
if (*peMagic == pe::S_NT) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Executable* PEFileBuilder::build(AbstractByteBuffer *buf)
|
|
{
|
|
Executable *exe = NULL;
|
|
if (signatureMatches(buf) == false) return NULL;
|
|
|
|
try {
|
|
exe = new PEFile(buf);
|
|
} catch (ExeException &e) {
|
|
//
|
|
}
|
|
return exe;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
|
|
PEFile::PEFile(AbstractByteBuffer *v_buf)
|
|
: DOSExe(v_buf), fHdr(NULL), optHdr(NULL), sects(NULL),
|
|
album(NULL)
|
|
{
|
|
bitMode = Executable::BITS_32;
|
|
album = new ResourcesAlbum(this);
|
|
wrap(v_buf);
|
|
}
|
|
|
|
void PEFile::clearWrappers()
|
|
{
|
|
MappedExe::clearWrappers();
|
|
TRACE();
|
|
// unmap DirEntries
|
|
for (size_t i = 0 ; i < pe::DIR_ENTRIES_COUNT; i++) {
|
|
dataDirEntries[pe::DIR_ENTRIES_COUNT] = NULL;
|
|
}
|
|
}
|
|
|
|
void PEFile::wrap()
|
|
{
|
|
clearWrappers();
|
|
DOSExe::wrap(this->buf);
|
|
PEFile::wrap(this->buf);
|
|
}
|
|
|
|
void PEFile::wrap(AbstractByteBuffer *v_buf)
|
|
{
|
|
core.wrap(v_buf);
|
|
|
|
this->fHdr = new FileHdrWrapper(this);
|
|
if (fHdr->getPtr() == NULL) throw ExeException("Cannot parse FileHdr: It is not PE File!");
|
|
this->wrappers[WR_FILE_HDR] = fHdr;
|
|
|
|
this->optHdr = new OptHdrWrapper(this);
|
|
if (optHdr->getPtr() == NULL) throw ExeException("Cannot parse OptionalHeader: It is not PE File!");
|
|
this->wrappers[WR_OPTIONAL_HDR] = optHdr;
|
|
|
|
this->wrappers[WR_DATADIR] = new DataDirWrapper(this);
|
|
|
|
bool isOk = false;
|
|
size_t secNum = fHdr->getNumValue(FileHdrWrapper::SEC_NUM, &isOk);
|
|
if (isOk){
|
|
sects = new SectHdrsWrapper(this);
|
|
this->wrappers[WR_SECTIONS] = sects;
|
|
}
|
|
// map Data Dirs
|
|
dataDirEntries[pe::DIR_IMPORT] = new ImportDirWrapper(this);
|
|
dataDirEntries[pe::DIR_DELAY_IMPORT] = new DelayImpDirWrapper(this);
|
|
dataDirEntries[pe::DIR_BOUND_IMPORT] = new BoundImpDirWrapper(this);
|
|
dataDirEntries[pe::DIR_DEBUG] = new DebugDirWrapper(this);
|
|
dataDirEntries[pe::DIR_EXPORT] = new ExportDirWrapper(this);
|
|
dataDirEntries[pe::DIR_SECURITY] = new SecurityDirWrapper(this);
|
|
dataDirEntries[pe::DIR_TLS] = new TlsDirWrapper(this);
|
|
dataDirEntries[pe::DIR_LOAD_CONFIG] = new LdConfigDirWrapper(this);
|
|
dataDirEntries[pe::DIR_BASERELOC] = new RelocDirWrapper(this);
|
|
dataDirEntries[pe::DIR_EXCEPTION] = new ExceptionDirWrapper(this);
|
|
dataDirEntries[pe::DIR_RESOURCE] = new ResourceDirWrapper(this, album);
|
|
|
|
for (size_t i = 0; i < pe::DIR_ENTRIES_COUNT; i++) {
|
|
this->wrappers[WR_DIR_ENTRY + i] = dataDirEntries[i];
|
|
}
|
|
|
|
if (this->album) {
|
|
this->album->wrapLeafsContent();
|
|
}
|
|
}
|
|
|
|
offset_t PEFile::peDataDirOffset()
|
|
{
|
|
if (this->optHdr == NULL) return INVALID_ADDR;
|
|
return optHdr->getFieldOffset(OptHdrWrapper::DATA_DIR);
|
|
}
|
|
|
|
IMAGE_DATA_DIRECTORY* PEFile::getDataDirectory()
|
|
{
|
|
if (this->wrappers[WR_DATADIR] == NULL) return NULL;
|
|
return static_cast<IMAGE_DATA_DIRECTORY*>(this->wrappers[WR_DATADIR]->getPtr());
|
|
}
|
|
|
|
bufsize_t PEFile::getMappedSize(Executable::addr_type aType)
|
|
{
|
|
if (aType == Executable::RAW) {
|
|
return this->getContentSize();
|
|
}
|
|
//TODO...
|
|
if (aType == Executable::VA || aType == Executable::RVA) {
|
|
return core.getImageSize();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
offset_t PEFile::getEntryPoint()
|
|
{
|
|
if (optHdr == NULL) return INVALID_ADDR;
|
|
|
|
bool isOk = false;
|
|
offset_t entryPoint = static_cast<offset_t> (optHdr->getNumValue(OptHdrWrapper::EP, &isOk));
|
|
if (isOk == false) return INVALID_ADDR;
|
|
return entryPoint;
|
|
}
|
|
|
|
size_t PEFile::hdrSectionsNum()
|
|
{
|
|
bool isOk = false;
|
|
uint64_t secNum = this->fHdr->getNumValue(FileHdrWrapper::SEC_NUM , &isOk);
|
|
if (isOk == false) return 0;
|
|
|
|
return static_cast<size_t> (secNum);
|
|
}
|
|
|
|
bool PEFile::setHdrSectionsNum(size_t newNum)
|
|
{
|
|
uint64_t count = newNum;
|
|
bool canSet = fHdr->setNumValue(FileHdrWrapper::SEC_NUM , count);
|
|
if (canSet == false) {
|
|
if (DBG_LVL) printf("Can not change FileHdr!\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
offset_t PEFile::fileAddrToRva(offset_t raw, bool getClosestIfInCave)
|
|
{
|
|
if (raw >= this->getMappedSize(Executable::RAW)) return INVALID_ADDR;
|
|
|
|
SectionHdrWrapper* sec = this->getSecHdrAtOffset(raw, Executable::RAW, true);
|
|
if (sec) {
|
|
offset_t bgnVA = sec->getContentOffset(Executable::VA);
|
|
offset_t bgnRaw = sec->getContentOffset(Executable::RAW);
|
|
if (bgnVA == INVALID_ADDR || bgnRaw == INVALID_ADDR) return INVALID_ADDR;
|
|
|
|
bufsize_t curr = (raw - bgnRaw);
|
|
|
|
bufsize_t vSize = sec->getContentSize(Executable::VA, true);
|
|
if (curr >= vSize) {
|
|
//address out of section. return last addr of the section.
|
|
return bgnVA + vSize;
|
|
}
|
|
return bgnVA + curr;
|
|
}
|
|
//TODO...
|
|
return raw;
|
|
}
|
|
|
|
offset_t PEFile::rvaToFileAddr(offset_t rva, bool getClosestIfInCave)
|
|
{
|
|
if (rva >= this->getMappedSize(Executable::RVA)) return INVALID_ADDR;
|
|
|
|
SectionHdrWrapper* sec = this->getSecHdrAtOffset(rva, Executable::RVA, true);
|
|
if (sec) {
|
|
offset_t bgnRVA = sec->getContentOffset(Executable::RVA);
|
|
offset_t bgnRaw = sec->getContentOffset(Executable::RAW);
|
|
if (bgnRVA == INVALID_ADDR || bgnRaw == INVALID_ADDR) return INVALID_ADDR;
|
|
|
|
bufsize_t curr = (rva - bgnRVA);
|
|
bufsize_t rawSize = sec->getContentSize(Executable::RAW, true);
|
|
if (curr >= rawSize) {
|
|
//address out of section. return last addr of the section.
|
|
return bgnRaw + rawSize;
|
|
}
|
|
return bgnRaw + curr;
|
|
}
|
|
//TODO...
|
|
return rva;
|
|
}
|
|
|
|
|