Rizin
unix-like reverse engineering framework and cli tools
hack.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2020 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_core.h>
5 
6 /* We can not use some kind of structure type with
7  * a string for each case, because some architectures (like ARM)
8  * have several modes/alignment requirements.
9  */
10 
11 RZ_API void rz_core_hack_help(const RzCore *core) {
12  const char *help_msg[] = {
13  "wao", " [op]", "performs a modification on current opcode",
14  "wao", " nop", "nop current opcode",
15  "wao", " jinf", "assemble an infinite loop",
16  "wao", " jz", "make current opcode conditional (zero)",
17  "wao", " jnz", "make current opcode conditional (not zero)",
18  "wao", " ret1", "make the current opcode return 1",
19  "wao", " ret0", "make the current opcode return 0",
20  "wao", " retn", "make the current opcode return -1",
21  "wao", " nocj", "remove conditional operation from branch (make it unconditional)",
22  "wao", " trap", "make the current opcode a trap",
23  "wao", " recj", "reverse (swap) conditional branch instruction",
24  "WIP:", "", "not all archs are supported and not all commands work on all archs",
25  NULL
26  };
27  rz_core_cmd_help(core, help_msg);
28 }
29 
30 RZ_API bool rz_core_hack_dalvik(RzCore *core, const char *op, const RzAnalysisOp *analop) {
31  if (!strcmp(op, "nop")) {
32  rz_core_write_hexpair(core, core->offset, "0000");
33  } else if (!strcmp(op, "ret2")) {
34  rz_core_write_hexpair(core, core->offset, "12200f00"); // mov v0, 2;ret v0
35  } else if (!strcmp(op, "jinf")) {
36  rz_core_write_hexpair(core, core->offset, "2800");
37  } else if (!strcmp(op, "ret1")) {
38  rz_core_write_hexpair(core, core->offset, "12100f00"); // mov v0, 1;ret v0
39  } else if (!strcmp(op, "ret0")) {
40  rz_core_write_hexpair(core, core->offset, "12000f00"); // mov v0, 0;ret v0
41  } else {
42  eprintf("Unsupported operation '%s'\n", op);
43  return false;
44  }
45  return true;
46 }
47 
48 RZ_API bool rz_core_hack_arm64(RzCore *core, const char *op, const RzAnalysisOp *analop) {
49  if (!strcmp(op, "nop")) {
50  rz_core_write_hexpair(core, core->offset, "1f2003d5");
51  } else if (!strcmp(op, "ret")) {
52  rz_core_write_hexpair(core, core->offset, "c0035fd6t");
53  } else if (!strcmp(op, "trap")) {
54  rz_core_write_hexpair(core, core->offset, "000020d4");
55  } else if (!strcmp(op, "jz")) {
56  eprintf("ARM jz hack not supported\n");
57  return false;
58  } else if (!strcmp(op, "jinf")) {
59  rz_core_write_hexpair(core, core->offset, "00000014");
60  } else if (!strcmp(op, "jnz")) {
61  eprintf("ARM jnz hack not supported\n");
62  return false;
63  } else if (!strcmp(op, "nocj")) {
64  eprintf("ARM jnz hack not supported\n");
65  return false;
66  } else if (!strcmp(op, "recj")) {
67  eprintf("TODO: use jnz or jz\n");
68  return false;
69  } else if (!strcmp(op, "ret1")) {
70  rz_core_write_assembly(core, core->offset, "mov x0, 1,,ret");
71  } else if (!strcmp(op, "ret0")) {
72  rz_core_write_assembly(core, core->offset, "mov x0, 0,,ret");
73  } else if (!strcmp(op, "retn")) {
74  rz_core_write_assembly(core, core->offset, "mov x0, -1,,ret");
75  } else {
76  eprintf("Invalid operation '%s'\n", op);
77  return false;
78  }
79  return true;
80 }
81 
82 RZ_API bool rz_core_hack_arm(RzCore *core, const char *op, const RzAnalysisOp *analop) {
83  const int bits = core->rasm->bits;
84  const ut8 *b = core->block;
85 
86  if (!strcmp(op, "nop")) {
87  const int nopsize = (bits == 16) ? 2 : 4;
88  const char *nopcode = (bits == 16) ? "00bf" : "0000a0e1";
89  const int len = analop->size;
90  char *str;
91  int i;
92 
93  if (len % nopsize) {
94  eprintf("Invalid nopcode size\n");
95  return false;
96  }
97 
98  str = calloc(len + 1, 2);
99  if (!str) {
100  return false;
101  }
102  for (i = 0; i < len; i += nopsize) {
103  memcpy(str + i * 2, nopcode, nopsize * 2);
104  }
105  str[len * 2] = '\0';
106  rz_core_write_hexpair(core, core->offset, str);
107  free(str);
108  } else if (!strcmp(op, "jinf")) {
109  rz_core_write_hexpair(core, core->offset, (bits == 16) ? "fee7" : "feffffea");
110  } else if (!strcmp(op, "trap")) {
111  rz_core_write_hexpair(core, core->offset, (bits == 16) ? "bebe" : "fedeffe7");
112  } else if (!strcmp(op, "jz")) {
113  if (bits == 16) {
114  switch (b[1]) {
115  case 0xb9: // CBNZ
116  rz_core_write_hexpair(core, core->offset + 1, "b1"); // CBZ
117  break;
118  case 0xbb: // CBNZ
119  rz_core_write_hexpair(core, core->offset + 1, "b3"); // CBZ
120  break;
121  case 0xd1: // BNE
122  rz_core_write_hexpair(core, core->offset + 1, "d0"); // BEQ
123  break;
124  default:
125  eprintf("Current opcode is not conditional\n");
126  return false;
127  }
128  } else {
129  eprintf("ARM jz hack not supported\n");
130  return false;
131  }
132  } else if (!strcmp(op, "jnz")) {
133  if (bits == 16) {
134  switch (b[1]) {
135  case 0xb1: // CBZ
136  rz_core_write_hexpair(core, core->offset + 1, "b9"); // CBNZ
137  break;
138  case 0xb3: // CBZ
139  rz_core_write_hexpair(core, core->offset + 1, "bb"); // CBNZ
140  break;
141  case 0xd0: // BEQ
142  rz_core_write_hexpair(core, core->offset + 1, "d1"); // BNE
143  break;
144  default:
145  eprintf("Current opcode is not conditional\n");
146  return false;
147  }
148  } else {
149  eprintf("ARM jnz hack not supported\n");
150  return false;
151  }
152  } else if (!strcmp(op, "nocj")) {
153  // TODO: drop conditional bit instead of that hack
154  if (bits == 16) {
155  switch (b[1]) {
156  case 0xb1: // CBZ
157  case 0xb3: // CBZ
158  case 0xd0: // BEQ
159  case 0xb9: // CBNZ
160  case 0xbb: // CBNZ
161  case 0xd1: // BNE
162  rz_core_write_hexpair(core, core->offset + 1, "e0"); // BEQ
163  break;
164  default:
165  eprintf("Current opcode is not conditional\n");
166  return false;
167  }
168  } else {
169  eprintf("ARM un-cjmp hack not supported\n");
170  return false;
171  }
172  } else if (!strcmp(op, "recj")) {
173  eprintf("TODO: use jnz or jz\n");
174  return false;
175  } else if (!strcmp(op, "ret1")) {
176  if (bits == 16) {
177  rz_core_write_hexpair(core, core->offset, "01207047"); // mov r0, 1; bx lr
178  } else {
179  rz_core_write_hexpair(core, core->offset, "0100b0e31eff2fe1"); // movs r0, 1; bx lr
180  }
181  } else if (!strcmp(op, "ret0")) {
182  if (bits == 16) {
183  rz_core_write_hexpair(core, core->offset, "00207047"); // mov r0, 0; bx lr
184  } else {
185  rz_core_write_hexpair(core, core->offset, "0000a0e31eff2fe1"); // movs r0, 0; bx lr
186  }
187  } else if (!strcmp(op, "retn")) {
188  if (bits == 16) {
189  rz_core_write_hexpair(core, core->offset, "ff207047"); // mov r0, -1; bx lr
190  } else {
191  rz_core_write_hexpair(core, core->offset, "ff00a0e31eff2fe1"); // movs r0, -1; bx lr
192  }
193  } else {
194  eprintf("Invalid operation\n");
195  return false;
196  }
197  return true;
198 }
199 
200 RZ_API bool rz_core_hack_x86(RzCore *core, const char *op, const RzAnalysisOp *analop) {
201  const ut8 *b = core->block;
202  int i, size = analop->size;
203  if (!strcmp(op, "nop")) {
204  if (size * 2 + 1 < size) {
205  return false;
206  }
207  char *str = malloc(size * 2 + 1);
208  if (!str) {
209  return false;
210  }
211  for (i = 0; i < size; i++) {
212  memcpy(str + (i * 2), "90", 2);
213  }
214  str[size * 2] = '\0';
215  rz_core_write_hexpair(core, core->offset, str);
216  free(str);
217  } else if (!strcmp(op, "trap")) {
218  rz_core_write_hexpair(core, core->offset, "cc");
219  } else if (!strcmp(op, "jz")) {
220  if (b[0] == 0x75) {
221  rz_core_write_hexpair(core, core->offset, "74");
222  } else {
223  eprintf("Current opcode is not conditional\n");
224  return false;
225  }
226  } else if (!strcmp(op, "jinf")) {
227  rz_core_write_hexpair(core, core->offset, "ebfe");
228  } else if (!strcmp(op, "jnz")) {
229  if (b[0] == 0x74) {
230  rz_core_write_hexpair(core, core->offset, "75");
231  } else {
232  eprintf("Current opcode is not conditional\n");
233  return false;
234  }
235  } else if (!strcmp(op, "nocj")) {
236  if (*b == 0xf) {
237  rz_core_write_hexpair(core, core->offset, "90e9");
238  } else if (b[0] >= 0x70 && b[0] <= 0x7f) {
239  rz_core_write_hexpair(core, core->offset, "eb");
240  } else {
241  eprintf("Current opcode is not conditional\n");
242  return false;
243  }
244  } else if (!strcmp(op, "recj")) {
245  int is_near = (*b == 0xf);
246  if (b[0] < 0x80 && b[0] >= 0x70) { // short jmps: jo, jno, jb, jae, je, jne, jbe, ja, js, jns
247  char *opcode = rz_str_newf("%x", (b[0] % 2) ? b[0] - 1 : b[0] + 1);
248  rz_core_write_hexpair(core, core->offset, opcode);
249  free(opcode);
250  } else if (is_near && b[1] < 0x90 && b[1] >= 0x80) { // near jmps: jo, jno, jb, jae, je, jne, jbe, ja, js, jns
251  char *opcode = rz_str_newf("0f%x", (b[1] % 2) ? b[1] - 1 : b[1] + 1);
252  rz_core_write_hexpair(core, core->offset, opcode);
253  free(opcode);
254  } else {
255  eprintf("Invalid conditional jump opcode\n");
256  return false;
257  }
258  } else if (!strcmp(op, "ret1")) {
259  rz_core_write_hexpair(core, core->offset, "c20100");
260  } else if (!strcmp(op, "ret0")) {
261  rz_core_write_hexpair(core, core->offset, "c20000");
262  } else if (!strcmp(op, "retn")) {
263  rz_core_write_hexpair(core, core->offset, "c2ffff");
264  } else {
265  eprintf("Invalid operation '%s'\n", op);
266  return false;
267  }
268  return true;
269 }
270 
280 RZ_API bool rz_core_hack(RzCore *core, const char *op) {
281  // TODO: op should not be an unstructered string
282  // TODO: asm/analysis plugins should provide the operations, instead of doing this here
283  bool (*hack)(RzCore * core, const char *op, const RzAnalysisOp *analop) = NULL;
284  const char *asmarch = rz_config_get(core->config, "asm.arch");
285  const int asmbits = core->rasm->bits;
286 
287  if (!asmarch) {
288  return false;
289  }
290  if (strstr(asmarch, "x86")) {
291  hack = rz_core_hack_x86;
292  } else if (strstr(asmarch, "dalvik")) {
293  hack = rz_core_hack_dalvik;
294  } else if (strstr(asmarch, "arm")) {
295  if (asmbits == 64) {
296  hack = rz_core_hack_arm64;
297  } else {
298  hack = rz_core_hack_arm;
299  }
300  } else {
301  eprintf("TODO: write hacks are only for x86\n");
302  }
303  if (hack) {
305  if (rz_analysis_op(core->analysis, &analop, core->offset, core->block, core->blocksize, RZ_ANALYSIS_OP_MASK_BASIC) < 1) {
306  eprintf("analysis op fail\n");
307  return false;
308  }
309  return hack(core, op, &analop);
310  }
311  return false;
312 }
size_t len
Definition: 6502dis.c:15
ut8 op
Definition: 6502dis.c:13
static int is_near(const RzANode *n, int x, int y, int is_next)
Definition: agraph.c:2535
static int analop(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask)
lzma_index ** i
Definition: index.h:629
int bits(struct state *s, int need)
Definition: blast.c:72
RZ_API int rz_core_write_hexpair(RzCore *core, ut64 addr, const char *pairs)
Definition: cio.c:268
RZ_API int rz_core_write_assembly(RzCore *core, ut64 addr, RZ_NONNULL const char *instructions)
Assembles instructions and writes the resulting data at the given offset.
Definition: cio.c:327
RZ_API void rz_core_cmd_help(const RzCore *core, const char *help[])
Definition: cmd.c:163
RZ_API RZ_BORROW const char * rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:75
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RZ_API bool rz_core_hack_dalvik(RzCore *core, const char *op, const RzAnalysisOp *analop)
Definition: hack.c:30
RZ_API bool rz_core_hack_arm64(RzCore *core, const char *op, const RzAnalysisOp *analop)
Definition: hack.c:48
RZ_API void rz_core_hack_help(const RzCore *core)
Definition: hack.c:11
RZ_API bool rz_core_hack(RzCore *core, const char *op)
Write/Modify instructions at current offset based on op.
Definition: hack.c:280
RZ_API bool rz_core_hack_x86(RzCore *core, const char *op, const RzAnalysisOp *analop)
Definition: hack.c:200
RZ_API bool rz_core_hack_arm(RzCore *core, const char *op, const RzAnalysisOp *analop)
Definition: hack.c:82
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
Definition: op.c:96
#define eprintf(x, y...)
Definition: rlcc.c:7
@ RZ_ANALYSIS_OP_MASK_BASIC
Definition: rz_analysis.h:440
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
#define b(i)
Definition: sha256.c:42
int bits
Definition: rz_asm.h:100
ut64 offset
Definition: rz_core.h:301
RzAsm * rasm
Definition: rz_core.h:323
RzAnalysis * analysis
Definition: rz_core.h:322
ut8 * block
Definition: rz_core.h:305
ut32 blocksize
Definition: rz_core.h:303
RzConfig * config
Definition: rz_core.h:300
#define bool
Definition: sysdefs.h:146
Definition: dis.c:32