/* udis86 - udcli/udcli.c * * Copyright (c) 2002-2013 Vivek Thampi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #ifdef _MSC_VER #include "..\udis86.h" #define PACKAGE_STRING "udis86 pre-1.8" #else #include #include #endif #if defined(__APPLE__) # define FMT64 "ll" #elif defined(__amd64__) || defined(__x86_64__) # define FMT64 "l" # else # define FMT64 "ll" #endif #if defined(__DJGPP__) || defined(_WIN32) # include # include #endif #ifdef __DJGPP__ # include /* for isatty() */ # define _setmode setmode # define _fileno fileno # define _O_BINARY O_BINARY #endif /* help string */ static char help[] = { "Usage: %s [-option[s]] file\n" "Options:\n" " -16 : Set the disassembly mode to 16 bits. \n" " -32 : Set the disassembly mode to 32 bits. (default)\n" " -64 : Set the disassembly mode to 64 bits.\n" " -intel : Set the output to INTEL (NASM like) syntax. (default)\n" " -att : Set the output to AT&T (GAS like) syntax.\n" " -v : Set vendor. = {intel, amd}.\n" " -o : Set the value of program counter to . (default = 0)\n" " -s : Set the number of bytes to skip before disassembly to .\n" " -c : Set the number of bytes to disassemble to .\n" " -x : Set the input mode to whitespace separated 8-bit numbers in\n" " hexadecimal representation. Example: 0f 01 ae 00\n" " -noff : Do not display the offset of instructions.\n" " -nohex : Do not display the hexadecimal code of instructions.\n" " -eflags : Display information on EFLAGS register.\n" " -access : Display access information of operand.\n" " -implicit : Display implicit registers used or modified by the instruction.\n" " -h : Display this help message.\n" " --version : Show version.\n" "\n" "Udcli is a front-end to the Udis86 Disassembler Library.\n" "http://udis86.sourceforge.net/\n" }; extern const char* ud_reg_tab[]; FILE* fptr = NULL; uint64_t o_skip = 0; uint64_t o_count = 0; unsigned char o_do_count= 0; unsigned char o_do_off = 1; unsigned char o_do_hex = 1; unsigned char o_do_x = 0; unsigned char o_do_eflags = 0; unsigned char o_do_access = 0; unsigned char o_do_implicit = 0; unsigned o_vendor = UD_VENDOR_AMD; int input_hook_x(ud_t* u); int input_hook_file(ud_t* u); void print_flag(enum ud_eflag_state flag) { switch(flag) { case UD_FLAG_UNCHANGED: printf("_"); break; case UD_FLAG_TESTED: printf("T"); break; case UD_FLAG_MODIFIED: printf("M"); break; case UD_FLAG_RESET: printf("R"); break; case UD_FLAG_SET: printf("S"); break; case UD_FLAG_UNDEFINED: printf("U"); break; case UD_FLAG_PRIOR: printf("P"); break; } } void print_eflags(const struct ud_eflags *state) { printf("of:"); print_flag(state->flag[UD_FLAG_OF]); printf(" "); printf("sf:"); print_flag(state->flag[UD_FLAG_SF]); printf(" "); printf("zf:"); print_flag(state->flag[UD_FLAG_ZF]); printf(" "); printf("af:"); print_flag(state->flag[UD_FLAG_AF]); printf(" "); printf("pf:"); print_flag(state->flag[UD_FLAG_PF]); printf(" "); printf("cf:"); print_flag(state->flag[UD_FLAG_CF]); printf(" "); printf("tf:"); print_flag(state->flag[UD_FLAG_TF]); printf(" "); printf("if:"); print_flag(state->flag[UD_FLAG_IF]); printf(" "); printf("df:"); print_flag(state->flag[UD_FLAG_DF]); printf(" "); printf("nf:"); print_flag(state->flag[UD_FLAG_NF]); printf(" "); printf("rf:"); print_flag(state->flag[UD_FLAG_RF]); printf(" "); printf("ac:"); print_flag(state->flag[UD_FLAG_AC]); } int main(int argc, char **argv) { char *prog_path = *argv; char *s; ud_t ud_obj; int i; /* initialize */ ud_init(&ud_obj); ud_set_mode(&ud_obj, 32); ud_set_syntax(&ud_obj, UD_SYN_INTEL); #ifdef __DJGPP__ if ( !isatty( fileno( stdin ) ) ) #endif #if defined(__DJGPP) || defined(_WIN32) _setmode(_fileno(stdin), _O_BINARY); #endif fptr = stdin; argv++; /* loop through the args */ while(--argc > 0) { if (strcmp(*argv, "-h") == 0) { printf(help, prog_path); exit(EXIT_SUCCESS); } else if (strcmp(*argv,"-16") == 0) { ud_set_mode(&ud_obj, 16); } else if (strcmp(*argv,"-32") == 0) { ud_set_mode(&ud_obj, 32); } else if (strcmp(*argv,"-64") == 0) { ud_set_mode(&ud_obj, 64); } else if (strcmp(*argv,"-intel") == 0) ud_set_syntax(&ud_obj, UD_SYN_INTEL); else if (strcmp(*argv,"-att") == 0) ud_set_syntax(&ud_obj, UD_SYN_ATT); else if (strcmp(*argv,"-noff") == 0) o_do_off = 0; else if (strcmp(*argv,"-nohex") == 0) o_do_hex = 0; else if (strcmp(*argv,"-eflags") == 0) o_do_eflags = 1; else if (strcmp(*argv,"-access") == 0) o_do_access = 1; else if (strcmp(*argv,"-implicit") == 0) o_do_implicit = 1; else if (strcmp(*argv,"-x") == 0) o_do_x = 1; else if (strcmp(*argv,"-s") == 0) if (--argc) { s = *(++argv); if (sscanf(s, "%" FMT64 "u", &o_skip) == 0) fprintf(stderr, "Invalid value given for -s.\n"); } else { fprintf(stderr, "No value given for -s.\n"); printf(help, prog_path); exit(EXIT_FAILURE); } else if (strcmp(*argv,"-c") == 0) if (--argc) { o_do_count= 1; s = *(++argv); if (sscanf(s, "%" FMT64 "u", &o_count) == 0) fprintf(stderr, "Invalid value given for -c.\n"); } else { fprintf(stderr, "No value given for -c.\n"); printf(help, prog_path); exit(EXIT_FAILURE); } else if (strcmp(*argv,"-v") == 0) if (--argc) { s = *(++argv); if (*s == 'i') ud_set_vendor(&ud_obj, UD_VENDOR_INTEL); } else { fprintf(stderr, "No value given for -v.\n"); printf(help, prog_path); exit(EXIT_FAILURE); } else if (strcmp(*argv,"-o") == 0) { if (--argc) { uint64_t pc = 0; s = *(++argv); if (sscanf(s, "%" FMT64 "x", &pc) == 0) fprintf(stderr, "Invalid value given for -o.\n"); ud_set_pc(&ud_obj, pc); } else { fprintf(stderr, "No value given for -o.\n"); printf(help, prog_path); exit(EXIT_FAILURE); } } else if ( strcmp( *argv, "--version" ) == 0 ) { fprintf(stderr, "%s\n", PACKAGE_STRING ); exit(0); } else if((*argv)[0] == '-') { fprintf(stderr, "Invalid option %s.\n", *argv); printf(help, prog_path); exit(EXIT_FAILURE); } else { static int i = 0; s = *argv; if (i) { fprintf(stderr, "Multiple files specified.\n"); exit(EXIT_FAILURE); } else i = 1; if ((fptr = fopen(s, "rb")) == NULL) { fprintf(stderr, "Failed to open file: %s.\n", s); exit(EXIT_FAILURE); } } argv++; } if (o_do_x) ud_set_input_hook(&ud_obj, input_hook_x); else ud_set_input_hook(&ud_obj, input_hook_file); if (o_skip) { o_count += o_skip; ud_input_skip(&ud_obj, o_skip); } // Note: I use another variable, because I plan to add // other options in the future. Hence, o_do_meta holds // the information about if we have to display any // metadata. unsigned char o_do_meta = o_do_eflags | o_do_access | o_do_implicit; /* disassembly loop */ while (ud_disassemble(&ud_obj)) { if (o_do_off) printf("%016" FMT64 "x ", ud_insn_off(&ud_obj)); if (o_do_hex) { const char* hex1, *hex2; hex1 = ud_insn_hex(&ud_obj); hex2 = hex1 + 16; printf("%-16.16s %-24s", hex1, ud_insn_asm(&ud_obj)); if (strlen(hex1) > 16) { printf("\n"); if (o_do_off) printf("%15s -", ""); printf("%-16s", hex2); } } else printf(" %-24s", ud_insn_asm(&ud_obj)); if (o_do_meta) { printf(" ; "); if (o_do_eflags) { const struct ud_eflags* eflags = ud_lookup_eflags(&ud_obj); print_eflags(eflags); } if (o_do_access) { o_do_access = 0; for (i=0; i<4; i++) { const struct ud_operand *op = ud_insn_opr(&ud_obj, i); if (op != NULL) { if (i == 0) { if (o_do_eflags) printf(", "); printf("access"); o_do_access = 1; } printf(" op%d=", i); if (op->access == UD_OP_ACCESS_READ) printf("R"); else if (op->access == UD_OP_ACCESS_WRITE) printf("W"); else if (op->access == (UD_OP_ACCESS_READ|UD_OP_ACCESS_WRITE)) printf("RW"); else printf("-"); } } } if (o_do_implicit) { if (o_do_eflags | o_do_access) printf(", "); const enum ud_type *imp_used = ud_lookup_implicit_reg_used_list(&ud_obj); const enum ud_type *imp_modified = ud_lookup_implicit_reg_defined_list(&ud_obj); printf("implicit reg used:"); if (imp_used == NULL || *imp_used == UD_NONE) { printf(" none"); } while (*imp_used != UD_NONE) { printf(" %s", ud_reg_tab[*imp_used++ - 1]); } printf(", implicit reg modified:"); if (imp_modified == NULL || *imp_modified == UD_NONE) { printf(" none"); } while (*imp_modified != UD_NONE) { printf(" %s", ud_reg_tab[*imp_modified++ - 1]); } } } printf("\n"); } exit(EXIT_SUCCESS); return 0; } int input_hook_x(ud_t* u) { unsigned int c, i; if (o_do_count) { if (! o_count) return UD_EOI; else --o_count; } i = fscanf(fptr, "%x", &c); if (i == EOF) return UD_EOI; if (i == 0) { fprintf(stderr, "Error: Invalid input, should be in hexadecimal form (8-bit).\n"); return UD_EOI; } if (c > 0xFF) fprintf(stderr, "Warning: Casting non-8-bit input (%x), to %x.\n", c, c & 0xFF); return (int) (c & 0xFF); } int input_hook_file(ud_t* u) { int c; if (o_do_count) { if (! o_count) { return -1; } else o_count -- ; } if ((c = fgetc(fptr)) == EOF) return UD_EOI; return c; }