Rizin
unix-like reverse engineering framework and cli tools
bfvm.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2008-2011 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include "bfvm.h"
5 
6 static ut8 bfvm_op(BfvmCPU *c) {
7  // XXX: this is slow :(
8  ut8 buf[4] = { 0 };
9  if (c && c->iob.read_at && !c->iob.read_at(c->iob.io, c->eip, buf, 4)) {
10  return 0xff;
11  }
12  return buf[0];
13 }
14 
16  switch (bfvm_op(c)) {
17  case 0x00:
18  case 0xcc:
19  case 0xff:
20  return 1;
21  }
22  return 0;
23 }
24 
26  memset(c->mem, '\0', c->size);
27  memset(c->input_buf, '\0', c->input_size);
28  memset(c->screen_buf, '\0', c->screen_size);
29  c->base = BFVM_DATA_ADDR;
30  c->input = BFVM_INPUT_ADDR;
31  c->input_idx = 0;
32  c->screen = BFVM_SCREEN_ADDR;
33  c->screen_idx = 0;
34  c->eip = 0; // TODO look forward nops
35  c->ptr = 0;
36  c->esp = c->base;
37 }
38 
39 RZ_API int bfvm_init(BfvmCPU *c, ut32 size, int circular) {
40  memset(c, '\0', sizeof(BfvmCPU));
41 
42  /* data */
43  c->mem = (ut8 *)malloc(size);
44  if (!c->mem) {
45  return 0;
46  }
47  memset(c->mem, '\0', size);
48 
49  /* setup */
50  c->circular = circular;
51  c->size = size;
52 
53  // TODO: use RzBuffer or so here.. this is spagueti
54  /* screen */
55  c->screen = BFVM_SCREEN_ADDR;
56  c->screen_size = BFVM_SCREEN_SIZE;
57  c->screen_buf = (ut8 *)malloc(c->screen_size);
58  memset(c->screen_buf, '\0', c->screen_size);
59 
60  /* input */
61  c->input_size = BFVM_INPUT_SIZE;
62  c->input_buf = (ut8 *)malloc(c->input_size);
63  bfvm_reset(c);
64  return 1;
65 }
66 
69  bfvm_init(c, 4096, 1);
70  memcpy(&c->iob, iob, sizeof(c->iob));
71  return c;
72 }
73 
75  free(c->mem);
76  c->mem = 0;
77  free(c->screen_buf);
78  c->screen_buf = 0;
79  free(c);
80  return NULL;
81 }
82 
84  if (at >= c->base) {
85  at -= c->base;
86  } else if (at >= c->size) {
87  at = c->circular ? 0 : c->size - 1;
88  }
89  return c->mem + at;
90 }
91 
93  // return bfvm_cpu.mem;
94  return bfvm_get_ptr_at(c, c->ptr);
95 }
96 
98  ut8 *ptr = bfvm_get_ptr(c);
99  return ptr ? *ptr : 0;
100 }
101 
103  ut8 *mem = bfvm_get_ptr(c);
104  if (mem != NULL) {
105  mem[0]++;
106  }
107 }
108 
110  ut8 *mem = bfvm_get_ptr(c);
111  if (mem != NULL) {
112  mem[0]--;
113  }
114 }
115 
116 RZ_API int bfvm_reg_set(BfvmCPU *c, const char *str) {
117  char *ptr = strchr(str, ' ');
118  if (!ptr) {
119  return 0;
120  }
121  if (strstr(str, "eip")) {
122  c->eip = rz_num_math(NULL, ptr + 1);
123  } else if (strstr(str, "esp")) {
124  c->esp = rz_num_math(NULL, ptr + 1);
125  } else if (strstr(str, "ptr")) {
126  c->ptr = rz_num_math(NULL, ptr + 1);
127  }
128  return 1;
129 }
130 
131 /* screen and input */
133  int idx = c->input_idx;
134  ut8 *ptr = bfvm_get_ptr(c);
135 
136  if (idx >= c->input_size) {
137  idx = 0;
138  }
139 
140  if (ptr) {
141  *ptr = c->input_buf[idx];
142  c->input_idx = idx + 1;
143  }
144 }
145 
147  int idx = c->screen_idx;
148  c->screen_buf[idx] = bfvm_get(c);
149  c->screen_idx = idx + 1;
150 }
151 
153  ut8 g;
154  switch (op) {
155  case '\0':
156  eprintf(" ; trap (%02x)\n", op);
157  // fallthrough
158  case '.':
159  case ',':
160  case '+':
161  case '-':
162  case '>':
163  case '<':
164  eprintf("%c", op);
165  break;
166  case '[':
167  case ']':
168  g = bfvm_get(c);
169  eprintf("%c ; [ptr] = %d\n", op, g);
170  if (g != 0) {
171  eprintf("[");
172  }
173  break;
174  }
175  return 0;
176 }
177 
178 #define T if (c->trace)
179 /* debug */
180 RZ_API int bfvm_step(BfvmCPU *c, int over) {
181  ut8 op2, op = bfvm_op(c);
182 
183  do {
184  T bfvm_trace_op(c, op);
185  switch (op) {
186  case '\0':
187  /* trap */
188  return 1;
189  case '.':
190  // bfvm_get_ptr (c);
191  bfvm_poke(c);
192  break;
193  case ',':
194  bfvm_peek(c);
195  /* TODO read */
196  break;
197  case '+':
198  bfvm_inc(c);
199  break;
200  case '-':
201  bfvm_dec(c);
202  break;
203  case '>':
204  c->ptr++;
205  break;
206  case '<':
207  c->ptr--;
208  break;
209  case '[':
210  break;
211  case ']':
212  if (bfvm_get(c) != 0) {
213  do {
214  /* control underflow */
215  if (c->eip < (c->eip - 1)) {
216  c->eip = 0;
217  break;
218  }
219  c->eip--;
220  } while (bfvm_op(c) != '[');
221  }
222  break;
223  default:
224  break;
225  }
226  c->eip++;
227  op2 = bfvm_op(c);
228  } while (over && op == op2);
229 
230  return 0;
231 }
232 
234  c->breaked = 0;
235  while (!c->breaked) {
236  bfvm_step(c, 0);
237  if (bfvm_in_trap(c)) {
238  eprintf("Trap instruction at 0x%08" PFMT64x "\n", c->eip);
239  break;
240  }
241  switch (bfvm_op(c)) {
242  case ',':
243  eprintf("contsc: read from input trap\n");
244  c->breaked = 1;
245  continue;
246  case '.':
247  eprintf("contsc: print to screen trap\n");
248  c->breaked = 1;
249  continue;
250  }
251  }
252  return 0;
253 }
254 
255 RZ_API int bfvm_cont(BfvmCPU *c, ut64 until) {
256  c->breaked = 0;
257  while (!c->breaked && c->eip != until) {
258  bfvm_step(c, 0);
259  if (bfvm_in_trap(c)) {
260  eprintf("Trap instruction at 0x%" PFMT64x "\n", c->eip);
261  break;
262  }
263  }
264  return 0;
265 }
266 
268  c->trace = 1;
269  bfvm_cont(c, until);
270  c->trace = 0;
271  return 0;
272 }
273 
274 RZ_API void bfvm_show_regs(BfvmCPU *c, int rad) {
275  if (rad) {
276  eprintf("fs regs\n");
277  eprintf("f eip @ 0x%08" PFMT64x "\n", (ut64)c->eip);
278  eprintf("f esp @ 0x%08" PFMT64x "\n", (ut64)c->esp);
279  eprintf("f ptr @ 0x%08" PFMT64x "\n", (ut64)c->ptr + c->base);
280  eprintf("fs *\n");
281  } else {
282  ut8 ch = bfvm_get(c);
283  eprintf(" eip 0x%08" PFMT64x " esp 0x%08" PFMT64x "\n",
284  (ut64)c->eip, (ut64)c->esp);
285  eprintf(" ptr 0x%08x [ptr] %d = 0x%02x '%c'\n",
286  (ut32)c->ptr, ch, ch, IS_PRINTABLE(ch) ? ch : ' ');
287  }
288 }
289 
290 RZ_API void bfvm_maps(BfvmCPU *c, int rad) {
291  if (rad) {
292  eprintf("fs sections\n");
293  eprintf("e cmd.vprompt=px@screen\n");
294  eprintf("f section_code @ 0x%08" PFMT64x "\n", (ut64)BFVM_CODE_ADDR);
295  eprintf("f section_code_end @ 0x%08" PFMT64x "\n", (ut64)BFVM_CODE_ADDR + BFVM_CODE_SIZE);
296  eprintf("f section_data @ 0x%08" PFMT64x "\n", (ut64)c->base);
297  eprintf("f section_data_end @ 0x%08" PFMT64x "\n", (ut64)c->base + c->size);
298  eprintf("f screen @ 0x%08" PFMT64x "\n", (ut64)c->screen);
299  eprintf("f section_screen @ 0x%08" PFMT64x "\n", (ut64)c->screen);
300  eprintf("f section_screen_end @ 0x%08" PFMT64x "\n", (ut64)c->screen + c->screen_size);
301  eprintf("f input @ 0x%08" PFMT64x "\n", (ut64)c->input);
302  eprintf("f section_input @ 0x%08" PFMT64x "\n", (ut64)c->input);
303  eprintf("f section_input_end @ 0x%08" PFMT64x "\n", (ut64)c->input + c->input_size);
304  eprintf("fs *\n");
305  } else {
306  eprintf("0x%08" PFMT64x " - 0x%08" PFMT64x " rwxu 0x%08" PFMT64x " .code\n",
307  (ut64)0, (ut64)c->size, (ut64)c->size);
308  eprintf("0x%08" PFMT64x " - 0x%08" PFMT64x " rw-- 0x%08" PFMT64x " .data\n",
309  (ut64)c->base, (ut64)(c->base + c->size), (ut64)c->size);
310  eprintf("0x%08" PFMT64x " - 0x%08" PFMT64x " rw-- 0x%08" PFMT64x " .screen\n",
311  (ut64)c->screen, (ut64)(c->screen + c->screen_size), (ut64)c->screen_size);
312  eprintf("0x%08" PFMT64x " - 0x%08" PFMT64x " rw-- 0x%08" PFMT64x " .input\n",
313  (ut64)c->input, (ut64)(c->input + c->input_size), (ut64)c->input_size);
314  }
315 }
RZ_API BfvmCPU * bfvm_new(RzIOBind *iob)
Definition: bfvm.c:67
RZ_API void bfvm_show_regs(BfvmCPU *c, int rad)
Definition: bfvm.c:274
#define T
Definition: bfvm.c:178
RZ_API int bfvm_in_trap(BfvmCPU *c)
Definition: bfvm.c:15
RZ_API void bfvm_reset(BfvmCPU *c)
Definition: bfvm.c:25
RZ_API void bfvm_inc(BfvmCPU *c)
Definition: bfvm.c:102
RZ_API ut8 * bfvm_get_ptr_at(BfvmCPU *c, ut64 at)
Definition: bfvm.c:83
RZ_API BfvmCPU * bfvm_free(BfvmCPU *c)
Definition: bfvm.c:74
RZ_API void bfvm_peek(BfvmCPU *c)
Definition: bfvm.c:132
RZ_API void bfvm_maps(BfvmCPU *c, int rad)
Definition: bfvm.c:290
RZ_API int bfvm_reg_set(BfvmCPU *c, const char *str)
Definition: bfvm.c:116
RZ_API int bfvm_cont(BfvmCPU *c, ut64 until)
Definition: bfvm.c:255
static ut8 bfvm_op(BfvmCPU *c)
Definition: bfvm.c:6
RZ_API int bfvm_contsc(BfvmCPU *c)
Definition: bfvm.c:233
RZ_API int bfvm_step(BfvmCPU *c, int over)
Definition: bfvm.c:180
RZ_API int bfvm_trace(BfvmCPU *c, ut64 until)
Definition: bfvm.c:267
RZ_API void bfvm_poke(BfvmCPU *c)
Definition: bfvm.c:146
RZ_API void bfvm_dec(BfvmCPU *c)
Definition: bfvm.c:109
RZ_API int bfvm_init(BfvmCPU *c, ut32 size, int circular)
Definition: bfvm.c:39
RZ_API ut8 bfvm_get(BfvmCPU *c)
Definition: bfvm.c:97
RZ_API int bfvm_trace_op(BfvmCPU *c, ut8 op)
Definition: bfvm.c:152
RZ_API ut8 * bfvm_get_ptr(BfvmCPU *c)
Definition: bfvm.c:92
#define BFVM_SCREEN_ADDR
Definition: bfvm.h:10
#define BFVM_INPUT_ADDR
Definition: bfvm.h:12
#define BFVM_INPUT_SIZE
Definition: bfvm.h:13
#define BFVM_SCREEN_SIZE
Definition: bfvm.h:11
#define BFVM_CODE_ADDR
Definition: bfvm.h:16
#define BFVM_CODE_SIZE
Definition: bfvm.h:17
#define BFVM_DATA_ADDR
Definition: bfvm.h:14
#define RZ_API
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
struct @667 g
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * mem
Definition: libc.cpp:91
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * malloc(size_t size)
Definition: malloc.c:123
int idx
Definition: setup.py:197
#define eprintf(x, y...)
Definition: rlcc.c:7
RZ_API ut64 rz_num_math(RzNum *num, const char *str)
Definition: unum.c:456
#define IS_PRINTABLE(x)
Definition: rz_str_util.h:10
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define PFMT64x
Definition: rz_types.h:393
#define c(i)
Definition: sha256.c:43
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()