11#include " lua_bytecode_parser.h"
22#include < algorithm>
3+ #include < format>
4+ #include < print>
35#include < stdexcept>
46
7+
58#define LUA_SIGNATURE_53 " \x1B Lua"
69#define LUAC_VERSION_53_MAJOR 0x5
710#define LUAC_VERSION_53_MINOR 0x3
@@ -17,60 +20,38 @@ template <typename T> T bytes_to_value(const char *bytes) {
1720}
1821
1922LuaBytecodeParser::LuaBytecodeParser (const std::vector<char > &bytecode_data)
20- : data_(bytecode_data), offset_(0 ) {}
23+ : data_(bytecode_data), offset_(0 ), encrypt_key_(0 ),
24+ is_ce_bytecode_(false ) {}
2125
2226void LuaBytecodeParser::error (const std::string &msg) {
2327 throw std::runtime_error (" Bytecode parsing error: " + msg);
2428}
2529
26- std::uint8_t LuaBytecodeParser::read_byte () {
27- if (offset_ + sizeof (std::uint8_t ) > data_.size ()) {
28- error (" truncated (byte)" );
29- }
30- std::uint8_t value = bytes_to_value<std::uint8_t >(&data_[offset_]);
31- offset_ += sizeof (std::uint8_t );
32- return value;
33- }
34-
35- std::uint32_t LuaBytecodeParser::read_int () {
36- if (offset_ + sizeof (std::uint32_t ) > data_.size ()) {
37- error (" truncated (int)" );
38- }
39- std::uint32_t value = bytes_to_value<std::uint32_t >(&data_[offset_]);
40- offset_ += sizeof (std::uint32_t );
41- return value;
42- }
43-
44- lua_Number LuaBytecodeParser::read_number () {
45- if (offset_ + sizeof (lua_Number) > data_.size ()) {
46- error (" truncated (number)" );
47- }
48- lua_Number value = bytes_to_value<lua_Number>(&data_[offset_]);
49- offset_ += sizeof (lua_Number);
50- return value;
51- }
52-
53- lua_Integer LuaBytecodeParser::read_integer () {
54- if (offset_ + sizeof (lua_Integer) > data_.size ()) {
55- error (" truncated (integer)" );
56- }
57- lua_Integer value = bytes_to_value<lua_Integer>(&data_[offset_]);
58- offset_ += sizeof (lua_Integer);
59- return value;
60- }
61-
6230void LuaBytecodeParser::read_block (char *buffer, size_t size) {
6331 if (offset_ + size > data_.size ()) {
6432 error (" truncated (block)" );
6533 }
6634 std::copy (data_.begin () + offset_, data_.begin () + offset_ + size, buffer);
35+
36+ if (is_ce_bytecode_ && encrypt_key_ != 0 ) {
37+ std::println (" decrypting: key = {}, size = {}" , encrypt_key_, size);
38+ for (size_t i = 0 ; i < size; ++i) {
39+ char decrypt_byte;
40+ if ((((i + (i >> 3 ) & 7 ) & 7 ) - ((i >> 3 ) & 7 )) != 0 ) {
41+ decrypt_byte = (char )(encrypt_key_ >> (i % 0xe ));
42+ } else {
43+ decrypt_byte = (char )0xce ;
44+ }
45+ buffer[i] ^= decrypt_byte;
46+ }
47+ }
6748 offset_ += size;
6849}
6950
7051std::string LuaBytecodeParser::read_string () {
7152 size_t size = read_byte ();
7253 if (size == 0xFF ) {
73- size = read_integer ();
54+ size = read_uint64 ();
7455 }
7556
7657 if (size == 0 ) {
@@ -83,13 +64,22 @@ std::string LuaBytecodeParser::read_string() {
8364 }
8465}
8566
67+ static std::string hexdump (const std::string &s) {
68+ std::string result;
69+ for (unsigned char c : s) {
70+ result += std::format (" {:02x} " , c);
71+ }
72+ return result;
73+ }
74+
8675void LuaBytecodeParser::check_literal (const std::string &expected,
8776 const std::string &error_msg) {
8877 std::string buffer (expected.length (), ' \0 ' );
8978 read_block (&buffer[0 ], expected.length ());
9079
9180 if (buffer != expected) {
92- error (error_msg);
81+ error (error_msg + std::format (" expected '{}', got '{}'" , hexdump (expected),
82+ hexdump (buffer)));
9383 }
9484}
9585
@@ -114,34 +104,52 @@ void LuaBytecodeParser::check_header() {
114104 error (" version mismatch" );
115105 }
116106
117- if (read_byte () != LUAC_FORMAT_53) {
118- error (" format mismatch" );
107+ std::uint8_t format = read_byte ();
108+ if (format != LUAC_FORMAT_53) {
109+ if (format == 1 ) {
110+ encrypt_key_ = read_uint64 ();
111+ } else {
112+ error (" format mismatch" );
113+ }
119114 }
120115
121116 check_literal (LUAC_DATA_53, " corrupted data section" );
122117
123118 check_size (sizeof (int ), " int" );
124- check_size (sizeof (size_t ), " size_t" );
119+ if (is_ce_bytecode_) {
120+ check_size (8 , " LUA_DUMP_STRINGSIZE_FORMAT2" );
121+ } else {
122+ check_size (sizeof (size_t ), " size_t" );
123+ }
125124 check_size (sizeof (Instruction), " Instruction" );
126125 check_size (sizeof (lua_Integer), " lua_Integer" );
127126 check_size (sizeof (lua_Number), " lua_Number" );
128127
129- if (read_integer () != LUAC_INT_53) {
128+ if (read_uint64 () != LUAC_INT_53) {
130129 error (" endianness mismatch" );
131130 }
132- if (read_number () != LUAC_NUM_53) {
131+ if (read_double () != LUAC_NUM_53) {
133132 error (" float format mismatch" );
134133 }
134+
135+ if (format == 1 )
136+ is_ce_bytecode_ = true ;
135137}
136138
137139void LuaBytecodeParser::load_code (LuaProto &f) {
138- int n = read_int ();
140+ int n = read_uint32 ();
139141 f.code .resize (n);
140142 read_block (reinterpret_cast <char *>(f.code .data ()), n * sizeof (Instruction));
143+
144+ if (is_ce_bytecode_ && encrypt_key_ != 0 ) {
145+ for (int i = 0 ; i < n; ++i) {
146+ f.code [i] -= (i & 3 );
147+ }
148+ }
141149}
142150
143151void LuaBytecodeParser::load_constants (LuaProto &f) {
144- std::uint32_t n = read_int ();
152+ std::uint32_t n = read_uint32 ();
145153 f.constants .resize (n);
146154 for (std::uint32_t i = 0 ; i < n; ++i) {
147155 LuaType t = static_cast <LuaType>(read_byte ());
@@ -153,10 +161,10 @@ void LuaBytecodeParser::load_constants(LuaProto &f) {
153161 f.constants [i].bval = (read_byte () != 0 );
154162 break ;
155163 case LUA_TNUMFLT:
156- f.constants [i].nval = read_number ();
164+ f.constants [i].nval = read_double ();
157165 break ;
158166 case LUA_TNUMINT:
159- f.constants [i].ival = read_integer ();
167+ f.constants [i].ival = read_uint64 ();
160168 break ;
161169 case LUA_TSHRSTR:
162170 case LUA_TLNGSTR:
@@ -169,7 +177,7 @@ void LuaBytecodeParser::load_constants(LuaProto &f) {
169177}
170178
171179void LuaBytecodeParser::load_upvalues (LuaProto &f) {
172- int n = read_int ();
180+ int n = read_uint32 ();
173181 f.upvalues .resize (n);
174182 for (int i = 0 ; i < n; ++i) {
175183 f.upvalues [i].instack = read_byte ();
@@ -178,7 +186,7 @@ void LuaBytecodeParser::load_upvalues(LuaProto &f) {
178186}
179187
180188void LuaBytecodeParser::load_protos (LuaProto &f) {
181- int n = read_int ();
189+ int n = read_uint32 ();
182190 f.protos .resize (n);
183191 for (int i = 0 ; i < n; ++i) {
184192 f.protos [i] = std::make_shared<LuaProto>();
@@ -187,20 +195,20 @@ void LuaBytecodeParser::load_protos(LuaProto &f) {
187195}
188196
189197void LuaBytecodeParser::load_debug (LuaProto &f) {
190- std::uint32_t n_lineinfo = read_int ();
198+ std::uint32_t n_lineinfo = read_uint32 ();
191199 f.lineinfo .resize (n_lineinfo);
192200 read_block (reinterpret_cast <char *>(f.lineinfo .data ()),
193201 n_lineinfo * sizeof (std::uint32_t ));
194202
195- std::uint32_t n_locvars = read_int ();
203+ std::uint32_t n_locvars = read_uint32 ();
196204 f.locvars .resize (n_locvars);
197205 for (std::uint32_t i = 0 ; i < n_locvars; ++i) {
198206 f.locvars [i].varname = read_string ();
199- f.locvars [i].startpc = read_int ();
200- f.locvars [i].endpc = read_int ();
207+ f.locvars [i].startpc = read_uint32 ();
208+ f.locvars [i].endpc = read_uint32 ();
201209 }
202210
203- std::uint32_t n_upvalue_names = read_int ();
211+ std::uint32_t n_upvalue_names = read_uint32 ();
204212 f.upvalue_names .resize (n_upvalue_names);
205213 for (std::uint32_t i = 0 ; i < n_upvalue_names; ++i) {
206214 f.upvalue_names [i] = read_string ();
@@ -212,8 +220,8 @@ void LuaBytecodeParser::load_function(LuaProto &f, const std::string &psource) {
212220 if (f.source .empty ()) {
213221 f.source = psource;
214222 }
215- f.linedefined = read_int ();
216- f.lastlinedefined = read_int ();
223+ f.linedefined = read_uint32 ();
224+ f.lastlinedefined = read_uint32 ();
217225 f.numparams = read_byte ();
218226 f.is_vararg = read_byte ();
219227 f.maxstacksize = read_byte ();
@@ -408,7 +416,7 @@ void LuaBytecodeWriter::write_string(const std::string &s) {
408416 write_byte (0 );
409417 return ;
410418 }
411-
419+
412420 size_t size = s.length () + 1 ;
413421 if (size < 0xFF ) {
414422 write_byte (static_cast <std::uint8_t >(size));
0 commit comments