mirror of
https://github.com/BeneficialCode/WinArk
synced 2026-08-09 12:00:31 +00:00
177 lines
4.8 KiB
C++
177 lines
4.8 KiB
C++
#include "pch.h"
|
|
#include "PEParser.h"
|
|
|
|
PEParser::PEParser(PVOID base) {
|
|
_address = reinterpret_cast<PUCHAR>(base);
|
|
CheckValidity();
|
|
}
|
|
|
|
PEParser::PEParser(const wchar_t* path) {
|
|
UNICODE_STRING fileName;
|
|
RtlInitUnicodeString(&fileName, path);
|
|
NTSTATUS status = _file.Open(&fileName, FileAccessMask::Read);
|
|
IO_STATUS_BLOCK ioStatus;
|
|
if (NT_SUCCESS(status)) {
|
|
LARGE_INTEGER fileSize;
|
|
_file.GetFileSize(&fileSize);
|
|
_address = (PUCHAR)ExAllocatePool(NonPagedPool, fileSize.QuadPart); // 未释放申请的内存
|
|
status = _file.ReadFile(_address, fileSize.LowPart, &ioStatus, nullptr);
|
|
if (!NT_SUCCESS(status)) {
|
|
if(_address)
|
|
ExFreePool(_address);
|
|
}
|
|
_file.Close();
|
|
}
|
|
CheckValidity();
|
|
return;
|
|
}
|
|
|
|
PEParser::~PEParser() {
|
|
|
|
}
|
|
|
|
void PEParser::CheckValidity() {
|
|
_dosHeader = reinterpret_cast<IMAGE_DOS_HEADER*>(_address);
|
|
if (_dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
_valid = false;
|
|
return;
|
|
}
|
|
else {
|
|
auto ntHeader = (PIMAGE_NT_HEADERS64)(_address + _dosHeader->e_lfanew);
|
|
if (ntHeader->Signature != IMAGE_NT_SIGNATURE) {
|
|
_valid = false;
|
|
return;
|
|
}
|
|
_ntHeader = ntHeader;
|
|
_fileHeader = &ntHeader->FileHeader;
|
|
_opt64 = &ntHeader->OptionalHeader;
|
|
_opt32 = (PIMAGE_OPTIONAL_HEADER32)_opt64;
|
|
_sections = (PIMAGE_SECTION_HEADER)((UCHAR*)_opt64 + _fileHeader->SizeOfOptionalHeader);
|
|
_valid = true;
|
|
}
|
|
}
|
|
|
|
int PEParser::GetSectionCount() const {
|
|
if (!IsValid())
|
|
return -1;
|
|
|
|
return _fileHeader->NumberOfSections;
|
|
}
|
|
|
|
ULONG PEParser::RvaToFileOffset(ULONG rva) const {
|
|
auto sections = _sections;
|
|
for (int i = 0; i < GetSectionCount(); ++i) {
|
|
if (rva >= sections[i].VirtualAddress && rva < sections[i].VirtualAddress + _sections[i].Misc.VirtualSize) // 在节区内
|
|
return sections[i].PointerToRawData + rva - sections[i].VirtualAddress;
|
|
}
|
|
return rva;
|
|
}
|
|
|
|
bool PEParser::IsValid() const {
|
|
return _valid;
|
|
}
|
|
|
|
bool PEParser::IsPe64() const {
|
|
return _opt64 ? _opt64->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC : IsObjectPe64();
|
|
}
|
|
|
|
bool PEParser::IsObjectPe64() const {
|
|
auto machine = _fileHeader->Machine;
|
|
return machine == IMAGE_FILE_MACHINE_AMD64 || machine == IMAGE_FILE_MACHINE_ARM64 || machine == IMAGE_FILE_MACHINE_IA64;
|
|
}
|
|
|
|
bool PEParser::HasExports() const {
|
|
return _opt64 ? GetDataDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)->VirtualAddress != 0 : false;
|
|
}
|
|
|
|
|
|
const IMAGE_DATA_DIRECTORY* PEParser::GetDataDirectory(int index) const {
|
|
if (_opt64 == nullptr||_opt32 == nullptr)
|
|
return nullptr;
|
|
if (!IsValid() || index < 0 || index>15)
|
|
return nullptr;
|
|
|
|
return IsPe64() ? &_opt64->DataDirectory[index] : &_opt32->DataDirectory[index];
|
|
}
|
|
|
|
void* PEParser::GetAddress(ULONG rva) const {
|
|
if (!IsValid())
|
|
return nullptr;
|
|
|
|
return _address + RvaToFileOffset(rva);
|
|
}
|
|
|
|
ULONG PEParser::GetExportByName(PCSTR exportName) {
|
|
ULONG offset = 0;
|
|
if (!HasExports())
|
|
return 0;
|
|
|
|
auto dir = GetDataDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT);
|
|
if (dir == nullptr || dir->Size == 0)
|
|
return 0;
|
|
|
|
auto data = static_cast<IMAGE_EXPORT_DIRECTORY*>(GetAddress(dir->VirtualAddress));
|
|
auto ordinals = (PUCHAR)(data->AddressOfNameOrdinals != 0 ? GetAddress(data->AddressOfNameOrdinals) : nullptr);
|
|
auto names = (PUCHAR)(data->AddressOfNames != 0 ? GetAddress(data->AddressOfNames) : nullptr);
|
|
auto functions = (PULONG)GetAddress(data->AddressOfFunctions);
|
|
auto ordinalBase = data->Base;
|
|
PCSTR name = nullptr;
|
|
|
|
for (ULONG i = 0; i < data->NumberOfNames; ++i) {
|
|
int ordinal = i;
|
|
if (ordinals) {
|
|
ordinal = *(USHORT*)(ordinals + i * 2) + (USHORT)ordinalBase;
|
|
}
|
|
if (names) {
|
|
offset = *(ULONG*)(names + i * 4);
|
|
name = (PCSTR)GetAddress(offset);
|
|
}
|
|
auto address = *(functions + ordinal - ordinalBase);
|
|
if (address > dir->VirtualAddress && address < dir->VirtualAddress + dir->Size) {
|
|
// we ignore forwarded exports
|
|
continue;
|
|
}
|
|
// compare the export name to the requested export
|
|
if (name) {
|
|
if (!strcmp(name, exportName)) {
|
|
offset = RvaToFileOffset(address);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
PIMAGE_SECTION_HEADER PEParser::RvaToSection(PIMAGE_NT_HEADERS ntHeader, PVOID base, ULONG rva) {
|
|
PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(ntHeader);
|
|
for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) {
|
|
if (sections[i].VirtualAddress <= rva) {
|
|
if ((sections[i].VirtualAddress + sections[i].Misc.VirtualSize) > rva) {
|
|
return §ions[i];
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
void* PEParser::GetBaseAddress() const {
|
|
return _address;
|
|
}
|
|
|
|
void* PEParser::GetAddressEntryPoint() const {
|
|
return _opt64->AddressOfEntryPoint + _address;
|
|
}
|
|
|
|
const IMAGE_SECTION_HEADER* PEParser::GetSectionHeader(ULONG section) const {
|
|
if (!IsValid() || section >= _fileHeader->NumberOfSections)
|
|
return nullptr;
|
|
|
|
return _sections + section;
|
|
}
|
|
|
|
IMAGE_SECTION_HEADER* PEParser::GetSectionHeader(ULONG section) {
|
|
if (!IsValid() || section >= _fileHeader->NumberOfSections)
|
|
return nullptr;
|
|
|
|
return _sections + section;
|
|
} |