mirror of
https://github.com/bitdefender/bddisasm.git
synced 2024-10-31 20:39:14 +00:00
1175 lines
31 KiB
C++
1175 lines
31 KiB
C++
/*
|
|
* Copyright (c) 2020 Bitdefender
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include "disasm.hpp"
|
|
|
|
#include <iostream>
|
|
|
|
#include <rapidjson/document.h>
|
|
#include <rapidjson/writer.h>
|
|
|
|
|
|
using namespace rapidjson;
|
|
|
|
|
|
static void _start_object(Writer<StringBuffer> &writer)
|
|
{
|
|
writer.StartObject();
|
|
}
|
|
|
|
|
|
static void _start_object(Writer<StringBuffer> &writer, const char *key)
|
|
{
|
|
writer.Key(key);
|
|
writer.StartObject();
|
|
}
|
|
|
|
static void _end_object(Writer<StringBuffer> &writer)
|
|
{
|
|
writer.EndObject();
|
|
}
|
|
|
|
|
|
static void _start_array(Writer<StringBuffer> &writer)
|
|
{
|
|
writer.StartArray();
|
|
}
|
|
|
|
|
|
static void _start_array(Writer<StringBuffer> &writer, const char *key)
|
|
{
|
|
writer.Key(key);
|
|
writer.StartArray();
|
|
}
|
|
|
|
static void _end_array(Writer<StringBuffer> &writer)
|
|
{
|
|
writer.EndArray();
|
|
}
|
|
|
|
|
|
static void _write_uint(Writer<StringBuffer> &writer, unsigned int value)
|
|
{
|
|
writer.Uint(value);
|
|
}
|
|
|
|
|
|
static void _write_uint(Writer<StringBuffer> &writer, const char *key, unsigned int value)
|
|
{
|
|
writer.Key(key);
|
|
writer.Uint(value);
|
|
}
|
|
|
|
|
|
static void _write_int(Writer<StringBuffer> &writer, int value)
|
|
{
|
|
writer.Int(value);
|
|
}
|
|
|
|
|
|
static void _write_int(Writer<StringBuffer> &writer, const char *key, int value)
|
|
{
|
|
writer.Key(key);
|
|
writer.Int(value);
|
|
}
|
|
|
|
|
|
static void _write_uint64(Writer<StringBuffer> &writer, uint64_t value)
|
|
{
|
|
writer.Int(value);
|
|
}
|
|
|
|
|
|
static void _write_uint64(Writer<StringBuffer> &writer, const char *key, uint64_t value)
|
|
{
|
|
writer.Key(key);
|
|
writer.Int(value);
|
|
}
|
|
|
|
|
|
static void _write_int64(Writer<StringBuffer> &writer, int64_t value)
|
|
{
|
|
writer.Int(value);
|
|
}
|
|
|
|
|
|
static void _write_int64(Writer<StringBuffer> &writer, const char *key, int64_t value)
|
|
{
|
|
writer.Key(key);
|
|
writer.Int(value);
|
|
}
|
|
|
|
|
|
static void _write_string(Writer<StringBuffer> &writer, const std::string& value)
|
|
{
|
|
writer.String(value.c_str());
|
|
}
|
|
|
|
|
|
static void _write_string(Writer<StringBuffer> &writer, const char *key, const std::string& value)
|
|
{
|
|
writer.Key(key);
|
|
writer.String(value.c_str());
|
|
}
|
|
|
|
|
|
static void _write_string(Writer<StringBuffer> &writer, const char *value)
|
|
{
|
|
writer.String(value);
|
|
}
|
|
|
|
|
|
static void _write_string(Writer<StringBuffer> &writer, const char *key, const char *value)
|
|
{
|
|
writer.Key(key);
|
|
writer.String(value);
|
|
}
|
|
|
|
|
|
static void _write_bool(Writer<StringBuffer> &writer, bool value)
|
|
{
|
|
writer.Bool(value);
|
|
}
|
|
|
|
|
|
static void _write_bool(Writer<StringBuffer> &writer, const char *key, bool value)
|
|
{
|
|
writer.Key(key);
|
|
writer.Bool(value);
|
|
}
|
|
|
|
|
|
static int _disasm_size_to_int(const uint8_t mode)
|
|
{
|
|
switch (mode) {
|
|
case 0: return 16;
|
|
case 1: return 32;
|
|
case 2: return 64;
|
|
}
|
|
|
|
return mode;
|
|
}
|
|
|
|
|
|
static void _write_rex(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
if (!instrux->HasRex)
|
|
return;
|
|
|
|
_start_object(writer, "rex");
|
|
|
|
_write_uint(writer, "value", instrux->Rex.Rex);
|
|
|
|
_write_uint(writer, "b", static_cast<uint8_t>(instrux->Rex.b));
|
|
_write_uint(writer, "x", static_cast<uint8_t>(instrux->Rex.x));
|
|
_write_uint(writer, "r", static_cast<uint8_t>(instrux->Rex.r));
|
|
_write_uint(writer, "w", static_cast<uint8_t>(instrux->Rex.w));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_modrm(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
if (!instrux->HasModRm)
|
|
return;
|
|
|
|
_start_object(writer, "modrm");
|
|
|
|
_write_uint(writer, "value", instrux->ModRm.ModRm);
|
|
_write_uint(writer, "rm", static_cast<uint8_t>(instrux->ModRm.rm));
|
|
_write_uint(writer, "reg", static_cast<uint8_t>(instrux->ModRm.reg));
|
|
_write_uint(writer, "mod", static_cast<uint8_t>(instrux->ModRm.mod));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_sib(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
if (!instrux->HasSib)
|
|
return;
|
|
|
|
_start_object(writer, "sib");
|
|
|
|
_write_uint(writer, "value", instrux->Sib.Sib);
|
|
_write_uint(writer, "base", static_cast<uint8_t>(instrux->Sib.base));
|
|
_write_uint(writer, "index", static_cast<uint8_t>(instrux->Sib.index));
|
|
_write_uint(writer, "scale", static_cast<uint8_t>(instrux->Sib.scale));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_drex(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
if (!instrux->HasDrex)
|
|
return;
|
|
|
|
_start_object(writer, "drex");
|
|
|
|
_write_uint(writer, "value", instrux->Drex.Drex);
|
|
_write_uint(writer, "b", static_cast<uint8_t>(instrux->Drex.b));
|
|
_write_uint(writer, "x", static_cast<uint8_t>(instrux->Drex.x));
|
|
_write_uint(writer, "r", static_cast<uint8_t>(instrux->Drex.r));
|
|
_write_uint(writer, "oc", static_cast<uint8_t>(instrux->Drex.oc0));
|
|
_write_uint(writer, "vd", static_cast<uint8_t>(instrux->Drex.vd));
|
|
_write_uint(writer, "d", static_cast<uint8_t>(instrux->Drex.d));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_vex2(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
if (!instrux->HasVex || ND_VEXM_2B != instrux->VexMode)
|
|
return;
|
|
|
|
_start_object(writer, "vex2");
|
|
|
|
_start_array(writer, "value");
|
|
_write_uint(writer, instrux->Vex2.Vex[0]);
|
|
_write_uint(writer, instrux->Vex2.Vex[1]);
|
|
_end_array(writer);
|
|
|
|
_write_uint(writer, "op", instrux->Vex2.op);
|
|
_write_uint(writer, "p", static_cast<uint8_t>(instrux->Vex2.p));
|
|
_write_uint(writer, "l", static_cast<uint8_t>(instrux->Vex2.l));
|
|
_write_uint(writer, "v", static_cast<uint8_t>(instrux->Vex2.v));
|
|
_write_uint(writer, "r", static_cast<uint8_t>(instrux->Vex2.r));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_vex3(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
if (!instrux->HasVex || ND_VEXM_3B != instrux->VexMode)
|
|
return;
|
|
|
|
_start_object(writer, "vex3");
|
|
|
|
_start_array(writer, "value");
|
|
_write_uint(writer, instrux->Vex3.Vex[0]);
|
|
_write_uint(writer, instrux->Vex3.Vex[1]);
|
|
_write_uint(writer, instrux->Vex3.Vex[2]);
|
|
_end_array(writer);
|
|
|
|
_write_uint(writer, "op", instrux->Vex3.op);
|
|
_write_uint(writer, "m", static_cast<uint8_t>(instrux->Vex3.m));
|
|
_write_uint(writer, "b", static_cast<uint8_t>(instrux->Vex3.b));
|
|
_write_uint(writer, "x", static_cast<uint8_t>(instrux->Vex3.x));
|
|
_write_uint(writer, "r", static_cast<uint8_t>(instrux->Vex3.r));
|
|
_write_uint(writer, "p", static_cast<uint8_t>(instrux->Vex3.p));
|
|
_write_uint(writer, "l", static_cast<uint8_t>(instrux->Vex3.l));
|
|
_write_uint(writer, "v", static_cast<uint8_t>(instrux->Vex3.v));
|
|
_write_uint(writer, "w", static_cast<uint8_t>(instrux->Vex3.w));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_xop(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
if (!instrux->HasXop)
|
|
return;
|
|
|
|
_start_object(writer, "xop");
|
|
|
|
_start_array(writer, "value");
|
|
_write_uint(writer, instrux->Xop.Xop[0]);
|
|
_write_uint(writer, instrux->Xop.Xop[1]);
|
|
_write_uint(writer, instrux->Xop.Xop[2]);
|
|
_end_array(writer);
|
|
|
|
_write_uint(writer, "op", instrux->Xop.op);
|
|
_write_uint(writer, "m", static_cast<uint8_t>(instrux->Xop.m));
|
|
_write_uint(writer, "b", static_cast<uint8_t>(instrux->Xop.b));
|
|
_write_uint(writer, "x", static_cast<uint8_t>(instrux->Xop.x));
|
|
_write_uint(writer, "r", static_cast<uint8_t>(instrux->Xop.r));
|
|
_write_uint(writer, "p", static_cast<uint8_t>(instrux->Xop.p));
|
|
_write_uint(writer, "l", static_cast<uint8_t>(instrux->Xop.l));
|
|
_write_uint(writer, "v", static_cast<uint8_t>(instrux->Xop.v));
|
|
_write_uint(writer, "w", static_cast<uint8_t>(instrux->Xop.w));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_evex(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
if (!instrux->HasEvex)
|
|
return;
|
|
|
|
_start_object(writer, "evex");
|
|
|
|
_start_array(writer, "value");
|
|
_write_uint(writer, instrux->Evex.Evex[0]);
|
|
_write_uint(writer, instrux->Evex.Evex[1]);
|
|
_write_uint(writer, instrux->Evex.Evex[2]);
|
|
_write_uint(writer, instrux->Evex.Evex[3]);
|
|
_end_array(writer);
|
|
|
|
_write_uint(writer, "op", instrux->Evex.op);
|
|
_write_uint(writer, "m", static_cast<uint8_t>(instrux->Evex.m));
|
|
_write_uint(writer, "zero", static_cast<uint8_t>(instrux->Evex.zero));
|
|
_write_uint(writer, "rp", static_cast<uint8_t>(instrux->Evex.rp));
|
|
_write_uint(writer, "b", static_cast<uint8_t>(instrux->Evex.b));
|
|
_write_uint(writer, "x", static_cast<uint8_t>(instrux->Evex.x));
|
|
_write_uint(writer, "r", static_cast<uint8_t>(instrux->Evex.r));
|
|
_write_uint(writer, "p", static_cast<uint8_t>(instrux->Evex.p));
|
|
_write_uint(writer, "one", static_cast<uint8_t>(instrux->Evex.one));
|
|
_write_uint(writer, "v", static_cast<uint8_t>(instrux->Evex.v));
|
|
_write_uint(writer, "w", static_cast<uint8_t>(instrux->Evex.w));
|
|
_write_uint(writer, "a", static_cast<uint8_t>(instrux->Evex.a));
|
|
_write_uint(writer, "vp", static_cast<uint8_t>(instrux->Evex.vp));
|
|
_write_uint(writer, "bm", static_cast<uint8_t>(instrux->Evex.bm));
|
|
_write_uint(writer, "l", static_cast<uint8_t>(instrux->Evex.l));
|
|
_write_uint(writer, "z", static_cast<uint8_t>(instrux->Evex.z));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_exs(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
_start_object(writer, "exs");
|
|
|
|
_write_uint(writer, "w", static_cast<uint8_t>(instrux->Exs.w));
|
|
_write_uint(writer, "r", static_cast<uint8_t>(instrux->Exs.r));
|
|
_write_uint(writer, "x", static_cast<uint8_t>(instrux->Exs.x));
|
|
_write_uint(writer, "b", static_cast<uint8_t>(instrux->Exs.b));
|
|
_write_uint(writer, "rp", static_cast<uint8_t>(instrux->Exs.rp));
|
|
_write_uint(writer, "p", static_cast<uint8_t>(instrux->Exs.p));
|
|
_write_uint(writer, "m", static_cast<uint8_t>(instrux->Exs.m));
|
|
_write_uint(writer, "l", static_cast<uint8_t>(instrux->Exs.l));
|
|
_write_uint(writer, "v", static_cast<uint8_t>(instrux->Exs.v));
|
|
_write_uint(writer, "vp", static_cast<uint8_t>(instrux->Exs.vp));
|
|
_write_uint(writer, "bm", static_cast<uint8_t>(instrux->Exs.bm));
|
|
_write_uint(writer, "e", static_cast<uint8_t>(instrux->Exs.e));
|
|
_write_uint(writer, "z", static_cast<uint8_t>(instrux->Exs.z));
|
|
_write_uint(writer, "k", static_cast<uint8_t>(instrux->Exs.k));
|
|
_write_uint(writer, "s", static_cast<uint8_t>(instrux->Exs.s));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_prefixes(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
_start_array(writer, "prefixes");
|
|
|
|
if (instrux->HasRex)
|
|
_write_string(writer, "rex");
|
|
|
|
if (instrux->HasVex)
|
|
_write_string(writer, "vex");
|
|
|
|
if (instrux->HasXop)
|
|
_write_string(writer, "xop");
|
|
|
|
if (instrux->HasEvex)
|
|
_write_string(writer, "evex");
|
|
|
|
if (instrux->HasMvex)
|
|
_write_string(writer, "mvex");
|
|
|
|
if (instrux->HasOpSize)
|
|
_write_string(writer, "op_size");
|
|
|
|
if (instrux->HasAddrSize)
|
|
_write_string(writer, "addr_size");
|
|
|
|
if (instrux->HasLock)
|
|
_write_string(writer, "lock");
|
|
|
|
if (instrux->HasRepnzXacquireBnd)
|
|
_write_string(writer, "repnz_xacquire_bnd");
|
|
|
|
if (instrux->HasRepRepzXrelease)
|
|
_write_string(writer, "rep_repz_xrelease");
|
|
|
|
if (instrux->HasSeg)
|
|
_write_string(writer, "seg");
|
|
|
|
_end_array(writer);
|
|
}
|
|
|
|
|
|
static void _write_chunks(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
_start_array(writer, "chunks");
|
|
|
|
if (instrux->HasModRm)
|
|
_write_string(writer, "mod_rm");
|
|
|
|
if (instrux->HasSib)
|
|
_write_string(writer, "sib");
|
|
|
|
if (instrux->HasDrex)
|
|
_write_string(writer, "drex");
|
|
|
|
if (instrux->HasDisp)
|
|
_write_string(writer, "disp");
|
|
|
|
if (instrux->HasAddr)
|
|
_write_string(writer, "addr");
|
|
|
|
if (instrux->HasMoffset)
|
|
_write_string(writer, "moffset");
|
|
|
|
if (instrux->HasImm1)
|
|
_write_string(writer, "imm1");
|
|
|
|
if (instrux->HasImm2)
|
|
_write_string(writer, "imm2");
|
|
|
|
if (instrux->HasImm3)
|
|
_write_string(writer, "imm3");
|
|
|
|
if (instrux->HasRelOffs)
|
|
_write_string(writer, "rel_offs");
|
|
|
|
if (instrux->HasSseImm)
|
|
_write_string(writer, "sse_imm");
|
|
|
|
if (instrux->HasCompDisp)
|
|
_write_string(writer, "comp_disp");
|
|
|
|
if (instrux->HasBroadcast)
|
|
_write_string(writer, "broadcast");
|
|
|
|
if (instrux->HasMask)
|
|
_write_string(writer, "mask");
|
|
|
|
if (instrux->HasZero)
|
|
_write_string(writer, "zero");
|
|
|
|
if (instrux->HasEr)
|
|
_write_string(writer, "er");
|
|
|
|
if (instrux->HasSae)
|
|
_write_string(writer, "sae");
|
|
|
|
if (instrux->SignDisp)
|
|
_write_string(writer, "sign_disp");
|
|
|
|
_end_array(writer);
|
|
}
|
|
|
|
|
|
static void _write_access(Writer<StringBuffer> &writer, const char *key, const uint8_t access)
|
|
{
|
|
_start_array(writer, key);
|
|
|
|
if (access & ND_ACCESS_READ)
|
|
_write_string(writer, "read");
|
|
|
|
if (access & ND_ACCESS_WRITE)
|
|
_write_string(writer, "write");
|
|
|
|
if (access & ND_ACCESS_COND_READ)
|
|
_write_string(writer, "cond_read");
|
|
|
|
if (access & ND_ACCESS_COND_WRITE)
|
|
_write_string(writer, "cond_write");
|
|
|
|
if (access == ND_ACCESS_NONE)
|
|
_write_string(writer, "none");
|
|
|
|
_end_array(writer);
|
|
}
|
|
|
|
|
|
static void _start_write_default_op(Writer<StringBuffer> &writer, const ND_OPERAND &op)
|
|
{
|
|
_start_object(writer);
|
|
|
|
_start_array(writer, "flags");
|
|
|
|
if (op.Flags.IsDefault)
|
|
_write_string(writer, "default");
|
|
|
|
if (op.Flags.SignExtendedOp1)
|
|
_write_string(writer, "sign_extended_op1");
|
|
|
|
if (op.Flags.SignExtendedDws)
|
|
_write_string(writer, "sign_extended_dws");
|
|
|
|
_end_array(writer);
|
|
|
|
_write_uint(writer, "size", op.Size);
|
|
_write_uint(writer, "raw_size", op.RawSize);
|
|
|
|
_write_access(writer, "access", op.Access.Access);
|
|
|
|
_start_object(writer, "decorator");
|
|
|
|
if (op.Decorator.HasMask)
|
|
_write_uint(writer, "mask", op.Decorator.Mask.Msk); // TODO: k0-k7
|
|
|
|
if (op.Decorator.HasZero)
|
|
_write_bool(writer, "zeroing", true);
|
|
|
|
if (op.Decorator.HasBroadcast) {
|
|
_start_object(writer, "broadcast");
|
|
|
|
_write_uint(writer, "count", op.Decorator.Broadcast.Count);
|
|
_write_uint(writer, "size", op.Decorator.Broadcast.Size);
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
if (op.Decorator.HasEr)
|
|
_write_bool(writer, "er", true);
|
|
|
|
if (op.Decorator.HasSae)
|
|
_write_bool(writer, "sae", true);
|
|
|
|
_end_object(writer); // "decorator"
|
|
|
|
switch (op.Type) {
|
|
case ND_OP_NOT_PRESENT:
|
|
_write_string(writer, "type", "not_preset");
|
|
break;
|
|
|
|
case ND_OP_REG:
|
|
_write_string(writer, "type", "register");
|
|
break;
|
|
|
|
case ND_OP_MEM:
|
|
_write_string(writer, "type", "memory");
|
|
break;
|
|
|
|
case ND_OP_IMM:
|
|
_write_string(writer, "type", "immediate");
|
|
break;
|
|
|
|
case ND_OP_OFFS:
|
|
_write_string(writer, "type", "offset");
|
|
break;
|
|
|
|
case ND_OP_ADDR:
|
|
_write_string(writer, "type", "address");
|
|
break;
|
|
|
|
case ND_OP_CONST:
|
|
_write_string(writer, "type", "constant");
|
|
break;
|
|
|
|
case ND_OP_BANK:
|
|
_write_string(writer, "type", "bank");
|
|
break;
|
|
|
|
default:
|
|
_write_string(writer, "type", "<unknown>");
|
|
break;
|
|
}
|
|
|
|
// returns without closing the object
|
|
}
|
|
|
|
|
|
static void _write_op_reg(Writer<StringBuffer> &writer, const ND_OPERAND &op)
|
|
{
|
|
const auto& reg = op.Info.Register;
|
|
|
|
_write_uint(writer, "size", reg.Size);
|
|
|
|
_write_string(writer, "reg_type", reg_type_to_str(reg.Type));
|
|
_write_string(writer, "reg", reg_to_str(reg.Reg, reg.Type));
|
|
|
|
_write_uint(writer, "reg_id", reg.Reg);
|
|
_write_uint(writer, "count", reg.Count);
|
|
|
|
if (reg.IsHigh8)
|
|
_write_bool(writer, "is_high8", true);
|
|
|
|
if (reg.IsBlock)
|
|
_write_bool(writer, "is_block", true);
|
|
}
|
|
|
|
|
|
static void _write_op_mem(Writer<StringBuffer> &writer, const ND_OPERAND &op)
|
|
{
|
|
const auto& mem = op.Info.Memory;
|
|
|
|
_start_array(writer, "flags");
|
|
|
|
if (mem.IsRipRel)
|
|
_write_string(writer, "rip_rel");
|
|
|
|
if (mem.IsStack)
|
|
_write_string(writer, "stack");
|
|
|
|
if (mem.IsString)
|
|
_write_string(writer, "string");
|
|
|
|
if (mem.IsShadowStack)
|
|
_write_string(writer, "shadow_stack");
|
|
|
|
if (mem.IsDirect)
|
|
_write_string(writer, "direct");
|
|
|
|
if (mem.IsBitbase)
|
|
_write_string(writer, "bitbase");
|
|
|
|
if (mem.IsAG)
|
|
_write_string(writer, "ag");
|
|
|
|
if (mem.IsMib)
|
|
_write_string(writer, "mib");
|
|
|
|
if (mem.HasBroadcast)
|
|
_write_string(writer, "broadcast");
|
|
|
|
_end_array(writer);
|
|
|
|
if (mem.IsVsib) {
|
|
_start_object(writer, "vsib");
|
|
|
|
_write_uint(writer, "index_size", mem.Vsib.IndexSize);
|
|
_write_uint(writer, "elem_size", mem.Vsib.ElemSize);
|
|
_write_uint(writer, "elem_count", mem.Vsib.ElemCount);
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
if (mem.HasSeg)
|
|
_write_uint(writer, "seg", mem.Seg);
|
|
|
|
if (mem.HasBase) {
|
|
_write_uint(writer, "base_size", mem.BaseSize);
|
|
_write_uint(writer, "base", mem.Base);
|
|
}
|
|
|
|
if (mem.HasIndex) {
|
|
_write_uint(writer, "index_size", mem.IndexSize);
|
|
_write_uint(writer, "index", mem.Index);
|
|
_write_uint(writer, "scale", mem.Scale);
|
|
}
|
|
|
|
if (mem.HasDisp || mem.HasCompDisp) {
|
|
if (mem.HasDisp)
|
|
_write_uint(writer, "disp_size", mem.DispSize);
|
|
|
|
if (mem.HasCompDisp)
|
|
_write_uint(writer, "comp_disp_size", mem.CompDispSize);
|
|
|
|
_write_uint(writer, "disp", mem.Disp);
|
|
}
|
|
}
|
|
|
|
|
|
static void _write_operands(Writer<StringBuffer> &writer, const INSTRUX *instrux)
|
|
{
|
|
_start_array(writer, "operands");
|
|
|
|
for (auto i = 0; i < instrux->OperandsCount; i++) {
|
|
const auto& op = instrux->Operands[i];
|
|
|
|
_start_write_default_op(writer, op);
|
|
|
|
_start_object(writer, "info");
|
|
|
|
switch (op.Type) {
|
|
case ND_OP_REG:
|
|
_write_op_reg(writer, op);
|
|
break;
|
|
|
|
case ND_OP_MEM:
|
|
_write_op_mem(writer, op);
|
|
break;
|
|
|
|
case ND_OP_IMM:
|
|
_write_uint64(writer, "imm", op.Info.Immediate.Imm);
|
|
break;
|
|
|
|
case ND_OP_OFFS:
|
|
_write_uint64(writer, "rel", op.Info.RelativeOffset.Rel);
|
|
break;
|
|
|
|
case ND_OP_ADDR:
|
|
_write_uint(writer, "base_seg", op.Info.Address.BaseSeg);
|
|
_write_uint64(writer, "offset", op.Info.Address.Offset);
|
|
|
|
break;
|
|
|
|
case ND_OP_CONST:
|
|
_write_uint64(writer, "const", op.Info.Constant.Const);
|
|
break;
|
|
|
|
case ND_OP_NOT_PRESENT:
|
|
case ND_OP_BANK:
|
|
break;
|
|
}
|
|
|
|
_end_object(writer); // "info"
|
|
_end_object(writer); // the one from _start_write_default_op
|
|
}
|
|
|
|
_end_array(writer);
|
|
}
|
|
|
|
|
|
static void _write_valid_modes(Writer<StringBuffer> &writer, const ND_VALID_MODES &modes)
|
|
{
|
|
_start_array(writer, "valid_modes");
|
|
|
|
if (modes.Ring0)
|
|
_write_string(writer, "ring0");
|
|
|
|
if (modes.Ring1)
|
|
_write_string(writer, "ring1");
|
|
|
|
if (modes.Ring2)
|
|
_write_string(writer, "ring2");
|
|
|
|
if (modes.Ring3)
|
|
_write_string(writer, "ring3");
|
|
|
|
if (modes.Real)
|
|
_write_string(writer, "real");
|
|
|
|
if (modes.V8086)
|
|
_write_string(writer, "v8086");
|
|
|
|
if (modes.Protected)
|
|
_write_string(writer, "protected");
|
|
|
|
if (modes.Compat)
|
|
_write_string(writer, "compatibility");
|
|
|
|
if (modes.Long)
|
|
_write_string(writer, "long");
|
|
|
|
if (modes.Smm)
|
|
_write_string(writer, "smm");
|
|
|
|
if (modes.Sgx)
|
|
_write_string(writer, "sgx");
|
|
|
|
if (modes.Tsx)
|
|
_write_string(writer, "tsx");
|
|
|
|
if (modes.VmxRoot)
|
|
_write_string(writer, "vmx_root");
|
|
|
|
if (modes.VmxNonRoot)
|
|
_write_string(writer, "vmx_non_root");
|
|
|
|
if (modes.VmxOff)
|
|
_write_string(writer, "vmx_off");
|
|
|
|
_end_array(writer);
|
|
}
|
|
|
|
|
|
static void _write_valid_prefixes(Writer<StringBuffer> &writer, const ND_VALID_PREFIXES &prefixes)
|
|
{
|
|
_start_array(writer, "valid_prefixes");
|
|
|
|
if (prefixes.Rep)
|
|
_write_string(writer, "rep");
|
|
|
|
if (prefixes.RepCond)
|
|
_write_string(writer, "rep_cond");
|
|
|
|
if (prefixes.Lock)
|
|
_write_string(writer, "lock");
|
|
|
|
if (prefixes.Hle)
|
|
_write_string(writer, "hle");
|
|
|
|
if (prefixes.Xacquire)
|
|
_write_string(writer, "xacquire");
|
|
|
|
if (prefixes.Xrelease)
|
|
_write_string(writer, "xrelease");
|
|
|
|
if (prefixes.Bnd)
|
|
_write_string(writer, "bnd");
|
|
|
|
if (prefixes.Bhint)
|
|
_write_string(writer, "bhint");
|
|
|
|
if (prefixes.HleNoLock)
|
|
_write_string(writer, "hle_no_lock");
|
|
|
|
if (prefixes.Dnt)
|
|
_write_string(writer, "dnt");
|
|
|
|
_end_array(writer);
|
|
}
|
|
|
|
|
|
static void _write_valid_decorators(Writer<StringBuffer> &writer, const ND_VALID_DECORATORS &decorators)
|
|
{
|
|
_start_array(writer, "valid_decorators");
|
|
|
|
if (decorators.Er)
|
|
_write_string(writer, "er");
|
|
|
|
if (decorators.Sae)
|
|
_write_string(writer, "Sae");
|
|
|
|
if (decorators.Zero)
|
|
_write_string(writer, "Zero");
|
|
|
|
if (decorators.Mask)
|
|
_write_string(writer, "mask");
|
|
|
|
if (decorators.Broadcast)
|
|
_write_string(writer, "broadcast");
|
|
|
|
_end_array(writer);
|
|
}
|
|
|
|
|
|
static void _write_cpuid_flag(Writer<StringBuffer> &writer, const ND_CPUID_FLAG &cpuid_flag)
|
|
{
|
|
if (0 == cpuid_flag.Flag)
|
|
return;
|
|
|
|
_start_object(writer, "cpuid_flag");
|
|
|
|
_write_uint64(writer, "flag", cpuid_flag.Flag);
|
|
_write_uint(writer, "leaf", cpuid_flag.Leaf);
|
|
_write_uint(writer, "sub_leaf", static_cast<uint32_t>(cpuid_flag.SubLeaf));
|
|
_write_uint(writer, "reg", static_cast<uint8_t>(cpuid_flag.Reg));
|
|
_write_uint(writer, "bit", static_cast<uint8_t>(cpuid_flag.Bit));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
static void _write_rflags(Writer<StringBuffer> &writer, const ND_RFLAGS &rflags, const char *key)
|
|
{
|
|
_start_array(writer, key);
|
|
|
|
if (rflags.CF)
|
|
_write_string(writer, "cf");
|
|
|
|
if (rflags.PF)
|
|
_write_string(writer, "pf");
|
|
|
|
if (rflags.AF)
|
|
_write_string(writer, "af");
|
|
|
|
if (rflags.ZF)
|
|
_write_string(writer, "zf");
|
|
|
|
if (rflags.SF)
|
|
_write_string(writer, "sf");
|
|
|
|
if (rflags.TF)
|
|
_write_string(writer, "tf");
|
|
|
|
if (rflags.IF)
|
|
_write_string(writer, "if");
|
|
|
|
if (rflags.DF)
|
|
_write_string(writer, "df");
|
|
|
|
if (rflags.OF)
|
|
_write_string(writer, "of");
|
|
|
|
if (rflags.IOPL)
|
|
_write_string(writer, "iopl");
|
|
|
|
if (rflags.NT)
|
|
_write_string(writer, "nt");
|
|
|
|
if (rflags.RF)
|
|
_write_string(writer, "rf");
|
|
|
|
if (rflags.VM)
|
|
_write_string(writer, "vm");
|
|
|
|
if (rflags.AC)
|
|
_write_string(writer, "ac");
|
|
|
|
if (rflags.VIF)
|
|
_write_string(writer, "vif");
|
|
|
|
if (rflags.VIP)
|
|
_write_string(writer, "vip");
|
|
|
|
if (rflags.ID)
|
|
_write_string(writer, "id");
|
|
|
|
_end_array(writer);
|
|
}
|
|
|
|
|
|
static void _write_flags_access(Writer<StringBuffer> &writer, INSTRUX *instrux)
|
|
{
|
|
if (ND_ACCESS_NONE == instrux->FlagsAccess.RegAccess)
|
|
return;
|
|
|
|
_start_object(writer, "flags_access");
|
|
|
|
_write_access(writer, "access", instrux->FlagsAccess.RegAccess);
|
|
|
|
if ((instrux->FlagsAccess.RegAccess & ND_ACCESS_ANY_READ) && instrux->FlagsAccess.Tested.Raw)
|
|
_write_rflags(writer, instrux->FlagsAccess.Tested, "tested");
|
|
|
|
if ((instrux->FlagsAccess.RegAccess & ND_ACCESS_ANY_WRITE) && instrux->FlagsAccess.Modified.Raw)
|
|
_write_rflags(writer, instrux->FlagsAccess.Modified, "modified");
|
|
|
|
if (instrux->FlagsAccess.Set.Raw)
|
|
_write_rflags(writer, instrux->FlagsAccess.Set, "set");
|
|
|
|
if (instrux->FlagsAccess.Cleared.Raw)
|
|
_write_rflags(writer, instrux->FlagsAccess.Cleared, "cleared");
|
|
|
|
if (instrux->FlagsAccess.Undefined.Raw)
|
|
_write_rflags(writer, instrux->FlagsAccess.Undefined, "undefined");
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
|
|
StringBuffer instrux_to_json(INSTRUX *instrux, size_t rip, bool text_only /* = false */)
|
|
{
|
|
char text[ND_MIN_BUF_SIZE];
|
|
|
|
auto status = NdToText(instrux, rip, sizeof(text), text);
|
|
if (!ND_SUCCESS(status))
|
|
text[0] = 0;
|
|
|
|
auto s = StringBuffer {nullptr, 4096};
|
|
auto writer = Writer<StringBuffer> {s, nullptr};
|
|
|
|
_start_object(writer);
|
|
|
|
_write_string(writer, "text", text);
|
|
|
|
if (text_only) {
|
|
_end_object(writer);
|
|
return s;
|
|
}
|
|
|
|
_write_uint(writer, "def_code", _disasm_size_to_int(instrux->DefCode));
|
|
_write_uint(writer, "def_data", _disasm_size_to_int(instrux->DefData));
|
|
_write_uint(writer, "def_stack", _disasm_size_to_int(instrux->DefStack));
|
|
|
|
_write_string(writer, "enc_mode", enc_mode_to_str(instrux->EncMode));
|
|
|
|
_write_uint(writer, "addr_mode", _disasm_size_to_int(instrux->AddrMode));
|
|
_write_uint(writer, "op_mode", _disasm_size_to_int(instrux->OpMode));
|
|
_write_uint(writer, "ef_op_mode", _disasm_size_to_int(instrux->EfOpMode));
|
|
_write_uint(writer, "vec_mode", _disasm_size_to_int(instrux->VecMode) * 8);
|
|
_write_uint(writer, "ef_vec_mnode", _disasm_size_to_int(instrux->EfVecMode) * 8);
|
|
|
|
_write_rex(writer, instrux);
|
|
_write_modrm(writer, instrux);
|
|
_write_sib(writer, instrux);
|
|
_write_drex(writer, instrux);
|
|
_write_vex2(writer, instrux);
|
|
_write_vex3(writer, instrux);
|
|
_write_xop(writer, instrux);
|
|
_write_evex(writer, instrux);
|
|
|
|
if (instrux->Rep)
|
|
_write_uint(writer, "rep", instrux->Rep);
|
|
|
|
if (instrux->Seg)
|
|
_write_uint(writer, "seg", instrux->Seg);
|
|
|
|
_write_uint(writer, "stack_words", instrux->StackWords);
|
|
|
|
_write_exs(writer, instrux);
|
|
_write_prefixes(writer, instrux);
|
|
_write_chunks(writer, instrux);
|
|
|
|
if (instrux->IsRepeated)
|
|
_write_bool(writer, "is_repeated", true);
|
|
|
|
if (instrux->IsXacquireEnabled)
|
|
_write_bool(writer, "is_xacquire_enabled", true);
|
|
|
|
if (instrux->IsXreleaseEnabled)
|
|
_write_bool(writer, "is_xrelease_enabled", true);
|
|
|
|
if (instrux->IsRipRelative)
|
|
_write_bool(writer, "is_rip_relative", true);
|
|
|
|
if (instrux->IsCetTracked)
|
|
_write_bool(writer, "is_cet_tracked", true);
|
|
|
|
if (instrux->HasMandatory66)
|
|
_write_bool(writer, "mandatory_66", true);
|
|
|
|
if (instrux->HasMandatoryF2)
|
|
_write_bool(writer, "mandatory_f2", true);
|
|
|
|
if (instrux->HasMandatoryF3)
|
|
_write_bool(writer, "mandatory_f3", true);
|
|
|
|
_write_uint(writer, "length", instrux->Length);
|
|
_write_uint(writer, "word_length", static_cast<uint32_t>(instrux->WordLength));
|
|
_write_uint(writer, "pref_length", static_cast<uint32_t>(instrux->PrefLength));
|
|
|
|
_start_object(writer, "address");
|
|
|
|
_write_uint(writer, "ip", instrux->Address.Ip);
|
|
_write_uint(writer, "cs", instrux->Address.Cs);
|
|
|
|
_end_object(writer);
|
|
|
|
_write_uint(writer, "op_offset", static_cast<uint8_t>(instrux->OpOffset));
|
|
_write_uint(writer, "main_op_offset", static_cast<uint8_t>(instrux->MainOpOffset));
|
|
|
|
if (instrux->HasAddr) {
|
|
_start_object(writer, "addr");
|
|
|
|
_write_uint(writer, "len", static_cast<uint8_t>(instrux->AddrLength));
|
|
_write_uint(writer, "offset", static_cast<uint8_t>(instrux->AddrOffset));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
if (instrux->HasMoffset) {
|
|
_start_object(writer, "moffset");
|
|
|
|
_write_uint64(writer, "value", instrux->Moffset);
|
|
_write_uint(writer, "len", static_cast<uint8_t>(instrux->MoffsetLength));
|
|
_write_uint(writer, "offset", static_cast<uint8_t>(instrux->MoffsetOffset));
|
|
|
|
_end_object(writer);
|
|
};
|
|
|
|
if (instrux->HasDisp) {
|
|
_start_object(writer, "displacement");
|
|
|
|
_write_uint(writer, "value", instrux->Displacement);
|
|
_write_uint(writer, "len", static_cast<uint8_t>(instrux->DispLength));
|
|
_write_uint(writer, "offset", static_cast<uint8_t>(instrux->DispOffset));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
if (instrux->HasRelOffs) {
|
|
_start_object(writer, "relative_offset");
|
|
|
|
_write_uint(writer, "value", instrux->RelativeOffset);
|
|
_write_uint(writer, "len", static_cast<uint8_t>(instrux->RelOffsLength));
|
|
_write_uint(writer, "offset", static_cast<uint8_t>(instrux->RelOffsOffset));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
if (instrux->HasImm1) {
|
|
_start_object(writer, "immediate1");
|
|
|
|
_write_uint64(writer, "value", instrux->Immediate1);
|
|
_write_uint(writer, "len", static_cast<uint8_t>(instrux->Imm1Length));
|
|
_write_uint(writer, "offset", static_cast<uint8_t>(instrux->Imm1Offset));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
if (instrux->HasImm2) {
|
|
_start_object(writer, "immediate2");
|
|
|
|
_write_uint(writer, "value", instrux->Immediate2);
|
|
_write_uint(writer, "len", static_cast<uint8_t>(instrux->Imm2Length));
|
|
_write_uint(writer, "offset", static_cast<uint8_t>(instrux->Imm2Offset));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
if (instrux->HasImm3) {
|
|
_start_object(writer, "immediate3");
|
|
|
|
_write_uint(writer, "value", instrux->Immediate3);
|
|
_write_uint(writer, "len", static_cast<uint8_t>(instrux->Imm3Length));
|
|
_write_uint(writer, "offset", static_cast<uint8_t>(instrux->Imm3Offset));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
if (instrux->HasSseImm) {
|
|
_start_object(writer, "sse_immediate");
|
|
|
|
_write_uint(writer, "value", instrux->SseImmediate);
|
|
_write_uint(writer, "offset", static_cast<uint8_t>(instrux->SseImmOffset));
|
|
|
|
_end_object(writer);
|
|
}
|
|
|
|
_write_uint(writer, "sse_condition", instrux->SseCondition);
|
|
_write_uint(writer, "condition", instrux->Condition);
|
|
|
|
_write_uint(writer, "operands_count", instrux->OperandsCount);
|
|
_write_uint(writer, "exp_operands_count", instrux->ExpOperandsCount);
|
|
_write_uint(writer, "operands_encoding_map", instrux->OperandsEncodingMap);
|
|
|
|
_write_operands(writer, instrux);
|
|
|
|
_write_access(writer, "rip_access", instrux->RipAccess);
|
|
_write_access(writer, "memory_access", instrux->MemoryAccess);
|
|
_write_access(writer, "stack_access", instrux->StackAccess);
|
|
|
|
_write_flags_access(writer, instrux);
|
|
|
|
_write_uint(writer, "attributes", instrux->Attributes);
|
|
|
|
_write_string(writer, "class", ins_class_to_str(instrux->Iclass));
|
|
_write_string(writer, "category", ins_cat_to_str(instrux->Category));
|
|
_write_string(writer, "set", ins_set_to_str(instrux->IsaSet));
|
|
|
|
_write_cpuid_flag(writer, instrux->CpuidFlag);
|
|
|
|
_write_valid_modes(writer, instrux->ValidModes);
|
|
_write_valid_prefixes(writer, instrux->ValidPrefixes);
|
|
_write_valid_decorators(writer, instrux->ValidDecorators);
|
|
|
|
_write_string(writer, "mnemonic", instrux->Mnemonic);
|
|
|
|
_start_array(writer, "opcode_bytes");
|
|
|
|
for (int i = 0; i < instrux->OpLength; i++)
|
|
_write_uint(writer, instrux->OpCodeBytes[i]);
|
|
|
|
_end_array(writer);
|
|
|
|
_write_uint(writer, "primary_opcode", instrux->PrimaryOpCode);
|
|
|
|
_start_array(writer, "bytes");
|
|
|
|
for (int i = 0; i < instrux->Length; i++)
|
|
_write_uint(writer, instrux->InstructionBytes[i]);
|
|
|
|
_end_array(writer);
|
|
|
|
_end_object(writer);
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
StringBuffer byte_to_json(uint8_t byte, size_t rip)
|
|
{
|
|
auto s = StringBuffer {nullptr, 64};
|
|
auto writer = Writer<StringBuffer> {s, nullptr};
|
|
|
|
_start_object(writer);
|
|
|
|
_write_uint(writer, "byte", byte);
|
|
_write_uint(writer, "length", 1);
|
|
_write_uint64(writer, "rip", rip);
|
|
|
|
_end_object(writer);
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
const char *json_to_string(StringBuffer &j)
|
|
{
|
|
return j.GetString();
|
|
}
|