Compare commits

...

10 Commits

Author SHA1 Message Date
Lucy
f548643933 encodings: Add English Pokémon generation 1 character encoding (#42)
* encodings: Add English Pokémon generation 1 character encoding

Source: https://bulbapedia.bulbagarden.net/wiki/Character_encoding_(Generation_I)#English

* readme: Add `pokegen1_en.tbl`
2022-08-14 17:46:40 +02:00
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
12 changed files with 1106 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
@@ -98,6 +99,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed
| JIS X 0211 | `encodings/jis_x_0211.tbl` | JIS X 0211 encoding in UTF-8 |
| JIS 0213 | `encodings/jis_x_0213.tbl` | JIS X 0213 encoding in UTF-8 |
| Macintosh | `encodings/macintosh.tbl` | Macintosh character encoding used by the Kermit protocol |
| Pokémon (English, Generation 1) | `encodings/pokegen1_en.tbl` | Character encoding used by the English generation 1 Pokémon games |
| Shift-JIS UTF-8 | `encodings/shiftjis.tbl` | Shift-JIS encoding in UTF-8 |
| Thai | `encodings/thai.tbl` | Thai character encoding |
| Turkish ISO | `encodings/turkish_iso.tbl` | Turkish ISO encoding |

255
encodings/pokegen1_en.tbl Normal file
View File

@@ -0,0 +1,255 @@
00=NUL
01
02
03
04
05
06
07
08
09
0A
0B
0C
0D
0E
0F
11
12
13
14
15
16
17
18
19
1A
1B
1C
1D
1E
1F
20
21
22
23
24
25
26
27
28
29
2A
2B
2C
2D
2E
2F
30
31
32
33
34
35
36
37
38
39
3A
3B
3C
3D
3E
3F
40
41
42
43
44
45
46
47
48
49=page
4A=PkMn
4B=_cont
4C=autocont
4D
4E=next line
4F=bottom line
50=end
51=paragraph
52=player name
53=rival name
54=Poké
55=cont
56=......
57=done
58=prompt
59=target
5A=user
5B=PC
5C=TM
5D=TRAINER
5E=ROCKET
5F=dex
60=A
61=B
62=C
63=D
64=E
65=F
66=G
67=H
68=I
69=V
6A=S
6B=L
6C=M
6D=:
6E=ぃ
6F=ぅ
70=
71=
72=“
73=”
74=・
75=⋯
76=ぁ
77=ぇ
78=ぉ
79
7A
7B
7C
7D
7E
7F
80=A
81=B
82=C
83=D
84=E
85=F
86=G
87=H
88=I
89=J
8A=K
8B=L
8C=M
8D=N
8E=O
8F=P
90=Q
91=R
92=S
93=T
94=U
95=V
96=W
97=X
98=Y
99=Z
9A=(
9B=)
9C=
9D=;
9E=[
9F=]
A0=a
A1=b
A2=c
A3=d
A4=e
A5=f
A6=g
A7=h
A8=i
A9=j
AA=k
AB=l
AC=m
AD=n
AE=o
AF=p
B0=q
B1=r
B2=s
B3=t
B4=u
B5=v
B6=w
B7=x
B8=y
B9=z
BA=é
BB='d
BC='l
BD='s
BE='t
BF='v
C0
C1
C2
C3
C4
C5
C6
C7
C8
C9
CA
CB
CC
CD
CE
CF
D0
D1
D2
D3
D4
D5
D6
D7
D8
D9
DA
DB
DC
DD
DE
DF
E0='
E1=Pk
E2=Mn
E3=-
E4='r
E5='m
E6=?
E7=!
E8=.
E9=ァ
EA=ゥ
EB=ェ
EC=▷
ED=▶
EE=▼
EF=♂
F0=$
F1=×
F2=.
F3=/
F4=,
F5=♀
F6=0
F7=1
F8=2
F9=3
FA=4
FB=5
FC=6
FD=7
FE=8
FF=9

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);