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 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 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. 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 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 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 if (j > 0) 332 putchar(' '); 333 printf("%02x", insn[i].bytes[j]); 334 } 335 // X86 instruction size is variable. 336 // align assembly instruction after the opcode 337 if (arch == CS_ARCH_X86) { 338 339 for (; j < 16; j++) { 340 printf(" "); 341 } 342 } 343 344 printf(" %s\t%s\n", insn[i].mnemonic, insn[i].op_str); 345 346 if (detail_flag) { 347 if (arch == CS_ARCH_X86) { 348 print_insn_detail_x86(handle, md, &insn[i]); 349 } 350 351 if (arch == CS_ARCH_ARM) { 352 print_insn_detail_arm(handle, &insn[i]); 353 } 354 355 if (arch == CS_ARCH_ARM64) { 356 print_insn_detail_arm64(handle,&insn[i]); 357 } 358 359 if (arch == CS_ARCH_MIPS) { 360 print_insn_detail_mips(handle, &insn[i]); 361 } 362 363 if (arch == CS_ARCH_PPC) { 364 print_insn_detail_ppc(handle, &insn[i]); 365 } 366 367 if (arch == CS_ARCH_SPARC) { 368 print_insn_detail_sparc(handle, &insn[i]); 369 } 370 371 if (arch == CS_ARCH_SYSZ) { 372 print_insn_detail_sysz(handle, &insn[i]); 373 } 374 375 if (arch == CS_ARCH_XCORE) { 376 print_insn_detail_xcore(handle, &insn[i]); 377 } 378 379 if (insn[i].detail->groups_count) { 380 int j; 381 382 printf("\tGroups: "); 383 for(j = 0; j < insn[i].detail->groups_count; j++) { 384 printf("%s ", cs_group_name(handle, insn[i].detail->groups[j])); 385 } 386 printf("\n"); 387 } 388 389 printf("\n"); 390 } 391 } 392 cs_free(insn, count); 393 } else { 394 printf("ERROR: invalid assembly code\n"); 395 return(-4); 396 } 397 398 cs_close(&handle); 399 400 return 0; 401 } 402