2016-10-19 14:28:05 +00:00
|
|
|
/* Tang Yuhang <tyh000011112222@gmail.com> 2016 */
|
2016-10-10 07:16:56 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2016-10-10 16:04:46 +00:00
|
|
|
#include <capstone/capstone.h>
|
2016-10-10 07:16:56 +00:00
|
|
|
|
2016-10-19 14:28:05 +00:00
|
|
|
#define VERSION "2.0"
|
2016-10-10 07:16:56 +00:00
|
|
|
|
2016-10-14 09:29:56 +00:00
|
|
|
void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins);
|
2016-10-14 12:47:29 +00:00
|
|
|
void print_insn_detail_arm(csh handle, cs_insn *ins);
|
|
|
|
void print_insn_detail_arm64(csh handle, cs_insn *ins);
|
|
|
|
void print_insn_detail_mips(csh handle, cs_insn *ins);
|
|
|
|
void print_insn_detail_ppc(csh handle, cs_insn *ins);
|
|
|
|
void print_insn_detail_sparc(csh handle, cs_insn *ins);
|
|
|
|
void print_insn_detail_sysz(csh handle, cs_insn *ins);
|
|
|
|
void print_insn_detail_xcore(csh handle, cs_insn *ins);
|
2016-10-14 09:29:56 +00:00
|
|
|
|
2016-10-10 07:16:56 +00:00
|
|
|
// convert hexchar to hexnum
|
|
|
|
static uint8_t char_to_hexnum(char c)
|
|
|
|
{
|
2016-10-10 15:20:29 +00:00
|
|
|
if (c >= '0' && c <= '9') {
|
2016-10-19 14:28:05 +00:00
|
|
|
return (uint8_t)(c - '0');
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (c >= 'a' && c <= 'f') {
|
|
|
|
return (uint8_t)(10 + c - 'a');
|
|
|
|
}
|
|
|
|
|
|
|
|
// c >= 'A' && c <= 'F'
|
|
|
|
return (uint8_t)(10 + c - 'A');
|
2016-10-10 07:16:56 +00:00
|
|
|
}
|
|
|
|
|
2016-10-10 15:20:29 +00:00
|
|
|
// convert user input (char[]) to uint8_t[], each element of which is
|
|
|
|
// valid hexadecimal, and return actual length of uint8_t[] in @size.
|
2016-10-10 07:16:56 +00:00
|
|
|
static uint8_t *preprocess(char *code, size_t *size)
|
|
|
|
{
|
2016-10-19 14:28:05 +00:00
|
|
|
size_t i = 0, j = 0;
|
2016-10-10 15:20:29 +00:00
|
|
|
uint8_t high, low;
|
|
|
|
uint8_t *result;
|
|
|
|
|
|
|
|
result = (uint8_t *)malloc(strlen(code));
|
|
|
|
if (result != NULL) {
|
|
|
|
while (code[i] != '\0') {
|
|
|
|
if (isxdigit(code[i]) && isxdigit(code[i+1])) {
|
|
|
|
high = 16 * char_to_hexnum(code[i]);
|
|
|
|
low = char_to_hexnum(code[i+1]);
|
|
|
|
result[j] = high + low;
|
|
|
|
i++;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
*size = j;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2016-10-10 07:16:56 +00:00
|
|
|
}
|
|
|
|
|
2016-10-10 15:20:29 +00:00
|
|
|
static void usage(char *prog)
|
2016-10-10 07:16:56 +00:00
|
|
|
{
|
2016-10-11 15:21:12 +00:00
|
|
|
printf("Cstool v%s for Capstone Disassembler Engine (www.capstone-engine.org)\n\n", VERSION);
|
2016-10-14 09:29:56 +00:00
|
|
|
printf("Syntax: %s [-d:print all debug information] <arch+mode> <assembly-hexstring> [start-address-in-hex-format]\n", prog);
|
2016-10-10 15:20:29 +00:00
|
|
|
printf("\nThe following <arch+mode> options are supported:\n");
|
|
|
|
|
|
|
|
if (cs_support(CS_ARCH_X86)) {
|
|
|
|
printf(" x16: 16-bit mode (X86)\n");
|
|
|
|
printf(" x32: 32-bit mode (X86)\n");
|
|
|
|
printf(" x64: 64-bit mode (X86)\n");
|
|
|
|
printf(" x16att: 16-bit mode (X86) syntax-att\n");
|
|
|
|
printf(" x32att: 32-bit mode (X86) syntax-att\n");
|
|
|
|
printf(" x64att: 64-bit mode (X86) syntax-att\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cs_support(CS_ARCH_ARM)) {
|
|
|
|
printf(" arm: arm\n");
|
|
|
|
printf(" armb: arm + big endian\n");
|
|
|
|
printf(" arml: arm + little endian\n");
|
|
|
|
printf(" thumb: thumb mode\n");
|
|
|
|
printf(" thumbbe: thumb + big endian\n");
|
|
|
|
printf(" thumble: thumb + billtle endian\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cs_support(CS_ARCH_ARM64)) {
|
|
|
|
printf(" arm64: aarch64 mode\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cs_support(CS_ARCH_MIPS)) {
|
|
|
|
printf(" mips: mips32 + little endian\n");
|
|
|
|
printf(" mipsbe: mips32 + big endian\n");
|
|
|
|
printf(" mips64: mips64 + little endian\n");
|
|
|
|
printf(" mips64be: mips64 + big endian\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cs_support(CS_ARCH_PPC)) {
|
|
|
|
printf(" ppc64: ppc64 + little endian\n");
|
|
|
|
printf(" ppc64be: ppc64 + big endian\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cs_support(CS_ARCH_SPARC)) {
|
|
|
|
printf(" sparc: sparc\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cs_support(CS_ARCH_SYSZ)) {
|
|
|
|
printf(" systemz: systemz (s390x)\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cs_support(CS_ARCH_XCORE)) {
|
|
|
|
printf(" xcore: xcore\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("\n");
|
2016-10-10 07:16:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2016-10-10 15:20:29 +00:00
|
|
|
csh handle;
|
|
|
|
char *mode;
|
|
|
|
uint8_t *assembly;
|
|
|
|
size_t count, size;
|
|
|
|
uint64_t address = 0;
|
|
|
|
cs_insn *insn;
|
|
|
|
cs_err err;
|
2016-10-14 09:29:56 +00:00
|
|
|
cs_mode md;
|
2016-10-14 12:47:29 +00:00
|
|
|
char *arch;
|
|
|
|
bool debug_flag = false;
|
2016-10-10 15:20:29 +00:00
|
|
|
|
2016-10-14 09:29:56 +00:00
|
|
|
if (argc != 3 && argc != 4 && argc != 5) {
|
2016-10-10 15:20:29 +00:00
|
|
|
usage(argv[0]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-10-14 09:29:56 +00:00
|
|
|
if (!strcmp(argv[1], "-d")) {
|
|
|
|
if (argc == 3) {
|
|
|
|
usage(argv[0]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
debug_flag = true;
|
|
|
|
mode = argv[2];
|
|
|
|
assembly = preprocess(argv[3], &size);
|
|
|
|
if (argc == 5) {
|
|
|
|
char *temp;
|
|
|
|
address = strtoull(argv[4], &temp, 16);
|
|
|
|
if (temp == argv[4] || *temp != '\0' || errno == ERANGE) {
|
|
|
|
printf("ERROR: invalid address argument, quit!\n");
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (argc == 5) {
|
|
|
|
usage(argv[0]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mode = argv[1];
|
|
|
|
assembly = preprocess(argv[2], &size);
|
|
|
|
if (assembly == NULL) {
|
|
|
|
printf("ERROR: invalid assembler-string argument, quit!\n");
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc == 4) {
|
|
|
|
// cstool <arch> <assembly> <address>
|
|
|
|
char *temp;
|
|
|
|
address = strtoull(argv[3], &temp, 16);
|
|
|
|
if (temp == argv[3] || *temp != '\0' || errno == ERANGE) {
|
|
|
|
printf("ERROR: invalid address argument, quit!\n");
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-10 15:20:29 +00:00
|
|
|
if (!strcmp(mode, "arm")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "arm";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "armb")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "arm";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_BIG_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "arml")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "arm";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_LITTLE_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "thumb")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "arm";
|
|
|
|
err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_LITTLE_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "thumbbe")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "arm";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_BIG_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "thumble")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "arm";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_LITTLE_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "arm64")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "arm64";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "mips")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "mips";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "mipsbe")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "mips";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "mips64")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "mips";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "mips64be")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "mips";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "x16")) {
|
2016-10-19 14:28:05 +00:00
|
|
|
md = CS_MODE_16;
|
|
|
|
arch = "x86";
|
|
|
|
err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "x32")) {
|
2016-10-14 09:29:56 +00:00
|
|
|
md = CS_MODE_32;
|
2016-10-19 14:28:05 +00:00
|
|
|
arch = "x86";
|
|
|
|
err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "x64")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
md = CS_MODE_64;
|
|
|
|
arch = "x86";
|
2016-10-10 15:20:29 +00:00
|
|
|
err = cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "x16att")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
md = CS_MODE_16;
|
|
|
|
arch = "x86";
|
2016-10-19 14:28:05 +00:00
|
|
|
err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle);
|
|
|
|
if (!err) {
|
|
|
|
cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode,"x32att")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
md = CS_MODE_32;
|
|
|
|
arch = "x86";
|
2016-10-10 15:20:29 +00:00
|
|
|
err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
|
|
|
|
if (!err) {
|
|
|
|
cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode,"x64att")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
md = CS_MODE_64;
|
|
|
|
arch = "x86";
|
2016-10-10 15:20:29 +00:00
|
|
|
err = cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
|
|
|
|
if (!err) {
|
|
|
|
cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode,"ppc64")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "ppc";
|
2016-10-10 15:20:29 +00:00
|
|
|
err = cs_open(CS_ARCH_PPC, CS_MODE_64+CS_MODE_LITTLE_ENDIAN, &handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode,"ppc64be")) {
|
2016-10-19 14:28:05 +00:00
|
|
|
arch = "ppc";
|
|
|
|
err = cs_open(CS_ARCH_PPC,CS_MODE_64+CS_MODE_BIG_ENDIAN, &handle);
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode,"sparc")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "sparc";
|
2016-10-10 15:20:29 +00:00
|
|
|
err = cs_open(CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN, &handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode, "systemz") || !strcmp(mode, "sysz") || !strcmp(mode, "s390x")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "sysz";
|
2016-10-10 15:20:29 +00:00
|
|
|
err = cs_open(CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN, &handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(mode,"xcore")) {
|
2016-10-14 12:47:29 +00:00
|
|
|
arch = "xcore";
|
2016-10-10 15:20:29 +00:00
|
|
|
err = cs_open(CS_ARCH_XCORE, CS_MODE_BIG_ENDIAN, &handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
printf("ERROR: Failed on cs_open(), quit!\n");
|
|
|
|
usage(argv[0]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-10-14 09:29:56 +00:00
|
|
|
if (debug_flag) {
|
|
|
|
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
|
|
|
|
}
|
|
|
|
|
|
|
|
count = cs_disasm(handle, assembly, size, address, 0, &insn);
|
2016-10-10 15:20:29 +00:00
|
|
|
if (count > 0) {
|
2016-10-11 08:19:27 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
int j;
|
|
|
|
printf("%"PRIx64" ", insn[i].address);
|
|
|
|
for (j = 0; j < insn[i].size; j++) {
|
|
|
|
printf("%02x", insn[i].bytes[j]);
|
|
|
|
}
|
|
|
|
// X86 instruction size is variable.
|
|
|
|
// align assembly instruction after the opcode
|
2016-10-14 12:47:29 +00:00
|
|
|
if (!strcmp(arch, "x86")) {
|
2016-10-11 08:19:27 +00:00
|
|
|
for (; j < 16; j++) {
|
|
|
|
printf(" ");
|
|
|
|
}
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
2016-10-11 08:19:27 +00:00
|
|
|
printf(" %s\t%s\n", insn[i].mnemonic, insn[i].op_str);
|
2016-10-16 08:56:55 +00:00
|
|
|
if (debug_flag) {
|
2016-10-14 12:47:29 +00:00
|
|
|
if (!strcmp(arch, "x86")) {
|
2016-10-14 09:29:56 +00:00
|
|
|
print_insn_detail_x86(handle, md, &insn[i]);
|
|
|
|
}
|
2016-10-14 12:47:29 +00:00
|
|
|
|
|
|
|
if (!strcmp(arch, "arm")) {
|
|
|
|
print_insn_detail_arm(handle, &insn[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(arch,"arm64")) {
|
|
|
|
print_insn_detail_arm64(handle,&insn[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(arch, "mips")) {
|
|
|
|
print_insn_detail_mips(handle, &insn[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(arch, "ppc")) {
|
|
|
|
print_insn_detail_ppc(handle, &insn[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(arch, "sparc")) {
|
|
|
|
print_insn_detail_sparc(handle, &insn[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(arch, "sysz")) {
|
|
|
|
print_insn_detail_sysz(handle, &insn[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(arch, "xcore")) {
|
|
|
|
print_insn_detail_xcore(handle, &insn[i]);
|
|
|
|
}
|
2016-10-14 09:29:56 +00:00
|
|
|
}
|
2016-10-10 15:20:29 +00:00
|
|
|
}
|
|
|
|
cs_free(insn, count);
|
|
|
|
} else {
|
|
|
|
printf("ERROR: invalid assembly code\n");
|
|
|
|
return(-4);
|
|
|
|
}
|
|
|
|
|
|
|
|
cs_close(&handle);
|
|
|
|
|
|
|
|
return 0;
|
2016-10-10 07:16:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|