Rizin
unix-like reverse engineering framework and cli tools
analysis_bf.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2016 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <string.h>
6 #include <rz_types.h>
7 #include <rz_lib.h>
8 #include <rz_asm.h>
9 #include <rz_analysis.h>
10 
11 static int getid(char ch) {
12  const char *keys = "[]<>+-,.";
13  const char *cidx = strchr(keys, ch);
14  return cidx ? cidx - keys + 1 : 0;
15 }
16 
17 /* New IL uplift bf */
18 #define BF_ADDR_MEM 0x10000
19 #define BF_ADDR_SIZE 64
20 #define BF_BYTE_SIZE 8
21 #define BF_ID_STACK 32
22 
23 #define bf_il_ptr() rz_il_op_new_var("ptr", RZ_IL_VAR_KIND_GLOBAL)
24 #define bf_il_set_ptr(x) rz_il_op_new_set("ptr", false, x)
25 #define bf_il_one(l) rz_il_op_new_bitv_from_ut64(l, 1)
26 
27 static void bf_syscall_read(RzILVM *vm, RzILOpEffect *op) {
28  ut8 c = getc(stdin);
31  if (ptr_val->type == RZ_IL_TYPE_PURE_BITVECTOR) {
32  rz_il_vm_mem_store(vm, 0, ptr_val->data.bv, bv);
33  } else {
35  }
36  rz_bv_free(bv);
37 }
38 
39 static void bf_syscall_write(RzILVM *vm, RzILOpEffect *op) {
41  if (ptr_val->type != RZ_IL_TYPE_PURE_BITVECTOR) {
43  return;
44  }
45  RzBitVector *bv = rz_il_vm_mem_load(vm, 0, ptr_val->data.bv);
46  ut32 c = rz_bv_to_ut32(bv);
47  if (c) {
48  putchar(c);
49  fflush(stdout);
50  }
51  rz_bv_free(bv);
52 }
53 
55  // (set ptr (+ (val ptr) (int 1)))
57  return bf_il_set_ptr(add);
58 }
59 
61  // (set ptr (- (val ptr) (int 1)))
63  return bf_il_set_ptr(sub);
64 }
65 
67  // (store mem (var ptr) (+ (load (var ptr)) (int 1)))
68  // mem == 0 because is the only mem in bf
71  return rz_il_op_new_store(0, bf_il_ptr(), add);
72 }
73 
75  // (store mem (var ptr) (- (load (var ptr)) (int 1)))
76  // mem == 0 because is the only mem in bf
79  return rz_il_op_new_store(0, bf_il_ptr(), sub);
80 }
81 
83  // (goto write)
84  return rz_il_op_new_goto("write");
85 }
86 
88  // (goto hook_read)
89  return rz_il_op_new_goto("read");
90 }
91 
95 static ut64 find_matching_bracket(RzAnalysis *analysis, ut64 addr, int dir) {
96  if (!analysis->read_at) {
97  return UT64_MAX;
98  }
99  static const ut64 max_dist = 2048; // some upper bound to avoid (almost) infinite loops
100  ut64 dist = 0;
101  int lev = dir;
102  while (dist < max_dist) {
103  dist++;
104  addr += dir;
105  if (addr == UT64_MAX) {
106  break;
107  }
108  ut8 c;
109  analysis->read_at(analysis, addr, &c, 1);
110  switch (c) {
111  case '[':
112  lev++;
113  break;
114  case ']':
115  lev--;
116  break;
117  case 0:
118  case 0xff:
119  // invalid code
120  return UT64_MAX;
121  default:
122  continue;
123  }
124  if (lev == 0) {
125  return addr;
126  }
127  }
128  return UT64_MAX;
129 }
130 
132  // (perform (branch (load mem (var ptr))
133  // (do nothing)
134  // (goto ]))
137  // goto ]
139  // branch if (load mem (var ptr)) is false then goto ]
140  return rz_il_op_new_branch(cond, NULL, jmp);
141 }
142 
144  // (perform (branch (load mem (var ptr))
145  // (goto [)
146  // (do nothing))
149  // goto [
151  // branch if (load mem (var ptr)) is true then goto ]
153  return branch;
154 }
155 
157  RzAnalysisILConfig *cfg = rz_analysis_il_config_new(64, false, 64);
159  if (!cfg->init_state) {
161  return NULL;
162  }
165  read_label->hook = bf_syscall_read;
166  rz_analysis_il_config_add_label(cfg, read_label);
168  write_label->hook = bf_syscall_write;
169  rz_analysis_il_config_add_label(cfg, write_label);
170  return cfg;
171 }
172 
173 static int bf_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) {
174  rz_return_val_if_fail(analysis && op, -1);
175 
176  op->size = 1;
177  op->id = getid(buf[0]);
178  op->addr = addr;
179 
180  switch (buf[0]) {
181  case '[':
182  // Find the jump target, +1 because we jump directly after the matching bracket.
183  // If not found this returns UT64_MAX, so this overflows to 0, which is considered the "invalid"
184  // value for RzAnalysisOp, so it's fine.
185  op->jump = find_matching_bracket(analysis, addr, 1) + 1;
187  op->il_op = bf_llimit(analysis, addr, op->jump);
188  }
190  op->fail = addr + 1;
191  break;
192  case ']':
193  // same idea for target as above
194  op->jump = find_matching_bracket(analysis, addr, -1) + 1;
196  op->il_op = bf_rlimit(analysis, addr, op->jump);
197  }
199  break;
200  case '>':
201  op->type = RZ_ANALYSIS_OP_TYPE_ADD;
203  op->il_op = bf_right_arrow();
204  }
205  break;
206  case '<':
207  op->type = RZ_ANALYSIS_OP_TYPE_SUB;
209  op->il_op = bf_left_arrow();
210  }
211  break;
212  case '+':
213  op->type = RZ_ANALYSIS_OP_TYPE_ADD;
215  op->il_op = bf_inc();
216  }
217  break;
218  case '-':
219  op->type = RZ_ANALYSIS_OP_TYPE_SUB;
221  op->il_op = bf_dec();
222  }
223  break;
224  case '.':
226  op->il_op = bf_out();
227  }
229  break;
230  case ',':
232  op->il_op = bf_in();
233  }
235  break;
236  case 0x00:
237  case 0xff:
239  break;
240  default:
241  op->type = RZ_ANALYSIS_OP_TYPE_NOP;
243  op->il_op = rz_il_op_new_nop();
244  }
245  break;
246  }
247  return op->size;
248 }
249 
250 static char *get_reg_profile(RzAnalysis *analysis) {
251  return strdup(
252  "=PC pc\n"
253  "=BP ptr\n"
254  "=SP ptr\n"
255  "=A0 ptr\n"
256  "=A1 ptr\n"
257  "=A2 ptr\n"
258  "=A3 ptr\n"
259  "gpr ptr .64 0 0\n" // data pointer
260  "gpr pc .64 8 0\n" // program counter
261  );
262 }
263 
265  .name = "bf",
266  .desc = "brainfuck code analysis plugin",
267  .license = "LGPL3",
268  .arch = "bf",
269  .bits = 64, // RzIL emulation of bf and the reg definitions above use 64bit values
270  .op = &bf_op,
271  .get_reg_profile = get_reg_profile,
272  .il_config = il_config
273 };
274 
275 #ifndef RZ_PLUGIN_INCORE
278  .data = &rz_analysis_plugin_bf,
280 };
281 #endif
size_t len
Definition: 6502dis.c:15
#define jmp
#define BF_BYTE_SIZE
Definition: analysis_bf.c:20
#define bf_il_set_ptr(x)
Definition: analysis_bf.c:24
#define BF_ADDR_SIZE
Definition: analysis_bf.c:19
static void bf_syscall_read(RzILVM *vm, RzILOpEffect *op)
Definition: analysis_bf.c:27
static char * get_reg_profile(RzAnalysis *analysis)
Definition: analysis_bf.c:250
RzILOpEffect * bf_right_arrow()
Definition: analysis_bf.c:54
#define bf_il_ptr()
Definition: analysis_bf.c:23
static RzAnalysisILConfig * il_config(RzAnalysis *analysis)
Definition: analysis_bf.c:156
RzILOpEffect * bf_dec()
Definition: analysis_bf.c:74
#define bf_il_one(l)
Definition: analysis_bf.c:25
static int getid(char ch)
Definition: analysis_bf.c:11
RzILOpEffect * bf_left_arrow()
Definition: analysis_bf.c:60
static void bf_syscall_write(RzILVM *vm, RzILOpEffect *op)
Definition: analysis_bf.c:39
static ut64 find_matching_bracket(RzAnalysis *analysis, ut64 addr, int dir)
Definition: analysis_bf.c:95
RzILOpEffect * bf_out()
Definition: analysis_bf.c:82
RzILOpEffect * bf_inc()
Definition: analysis_bf.c:66
RZ_API RzLibStruct rizin_plugin
Definition: analysis_bf.c:276
static int bf_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask)
Definition: analysis_bf.c:173
RzAnalysisPlugin rz_analysis_plugin_bf
Definition: analysis_bf.c:264
RzILOpEffect * bf_rlimit(RzAnalysis *analysis, ut64 addr, ut64 target)
Definition: analysis_bf.c:143
RzILOpEffect * bf_llimit(RzAnalysis *analysis, ut64 addr, ut64 target)
Definition: analysis_bf.c:131
#define BF_ADDR_MEM
Definition: analysis_bf.c:18
RzILOpEffect * bf_in()
Definition: analysis_bf.c:87
#define mask()
RZ_API void rz_analysis_il_config_add_label(RZ_NONNULL RzAnalysisILConfig *cfg, RZ_NONNULL RZ_OWN RzILEffectLabel *label)
Definition: analysis_il.c:77
RZ_API RZ_OWN RzAnalysisILConfig * rz_analysis_il_config_new(ut32 pc_size, bool big_endian, ut32 mem_key_size)
Definition: analysis_il.c:53
RZ_API void rz_analysis_il_config_free(RzAnalysisILConfig *cfg)
Definition: analysis_il.c:66
RZ_API RzAnalysisILInitState * rz_analysis_il_init_state_new()
Definition: analysis_il.c:19
RZ_API void rz_analysis_il_init_state_set_var(RZ_NONNULL RzAnalysisILInitState *state, RZ_NONNULL const char *name, RZ_NONNULL RZ_OWN RzILVal *val)
Definition: analysis_il.c:38
#define RZ_API
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
RZ_API RZ_OWN RzILVal * rz_il_value_new_bitv(RZ_NONNULL RzBitVector *bv)
Definition: value.c:28
RZ_API RZ_OWN RzILOpPure * rz_il_op_new_load(RzILMemIndex mem, RZ_NONNULL RzILOpPure *key)
Helper to create RzILOpArgsLoad.
Definition: il_opcodes.c:718
RZ_API RZ_OWN RzILOpEffect * rz_il_op_new_branch(RZ_NONNULL RzILOpBool *condition, RZ_NULLABLE RzILOpEffect *true_eff, RZ_NULLABLE RzILOpEffect *false_eff)
op structure for branch (bool -> 'a eff -> 'a eff -> 'a eff)
Definition: il_opcodes.c:702
RZ_API RZ_OWN RzILOpBitVector * rz_il_op_new_sub(RZ_NONNULL RzILOpBitVector *x, RZ_NONNULL RzILOpBitVector *y)
op structure for two-operand algorithm and logical operations ('s bitv -> 's bitv -> 's bitv)
Definition: il_opcodes.c:409
RZ_API RZ_OWN RzILOpEffect * rz_il_op_new_jmp(RZ_NONNULL RzILOpBitVector *dst)
op structure for jmp (_ bitv -> ctrl eff)
Definition: il_opcodes.c:589
RZ_API RZ_OWN RzILOpEffect * rz_il_op_new_store(RzILMemIndex mem, RZ_NONNULL RzILOpBitVector *key, RZ_NONNULL RzILOpBitVector *value)
Helper to create RzILOpArgsStoreW.
Definition: il_opcodes.c:728
RZ_API RZ_OWN RzILOpEffect * rz_il_op_new_goto(RZ_NONNULL const char *lbl)
op structure for goto (label -> ctrl eff)
Definition: il_opcodes.c:601
RZ_API RZ_OWN RzILOpBool * rz_il_op_new_bitv_from_ut64(ut32 length, ut64 number)
op structure for bitvector converted from ut64
Definition: il_opcodes.c:173
RZ_API RZ_OWN RzILOpBool * rz_il_op_new_non_zero(RZ_NONNULL RzILOpPure *bv)
Definition: il_opcodes.c:243
RZ_API RZ_OWN RzILOpBitVector * rz_il_op_new_add(RZ_NONNULL RzILOpBitVector *x, RZ_NONNULL RzILOpBitVector *y)
op structure for two-operand algorithm and logical operations ('s bitv -> 's bitv -> 's bitv)
Definition: il_opcodes.c:397
RZ_API RZ_OWN RzILOpPure * rz_il_op_new_var(RZ_NONNULL const char *v, RzILVarKind kind)
op structure for var ('a var -> 'a pure)
Definition: il_opcodes.c:65
RZ_API RZ_OWN RzILOpEffect * rz_il_op_new_nop()
Definition: il_opcodes.c:566
RZ_API RZ_BORROW RzILVal * rz_il_vm_get_var_value(RZ_NONNULL RzILVM *vm, RzILVarKind kind, const char *name)
Definition: il_vm.c:264
RZ_API void rz_il_vm_mem_store(RzILVM *vm, RzILMemIndex index, RzBitVector *key, RzBitVector *value)
Definition: il_vm_eval.c:144
RZ_API RzBitVector * rz_il_vm_mem_load(RzILVM *vm, RzILMemIndex index, RzBitVector *key)
Definition: il_vm_eval.c:124
voidpf void * buf
Definition: ioapi.h:138
RZ_API RzILEffectLabel * rz_il_effect_label_new(RZ_NONNULL const char *name, RzILEffectLabelType type)
Definition: label.c:6
@ EFFECT_LABEL_HOOK
Definition: label.h:20
@ EFFECT_LABEL_SYSCALL
Definition: label.h:19
uint8_t ut8
Definition: lh5801.h:11
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static struct @218 keys[]
void * load(const char *name, size_t *len)
Definition: pufftest.c:60
RzAnalysisOpMask
Definition: rz_analysis.h:439
@ RZ_ANALYSIS_OP_MASK_IL
Definition: rz_analysis.h:446
@ RZ_ANALYSIS_OP_TYPE_SUB
Definition: rz_analysis.h:402
@ RZ_ANALYSIS_OP_TYPE_LOAD
Definition: rz_analysis.h:416
@ RZ_ANALYSIS_OP_TYPE_UJMP
Definition: rz_analysis.h:369
@ RZ_ANALYSIS_OP_TYPE_TRAP
Definition: rz_analysis.h:392
@ RZ_ANALYSIS_OP_TYPE_ADD
Definition: rz_analysis.h:401
@ RZ_ANALYSIS_OP_TYPE_STORE
Definition: rz_analysis.h:415
@ RZ_ANALYSIS_OP_TYPE_CJMP
Definition: rz_analysis.h:373
@ RZ_ANALYSIS_OP_TYPE_NOP
Definition: rz_analysis.h:389
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API void rz_bv_free(RZ_NULLABLE RzBitVector *bv)
Definition: bitvector.c:85
RZ_API ut32 rz_bv_to_ut32(RZ_NONNULL const RzBitVector *x)
Definition: bitvector.c:1435
RZ_API RZ_OWN RzBitVector * rz_bv_new_from_ut64(ut32 length, ut64 value)
Definition: bitvector.c:1161
@ RZ_LIB_TYPE_ANALYSIS
Definition: rz_lib.h:73
#define UT64_MAX
Definition: rz_types_base.h:86
#define RZ_VERSION
Definition: rz_version.h:8
#define c(i)
Definition: sha256.c:43
@ RZ_IL_TYPE_PURE_BITVECTOR
Definition: sort.h:25
#define cond(bop, top, mask, flags)
structure for bitvector
Definition: rz_bitvector.h:19
Description of the global context of an RzAnalysisILVM.
Definition: rz_analysis.h:1134
RZ_NULLABLE RzAnalysisILInitState * init_state
optional, initial contents for variables/registers, etc.
Definition: rz_analysis.h:1144
const char * version
Definition: rz_analysis.h:1239
bool(* read_at)(struct rz_analysis_t *analysis, ut64 addr, ut8 *buf, int len)
Definition: rz_analysis.h:614
void * hook
Function pointer if EFFECT_LABEL_SYSCALL / EFFECT_LABEL_HOOK.
Definition: label.h:28
An IL op performing a pure computation, 'a pure.
RzValUnion data
data pointer
Definition: value.h:26
RzILTypePure type
type of value
Definition: value.h:25
Low-level VM to execute raw IL code.
Definition: rz_il_vm.h:37
RzBitVector * bv
Definition: value.h:17
Definition: dis.c:32
@ RZ_IL_VAR_KIND_GLOBAL
global var, usually bound to a physical representation like a register.
Definition: variable.h:47
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58
static int add(char *argv[])
Definition: ziptool.c:84