#pragma once #include #include #include #include #include #include #include #include using namespace std; using addr_t = uint64_t; struct ImportEntry { addr_t address; string name; string library; }; struct IndirectTarget { addr_t instruction_addr; addr_t resolved_target; string name; string library; bool resolved; }; struct XrefEntry { addr_t target; vector> callers; }; struct Instruction { addr_t address; vector bytes; string mnemonic; string operands; uint8_t size; int64_t stack_offset = 0; }; struct BasicBlock { addr_t address; vector instructions; vector successors; bool is_prolog; bool is_epilog; }; struct Function { addr_t address; addr_t end_address = 0; string name; vector blocks; bool is_thunk = false; }; struct CFG { string binary_path; string arch_str; string format_str; string mode_str; addr_t entry_point; vector functions; vector imports; vector indirect_targets; vector xrefs; bool has_stack_offsets = false; static string escapeJSON(const string& s) { ostringstream os; for (char c : s) { switch (c) { case '"': os << "\\\""; break; case '\\': os << "\\\\"; break; case '\n': os << "\\n"; break; case '\r': os << "\\r"; break; case '\t': os << "\\t"; break; default: os << c; } } return os.str(); } string toJSON() const { ostringstream os; os << "{\n"; os << " \"binary\": \"" << escapeJSON(binary_path) << "\",\n"; os << " \"mode\": \"" << escapeJSON(mode_str) << "\",\n"; os << " \"arch\": \"" << escapeJSON(arch_str) << "\",\n"; os << " \"format\": \"" << escapeJSON(format_str) << "\",\n"; os << " \"entry_point\": \"0x" << hex << entry_point << "\",\n"; os << " \"imports\": [\n"; for (size_t i = 0; i < imports.size(); ++i) { os << " {\n"; os << " \"address\": \"0x" << hex << imports[i].address << "\",\n"; os << " \"name\": \"" << escapeJSON(imports[i].name) << "\",\n"; os << " \"library\": \"" << escapeJSON(imports[i].library) << "\"\n"; os << " }"; if (i < imports.size() - 1) os << ","; os << "\n"; } os << " ],\n"; os << " \"indirect_targets\": [\n"; for (size_t i = 0; i < indirect_targets.size(); ++i) { const auto& it = indirect_targets[i]; os << " {\n"; os << " \"instruction\": \"0x" << hex << it.instruction_addr << "\",\n"; if (it.resolved) { os << " \"resolved_target\": \"0x" << it.resolved_target << "\",\n"; } else { os << " \"resolved_target\": null,\n"; } os << " \"name\": \"" << escapeJSON(it.name) << "\",\n"; os << " \"library\": \"" << escapeJSON(it.library) << "\"\n"; os << " }"; if (i < indirect_targets.size() - 1) os << ","; os << "\n"; } os << " ],\n"; os << " \"functions\": [\n"; for (size_t i = 0; i < functions.size(); ++i) { const auto& f = functions[i]; os << " {\n"; os << " \"address\": \"0x" << hex << f.address << "\",\n"; if (f.end_address) os << " \"end_address\": \"0x" << hex << f.end_address << "\",\n"; os << " \"name\": \"" << escapeJSON(f.name) << "\",\n"; if (f.is_thunk) os << " \"is_thunk\": true,\n"; os << " \"blocks\": [\n"; for (size_t j = 0; j < f.blocks.size(); ++j) { const auto& b = f.blocks[j]; os << " {\n"; os << " \"address\": \"0x" << hex << b.address << "\",\n"; os << " \"size\": " << dec << b.instructions.size() << ",\n"; os << " \"is_prolog\": " << (b.is_prolog ? "true" : "false") << ",\n"; os << " \"is_epilog\": " << (b.is_epilog ? "true" : "false") << ",\n"; os << " \"instructions\": [\n"; for (size_t k = 0; k < b.instructions.size(); ++k) { const auto& inst = b.instructions[k]; os << " {\n"; os << " \"address\": \"0x" << hex << inst.address << "\",\n"; os << " \"size\": " << dec << (int)inst.size << ",\n"; os << " \"mnemonic\": \"" << escapeJSON(inst.mnemonic) << "\",\n"; os << " \"operands\": \"" << escapeJSON(inst.operands) << "\""; if (has_stack_offsets) { os << ",\n"; os << " \"stack_offset\": " << dec << inst.stack_offset; } os << "\n"; os << " }"; if (k < b.instructions.size() - 1) os << ","; os << "\n"; } os << " ],\n"; os << " \"successors\": [\n"; for (size_t k = 0; k < b.successors.size(); ++k) { os << " \"0x" << hex << b.successors[k] << "\""; if (k < b.successors.size() - 1) os << ","; os << "\n"; } os << " ]\n"; os << " }"; if (j < f.blocks.size() - 1) os << ","; os << "\n"; } os << " ]\n"; os << " }"; if (i < functions.size() - 1) os << ","; os << "\n"; } if (!xrefs.empty()) { os << " ],\n"; os << " \"xrefs\": [\n"; for (size_t i = 0; i < xrefs.size(); ++i) { const auto& x = xrefs[i]; os << " {\n"; os << " \"target\": \"0x" << hex << x.target << "\",\n"; os << " \"callers\": [\n"; for (size_t j = 0; j < x.callers.size(); ++j) { os << " {\n"; os << " \"address\": \"0x" << hex << x.callers[j].first << "\",\n"; os << " \"type\": \"" << escapeJSON(x.callers[j].second) << "\"\n"; os << " }"; if (j < x.callers.size() - 1) os << ","; os << "\n"; } os << " ]\n"; os << " }"; if (i < xrefs.size() - 1) os << ","; os << "\n"; } os << " ]\n"; } else { os << " ]\n"; } os << "}\n"; return os.str(); } };