forked from WerWolv/ImHex-Patterns
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpopcap_luc.hexpat
More file actions
174 lines (140 loc) · 4.74 KB
/
popcap_luc.hexpat
File metadata and controls
174 lines (140 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#pragma author gluecia
#pragma description PopCap's proprietary Lua bytecode (.luc)
#pragma endian little
#pragma magic [ 1B 4C 75 61 56 ] @ 0x00;
import std.io;
import std.sys;
using PLChunk;
using PLConst;
using PLLocal;
using PLOp;
using PLStr;
using cType;
struct PLHeader {
char magic[5];
padding[18];
// *technically* this is a part of the first top level chunk, though
// it is essentially just a part of the header since it only appears there.
PLStr filename [[name("Source Name")]];
};
// LOCALS
fn fmtLocal(PLLocal l) {
return l.name;
};
struct PLLocal {
u32 nameLength [[hidden]];
char16 name[nameLength] [[name("Local")]];
u32 begin [[name("Begin")]];
u32 end [[name("End")]];
} [[format("fmtLocal")]];
// CONSTANTS
// constant types
fn fmtCType(cType t) {
match (t) {
(cType::Nil): return "nil";
(cType::Int): return "int";
(cType::Float): return "float";
(cType::Str): return "str";
(_): return "unknown";
}
};
enum cType : u8 {
Nil,
Float = 3,
Int,
Str
} [[format("fmtCType")]];
// lua strings
fn fmtStr(PLStr s) {
return std::format("\"{}\"", s.val);
};
struct PLStr {
u32 len [[hidden]];
if (len > 0)
char16 val[len];
} [[format("fmtStr"), sealed]];
// constants struct
fn fmtConst(PLConst c) {
if (c.type == cType::Nil) {
return c.type;
} else {
return std::format("{} ({})", c.val, c.type);
}
};
struct PLConst {
cType type;
match (type) {
(cType::Float): double val;
(cType::Int): s32 val;
(cType::Str): PLStr val;
// theres definitely a better way to handle the Nil case
(cType::Nil): u8 val = 0;
(_): std::error("unknown cType given");
}
} [[format("fmtConst"), sealed]];
// PROTOTYPES
struct PLPrototype {
padding[4];
PLChunk chunk;
} [[inline]];
// UPVALUES
struct PLUpvalue {
u32 len [[hidden]];
char name[len] [[name("Upvalue")]];
} [[inline]];
// OPERANDS
fn fmtPLOp(PLOp o) {
return o.opcode;
};
// source: https://github.com/wxarmstrong/PopLua-Disassembler/blob/master/popOp.cpp
enum PLOpType : u8 {
MOVE, LOADK, LOADBOOL, LOADNIL, GETUVPVAL,
GETGLOBAL, GETTABLE, SETGLOBAL, SETUPVAL,
SETTABLE, NEWTABLE, SELF, ADD, SUB, MUL,
DIV, MOD, POW, UNM, NOT, SIZ, CONCAT, JMP,
EQ, LT, LE, TEST, CALL, TAILCALL, RETURN,
FORLOOP, TFORLOOP, TFORPREP, SETLIST,
SETLISTO, CLOSE, ALTSELF, CONSTGLOBAL,
CONSTTABLE, DEFGLOBAL, DEFTABLE,
SETSELFORGLOBAL, GETSELFORGLOBAL,
SELFORGLOBAL, CALLSELFORGLOBAL,
TAILCALLSELFORGLOBAL, INT, BREAK,
CLOSURE
};
// this is for a different version of lua and its bytecode, but helped a LOT
// https://archive.org/details/a-no-frills-intro-to-lua-5.1-vm-instructions
struct PLOp {
u32 raw [[hidden]];
PLOpType opcode = raw & 0x3F [[name("Opcode"), hidden, export]];
u32 rawOperands = raw >> 6;
u8 opA = rawOperands & 0xFF [[name("Operand A"), export]];
match(opcode) {
(PLOpType::LOADK | PLOpType::CLOSURE): u32 Bx = (rawOperands >> 8) [[name("Operand Bx"), export]];
// 131071 is the bias for sBx to make it signed, formed from (2^18 - 1) >> 1
// where 2^18 - 1 is the maximum value for an 18 bit number
(PLOpType::JMP | PLOpType::FORLOOP | PLOpType::TFORLOOP): s32 opSBx = (rawOperands >> 8) - 131071 [[name("Operand sBx"), comment("Signed displacement added to the PC."), export]];
(_): {
u16 opB = (rawOperands >> 8) & 0xFF01 [[name("Operand B"), export]];
u16 opC = (rawOperands >> 17) & 0xFF01 [[name("Operand C"), export]];
}
}
} [[format("fmtPLOp")]];
// CHUNKS
struct PLChunk {
char intro[0xC] [[name("Chunk Intro"), comment("Holds information on the function, but the format is unknown.")]];
u32 sizecode [[name("Instructions Count")]];
u32 linesArray[sizecode] [[name("Line Numbers"), comment("The line numbers for the given operations, this should be interpreted with the operations array.")]];
u32 sizelocvars [[name("Locals Count")]];
PLLocal localsArray[sizelocvars] [[name("Locals")]];
u32 sizeupvalues [[name("Upvalues Count")]];
PLUpvalue upvalsArray[sizeupvalues] [[name("Upvalues")]];
u32 sizek [[name("Constants Count")]];
PLConst constsArray[sizek] [[name("Constants")]];
u32 sizep [[name("Prototype Count")]];
PLPrototype protoArray[sizep] [[name("Prototypes")]];
u32 sizecodeVerify [[hidden]];
std::assert(sizecode == sizecodeVerify, std::format("sizecode ({}) did not match sizecodeVerify ({})!", sizecode, sizecodeVerify));
PLOp opsArray[sizecode] [[name("Instructions"), comment("The raw bytes for operations, should be interpreted with the line numbers array.")]];
};
PLHeader Header @ 0x0;
PLChunk Body @ $;