Advertisement
Fare9

Disassembler Algorithms

Feb 14th, 2020
286
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.18 KB | None | 0 0
  1. #include "disassembler.h"
  2.  
  3. bool compareByAddress(const cs_insn *a,const cs_insn *b)
  4. {
  5.     return a->address < b->address;
  6. }
  7.  
  8. namespace disassembler {
  9.  
  10.     Disassembler::Disassembler(const char *filename) : instructions(nullptr),
  11.                                                         instruction_size(0),
  12.                                                         section(0),
  13.                                                         pc(nullptr),
  14.                                                         addr(0),
  15.                                                         offset(0),
  16.                                                         target(0),
  17.                                                         instruction(nullptr)
  18.     {
  19.         loader_v = std::make_unique<loader::Loader>(filename, loader::Binary::BIN_TYPE_AUTO);
  20.  
  21.         loader_v->load_binary();
  22.  
  23.         binary_v = loader_v->getBinary();
  24.     }
  25.    
  26.     Disassembler::Disassembler(loader::Binary *binary_v) : instructions(nullptr),
  27.                                                         instruction_size(0),
  28.                                                         section(0),
  29.                                                         pc(nullptr),
  30.                                                         addr(0),
  31.                                                         offset(0),
  32.                                                         target(0),
  33.                                                         instruction(nullptr)
  34.     {
  35.         this->binary_v = binary_v;
  36.     }
  37.  
  38.     void Disassembler::init_disassembler()
  39.     {
  40.         if (binary_v == nullptr)
  41.             throw exception_t::error("incorrect binary");
  42.  
  43.         // now init disassembler of capstone
  44.         if (binary_v->getBits() == loader::Binary::X86_32)
  45.         {
  46.             if (cs_open(CS_ARCH_X86, CS_MODE_32, &dis) != CS_ERR_OK)
  47.                 throw exception_t::error("failed to open capstone");
  48.         }
  49.         else if (binary_v->getBits() == loader::Binary::X86_64)
  50.         {
  51.             if (cs_open(CS_ARCH_X86, CS_MODE_64, &dis) != CS_ERR_OK)
  52.                 throw exception_t::error("failed to open capstone");
  53.         }
  54.         else
  55.             throw exception_t::error("not recognized or not supported binary class");
  56.     }
  57.  
  58.     cs_insn* Disassembler::linear_disassembly(const char *section_name)
  59.     {
  60.         char error_message[1000];
  61.         size_t i;
  62.  
  63.         memset(error_message, 0, 1000);
  64.  
  65.         if (section_name == nullptr)
  66.             throw exception_t::error("incorrect section name");
  67.        
  68.         if (strlen(section_name) == 0)
  69.             throw exception_t::error("incorrect section name");
  70.        
  71.         for (i = 0; i < binary_v->getSections().size(); i++)
  72.         {
  73.             if (!strcmp(binary_v->getSections()[i].getName(), section_name))
  74.             {
  75.                 section = &(binary_v->getSections()[i]);
  76.                 break;
  77.             }
  78.         }
  79.  
  80.         instruction_size = cs_disasm(dis, reinterpret_cast<const uint8_t*>(section->getBytes()), section->getSize(), section->getVMA(), 0, &instructions);
  81.  
  82.         if ( instruction_size  <= 0 )
  83.         {
  84.             snprintf(error_message, 999,
  85.                 "Disassembly error: %s", cs_strerror(cs_errno(dis)));
  86.             throw exception_t::error(error_message);
  87.         }
  88.  
  89.         return instructions;
  90.     }
  91.  
  92.     const std::vector<cs_insn *>& Disassembler::recursive_disassembly()
  93.     {
  94.         char error_message[1000];
  95.  
  96.         memset(error_message, 0, 1000);
  97.  
  98.         // get text section, where entry point is supposed to be
  99.         section = binary_v->get_text_sections();
  100.         if (section == nullptr)
  101.         {
  102.             throw exception_t::error("Nothing to disassemble");
  103.         }
  104.  
  105.         cs_option(dis, CS_OPT_DETAIL, CS_OPT_ON);
  106.  
  107.         addr = binary_v->getEntryPoint();
  108.  
  109.         if (section->contains(addr))
  110.             Q.push(addr);
  111.  
  112.         fprintf(stdout, "Entry Point: 0x%016jx\n", addr);
  113.  
  114.         for (auto &sym : binary_v->getSymbols())
  115.         {
  116.             if (sym.getSymbolType() == loader::Symbol::SYM_TYPE_FUNC
  117.                 && section->contains(sym.getAddr()))
  118.             {
  119.                 Q.push(sym.getAddr());
  120.                 fprintf(stdout, "Function symbol: 0x%016jx\n", sym.getAddr());
  121.             }
  122.         }
  123.  
  124.         while (!Q.empty())
  125.         {
  126.             addr = Q.front();
  127.             Q.pop();
  128.  
  129.             // if we've already seen that address
  130.             if (seen[addr])
  131.                 continue;
  132.            
  133.             offset              = addr - section->getVMA();
  134.             pc                  = section->getBytes() + offset;
  135.             remainder_size      = section->getSize() - offset;
  136.  
  137.             instruction = cs_malloc(dis);
  138.             if (!instruction)
  139.             {
  140.                 throw exception_t::error("Error calling cs_malloc, out of memory");
  141.             }
  142.  
  143.             while (cs_disasm_iter(
  144.                 dis,
  145.                 &pc,
  146.                 &remainder_size,
  147.                 &addr,
  148.                 instruction
  149.             ))
  150.             {
  151.                 instructions_vector.push_back(instruction);
  152.  
  153.                 if (instruction->id == X86_INS_INVALID ||
  154.                     instruction->size == 0)
  155.                     break;
  156.  
  157.                 seen[instruction->address] = true;
  158.  
  159.                 if (is_cs_cflow_ins(instruction))
  160.                 {
  161.                     target = get_cs_ins_immediate_target(instruction);
  162.  
  163.                     if (target && !seen[target] && section->contains(target))
  164.                     {
  165.                         Q.push(target);
  166.                         printf("   -> new target: 0x%016jx\n", target);    
  167.                     }
  168.                     if (is_cs_unconditional_cflow_ins(instruction))
  169.                         break;
  170.                 } else if (instruction->id == X86_INS_HLT)
  171.                     break;
  172.  
  173.                 instruction = cs_malloc(dis);
  174.                 if (!instruction)
  175.                 {
  176.                     throw exception_t::error("Error calling cs_malloc, out of memory");
  177.                 }
  178.             }
  179.         }
  180.  
  181.         std::sort(instructions_vector.begin(),instructions_vector.end(), compareByAddress);
  182.  
  183.         return instructions_vector;
  184.     }
  185.  
  186.     void Disassembler::destroy_instructions_vector()
  187.     {
  188.         size_t i, vector_size = instructions_vector.size();
  189.        
  190.         for (i = 0;i < vector_size; i++)
  191.             cs_free(instructions_vector[i], 1);
  192.  
  193.         instructions_vector.clear();
  194.     }
  195.  
  196.     void Disassembler::destroy_instructions()
  197.     {
  198.         if (instruction_size > 0)
  199.         {
  200.             cs_free(instructions, instruction_size);
  201.             instruction_size = 0;
  202.             instructions = nullptr;
  203.         }
  204.     }
  205.  
  206.     void Disassembler::destroy_disassembler()
  207.     {
  208.         cs_close(&dis);
  209.     }
  210.  
  211.     size_t Disassembler::get_instructions_number()
  212.     {
  213.         return instruction_size;
  214.     }
  215.  
  216.     bool Disassembler::is_cs_cflow_group(std::uint8_t g)
  217.     /*
  218.     *   Check if the instruction group is inside of
  219.     *   one of the control flow instruction groups
  220.     */
  221.     {
  222.         return (g == CS_GRP_JUMP) || (g == CS_GRP_CALL)
  223.                 || (g == CS_GRP_RET) || (g == CS_GRP_IRET);
  224.     }
  225.  
  226.     bool Disassembler::is_cs_cflow_ins(cs_insn *ins)
  227.     /*
  228.     *   Check if an instruction is a control flow instruction
  229.     */
  230.     {
  231.         for (size_t i = 0; i < ins->detail->groups_count; i++)
  232.         {
  233.             if (is_cs_cflow_group(ins->detail->groups[i]))
  234.                 return true;
  235.         }
  236.  
  237.         return false;
  238.     }
  239.  
  240.     bool Disassembler::is_cs_unconditional_cflow_ins(cs_insn *ins)
  241.     {
  242.         switch(ins->id)
  243.         {
  244.         case X86_INS_JMP:
  245.         case X86_INS_LJMP:
  246.         case X86_INS_RET:
  247.         case X86_INS_RETF:
  248.         case X86_INS_RETFQ:
  249.             return true;
  250.         default:
  251.             return false;
  252.         }
  253.     }
  254.  
  255.     std::uint64_t Disassembler::get_cs_ins_immediate_target(cs_insn *ins)
  256.     {
  257.         cs_x86_op *cs_op;
  258.  
  259.         for (size_t i = 0; i < ins->detail->groups_count; i++)
  260.         {
  261.             if (is_cs_cflow_group(ins->detail->groups[i]))
  262.             {
  263.                 for(size_t j = 0; j < ins->detail->x86.op_count; j++)
  264.                 {
  265.                     cs_op = &ins->detail->x86.operands[i];
  266.                     if (cs_op->type == X86_OP_IMM)
  267.                         return cs_op->imm;
  268.                 }
  269.             }
  270.         }
  271.  
  272.         return 0;
  273.     }
  274.  
  275.     const std::map<std::string, std::vector<std::uint64_t>>& Disassembler::find_rop_gadgets()
  276.     {
  277.         char error_message[1000];
  278.  
  279.         memset(error_message,0,1000);
  280.  
  281.         section = binary_v->get_text_sections();
  282.  
  283.         if (!section)
  284.         {
  285.             throw exception_t::error("Nothing to disassemble");
  286.         }
  287.  
  288.         cs_option(dis, CS_OPT_DETAIL, CS_OPT_ON);
  289.  
  290.         for (size_t i = 0; i < section->getSize(); i++)
  291.         {  
  292.             if (std::find(x86_opc_ret.begin(),x86_opc_ret.end(), section->getBytes()[i]) != x86_opc_ret.end())
  293.             {
  294.                 find_rop_gadgets_at_root(section->getVMA() + i);
  295.             }
  296.         }
  297.  
  298.         return rop_gadgets;
  299.     }
  300.  
  301.     void Disassembler::find_rop_gadgets_at_root(std::uint64_t root)
  302.     {
  303.         size_t len;
  304.         std::string gadget_str;
  305.         const size_t max_gadget_len = 5; // number of instructions
  306.         const size_t x86_max_ins_bytes = 15;
  307.         const std::uint64_t root_offset = max_gadget_len * x86_max_ins_bytes;
  308.  
  309.         instruction = cs_malloc(dis);
  310.         if (!instruction)
  311.         {
  312.             throw exception_t::error("Error calling cs_malloc, out of memory");
  313.         }
  314.  
  315.         for (std::uint64_t a = root -1;
  316.              a >= root - root_offset && a >= 0;
  317.              a--)
  318.         {
  319.             addr            = a;
  320.             offset          = addr - section->getVMA();
  321.             pc              = section->getBytes() + offset;
  322.             remainder_size  = section->getSize() - offset;
  323.             len             = 0;
  324.             gadget_str      = "";
  325.  
  326.             while (cs_disasm_iter(dis, &pc, &remainder_size, &addr, instruction))
  327.             {
  328.                 if (instruction->id == X86_INS_INVALID || instruction->size == 0)
  329.                     break;
  330.                 else if (instruction->address > root)
  331.                     break;
  332.                 else if (is_cs_cflow_ins(instruction) && !is_cs_ret_ins(instruction))
  333.                     break;
  334.                 else if (++len > max_gadget_len)
  335.                     break;
  336.                 else if (is_cs_ret_ins(instruction) && instruction->address != root)
  337.                     break;
  338.                 else if (instruction->address != root && !is_cs_valid_ins(instruction))
  339.                     break;
  340.  
  341.                 gadget_str += std::string(instruction->mnemonic)
  342.                               + " " + std::string(instruction->op_str);
  343.  
  344.                 if (instruction->address == root)
  345.                 {
  346.                     rop_gadgets[gadget_str].push_back(a);
  347.                     break;
  348.                 }
  349.  
  350.                 gadget_str += "; ";
  351.             }
  352.         }
  353.  
  354.         cs_free(instruction, 1);
  355.     }
  356.  
  357.     bool Disassembler::is_cs_ret_ins(cs_insn *ins)
  358.     {
  359.         switch (ins->id)
  360.         {
  361.         case X86_INS_RET:
  362.             return true;
  363.         default:
  364.             return false;
  365.         }
  366.     }
  367.  
  368.     bool Disassembler::is_cs_valid_ins(cs_insn *ins)
  369.     {
  370.         switch (ins->id)
  371.         {
  372.         case X86_INS_MOV:
  373.         case X86_INS_POP:
  374.         case X86_INS_ADD:
  375.         case X86_INS_ADC:
  376.         case X86_INS_SUB:
  377.         case X86_INS_XCHG:
  378.         case X86_INS_LEA:
  379.         case X86_INS_LES:
  380.         case X86_INS_LEAVE:
  381.                 return true;
  382.         case X86_INS_XOR:
  383.         case X86_INS_AND:
  384.         case X86_INS_OR:
  385.         case X86_INS_PUSH:
  386.                 for (size_t i = 0; i < ins->detail->x86.op_count; i++)
  387.                 {
  388.                     if (!ins->detail->x86.operands[i].reg)
  389.                         return false;
  390.                 }
  391.                 return true;
  392.             default:
  393.                 return false;
  394.         }
  395.     }
  396.  
  397. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement