Rizin
unix-like reverse engineering framework and cli tools
luac_bin.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 // SPDX-FileCopyrightText: 2021 Heersin <teablearcher@gmail.com>
3 
4 #include "luac_common.h"
5 
6 void luac_add_section(RzList *section_list, char *name, ut64 offset, ut32 size, bool is_func) {
8  if (!bin_sec) {
9  return;
10  }
11 
12  bin_sec->name = rz_str_new(name);
13  bin_sec->vaddr = bin_sec->paddr = offset;
14  bin_sec->size = bin_sec->vsize = size;
15  bin_sec->is_data = false;
16  bin_sec->bits = is_func ? sizeof(LUA_INSTRUCTION) * 8 : 8;
17  // bin_sec->has_strings = !is_func;
18  bin_sec->has_strings = false;
19  bin_sec->arch = rz_str_new("luac");
20 
21  if (is_func) {
22  bin_sec->perm = RZ_PERM_R | RZ_PERM_X;
23  } else {
24  bin_sec->perm = RZ_PERM_R;
25  }
26 
27  rz_list_append(section_list, bin_sec);
28 }
29 
30 void luac_add_symbol(RzList *symbol_list, char *name, ut64 offset, ut64 size, const char *type) {
31  RzBinSymbol *bin_sym = RZ_NEW0(RzBinSymbol);
32  if (!bin_sym) {
33  return;
34  }
35 
36  bin_sym->name = rz_str_new(name);
37  bin_sym->vaddr = bin_sym->paddr = offset;
38  bin_sym->size = size;
39  bin_sym->type = type;
40 
41  rz_list_append(symbol_list, bin_sym);
42 }
43 
44 void luac_add_entry(RzList *entry_list, ut64 offset, int entry_type) {
46  if (!entry) {
47  return;
48  }
49 
50  entry->vaddr = offset;
51  entry->paddr = offset;
52  entry->type = entry_type;
53 
54  rz_list_append(entry_list, entry);
55 }
56 
57 void luac_add_string(RzList *string_list, char *string, ut64 offset, ut64 size) {
58  RzBinString *bin_string = RZ_NEW0(RzBinString);
59  if (!bin_string) {
60  return;
61  }
62 
63  bin_string->paddr = offset;
64  bin_string->vaddr = offset;
65  bin_string->size = size;
66  bin_string->length = size;
67  bin_string->string = rz_str_new(string);
68  bin_string->type = RZ_STRING_ENC_UTF8;
69 
70  rz_list_append(string_list, bin_string);
71 }
72 
74  if (list != NULL) {
76  }
77 }
78 
80  if (!section) {
81  return;
82  }
83 
84  if (section->name) {
85  RZ_FREE(section->name);
86  }
87 
88  if (section->format) {
89  RZ_FREE(section->format);
90  }
91 
93 }
94 
95 static void free_rz_string(RzBinString *string) {
96  if (!string) {
97  return;
98  }
99 
100  if (string->string) {
101  RZ_FREE(string->string);
102  }
103 
104  RZ_FREE(string);
105 }
106 
107 static void free_rz_addr(RzBinAddr *addr) {
108  if (!addr) {
109  return;
110  }
111  RZ_FREE(addr);
112 }
113 
115  if (!proto) {
116  RZ_LOG_ERROR("Invalid luac file\n");
117  return NULL;
118  }
119 
121  if (!ret) {
122  return NULL;
123  }
124 
129 
130  if (!(ret->entry_list && ret->symbol_list && ret->section_list && ret->string_list)) {
135  }
136 
137  _luac_build_info(proto, ret);
138 
139  // add entry of main
140  ut64 main_entry_offset;
141  main_entry_offset = proto->code_offset + proto->code_skipped;
142  luac_add_entry(ret->entry_list, main_entry_offset, RZ_BIN_ENTRY_TYPE_PROGRAM);
143 
144  return ret;
145 }
146 
147 static const char *get_tag_string(ut8 tag) {
148  switch (tag) {
149  case LUA_VNIL:
150  return "CONST_NIL";
151  case LUA_VTRUE:
152  case LUA_VFALSE:
153  return "CONST_BOOL";
154  case LUA_VSHRSTR:
155  case LUA_VLNGSTR:
156  return "CONST_STRING";
157  case LUA_VNUMFLT:
158  case LUA_VNUMINT:
159  return "CONST_NUM";
160  default:
161  return "CONST_UNKNOWN";
162  }
163 }
164 
165 /* Heap allocated string */
166 static char *get_constant_symbol_name(char *proto_name, LuaConstEntry *entry) {
167  rz_return_val_if_fail(entry || proto_name, NULL);
168  ut8 tag = entry->tag;
169  char *ret;
170  int integer_value;
171  double float_value;
172 
173  switch (tag) {
174  case LUA_VNIL:
175  ret = rz_str_newf("%s_const_nil", proto_name);
176  break;
177  case LUA_VTRUE:
178  ret = rz_str_newf("%s_const_true", proto_name);
179  break;
180  case LUA_VFALSE:
181  ret = rz_str_newf("%s_const_false", proto_name);
182  break;
183  case LUA_VSHRSTR:
184  case LUA_VLNGSTR:
186  ret = rz_str_newf("%s_const_%s", proto_name, (char *)entry->data);
187  break;
188  case LUA_VNUMFLT:
190  if (entry->data_len < sizeof(double)) {
191  return NULL;
192  }
193  float_value = *(double *)entry->data;
194  ret = rz_str_newf("%s_const_%f", proto_name, float_value);
195  break;
196  case LUA_VNUMINT:
198  if (entry->data_len < sizeof(int)) {
199  return NULL;
200  }
201  integer_value = *(int *)entry->data;
202  ret = rz_str_newf("%s_const_%d", proto_name, integer_value);
203  break;
204  default:
205  ret = rz_str_newf("%s_const_0x%llx", proto_name, entry->offset);
206  break;
207  }
208  return ret;
209 }
210 
211 /* Heap allocated string */
212 static char *simple_build_upvalue_symbol(char *proto_name, LuaUpvalueEntry *entry) {
213  return rz_str_newf("%s_upvalue_0x%llx", proto_name, entry->offset);
214 }
215 
216 static char *get_upvalue_symbol_name(char *proto_name, LuaUpvalueEntry *entry, char *debug_name) {
217  rz_return_val_if_fail(proto_name || entry, NULL);
218  if (debug_name == NULL) {
219  return simple_build_upvalue_symbol(proto_name, entry);
220  }
221 
222  return rz_str_newf("%s_upvalue_%s", proto_name, debug_name);
223 }
224 
226  /* process proto header info */
227  char *section_name;
228  char *symbol_name;
229  char *proto_name;
230  RzListIter *iter;
231 
232  ut64 current_offset;
233  ut64 current_size;
234 
235  int i = 0; // iter
236 
237  // 0. check if stripped (proto name is lost)
238  if (proto->name_size == 0 || proto->proto_name == NULL) {
239  // replace name with current offset
240  proto_name = rz_str_newf("fcn.%08llx", proto->offset);
241  } else {
242  proto_name = rz_str_new((char *)proto->proto_name);
243  }
244 
245  // 1.1 set section name as function_name.header
246  current_offset = proto->offset;
247  current_size = proto->size;
248  section_name = rz_str_newf("%s.header", proto_name);
249  luac_add_section(info->section_list, section_name, current_offset, current_size, false);
250  RZ_FREE(section_name);
251 
252  // 1.2 set section name as function_name.code
253  current_offset = proto->code_offset;
254  current_size = proto->code_size;
255  section_name = rz_str_newf("%s.code", proto_name);
256  luac_add_section(info->section_list, section_name, current_offset, current_size, true);
257  RZ_FREE(section_name);
258 
259  // 1.3 set const section
260  current_offset = proto->const_offset;
261  current_size = proto->const_size;
262  section_name = rz_str_newf("%s.const", proto_name);
263  luac_add_section(info->section_list, section_name, current_offset, current_size, false);
264  RZ_FREE(section_name);
265 
266  // 1.4 upvalue section
267  current_offset = proto->upvalue_offset;
268  current_size = proto->upvalue_size;
269  section_name = rz_str_newf("%s.upvalues", proto_name);
270  luac_add_section(info->section_list, section_name, current_offset, current_size, false);
271  RZ_FREE(section_name);
272 
273  // 1.5 inner protos section
274  current_offset = proto->inner_proto_offset;
275  current_size = proto->inner_proto_size;
276  section_name = rz_str_newf("%s.protos", proto_name);
277  luac_add_section(info->section_list, section_name, current_offset, current_size, false);
278  RZ_FREE(section_name);
279 
280  // 1.6 debug section
281  current_offset = proto->debug_offset;
282  current_size = proto->debug_size;
283  section_name = rz_str_newf("%s.debug", proto_name);
284  luac_add_section(info->section_list, section_name, current_offset, current_size, false);
285  RZ_FREE(section_name);
286 
287  // 2.1 parse local var info
288  LuaLocalVarEntry *local_var_entry;
289  rz_list_foreach (proto->local_var_info_entries, iter, local_var_entry) {
291  info->string_list,
292  (char *)local_var_entry->varname,
293  local_var_entry->offset,
294  local_var_entry->varname_len);
295  }
296 
297  // 2.2 parse debug_upvalues
298  char **upvalue_names;
299  int real_upvalue_cnt;
300  LuaDbgUpvalueEntry *debug_upv_entry;
301  real_upvalue_cnt = rz_list_length(proto->upvalue_entries);
302  upvalue_names = RZ_NEWS0(char *, real_upvalue_cnt);
303  if (!upvalue_names) {
304  return;
305  }
306  rz_list_foreach (proto->dbg_upvalue_entries, iter, debug_upv_entry) {
307  upvalue_names[i] = (char *)debug_upv_entry->upvalue_name;
309  info->string_list,
310  upvalue_names[i],
311  debug_upv_entry->offset,
312  debug_upv_entry->name_len);
313  }
314 
315  // 3.1 construct constant symbols
316  LuaConstEntry *const_entry;
317  rz_list_foreach (proto->const_entries, iter, const_entry) {
318  symbol_name = get_constant_symbol_name(proto_name, const_entry);
320  info->symbol_list,
321  symbol_name,
322  const_entry->offset,
323  const_entry->data_len,
324  get_tag_string(const_entry->tag));
325  if (const_entry->tag == LUA_VLNGSTR || const_entry->tag == LUA_VSHRSTR) {
327  info->string_list,
328  (char *)const_entry->data,
329  const_entry->offset,
330  const_entry->data_len);
331  }
332  RZ_FREE(symbol_name);
333  }
334 
335  // 3.2 construct upvalue symbols
336  LuaUpvalueEntry *upvalue_entry;
337  i = 0;
338  rz_list_foreach (proto->upvalue_entries, iter, upvalue_entry) {
339  symbol_name = get_upvalue_symbol_name(proto_name, upvalue_entry, upvalue_names[i++]);
341  info->symbol_list,
342  symbol_name,
343  upvalue_entry->offset,
344  3,
345  "UPVALUE");
346  RZ_FREE(symbol_name);
347  }
348 
349  // 4. parse sub proto
350  LuaProto *sub_proto;
351  rz_list_foreach (proto->proto_entries, iter, sub_proto) {
352  _luac_build_info(sub_proto, info);
353  }
354 
355  RZ_FREE(proto_name);
356 }
lzma_index ** i
Definition: index.h:629
RZ_API void rz_bin_symbol_free(RzBinSymbol *sym)
Definition: bin.c:175
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
uint8_t ut8
Definition: lh5801.h:11
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
LuacBinInfo * luac_build_info(LuaProto *proto)
Definition: luac_bin.c:114
void luac_add_entry(RzList *entry_list, ut64 offset, int entry_type)
Definition: luac_bin.c:44
void luac_add_symbol(RzList *symbol_list, char *name, ut64 offset, ut64 size, const char *type)
Definition: luac_bin.c:30
static char * simple_build_upvalue_symbol(char *proto_name, LuaUpvalueEntry *entry)
Definition: luac_bin.c:212
void luac_add_string(RzList *string_list, char *string, ut64 offset, ut64 size)
Definition: luac_bin.c:57
void _luac_build_info(LuaProto *proto, LuacBinInfo *info)
Definition: luac_bin.c:225
static void try_free_empty_list(RzList *list)
Definition: luac_bin.c:73
static void free_rz_section(RzBinSection *section)
Definition: luac_bin.c:79
static void free_rz_addr(RzBinAddr *addr)
Definition: luac_bin.c:107
static void free_rz_string(RzBinString *string)
Definition: luac_bin.c:95
static const char * get_tag_string(ut8 tag)
Definition: luac_bin.c:147
static char * get_constant_symbol_name(char *proto_name, LuaConstEntry *entry)
Definition: luac_bin.c:166
void luac_add_section(RzList *section_list, char *name, ut64 offset, ut32 size, bool is_func)
Definition: luac_bin.c:6
static char * get_upvalue_symbol_name(char *proto_name, LuaUpvalueEntry *entry, char *debug_name)
Definition: luac_bin.c:216
#define LUA_VNUMFLT
Definition: luac_common.h:35
ut32 LUA_INSTRUCTION
Definition: luac_common.h:13
#define LUA_VLNGSTR
Definition: luac_common.h:37
#define LUA_VNUMINT
Definition: luac_common.h:34
#define LUA_VSHRSTR
Definition: luac_common.h:36
#define LUA_VFALSE
Definition: luac_common.h:32
#define LUA_VNIL
Definition: luac_common.h:31
#define LUA_VTRUE
Definition: luac_common.h:33
int type
Definition: mipsasm.c:17
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
#define RZ_BIN_ENTRY_TYPE_PROGRAM
Definition: rz_bin.h:33
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_new(const char *str)
Definition: str.c:865
@ RZ_STRING_ENC_UTF8
Definition: rz_str.h:21
#define RZ_PERM_R
Definition: rz_types.h:93
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_X
Definition: rz_types.h:95
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
#define RZ_FREE(x)
Definition: rz_types.h:369
Definition: zipcmp.c:77
Store constant type, data, and offset of this constant in luac file.
Definition: luac_common.h:93
ut64 offset
addr of this constant
Definition: luac_common.h:97
int data_len
len of data
Definition: luac_common.h:96
void * data
can be Number/Integer/String
Definition: luac_common.h:95
ut8 tag
type of this constant, see LUA_V* macros in luac_common.h
Definition: luac_common.h:94
Store upvalue's debug info.
Definition: luac_common.h:149
int name_len
length of name
Definition: luac_common.h:151
ut8 * upvalue_name
upvalue name
Definition: luac_common.h:150
ut64 offset
Definition: luac_common.h:152
Store local var names and other info.
Definition: luac_common.h:137
int varname_len
length of name
Definition: luac_common.h:139
ut64 offset
offset of this entry
Definition: luac_common.h:142
ut8 * varname
name of this variable
Definition: luac_common.h:138
Store valuable info when parsing. Treat luac file body as a main function.
Definition: luac_common.h:43
int name_size
size of proto name
Definition: luac_common.h:48
RzList * dbg_upvalue_entries
A list to store upvalue names.
Definition: luac_common.h:83
RzList * upvalue_entries
A list to store upvalue entries.
Definition: luac_common.h:68
ut64 size
current proto size
Definition: luac_common.h:45
ut64 inner_proto_offset
sub proto section offset
Definition: luac_common.h:74
ut64 code_skipped
opcode data offset to code_offset.
Definition: luac_common.h:60
ut64 const_offset
const section offset
Definition: luac_common.h:64
ut64 upvalue_size
upvalue section size
Definition: luac_common.h:70
RzList * local_var_info_entries
A list to store local var entries.
Definition: luac_common.h:82
RzList * const_entries
A list to store constant entries.
Definition: luac_common.h:63
ut8 * proto_name
current proto name
Definition: luac_common.h:47
ut64 code_offset
code section offset
Definition: luac_common.h:58
RzList * proto_entries
A list to store sub proto entries.
Definition: luac_common.h:73
ut64 upvalue_offset
upvalue section offset
Definition: luac_common.h:69
ut64 offset
proto offset in bytes
Definition: luac_common.h:44
ut64 debug_size
debug section size
Definition: luac_common.h:79
ut64 debug_offset
debug section offset
Definition: luac_common.h:78
ut64 const_size
const section size
Definition: luac_common.h:65
ut64 inner_proto_size
sub proto section size
Definition: luac_common.h:75
ut64 code_size
code section size
Definition: luac_common.h:59
Store upvalue attributes.
Definition: luac_common.h:104
ut64 offset
offset of this upvalue
Definition: luac_common.h:109
RzList * entry_list
list of entries
Definition: luac_common.h:164
RzList * section_list
list of sections
Definition: luac_common.h:162
RzList * symbol_list
list of symbols
Definition: luac_common.h:163
RzList * string_list
list of strings
Definition: luac_common.h:165
Definition: z80asm.h:102
const char * arch
Definition: rz_bin.h:627
char * name
Definition: rz_bin.h:619
bool has_strings
Definition: rz_bin.h:632
char * string
Definition: rz_bin.h:752
const char * type
Definition: rz_bin.h:682
char * name
Definition: rz_bin.h:675
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58