• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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