Compare commits

..

9 Commits

Author SHA1 Message Date
WerWolv
575e4d5381 scripts: Added helper scripts to extract old project files 2022-08-14 14:47:28 +02:00
WerWolv
6b0fad199e git: Remove LR line ending requirements 2022-08-10 19:22:35 +02:00
gmestanley
ece86f1124 patterns: Added enhancements for PE pattern (#41)
The current pattern file for the PE format doesn't have a lot of the format's quirks, so I decided to code them in after I noticed that it doesn't cover the structure known as Rich Header. (Forgive the garbage code for its ProductType enum, it was the only way I found to make the values appear.)
Here are my sources for the improvements included here:

How the MZ header works and some of its variables' names: [How to determine the size of an PE executable file from headers and or footers](https://stackoverflow.com/questions/34684660/how-to-determine-the-size-of-an-pe-executable-file-from-headers-and-or-footers)
The function of some of the MZ header variables: [https://github.com/corkami/pics/blob/master/binary/pe102.png](PE102 by Corkami)
The existence of sections: [https://github.com/corkami/pics/blob/master/binary/pe101/pe101.png](PE101 by Corkami)
The Machine values for LoongArch processors, the architecture enum and how it's used in the Optional Header, Subsystem types, DLL & Section characteristics, how sections, their line numbers and relocations work: [PE Format](https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-rsrc-section)
The Machine values for DECAlphaAXP and i860: [Peering Inside the PE: A Tour of the Win32 Portable Executable File Format](https://docs.microsoft.com/en-us/previous-versions/ms809762(v=msdn.10)#the-pe-header)
How the Rich Header works: [https://www.virusbulletin.com/virusbulletin/2020/01/vb2019-paper-rich-headers-leveraging-mysterious-artifact-pe-format/](VB2019 paper: Rich Headers: leveraging this mysterious artifact of the PE format)
Values of products in the Rich Header: [https://securelist.com/the-devils-in-the-rich-header/84348/](The devil’s in the Rich header)
Every other value not found in the above source: Ghidra
2022-08-10 15:06:10 +02:00
WerWolv
ce2b4d60ca patterns: Added very basic MBR and FAT32 filesystem pattern 2022-08-10 14:36:06 +02:00
WerWolv
7c88439681 git: Output errors when ctest fails 2022-08-09 16:10:27 +02:00
WerWolv
8d3c94be8f tests: Make tests compile with latest PatternLanguage update 2022-08-07 22:55:00 +02:00
WerWolv
0b15299980 patterns: Remove [[static]] attribute from non-static struct in elf pattern 2022-08-07 21:40:54 +02:00
WerWolv
eda13b2518 includes/type: Added [[sealed]] attribute to LEB128 type 2022-08-05 13:49:26 +02:00
Oded Shapira
aa6c90fa5b includes/type: Added LEB128 type (#40)
* Implement VarInt type

* VarInts are little endian, make result u128

* Rename VarInt to LEB128

* It didn't remove the varint file
2022-08-05 13:45:34 +02:00
11 changed files with 850 additions and 107 deletions

8
.gitattributes vendored
View File

@@ -1,10 +1,2 @@
*.pat linguist-language=Rust
*.hexpat linguist-language=Rust
constants/* text eol=lf
encodings/* text eol=lf
includes/* text eol=lf
magic/* text eol=lf
patterns/* text eol=lf
structs/* text eol=lf
tips/* text eol=lf
yara/* text eol=lf

View File

@@ -53,7 +53,7 @@ jobs:
- name: 🧪 Perform Unit Tests
run: |
cd tests/build
ctest
ctest --output-on-failure
- name: 📎 Validate JSON Files
run: |
cd constants

View File

@@ -32,6 +32,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed
| VDF | | `patterns/vdf.hexpat` | Binary Value Data Format (.vdf) files |
| IP | | `patterns/ip.hexpat` | Ethernet II Frames (IP Packets) |
| UF2 | | `patterns/uf2.hexpat` | [USB Flashing Format](https://github.com/microsoft/uf2) |
| File System | | `patterns/fs.hexpat` | Drive File System |
### Scripts

33
includes/type/leb128.pat Normal file
View File

@@ -0,0 +1,33 @@
#pragma once
#include <std/io.pat>
#include <std/mem.pat>
namespace type {
struct LEB128 {
u8 array[while($ == addressof(this) || std::mem::read_unsigned($-1, 1) & 0x80 != 0)] [[hidden]];
} [[sealed, format("type::impl::format_leb128"), transform("type::impl::transform_leb128")]];
namespace impl {
fn transform_leb128_array(auto array) {
u128 res = array[0] & 0x7f;
for(u8 i = 1, array[i-1] & 0x80 != 0, i+=1) {
res |= u64(array[i] & 0x7f) << 7 * i;
}
return res;
};
fn format_leb128(auto leb128) {
u128 res = type::impl::transform_leb128_array(leb128.array);
return std::format("{} ({:#x})", res, res);
};
fn transform_leb128(auto leb128) {
return type::impl::transform_leb128_array(leb128.array);
};
}
}

View File

@@ -181,7 +181,7 @@ namespace program {
u64 memory_size;
u64 alignment;
}
} [[static]];
};
}
@@ -251,7 +251,7 @@ namespace section {
u64 address_alignment;
u64 entry_size;
}
} [[static]];
};
}

168
patterns/fs.hexpat Normal file
View File

@@ -0,0 +1,168 @@
#include <std/io.pat>
struct DiskTimeStamp {
u8 seconds, minutes, hours;
};
enum DiskProtection : u16 {
None = 0x0000,
CopyProtected = 0x5A5A
};
bitfield CHS {
h : 8;
s : 6;
c : 10;
} [[right_to_left, format("chs_formatter")]];
fn chs_formatter(CHS chs) {
return std::format("({:X}, {:X}, {:X}) | 0x{:X}", chs.c, chs.h, chs.s, (chs.c * 16 + chs.h) * 63 + (chs.s - 1));
};
enum PartitionStatus : u8 {
None = 0x00,
Active = 0x80
};
enum PartitionType : u8 {
EmptyPartitionEntry = 0x00,
FAT32_CHS = 0x0B,
FAT32_LBA = 0x0C
};
namespace fat32 {
u64 bytesPerCluster;
struct FSInfo {
u32 leadSignature;
padding[480];
u32 structSignature;
u32 freeClusterCount;
u32 nextFreeCluster;
padding[12];
u32 trailSignature;
};
bitfield SequenceNumber {
padding : 1;
lastLogical : 1;
padding : 1;
number : 5;
} [[left_to_right]];
enum EntryStatus : u8 {
Regular = 0x00,
DotEntry = 0x2E,
DeletedEntry = 0xE5
};
union EntryStatusOrSequenceNumber {
EntryStatus entryStatus;
SequenceNumber sequenceNumber;
};
bitfield Attributes {
readOnly : 1;
hidden : 1;
systemFile : 1;
volumeLabel : 1;
subdirectory : 1;
archive : 1;
padding : 2;
} [[right_to_left]];
struct DirEntry {
char fileName[8];
char extension[3];
Attributes attributes;
u8 reserved[10];
u16 time, date;
u16 startingCluster;
u32 fileSize;
u8 data[fileSize] @ startingCluster * bytesPerCluster;
};
struct VFATDirEntry {
EntryStatusOrSequenceNumber entryStatusOrSequenceNumber;
char16 name1[5];
Attributes attributes;
u8 type;
u8 nameChecksum;
char16 name2[6];
u16 startingCluster;
char16 name3[2];
if (entryStatusOrSequenceNumber.sequenceNumber.number > 1)
VFATDirEntry nextLogicalEntry;
else
DirEntry physicalEntry;
};
struct Partition {
u8 jmpCode[3];
char oemName[8];
u16 bytesPerSector;
u8 sectorsPerCluster;
u16 reservedAreaSize;
u8 numFats;
u16 rootEntryCount;
u16 numSectors;
u8 mediaType;
u16 fatSize;
u16 sectorsPerTrack;
u16 numHeads;
u32 numHiddenSectors;
u32 numFsSectors;
u32 numFatSectors;
u16 extFlags;
u16 fsVersion;
u32 rootCluster;
u16 fsInfoSector;
u16 backupBootSector;
padding[12];
u8 driveNumber;
padding[1];
u8 bootSignature;
u32 volumeID;
char volumeLabel[11];
char fsType[8];
u8 bootstrapCode[420];
u16 signature;
bytesPerCluster = (sectorsPerCluster * 1024) * bytesPerSector;
FSInfo fsInfo @ addressof(this) + fsInfoSector * bytesPerSector;
VFATDirEntry rootDirEntry @ addressof(this) + rootCluster * bytesPerCluster;
};
}
struct PartitionEntry {
PartitionStatus status;
CHS chsFirstSectorAddress;
PartitionType type;
CHS chsLastSectorAddress;
u32 lbaFirstSectorAddress;
u32 numSectors;
if (type == PartitionType::EmptyPartitionEntry)
continue;
else if (type == PartitionType::FAT32_CHS || type == PartitionType::FAT32_LBA)
fat32::Partition partition @ lbaFirstSectorAddress * 512;
};
struct MasterBootRecord {
u8 bootstrapCodeArea1[218];
padding[2];
u8 originalPhysicalDrive;
DiskTimeStamp diskTimeStamp;
u8 bootstrapCodeArea2[216];
u32 diskSignature;
DiskProtection diskProtection;
PartitionEntry partitionEntries[4];
u16 bootSignature;
};
MasterBootRecord mbr @ 0x00;

View File

@@ -1,4 +1,10 @@
#pragma MIME application/x-dosexec
#pragma MIME application/x-msdownload
#pragma pattern_limit 100000
#pragma array_limit 10000
#include <std/mem.pat>
#include <std/string.pat>
#include <std/ctype.pat>
#include <std/io.pat>
enum MachineType : u16 {
Unknown = 0x00,
@@ -7,9 +13,13 @@ enum MachineType : u16 {
ARM = 0x1C0,
ARM64 = 0xAA64,
ARMNT = 0x1C4,
DECAlphaAXP = 0x183,
EBC = 0xEBC,
I386 = 0x14C,
I860 = 0x14D,
IA64 = 0x200,
LOONGARCH32 = 0x6232,
LOONGARCH64 = 0x6264,
M32R = 0x9041,
MIPS16 = 0x266,
MIPSFPU = 0x366,
@@ -28,32 +38,99 @@ enum MachineType : u16 {
WCEMIPSV2 = 0x169
};
enum PEFormat : u16 {
PE32 = 0x10B,
PE32Plus = 0x20B
};
enum SubsystemType : u16 {
Unknown = 0x00,
Native = 0x01,
WindowsGUI = 0x02,
WindowsCUI = 0x03,
OS2CUI = 0x05,
POSIXCUI = 0x07,
Windows9xNative = 0x08,
WindowsCEGUI = 0x09,
EFIApplication = 0x0A,
EFIBootServiceDriver = 0x0B,
EFIRuntimeDriver = 0x0C,
EFIROM = 0x0D,
Xbox = 0x0E,
WindowsBootApplication = 0x10
};
bitfield Characteristics {
stripped : 1;
relocationsStripped : 1;
executableImage : 1;
lineNumsStripped : 1;
localSymsStripped : 1;
lineNumbersStripped : 1;
localSymbolsStripped : 1;
aggressiveWsTrim : 1;
largeAddressAware : 1;
reserved : 1;
bytesReversedLo : 1;
is32BitMachine : 1;
debugStripped : 1;
debugInfoStripped : 1;
removableRunFromSwap : 1;
netRunFromSwap : 1;
system : 1;
dll : 1;
upSystemOnly : 1;
uniprocessorMachineOnly : 1;
bytesReversedHi : 1;
};
} [[right_to_left]];
bitfield DLLCharacteristics {
reserved : 4;
padding : 1;
highEntropyVA : 1;
dynamicBase : 1;
forceIntegrity : 1;
nxCompatible : 1;
noIsolation : 1;
noSEH : 1;
doNotBind : 1;
appContainer : 1;
wdmDriver : 1;
cfGuard : 1;
terminalServerAware : 1;
} [[right_to_left]];
bitfield SectionFlags {
reserved : 3;
doNotPad : 1;
reserved : 1;
containsCode : 1;
containsInitializedData : 1;
containsUninitializedData : 1;
linkOther : 1;
comments : 1;
reserved : 1;
remove : 1;
comdat : 1;
padding : 2;
globalPointerRelocation : 1;
purgeable : 1;
is16Bit : 1;
locked : 1;
preloaded : 1;
dataAlignment : 4;
extendedRelocations : 1;
discardable : 1;
notCacheable : 1;
notPageable : 1;
shared : 1;
executed : 1;
read : 1;
writtenTo : 1;
} [[right_to_left]];
struct DataDirectory {
u32 virtualAddress;
u32 size;
};
struct OptionalHeader32 {
u16 magic;
struct OptionalHeader {
PEFormat magic;
u8 majorLinkerVersion;
u8 minorLinkerVersion;
u32 sizeOfCode;
@@ -61,8 +138,13 @@ struct OptionalHeader32 {
u32 sizeOfUninitializedData;
u32 addressOfEntryPoint;
u32 baseOfCode;
u32 baseOfData;
u32 imageBase;
if (magic == PEFormat::PE32) {
u32 baseOfData;
u32 imageBase;
}
else if (magic == PEFormat::PE32Plus) {
u64 imageBase;
}
u32 sectionAlignment;
u32 fileAlignment;
u16 majorOperatingSystemVersion;
@@ -75,87 +157,90 @@ struct OptionalHeader32 {
u32 sizeOfImage;
u32 sizeOfHeaders;
u32 checksum;
u16 subsystem;
u16 dllCharacteristics;
u32 sizeOfStackReserve;
u32 sizeOfStackCommit;
u32 sizeOfHeapReserve;
u32 sizeOfHeapCommit;
SubsystemType subsystem;
DLLCharacteristics dllCharacteristics;
if (magic == PEFormat::PE32) {
u32 sizeOfStackReserve;
u32 sizeOfStackCommit;
u32 sizeOfHeapReserve;
u32 sizeOfHeapCommit;
}
else if (magic == PEFormat::PE32Plus) {
u64 sizeOfStackReserve;
u64 sizeOfStackCommit;
u64 sizeOfHeapReserve;
u64 sizeOfHeapCommit;
}
u32 loaderFlags;
u32 numberOfRvaAndSizes;
DataDirectory directories[numberOfRvaAndSizes];
u32 numberOfRVAsAndSizes;
DataDirectory directories[numberOfRVAsAndSizes];
};
struct OptionalHeader64 {
u16 magic;
u8 majorLinkerVersion;
u8 minorLinkerVersion;
u32 sizeOfCode;
u32 sizeOfInitializedData;
u32 sizeOfUninitializedData;
u32 addressOfEntryPoint;
u32 baseOfCode;
u64 imageBase;
u32 sectionAlignment;
u32 fileAlignment;
u16 majorOperatingSystemVersion;
u16 minorOperatingSystemVersion;
u16 majorImageVersion;
u16 minorImageVersion;
u16 majorSubsystemVersion;
u16 minorSubSystemVersion;
u32 win32VersionValue;
u32 sizeOfImage;
u32 sizeOfHeaders;
u32 checksum;
u16 subsystem;
u16 dllCharacteristics;
u64 sizeOfStackReserve;
u64 sizeOfStackCommit;
u64 sizeOfHeapReserve;
u64 sizeOfHeapCommit;
u32 loaderFlags;
u32 numberOfRvaAndSizes;
DataDirectory directories[numberOfRvaAndSizes];
};
struct COFFHeader {
u32 signature;
struct COFFHeader {
char signature[4];
MachineType machine;
u16 numberOfSections;
u32 timeDateStamp;
u32 pointerToSymbolTable;
u32 numberOfSymbolTable;
u32 numberOfSymbols;
u16 sizeOfOptionalHeader;
Characteristics characteristics;
if (machine == MachineType::AMD64) {
OptionalHeader64 optionalHeader;
} else {
OptionalHeader32 optionalHeader;
if (sizeOfOptionalHeader > 0x00) {
OptionalHeader optionalHeader;
}
};
struct DOSHeader {
u16 signature;
u8 header[0x3A];
COFFHeader *coffHeaderPointer : u32;
char signature[2];
u16 lastPageSize;
u16 numberOfPages;
u16 relocations;
u16 headerSizeInParagraphs;
u16 minimumAllocatedParagraphs;
u16 maximumAllocatedParagraphs;
u16 initialSSValue;
u16 initialRelativeSPValue;
u16 checksum;
u16 initialRelativeIPValue;
u16 initialCSValue;
u16 relocationsTablePointer;
u16 overlayNumber;
u16 reservedWords[4];
u16 oemIdentifier;
u16 oemInformation;
u16 reservedWords[10];
u32 coffHeaderPointer;
};
fn isdosmessage(char c) {
return std::ctype::isalnum(c) || c == '.' || c == ' ';
};
struct DOSStub {
u8 code[14];
s8 message[0x27];
u8 data[11];
u8 code[while(std::mem::read_string($, 4) != "This")];
char message[while(isdosmessage(std::mem::read_unsigned($, 1)))];
char data[while(std::mem::read_unsigned($, 1) != 0x00)];
};
union SectionMisc {
u32 physicalAddress;
u32 virtualSize;
struct PEHeader {
DOSHeader dosHeader;
if (dosHeader.headerSizeInParagraphs * 16 < std::mem::size()) {
DOSStub dosStub @ dosHeader.headerSizeInParagraphs * 16;
}
};
struct Section {
PEHeader peHeader @ 0x00;
COFFHeader coffHeader @ peHeader.dosHeader.coffHeaderPointer;
struct SectionHeader {
char name[8];
SectionMisc misc;
if (coffHeader.characteristics.executableImage) {
u32 virtualSize;
} else {
u32 physicalAddress;
}
u32 virtualAddress;
u32 sizeOfRawData;
u32 ptrRawData;
@@ -163,15 +248,436 @@ struct Section {
u32 ptrLineNumbers;
u16 numberOfRelocations;
u16 numberOfLineNumbers;
SectionFlags characteristics;
};
SectionHeader sectionTable[coffHeader.numberOfSections] @ (addressof(coffHeader.characteristics) + 2) + coffHeader.sizeOfOptionalHeader;
u16 currentSectionIndex;
fn updateSectionIndex() {
currentSectionIndex = currentSectionIndex + 1;
};
struct NullTerminatedString {
char string[while(std::mem::read_unsigned($, 1) != 0x00)];
padding[1];
} [[inline]];
// Declarations of sections and variables used by it
// Imports + Readonly Data Section
struct DirectoryTable {
u32 lookupTableRVA;
u32 timeDateStamp;
u32 forwarderChain;
u32 dllNameRVA;
u32 addressTableRVA;
};
struct ImportsSection {
DirectoryTable directoryTables[while(std::mem::read_unsigned($, 16) != 0x00)];
DirectoryTable nullDirectoryTable;
};
struct ReadonlyDataSection {
u8 readonlyDataStart[while($ < coffHeader.optionalHeader.directories[1].virtualAddress - (sectionTable[currentSectionIndex].virtualAddress - sectionTable[currentSectionIndex].ptrRawData))];
ImportsSection importsSection;
u8 readonlyDataEnd[while($ < sectionTable[currentSectionIndex+1].ptrRawData)];
};
// Resource Section
struct ResourceDirectoryTable {
u32 characteristics;
u32 timeDateStamp;
u16 majorVersion;
u16 minorVersion;
u16 nameEntriesAmount;
u16 idEntriesAmount;
};
enum ResourceID : u32 {
Bitmap = 0x02,
Icon = 0x03,
Menu = 0x04,
Dialog = 0x05,
String = 0x06,
GroupIcon = 0x0D,
Version = 0x10,
Manifest = 0x18
};
struct IdDirectoryEntry {
ResourceID id;
u32 relativeOffsetToData;
};
struct ResourceDirectory {
ResourceDirectoryTable resourceDirectoryTable;
IdDirectoryEntry idEntries[resourceDirectoryTable.idEntriesAmount];
};
struct ResourceSection {
ResourceDirectory rootDirectory;
};
// Exports Section
struct ExportDirectoryTable {
u32 exportFlags;
u32 timeDateStamp;
u16 majorVersion;
u16 minorVersion;
u32 nameRVA;
u32 ordinalBase;
u32 addressTableEntries;
u32 numberOfNamePointers;
u32 exportAddressTableRVA;
u32 namePointerRVA;
u32 ordinalTableRVA;
};
struct ExportAddress {
if (std::mem::read_unsigned($, 4) > sectionTable[currentSectionIndex].sizeOfRawData && std::mem::read_unsigned($, 4) < sectionTable[currentSectionIndex].ptrRawData) {
u32 exportRVA;
}
else {
u32 forwarderRVA;
}
};
struct ExportsSection {
ExportDirectoryTable exportDirectoryTable;
ExportAddress exportAddressTable[exportDirectoryTable.addressTableEntries];
u32 exportNamePointerTable[exportDirectoryTable.numberOfNamePointers];
};
// Exception Section
bitfield ExceptionSectionBits {
functionLength : 22;
instructions32Bit : 1;
exceptionHandler : 1;
} [[right_to_left]];
struct FunctionTableEntry {
if (coffHeader.machine == MachineType::MIPSFPU) {
u32 beginVA;
u32 endVA;
u32 exceptionHandlerPointer;
u32 handlerDataPointer;
u32 prologEndVA;
} else if (coffHeader.machine == MachineType::ARM || MachineType::ARM64 || MachineType::ARMNT || MachineType::POWERPC || MachineType::POWERPCFP || MachineType::SH3 || MachineType::SH4) {
u32 beginVA;
u8 prologLength;
ExceptionSectionBits miscellaneousBits;
} else if (coffHeader.machine == MachineType::AMD64 || MachineType::IA64) {
u32 beginRVA;
u32 endRVA;
u32 unwindInformationRVA;
}
};
struct ExceptionSection {
FunctionTableEntry functionTableEntries[while($ < sectionTable[currentSectionIndex].ptrRawData + sectionTable[currentSectionIndex].sizeOfRawData)];
};
// TLS Section
struct TLSSection {
if (coffHeader.optionalHeader.magic == PEFormat::PE32) {
u32 rawDataStartVA;
u32 rawDataEndVA;
u32 indexAddress;
u32 callbacksAddress;
}
else if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) {
u64 rawDataStartVA;
u64 rawDataEndVA;
u64 indexAddress;
u64 callbacksAddress;
}
u32 zeroFillSize;
u32 characteristics;
};
struct PEHeader {
DOSHeader dosHeader;
DOSStub dosStub;
// Relocations Section
bitfield RelocationWord {
type : 4;
offset : 12;
};
PEHeader peHeader @ 0x00;
struct BaseRelocationBlock {
u32 pageRVA;
u32 blockSize;
RelocationWord word;
};
Section sectionsTable[peHeader.dosHeader.coffHeaderPointer.numberOfSections]
@ addressof(peHeader.dosHeader.coffHeaderPointer) + sizeof(peHeader.dosHeader.coffHeaderPointer);
struct BaseRelocationTable {
BaseRelocationBlock baseRelocationBlocks[while(std::mem::read_unsigned($, 8) != 0x00)];
};
// General Section things
enum I386Relocations : u16 {
Absolute = 0x00,
Dir16 = 0x01,
Rel16 = 0x02,
Dir32 = 0x06
};
struct Relocation {
u32 virtualAddress;
u32 symbolTableIndex;
if (coffHeader.machine == MachineType::I386) {
I386Relocations type;
}
else {
u16 type;
}
};
struct LineNumber {
u32 lineNumber @ $ + 4;
if (lineNumber > 0x00) {
u32 virtualAddress @ $ - 8;
} else {
u32 symbolTableIndex @ $ - 8;
}
$ += 8;
};
fn importsSectionExists() {
bool returnedValue = false;
std::print("Checking which section is .idata for read-only data section");
for (u16 i = 0, i < coffHeader.numberOfSections, i = i + 1) {
std::print("Checking section " + std::string::to_string(i));
if (sectionTable[i].name == ".idata") {
std::print("Check successful. Section " + std::string::to_string(i) + " is .idata, so the read-only data section won't have an imports section in it");
returnedValue = true;
break;
}
}
if (!returnedValue) {
std::print("Check failed! This means there is no separate imports section");
}
return returnedValue;
};
struct Section {
if (std::string::starts_with(sectionTable[currentSectionIndex].name, ".pdata")) { // Exception section
ExceptionSection exceptionSection;
}
else if (std::string::starts_with(sectionTable[currentSectionIndex].name, ".rdata")) {// Read-only data section
if (importsSectionExists() || coffHeader.optionalHeader.directories[1].size == 0) {
u8 readonlyDataSection[sectionTable[currentSectionIndex].sizeOfRawData];
}
else {
ReadonlyDataSection readonlyDataSection;
}
}
else if (std::string::starts_with(sectionTable[currentSectionIndex].name, ".idata")) {// Imports section
ImportsSection importsSection;
}
else if (std::string::starts_with(sectionTable[currentSectionIndex].name, ".edata")) {// Exports section
ExportsSection exportsSection;
}
else if (std::string::starts_with(sectionTable[currentSectionIndex].name, ".rsrc")) { // Resource section
ResourceSection resourceSection;
}
else if (std::string::starts_with(sectionTable[currentSectionIndex].name, ".tls")) { // Thread-local storage section
TLSSection tlsSection;
}
else if (std::string::starts_with(sectionTable[currentSectionIndex].name, ".reloc")) {// Thread-local storage section
BaseRelocationTable relocationsSection;
}
else {
u8 freeformSection[sectionTable[currentSectionIndex].sizeOfRawData]; // Freeform data section
}
// Additional things
//Relocation relocations[sectionTable[currentSectionIndex].numberOfRelocations] @ sectionTable[currentSectionIndex].ptrRelocations;
LineNumber lineNumbers[sectionTable[currentSectionIndex].numberOfLineNumbers] @ sectionTable[currentSectionIndex].ptrLineNumbers;
// Next section
if (currentSectionIndex < coffHeader.numberOfSections-1) { // If it's not the last section (to avoid problems this code would have with it)
updateSectionIndex(); // Make the current section index the next section's index
if (sectionTable[currentSectionIndex].sizeOfRawData > 0) { // If the size of this section is bigger than 0
$ = sectionTable[currentSectionIndex].ptrRawData; // Put the current offset at the start of the next section
}
}
} [[inline]];
Section sections[coffHeader.numberOfSections] @ sectionTable[0].ptrRawData;
// Symbol & String Tables
enum SectionNumberType : s16 {
Undefined = 0,
Absolute = -1,
Debug = -2
};
enum SymbolTypeMSB : u8 {
Null = 0x00,
Pointer = 0x10,
Function = 0x20,
Array = 0x30
};
enum SymbolTypeLSB : u8 {
Null = 0x00,
Void = 0x01,
Char = 0x02,
Short = 0x03,
Integer = 0x04,
Long = 0x05,
Float = 0x06,
Double = 0x07,
Struct = 0x08,
Union = 0x09,
Enum = 0x0A,
MemberOfEnum = 0x0B,
Byte = 0x0C,
Word = 0x0D,
UInt = 0x0E,
DWord = 0x0F
};
enum StorageClassType : s8 {
EndOfFunction = -1,
Null = 0,
Automatic = 1,
External = 2,
Static = 3,
Register = 4,
DefinedExternally = 5,
Label = 6,
UndefinedLabel = 7,
MemberOfStruct = 8,
Argument = 9,
StructTag = 10,
MemberOfUnion = 11,
UnionTag = 12,
TypeDefinition = 13,
UndefinedStatic = 14,
EnumTag = 15,
MemberOfEnum = 16,
RegisterParameter = 17,
Bitfield = 18,
Block = 100,
BlockFunction = 101,
EndOfStruct = 102,
File = 103,
Section = 104,
WeakExternal = 105,
CLRToken = 107
};
struct SymbolNameAddress {
u32 zeroes;
u32 offset;
};
struct SymbolName {
if (std::mem::read_unsigned($, 4) == 0) {
SymbolNameAddress nameAddress;
}
else {
char shortName[8];
}
};
struct SymbolType {
SymbolTypeMSB msb;
SymbolTypeLSB lsb;
};
struct Symbol {
SymbolName name;
u32 value;
SectionNumberType sectionNumber;
SymbolType type;
StorageClassType storageClass;
u8 numberOfAuxSymbols;
};
Symbol symbolTable[coffHeader.numberOfSymbols] @ coffHeader.pointerToSymbolTable;
struct StringTable {
u32 size;
NullTerminatedString strings[while($ < addressof(this) + size)];
} [[inline]];
StringTable stringTable[coffHeader.numberOfSymbols > 0] @ addressof(symbolTable) + sizeof(symbolTable);
// Rich Header
enum ProductType : u16 {
Unmarked = 0x00 ^ richHeaderEnd[0].mask.maskArray[1],
Imports = 0x01 ^ richHeaderEnd[0].mask.maskArray[1],
STDLIBDLL = 0x04 ^ richHeaderEnd[0].mask.maskArray[1],
VC6CVTRes = 0x06 ^ richHeaderEnd[0].mask.maskArray[1],
VC6CCompiler = 0x0A ^ richHeaderEnd[0].mask.maskArray[1],
VC6CPPCompiler = 0x0B ^ richHeaderEnd[0].mask.maskArray[1],
OldNames = 0x0C ^ richHeaderEnd[0].mask.maskArray[1],
MASM613 = 0x0E ^ richHeaderEnd[0].mask.maskArray[1],
VC2003Assembler = 0x0F ^ richHeaderEnd[0].mask.maskArray[1],
VC2002Linker = 0x19 ^ richHeaderEnd[0].mask.maskArray[1],
VC2002CCompiler = 0x1C ^ richHeaderEnd[0].mask.maskArray[1],
VC2002CPPCompiler = 0x1D ^ richHeaderEnd[0].mask.maskArray[1],
VC2003SDKIMP = 0x5D ^ richHeaderEnd[0].mask.maskArray[1],
VC2003CPPCompiler = 0x60 ^ richHeaderEnd[0].mask.maskArray[1],
VC2008SDKIMP = 0x93 ^ richHeaderEnd[0].mask.maskArray[1],
Linker12 = 0x9D ^ richHeaderEnd[0].mask.maskArray[1],
MASM10 = 0x9E ^ richHeaderEnd[0].mask.maskArray[1],
VC2010CCompiler = 0xAA ^ richHeaderEnd[0].mask.maskArray[1],
VC2010CPPCompiler = 0xAB ^ richHeaderEnd[0].mask.maskArray[1]
};
union RichHeaderMask {
u32 maskVariable;
u16 maskArray[2];
};
struct RichHeaderEnd {
char signature[4];
RichHeaderMask mask;
} [[inline]];
u8 richHeaderAmount;
u8 richHeaderEndPosition;
u8 richHeaderCorpusPosition;
fn initializeRichHeader() {
$ = sizeof(peHeader);
while ($ < peHeader.dosHeader.coffHeaderPointer) {
if (std::mem::read_string($, 4) == "Rich") {
richHeaderAmount = 1;
richHeaderEndPosition = $;
break;
}
$ += 1;
}
};
initializeRichHeader();
RichHeaderEnd richHeaderEnd[richHeaderAmount] @ richHeaderEndPosition;
struct Product {
u16 buildNumber;
ProductType productID;
u32 objectCount;
};
struct RichHeaderCorpus {
char maskedSignature[4];
u32 nullPadding[3];
Product products[while($ != richHeaderEndPosition)];
} [[inline]];
fn setupRichHeader() {
if (richHeaderAmount > 0) {
//0x20 is the size of a Rich Header with one product
for (u8 richCursor = $ - 0x20, richCursor > sizeof(peHeader), richCursor = richCursor - 0x01) {
if (str(std::mem::read_unsigned(richCursor, 4) ^ richHeaderEnd[0].mask.maskVariable) == "DanS") {
richHeaderCorpusPosition = richCursor;
break;
}
}
}
};
setupRichHeader();
RichHeaderCorpus richHeaderCorpus[richHeaderAmount] @ richHeaderCorpusPosition;

View File

@@ -0,0 +1,35 @@
import json
import sys
from pathlib import Path
def extractData(projectName, jsonData, objectName, extension):
if objectName in jsonData:
with open(f"./{projectName}.{extension}", "w") as output:
output.write(jsonData[objectName])
def main():
if len(sys.argv) != 2 or not str(sys.argv[1]).endswith(".hexproj"):
print(f"Usage: {sys.argv[0]} <filename.hexproj>")
exit(1)
projectPath = sys.argv[1]
with open(projectPath, "r") as file:
jsonData = json.loads(file.read())
projectName = Path(projectPath).stem
extractData(projectName, jsonData, "dataProcessor", "hexnode")
extractData(projectName, jsonData, "pattern", "hexpat")
if "bookmarks" in jsonData:
with open(f"./{projectName}.hexbm", "w") as output:
jsonOutput = {}
jsonOutput["bookmarks"] = jsonData["bookmarks"]
output.write(json.dumps(jsonOutput, indent=4))
if "filePath" in jsonData:
print(f"Project file used file {jsonData['filePath']}")
if __name__ == "__main__":
main()

View File

@@ -1,5 +1,8 @@
#include <pl.hpp>
#include <helpers/file.hpp>
#include <pl/helpers/file.hpp>
#include <pl/core/errors/preprocessor_errors.hpp>
#include <pl/core/errors/evaluator_errors.hpp>
#include <fmt/format.h>
#include <cstdlib>
@@ -19,17 +22,20 @@ int main(int argc, char **argv) {
fmt::print("Running test {} on test file {}\n", includeName, includeFilePath.filename().string());
// Open pattern file
pl::fs::File patternFile(includeFilePath, pl::fs::File::Mode::Read);
pl::hlp::fs::File patternFile(includeFilePath, pl::hlp::fs::File::Mode::Read);
if (!patternFile.isValid())
return EXIT_FAILURE;
// Setup Pattern Language Runtime
pl::PatternLanguage runtime;
{
constexpr auto DummyPragmaHandler = [](const auto&, const auto&){ pl::LogConsole::abortEvaluation("Include files should never use this pragma!"); return true; };
constexpr auto DummyPragmaHandler = [](const auto&, const auto&){
pl::core::err::M0006.throwError("Include files should never use this pragma!");
return false;
};
runtime.setDataSource([&](pl::u64 address, pl::u8 *data, size_t size) {
pl::LogConsole::abortEvaluation("Include files should never read from memory directly!");
pl::core::err::E0011.throwError("Include files should never read from memory directly!");
}, 0x00, 0x100000);
runtime.setDangerousFunctionCallHandler([]{ return true; });
runtime.setIncludePaths({ includePath });
@@ -47,14 +53,15 @@ int main(int argc, char **argv) {
fmt::print("Error during execution!\n");
if (const auto &hardError = runtime.getError(); hardError.has_value())
fmt::print("Hard error: {}\n\n", hardError.value().what());
fmt::print("Hard error: {}:{} - {}\n\n", hardError->line, hardError->column, hardError->message);
for (const auto &[level, message] : runtime.getConsoleLog()) {
switch (level) {
case pl::LogConsole::Level::Debug: fmt::print(" [DEBUG] "); break;
case pl::LogConsole::Level::Info: fmt::print(" [INFO] "); break;
case pl::LogConsole::Level::Warning: fmt::print(" [WARN] "); break;
case pl::LogConsole::Level::Error: fmt::print(" [ERROR] "); break;
using enum pl::core::LogConsole::Level;
case Debug: fmt::print(" [DEBUG] "); break;
case Info: fmt::print(" [INFO] "); break;
case Warning: fmt::print(" [WARN] "); break;
case Error: fmt::print(" [ERROR] "); break;
}
fmt::print("{}\n", message);

View File

@@ -1,5 +1,5 @@
#include <helpers/file.hpp>
#include <helpers/guards.hpp>
#include <pl/helpers/file.hpp>
#include <pl/helpers/guards.hpp>
#include <fmt/format.h>
#include <cstdlib>

View File

@@ -1,5 +1,5 @@
#include <pl.hpp>
#include <helpers/file.hpp>
#include <pl/helpers/file.hpp>
#include <fmt/format.h>
#include <cstdlib>
@@ -27,12 +27,12 @@ int main(int argc, char **argv) {
fmt::print("Running test {} on test file {}\n", patternName, testFilePath.stem().string());
// Open pattern file
pl::fs::File patternFile(patternFilePath, pl::fs::File::Mode::Read);
pl::hlp::fs::File patternFile(patternFilePath, pl::hlp::fs::File::Mode::Read);
if (!patternFile.isValid())
return EXIT_FAILURE;
// Open test file
pl::fs::File testFile(testFilePath, pl::fs::File::Mode::Read);
pl::hlp::fs::File testFile(testFilePath, pl::hlp::fs::File::Mode::Read);
if (!testFile.isValid())
return EXIT_FAILURE;
@@ -55,14 +55,15 @@ int main(int argc, char **argv) {
fmt::print("Error during execution!\n");
if (const auto &hardError = runtime.getError(); hardError.has_value())
fmt::print("Hard error: {}\n\n", hardError.value().what());
fmt::print("Hard error: {}:{} - {}\n\n", hardError->line, hardError->column, hardError->message);
for (const auto &[level, message] : runtime.getConsoleLog()) {
switch (level) {
case pl::LogConsole::Level::Debug: fmt::print(" [DEBUG] "); break;
case pl::LogConsole::Level::Info: fmt::print(" [INFO] "); break;
case pl::LogConsole::Level::Warning: fmt::print(" [WARN] "); break;
case pl::LogConsole::Level::Error: fmt::print(" [ERROR] "); break;
using enum pl::core::LogConsole::Level;
case Debug: fmt::print(" [DEBUG] "); break;
case Info: fmt::print(" [INFO] "); break;
case Warning: fmt::print(" [WARN] "); break;
case Error: fmt::print(" [ERROR] "); break;
}
fmt::print("{}\n", message);