diff --git a/disasmtool_lix/disasm.hpp b/disasmtool_lix/disasm.hpp index e2e7a22..0768d2f 100644 --- a/disasmtool_lix/disasm.hpp +++ b/disasmtool_lix/disasm.hpp @@ -56,6 +56,8 @@ typedef size_t SIZE_T; std::string enc_mode_to_str(const uint8_t enc_mode); +std::string op_type_to_str(const ND_OPERAND_TYPE type); +std::string op_enc_to_str(const ND_OPERAND_ENCODING Encoding); std::string ins_class_to_str(const ND_INS_CLASS cls); std::string ins_cat_to_str(ND_INS_CATEGORY category); std::string ins_set_to_str(ND_INS_SET ins_set); diff --git a/disasmtool_lix/disasmtool.cpp b/disasmtool_lix/disasmtool.cpp index e9058d2..0469ddf 100644 --- a/disasmtool_lix/disasmtool.cpp +++ b/disasmtool_lix/disasmtool.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "external/argparse.h" @@ -49,6 +50,7 @@ struct options { bool interactive; bool comm; bool json_output; + bool extended; std::string in_file; std::string hex_string; @@ -57,6 +59,7 @@ struct options { // From here on, these are set internally std::unique_ptr bytes; size_t actual_size; + int address_size; bool output_redirected; }; @@ -223,11 +226,11 @@ void print_instruction(const size_t rip, INSTRUX *instrux, const options &opts) char instruxText[ND_MIN_BUF_SIZE]; uint32_t k = 0; - printf("%zx ", rip); + printf("%*zx ", opts.address_size, rip); if (!opts.no_color) { - _set_text_color(White); + _set_text_color(Magenta); for (uint32_t idx = 0; idx < instrux->PrefLength; idx++, k++) { printf("%02x", instrux->InstructionBytes[k]); @@ -282,187 +285,155 @@ void print_instruction(const size_t rip, INSTRUX *instrux, const options &opts) std::cout << instruxText << std::endl; - // if (Options->ExtendedInfo) - // { - // const BYTE opsize[3] = { 2, 4, 8 }; - // const BYTE adsize[3] = { 2, 4, 8 }; - // const BYTE veclen[3] = { 16, 32, 64 }; - - // printf(" DSIZE: %2d, ASIZE: %2d, VLEN: ", - // opsize[instrux->EfOpMode] * 8, adsize[instrux->AddrMode] * 8); - - // if (ND_HAS_VECTOR(instrux)) - // { - // printf("%2d\n", veclen[instrux->VecMode] * 8); - // } - // else - // { - // printf("-\n"); - // } - - // printf(" ISA Set: %s, Ins cat: %s, Ins class: %d, CET tracked: %s\n", - // set_to_string(instrux->IsaSet), category_to_string(instrux->Category), instrux->Instruction, - // instrux->IsCetTracked ? "yes" : "no"); - - // if (0 != instrux->CpuidFlag.Flag) - // { - // char *regs[4] = { "eax", "ecx", "edx", "ebx" }; - - // printf(" CPUID leaf: 0x%08x", instrux->CpuidFlag.Leaf); - - // if (instrux->CpuidFlag.SubLeaf != ND_CFF_NO_SUBLEAF) - // { - // printf(", sub-leaf: 0x%08x", instrux->CpuidFlag.SubLeaf); - // } - - // printf(", reg: %s, bit %d\n", regs[instrux->CpuidFlag.Reg], instrux->CpuidFlag.Bit); - // } - - // { - // DWORD fidx, all; - // char *flags[22] = { "CF", NULL, "PF", NULL, "AF", NULL, "ZF", "SF", "TF", "IF", "DF", "OF", "IOPL", NULL, "NT", NULL, "RF", "VM", "AC", "VIF", "VIP", "ID" }; - - // all = instrux->FlagsAccess.Tested.Raw | instrux->FlagsAccess.Modified.Raw | instrux->FlagsAccess.Set.Raw | - // instrux->FlagsAccess.Cleared.Raw | instrux->FlagsAccess.Undefined.Raw; - // printf(" FLAGS access: "); - - // for (fidx = 0; fidx < 21; fidx++) - // { - // if (flags[fidx] != NULL) - // { - // if (0 == (all & (1ULL << fidx))) - // { - // continue; - // } - - // printf("%s: ", flags[fidx]); - - // if (instrux->FlagsAccess.Tested.Raw & (1ULL << fidx)) - // { - // printf("t"); - // } - - // if (instrux->FlagsAccess.Modified.Raw & (1ULL << fidx)) - // { - // printf("m"); - // } - - // if (instrux->FlagsAccess.Set.Raw & (1ULL << fidx)) - // { - // printf("1"); - // } - - // if (instrux->FlagsAccess.Cleared.Raw & (1ULL << fidx)) - // { - // printf("0"); - // } - - // if (instrux->FlagsAccess.Undefined.Raw & (1ULL << fidx)) - // { - // printf("u"); - // } - - // printf("; "); - // } - // } - - // printf("\n"); - // } - - // printf(" Valid modes: R0: %s, R1: %s, R2: %s, R3: %s, Real: %s, V8086: %s, Prot: %s, Compat: %s, Long: %s, SMM: %s, SGX: %s, TSX: %s, VMXRoot: %s, VMXNonRoot: %s\n", - // instrux->ValidModes.Ring0 ? "yes" : "no", - // instrux->ValidModes.Ring1 ? "yes" : "no", - // instrux->ValidModes.Ring2 ? "yes" : "no", - // instrux->ValidModes.Ring3 ? "yes" : "no", - // instrux->ValidModes.Real ? "yes" : "no", - // instrux->ValidModes.V8086 ? "yes" : "no", - // instrux->ValidModes.Protected ? "yes" : "no", - // instrux->ValidModes.Compatibility ? "yes" : "no", - // instrux->ValidModes.Long ? "yes" : "no", - // instrux->ValidModes.Smm ? "yes" : "no", - // instrux->ValidModes.Sgx ? "yes" : "no", - // instrux->ValidModes.Tsx ? "yes" : "no", - // instrux->ValidModes.VmxRoot ? "yes" : "no", - // instrux->ValidModes.VmxNonRoot ? "yes" : "no" - // ); - - // for (i = 0; i < instrux->OperandsCount; i++) - // { - // printf(" Operand %d %s Type: %10s, Size: %2d, RawSize: %2d, Encoding: %s", i, - // instrux->Operands[i].Access.Read && instrux->Operands[i].Access.Write ? "RW" : - // instrux->Operands[i].Access.Write ? "-W" : instrux->Operands[i].Access.Read ? "R-" : "--", - // optype_to_string(instrux->Operands[i].Type), instrux->Operands[i].Size, - // instrux->Operands[i].RawSize, encoding_to_string(instrux->Operands[i].Encoding) - // ); - - // if (ND_OP_MEM == instrux->Operands[i].Type) - // { - // printf(", "); - - // if (instrux->Operands[i].Info.Memory.IsAG) - // { - // printf("Address Generator, "); - // } - - // if (instrux->Operands[i].Info.Memory.IsBitbase) - // { - // printf("Bitbase Addressing, "); - // } - - // if (instrux->Operands[i].Info.Memory.IsMib) - // { - // printf("MIB Addressing, "); - // } - - // if (instrux->Operands[i].Info.Memory.IsVsib) - // { - // printf("VSIB Addressing, "); - // } - - // if (instrux->Operands[i].Info.Memory.IsStack) - // { - // printf("Stack, "); - // } - - // if (instrux->Operands[i].Info.Memory.IsShadowStack) - // { - // printf("Shadow Stack, "); - // } - // } - - // if (ND_OP_REG == instrux->Operands[i].Type) - // { - // printf(", Type: %16s, Size: %2d, Reg: %d, Count: %d\n", - // regtype_to_string(instrux->Operands[i].Info.Register.Type), - // instrux->Operands[i].Info.Register.Size, - // instrux->Operands[i].Info.Register.Reg, - // instrux->Operands[i].Info.Register.Count); - // } - // else - // { - // printf("\n"); - // } - - // if (instrux->Operands[i].Decorator.HasBroadcast) - // { - // printf(" Decorator: Broadcast %d bytes element %d times\n", - // instrux->Operands[i].Decorator.Broadcast.Size, - // instrux->Operands[i].Decorator.Broadcast.Count); - // } - - // if (instrux->Operands[i].Decorator.HasMask) - // { - // printf(" Decorator: Mask k%d\n", instrux->Operands[i].Decorator.Mask.Msk); - // } - - // if (instrux->Operands[i].Decorator.HasZero) - // { - // printf(" Decorator: Zero (no merging)\n"); - // } - // } - - // printf("\n"); - // } + if (opts.extended) { + const uint8_t opsize[3] = { 2, 4, 8 }; + const uint8_t adsize[3] = { 2, 4, 8 }; + const uint8_t veclen[3] = { 16, 32, 64 }; + + printf(" DSIZE: %2d, ASIZE: %2d, VLEN: ", + opsize[instrux->EfOpMode] * 8, adsize[instrux->AddrMode] * 8); + + if (ND_HAS_VECTOR(instrux)) { + printf("%2d\n", veclen[instrux->VecMode] * 8); + } else { + printf("-\n"); + } + + printf(" ISA Set: %s, Ins cat: %s, Ins class: %d, CET tracked: %s\n", + ins_set_to_str(instrux->IsaSet).c_str(), ins_cat_to_str(instrux->Category).c_str(), instrux->Instruction, + instrux->IsCetTracked ? "yes" : "no"); + + if (0 != instrux->CpuidFlag.Flag) { + const char *regs[4] = { "eax", "ecx", "edx", "ebx" }; + + printf(" CPUID leaf: 0x%08x", instrux->CpuidFlag.Leaf); + + if (instrux->CpuidFlag.SubLeaf != ND_CFF_NO_SUBLEAF) + { + printf(", sub-leaf: 0x%08x", instrux->CpuidFlag.SubLeaf); + } + + printf(", reg: %s, bit %d\n", regs[instrux->CpuidFlag.Reg], instrux->CpuidFlag.Bit); + } + + printf(" FLAGS access: "); + + uint32_t all = instrux->FlagsAccess.Tested.Raw | instrux->FlagsAccess.Modified.Raw | instrux->FlagsAccess.Set.Raw + | instrux->FlagsAccess.Cleared.Raw | instrux->FlagsAccess.Undefined.Raw; + const char *flags[22] = { "CF", nullptr, "PF", nullptr, "AF", nullptr, "ZF", "SF", "TF", "IF", "DF", "OF", "IOPL", nullptr, "NT", nullptr, "RF", "VM", "AC", "VIF", "VIP", "ID" }; + + for (uint32_t fidx = 0; fidx < 21; fidx++) { + if (flags[fidx] != nullptr) { + if (0 == (all & (1ULL << fidx))) { + continue; + } + + printf("%s: ", flags[fidx]); + + if (instrux->FlagsAccess.Tested.Raw & (1ULL << fidx)) { + printf("t"); + } + + if (instrux->FlagsAccess.Modified.Raw & (1ULL << fidx)) { + printf("m"); + } + + if (instrux->FlagsAccess.Set.Raw & (1ULL << fidx)) { + printf("1"); + } + + if (instrux->FlagsAccess.Cleared.Raw & (1ULL << fidx)) { + printf("0"); + } + + if (instrux->FlagsAccess.Undefined.Raw & (1ULL << fidx)) { + printf("u"); + } + + printf("; "); + } + } + + printf("\n"); + + printf(" Valid modes: R0: %s, R1: %s, R2: %s, R3: %s, Real: %s, V8086: %s, Prot: %s, Compat: %s, Long: %s, SMM: %s, SGX: %s, TSX: %s, VMXRoot: %s, VMXNonRoot: %s\n", + instrux->ValidModes.Ring0 ? "yes" : "no", + instrux->ValidModes.Ring1 ? "yes" : "no", + instrux->ValidModes.Ring2 ? "yes" : "no", + instrux->ValidModes.Ring3 ? "yes" : "no", + instrux->ValidModes.Real ? "yes" : "no", + instrux->ValidModes.V8086 ? "yes" : "no", + instrux->ValidModes.Protected ? "yes" : "no", + instrux->ValidModes.Compat ? "yes" : "no", + instrux->ValidModes.Long ? "yes" : "no", + instrux->ValidModes.Smm ? "yes" : "no", + instrux->ValidModes.Sgx ? "yes" : "no", + instrux->ValidModes.Tsx ? "yes" : "no", + instrux->ValidModes.VmxRoot ? "yes" : "no", + instrux->ValidModes.VmxNonRoot ? "yes" : "no"); + + for (uint8_t i = 0; i < instrux->OperandsCount; i++) { + printf(" Operand %d %s Type: %10s, Size: %2d, RawSize: %2d, Encoding: %s", i, + instrux->Operands[i].Access.Read && instrux->Operands[i].Access.Write ? "RW" : + instrux->Operands[i].Access.Write ? "-W" : instrux->Operands[i].Access.Read ? "R-" : "--", + op_type_to_str(instrux->Operands[i].Type).c_str(), instrux->Operands[i].Size, + instrux->Operands[i].RawSize, op_enc_to_str(instrux->Operands[i].Encoding).c_str()); + + if (ND_OP_MEM == instrux->Operands[i].Type) { + printf(", "); + + if (instrux->Operands[i].Info.Memory.IsAG) { + printf("Address Generator, "); + } + + if (instrux->Operands[i].Info.Memory.IsBitbase) { + printf("Bitbase Addressing, "); + } + + if (instrux->Operands[i].Info.Memory.IsMib) { + printf("MIB Addressing, "); + } + + if (instrux->Operands[i].Info.Memory.IsVsib) { + printf("VSIB Addressing, "); + } + + if (instrux->Operands[i].Info.Memory.IsStack) { + printf("Stack, "); + } + + if (instrux->Operands[i].Info.Memory.IsShadowStack) { + printf("Shadow Stack, "); + } + } + + if (ND_OP_REG == instrux->Operands[i].Type) { + printf(", Type: %16s, Size: %2d, Reg: %d, Count: %d", + reg_type_to_str(instrux->Operands[i].Info.Register.Type).c_str(), + instrux->Operands[i].Info.Register.Size, + instrux->Operands[i].Info.Register.Reg, + instrux->Operands[i].Info.Register.Count); + } + + printf("\n"); + + if (instrux->Operands[i].Decorator.HasBroadcast) { + printf(" Decorator: Broadcast %d bytes element %d times\n", + instrux->Operands[i].Decorator.Broadcast.Size, + instrux->Operands[i].Decorator.Broadcast.Count); + } + + if (instrux->Operands[i].Decorator.HasMask) { + printf(" Decorator: Mask k%d\n", instrux->Operands[i].Decorator.Mask.Msk); + } + + if (instrux->Operands[i].Decorator.HasZero) { + printf(" Decorator: Zero (no merging)\n"); + } + } + + printf("\n"); + } } @@ -489,6 +460,8 @@ size_t disassemble(options &opts) auto bytes = opts.bytes.get(); auto disasm_size = std::min(opts.actual_size - opts.offset, opts.size); + opts.address_size = int(std::ceil(((8 * sizeof(opts.actual_size)) - __builtin_clzll(opts.actual_size)) / 4.0)); + while ((total_disasm < disasm_size) && (icount < opts.count)) { INSTRUX instrux; @@ -507,9 +480,9 @@ size_t disassemble(options &opts) auto j = byte_to_json(bytes[rel_rip], rel_rip + opts.rip); std::cout << j.GetString() << std::endl; } else { - printf("%zx ", rel_rip + opts.rip); + printf("%*zx ", opts.address_size, rel_rip + opts.rip); printf("%02x", bytes[rel_rip]); - printf("%s", gSpaces[16 - 1]); + printf("%s", gSpaces[16 - opts.address_size]); printf("db 0x%02x\n", bytes[rel_rip]); } } @@ -649,6 +622,7 @@ int main(int argc, char **argv) parser.add_argument("-b", "--bits", "Use the arch [16, 32, 64]", false); parser.add_argument("--verbose", "Verbose mode", false); parser.add_argument("--json", "Output to json", false); + parser.add_argument("--extended", "Extended instruction info", false); try { parser.parse(argc, argv); @@ -657,7 +631,7 @@ int main(int argc, char **argv) return 1; } - opts.bits = parser.get("bits"); + opts.bits = parser.get("bits"); opts.interactive = parser.get("interactive"); opts.comm = parser.get("comm"); opts.offset = _get_hex_opt(parser, "offset"); @@ -671,6 +645,7 @@ int main(int argc, char **argv) opts.dump_stats = parser.get("stats"); opts.verbose = parser.get("verbose"); opts.json_output = parser.get("json"); + opts.extended = parser.get("extended"); if (opts.verbose) { std::cout << "interactive: " << opts.interactive << std::endl; @@ -685,6 +660,7 @@ int main(int argc, char **argv) std::cout << "stats: " << opts.dump_stats << std::endl; std::cout << "hex: " << opts.hex_string << std::endl; std::cout << "json: " << opts.json_output << std::endl; + std::cout << "extended: " << opts.extended << std::endl; } if (!_validate_and_fix_args(opts)) { diff --git a/disasmtool_lix/dumpers.cpp b/disasmtool_lix/dumpers.cpp index 2a16988..e5e6f9c 100644 --- a/disasmtool_lix/dumpers.cpp +++ b/disasmtool_lix/dumpers.cpp @@ -18,6 +18,52 @@ std::string enc_mode_to_str(const uint8_t enc_mode) } +std::string op_enc_to_str(const ND_OPERAND_ENCODING Encoding) +{ + switch (Encoding) { + case ND_OPE_NP: return "NP"; + case ND_OPE_R: return "R"; + case ND_OPE_M: return "M"; + case ND_OPE_V: return "V"; + case ND_OPE_O: return "O"; + case ND_OPE_I: return "I"; + case ND_OPE_D: return "D"; + case ND_OPE_C: return "C"; + case ND_OPE_1: return "1"; + case ND_OPE_A: return "A"; + case ND_OPE_L: return "L"; + case ND_OPE_E: return "E"; + case ND_OPE_S: return "S"; + default: return ""; + } +} + + +std::string op_type_to_str(const ND_OPERAND_TYPE type) +{ + switch(type) { + case ND_OP_NOT_PRESENT: + return "not_present"; + case ND_OP_REG: + return "register"; + case ND_OP_MEM: + return "memory"; + case ND_OP_IMM: + return "immediate"; + case ND_OP_OFFS: + return "offset"; + case ND_OP_ADDR: + return "address"; + case ND_OP_CONST: + return "const"; + case ND_OP_BANK: + return "bank"; + } + + return ""; +} + + std::string ins_class_to_str(const ND_INS_CLASS cls) { switch (cls) {