1 /* Tang Yuhang <tyh000011112222@gmail.com> 2016 */
2 #include <string.h>
3 #include <ctype.h>
4 #include <errno.h>
5
6 #include <capstone.h>
7
8
9 void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins);
10 void print_insn_detail_arm(csh handle, cs_insn *ins);
11 void print_insn_detail_arm64(csh handle, cs_insn *ins);
12 void print_insn_detail_mips(csh handle, cs_insn *ins);
13 void print_insn_detail_ppc(csh handle, cs_insn *ins);
14 void print_insn_detail_sparc(csh handle, cs_insn *ins);
15 void print_insn_detail_sysz(csh handle, cs_insn *ins);
16 void print_insn_detail_xcore(csh handle, cs_insn *ins);
17
print_string_hex(char * comment,unsigned char * str,size_t len)18 void print_string_hex(char *comment, unsigned char *str, size_t len)
19 {
20 unsigned char *c;
21
22 printf("%s", comment);
23 for (c = str; c < str + len; c++) {
24 printf("0x%02x ", *c & 0xff);
25 }
26
27 printf("\n");
28 }
29
30 // convert hexchar to hexnum
char_to_hexnum(char c)31 static uint8_t char_to_hexnum(char c)
32 {
33 if (c >= '0' && c <= '9') {
34 return (uint8_t)(c - '0');
35 }
36
37 if (c >= 'a' && c <= 'f') {
38 return (uint8_t)(10 + c - 'a');
39 }
40
41 // c >= 'A' && c <= 'F'
42 return (uint8_t)(10 + c - 'A');
43 }
44
45 // convert user input (char[]) to uint8_t[], each element of which is
46 // valid hexadecimal, and return actual length of uint8_t[] in @size.
preprocess(char * code,size_t * size)47 static uint8_t *preprocess(char *code, size_t *size)
48 {
49 size_t i = 0, j = 0;
50 uint8_t high, low;
51 uint8_t *result;
52
53 result = (uint8_t *)malloc(strlen(code));
54 if (result != NULL) {
55 while (code[i] != '\0') {
56 if (isxdigit(code[i]) && isxdigit(code[i+1])) {
57 high = 16 * char_to_hexnum(code[i]);
58 low = char_to_hexnum(code[i+1]);
59 result[j] = high + low;
60 i++;
61 j++;
62 }
63 i++;
64 }
65 *size = j;
66 }
67
68 return result;
69 }
70
usage(char * prog)71 static void usage(char *prog)
72 {
73 printf("Cstool for Capstone Disassembler Engine v%u.%u.%u\n\n", CS_VERSION_MAJOR, CS_VERSION_MINOR, CS_VERSION_EXTRA);
74 printf("Syntax: %s [-d] <arch+mode> <assembly-hexstring> [start-address-in-hex-format]\n", prog);
75 printf("\nThe following <arch+mode> options are supported:\n");
76
77 if (cs_support(CS_ARCH_X86)) {
78 printf(" x16: 16-bit mode (X86)\n");
79 printf(" x32: 32-bit mode (X86)\n");
80 printf(" x64: 64-bit mode (X86)\n");
81 printf(" x16att: 16-bit mode (X86) syntax-att\n");
82 printf(" x32att: 32-bit mode (X86) syntax-att\n");
83 printf(" x64att: 64-bit mode (X86) syntax-att\n");
84 }
85
86 if (cs_support(CS_ARCH_ARM)) {
87 printf(" arm: arm\n");
88 printf(" armbe: arm + big endian\n");
89 printf(" thumb: thumb mode\n");
90 printf(" thumbbe: thumb + big endian\n");
91 }
92
93 if (cs_support(CS_ARCH_ARM64)) {
94 printf(" arm64: aarch64 mode\n");
95 printf(" arm64be: aarch64 + big endian\n");
96 }
97
98 if (cs_support(CS_ARCH_MIPS)) {
99 printf(" mips: mips32 + little endian\n");
100 printf(" mipsbe: mips32 + big endian\n");
101 printf(" mips64: mips64 + little endian\n");
102 printf(" mips64be: mips64 + big endian\n");
103 }
104
105 if (cs_support(CS_ARCH_PPC)) {
106 printf(" ppc64: ppc64 + little endian\n");
107 printf(" ppc64be: ppc64 + big endian\n");
108 }
109
110 if (cs_support(CS_ARCH_SPARC)) {
111 printf(" sparc: sparc\n");
112 }
113
114 if (cs_support(CS_ARCH_SYSZ)) {
115 printf(" systemz: systemz (s390x)\n");
116 }
117
118 if (cs_support(CS_ARCH_XCORE)) {
119 printf(" xcore: xcore\n");
120 }
121
122 printf("\n");
123 }
124
main(int argc,char ** argv)125 int main(int argc, char **argv)
126 {
127 csh handle;
128 char *mode;
129 uint8_t *assembly;
130 size_t count, size;
131 uint64_t address = 0;
132 cs_insn *insn;
133 cs_err err;
134 cs_mode md;
135 cs_arch arch;
136 bool detail_flag = false;
137
138 if (argc != 3 && argc != 4 && argc != 5) {
139 usage(argv[0]);
140 return -1;
141 }
142
143 if (!strcmp(argv[1], "-d")) {
144 if (argc == 3) {
145 usage(argv[0]);
146 return -1;
147 }
148 detail_flag = true;
149 mode = argv[2];
150 assembly = preprocess(argv[3], &size);
151 if (argc == 5) {
152 char *temp;
153 address = strtoull(argv[4], &temp, 16);
154 if (temp == argv[4] || *temp != '\0' || errno == ERANGE) {
155 printf("ERROR: invalid address argument, quit!\n");
156 return -2;
157 }
158 }
159 } else {
160 if (argc == 5) {
161 usage(argv[0]);
162 return -1;
163 }
164
165 mode = argv[1];
166 assembly = preprocess(argv[2], &size);
167 if (assembly == NULL) {
168 printf("ERROR: invalid assembler-string argument, quit!\n");
169 return -3;
170 }
171
172 if (argc == 4) {
173 // cstool <arch> <assembly> <address>
174 char *temp;
175 address = strtoull(argv[3], &temp, 16);
176 if (temp == argv[3] || *temp != '\0' || errno == ERANGE) {
177 printf("ERROR: invalid address argument, quit!\n");
178 return -2;
179 }
180 }
181 }
182
183 if (!strcmp(mode, "arm")) {
184 arch = CS_ARCH_ARM;
185 err = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle);
186 }
187
188 if (!strcmp(mode, "armb") || !strcmp(mode, "armbe") ) {
189 arch = CS_ARCH_ARM;
190 err = cs_open(CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_BIG_ENDIAN, &handle);
191 }
192
193 if (!strcmp(mode, "arml")) {
194 arch = CS_ARCH_ARM;
195 err = cs_open(CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_LITTLE_ENDIAN, &handle);
196 }
197
198 if (!strcmp(mode, "thumb")) {
199 arch = CS_ARCH_ARM;
200 err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB | CS_MODE_LITTLE_ENDIAN, &handle);
201 }
202
203 if (!strcmp(mode, "thumbbe")) {
204 arch = CS_ARCH_ARM;
205 err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB | CS_MODE_BIG_ENDIAN, &handle);
206 }
207
208 if (!strcmp(mode, "thumble")) {
209 arch = CS_ARCH_ARM;
210 err = cs_open(CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_LITTLE_ENDIAN, &handle);
211 }
212
213 if (!strcmp(mode, "arm64")) {
214 arch = CS_ARCH_ARM64;
215 err = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &handle);
216 }
217
218 if (!strcmp(mode, "arm64be")) {
219 arch = CS_ARCH_ARM64;
220 err = cs_open(CS_ARCH_ARM64, CS_MODE_BIG_ENDIAN, &handle);
221 }
222
223 if (!strcmp(mode, "mips")) {
224 arch = CS_ARCH_MIPS;
225 err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_LITTLE_ENDIAN, &handle);
226 }
227
228 if (!strcmp(mode, "mipsbe")) {
229 arch = CS_ARCH_MIPS;
230 err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_BIG_ENDIAN, &handle);
231 }
232
233 if (!strcmp(mode, "mips64")) {
234 arch = CS_ARCH_MIPS;
235 err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 | CS_MODE_LITTLE_ENDIAN, &handle);
236 }
237
238 if (!strcmp(mode, "mips64be")) {
239 arch = CS_ARCH_MIPS;
240 err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN, &handle);
241 }
242
243 if (!strcmp(mode, "x16")) {
244 md = CS_MODE_16;
245 arch = CS_ARCH_X86;
246 err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle);
247 }
248
249 if (!strcmp(mode, "x32")) {
250 md = CS_MODE_32;
251 arch = CS_ARCH_X86;
252 err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
253 }
254
255 if (!strcmp(mode, "x64")) {
256 md = CS_MODE_64;
257 arch = CS_ARCH_X86;
258 err = cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
259 }
260
261 if (!strcmp(mode, "x16att")) {
262 md = CS_MODE_16;
263 arch = CS_ARCH_X86;
264 err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle);
265 if (!err) {
266 cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
267 }
268 }
269
270 if (!strcmp(mode,"x32att")) {
271 md = CS_MODE_32;
272 arch = CS_ARCH_X86;
273 err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
274 if (!err) {
275 cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
276 }
277 }
278
279 if (!strcmp(mode,"x64att")) {
280 md = CS_MODE_64;
281 arch = CS_ARCH_X86;
282 err = cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
283 if (!err) {
284 cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
285 }
286 }
287
288 if (!strcmp(mode,"ppc64")) {
289 arch = CS_ARCH_PPC;
290 err = cs_open(CS_ARCH_PPC, CS_MODE_64 | CS_MODE_LITTLE_ENDIAN, &handle);
291 }
292
293 if (!strcmp(mode,"ppc64be")) {
294 arch = CS_ARCH_PPC;
295 err = cs_open(CS_ARCH_PPC,CS_MODE_64 | CS_MODE_BIG_ENDIAN, &handle);
296 }
297
298 if (!strcmp(mode,"sparc")) {
299 arch = CS_ARCH_SPARC;
300 err = cs_open(CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN, &handle);
301 }
302
303 if (!strcmp(mode, "systemz") || !strcmp(mode, "sysz") || !strcmp(mode, "s390x")) {
304 arch = CS_ARCH_SYSZ;
305 err = cs_open(CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN, &handle);
306 }
307
308 if (!strcmp(mode,"xcore")) {
309 arch = CS_ARCH_XCORE;
310 err = cs_open(CS_ARCH_XCORE, CS_MODE_BIG_ENDIAN, &handle);
311 }
312
313 if (err) {
314 printf("ERROR: Failed on cs_open(), quit!\n");
315 usage(argv[0]);
316 return -1;
317 }
318
319 if (detail_flag) {
320 cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
321 }
322
323 count = cs_disasm(handle, assembly, size, address, 0, &insn);
324 if (count > 0) {
325 size_t i;
326
327 for (i = 0; i < count; i++) {
328 int j;
329 printf("%"PRIx64" ", insn[i].address);
330 for (j = 0; j < insn[i].size; j++) {
331 printf("%02x", insn[i].bytes[j]);
332 }
333 // X86 instruction size is variable.
334 // align assembly instruction after the opcode
335 if (arch == CS_ARCH_X86) {
336
337 for (; j < 16; j++) {
338 printf(" ");
339 }
340 }
341
342 printf(" %s\t%s\n", insn[i].mnemonic, insn[i].op_str);
343
344 if (detail_flag) {
345 if (arch == CS_ARCH_X86) {
346 print_insn_detail_x86(handle, md, &insn[i]);
347 }
348
349 if (arch == CS_ARCH_ARM) {
350 print_insn_detail_arm(handle, &insn[i]);
351 }
352
353 if (arch == CS_ARCH_ARM64) {
354 print_insn_detail_arm64(handle,&insn[i]);
355 }
356
357 if (arch == CS_ARCH_MIPS) {
358 print_insn_detail_mips(handle, &insn[i]);
359 }
360
361 if (arch == CS_ARCH_PPC) {
362 print_insn_detail_ppc(handle, &insn[i]);
363 }
364
365 if (arch == CS_ARCH_SPARC) {
366 print_insn_detail_sparc(handle, &insn[i]);
367 }
368
369 if (arch == CS_ARCH_SYSZ) {
370 print_insn_detail_sysz(handle, &insn[i]);
371 }
372
373 if (arch == CS_ARCH_XCORE) {
374 print_insn_detail_xcore(handle, &insn[i]);
375 }
376
377 if (insn[i].detail->groups_count) {
378 int j;
379
380 printf("\tGroups: ");
381 for(j = 0; j < insn[i].detail->groups_count; j++) {
382 printf("%s ", cs_group_name(handle, insn[i].detail->groups[j]));
383 }
384 printf("\n");
385 }
386
387 printf("\n");
388 }
389 }
390 cs_free(insn, count);
391 } else {
392 printf("ERROR: invalid assembly code\n");
393 return(-4);
394 }
395
396 cs_close(&handle);
397
398 return 0;
399 }
400