You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bddisasm/pybddisasm/_pybddisasm/_pybddisasm.c

1199 lines
41 KiB

/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#define _SIGNAL_H
#include <Python.h>
#include <assert.h>
#include "pybddisasm.h"
static char module_docstring[] = "This module provides an interface for bddisasm.";
static char pybddisasm_decode_ex_docstring[] = "Disasemble at the provided address.";
static char pybddisasm_decode_ex2_docstring[] = "Disasemble at the provided address.";
static char pybddisasm_decode_docstring[] = "Disasemble at the provided address.";
static char pybddisasm_to_text_docstring[] = "Disasemble at the provided address and give back only the text.";
static char *OperandTypeToString(ND_OPERAND_TYPE Type)
{
switch (Type)
{
case ND_OP_NOT_PRESENT: return "not_present";
case ND_OP_REG: return "reg";
case ND_OP_MEM: return "mem";
case ND_OP_IMM: return "imm";
case ND_OP_OFFS: return "offs";
case ND_OP_ADDR: return "addr";
case ND_OP_CONST: return "const";
case ND_OP_BANK: return "bank";
}
return "unknown";
}
static char *OperandEncodingToString(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_D: return "D";
case ND_OPE_O: return "O";
case ND_OPE_I: return "I";
case ND_OPE_C: return "C";
case ND_OPE_1: return "1";
case ND_OPE_L: return "L";
case ND_OPE_A: return "A";
case ND_OPE_E: return "E";
case ND_OPE_S: return "S";
}
return "unknown";
}
static char *RegTypeToString(ND_REG_TYPE RegType)
{
switch (RegType)
{
case ND_REG_NOT_PRESENT: return "NOT_PRESENT";
case ND_REG_GPR: return "GPR";
case ND_REG_SEG: return "SEG";
case ND_REG_FPU: return "FPU";
case ND_REG_MMX: return "MMX";
case ND_REG_SSE: return "SSE";
case ND_REG_CR: return "CR";
case ND_REG_DR: return "DR";
case ND_REG_TR: return "TR";
case ND_REG_BND: return "BND";
case ND_REG_MSK: return "MSK";
case ND_REG_TILE: return "TILE";
case ND_REG_MSR: return "MSR";
case ND_REG_XCR: return "XCR";
case ND_REG_SYS: return "SYS";
case ND_REG_X87: return "X87";
case ND_REG_MXCSR: return "MXCSR";
case ND_REG_PKRU: return "PKRU";
case ND_REG_SSP: return "SSP";
case ND_REG_FLG: return "FLG";
case ND_REG_RIP: return "RIP";
case ND_REG_UIF: return "UIF";
}
return "unknown";
}
static char *TupleTypeToString(ND_TUPLE TupleType)
{
switch (TupleType)
{
case ND_TUPLE_None: return "None";
case ND_TUPLE_FV: return "FV";
case ND_TUPLE_HV: return "HV";
case ND_TUPLE_T1S8: return "T1S8";
case ND_TUPLE_T1S16: return "T1S16";
case ND_TUPLE_T1S: return "T1S";
case ND_TUPLE_T1F: return "T1F";
case ND_TUPLE_T2: return "T2";
case ND_TUPLE_T4: return "T4";
case ND_TUPLE_T8: return "T8";
case ND_TUPLE_FVM: return "FVM";
case ND_TUPLE_HVM: return "HVM";
case ND_TUPLE_QVM: return "QVM";
case ND_TUPLE_OVM: return "OVM";
case ND_TUPLE_M128: return "M128";
case ND_TUPLE_DUP: return "DUP";
case ND_TUPLE_T1_4X: return "4X";
}
return "unknown";
}
static char *RoundingModeToString(ND_ROUNDING RoundingMode)
{
switch (RoundingMode)
{
case ND_RND_RNE: return "RNE";
case ND_RND_RD: return "RD";
case ND_RND_RU: return "RU";
case ND_RND_RZ: return "RZ";
}
return "unknown";
}
static PyObject *_pybddisasm_build_rex(ND_REX *rex)
{
return Py_BuildValue("{s,B, s,B, s,B, s,B, s,B}",
"Rex", rex->Rex,
"b", rex->b,
"x", rex->x,
"r", rex->r,
"w", rex->w);
}
static PyObject *_pybddisasm_build_modrm(ND_MODRM *modrm)
{
return Py_BuildValue("{s,B, s,B, s,B, s,B}",
"ModRm", modrm->ModRm,
"rm", modrm->rm,
"reg", modrm->reg,
"mod", modrm->mod);
}
static PyObject *_pybddisasm_build_sib(ND_SIB *sib)
{
return Py_BuildValue("{s,B, s,B, s,B, s,B}",
"Sib", sib->Sib,
"base", sib->base,
"index", sib->index,
"scale", sib->scale);
}
static PyObject *_pybddisasm_build_drex(ND_DREX *drex)
{
return Py_BuildValue("{s,B, s,B, s,B, s,B, s,B, s,B, s,B}",
"Drex", drex->Drex,
"b", drex->b,
"x", drex->x,
"r", drex->r,
"oc0", drex->oc0,
"vd", drex->vd,
"d", drex->d);
}
static PyObject *_pybddisasm_build_op_access(ND_OPERAND_ACCESS *access)
{
return Py_BuildValue("{s,B, s,B, s,B, s,B, s,B}",
"Access", access->Access,
"Read", access->Read,
"Write", access->Write,
"CondRead", access->CondRead,
"CondWrite", access->CondWrite);
}
static PyObject *_pybddisasm_build_op_flags(ND_OPERAND_FLAGS *flags)
{
return Py_BuildValue("{s,B, s,B, s,B, s,B}",
"Flags", flags->Flags,
"IsDefault", flags->IsDefault,
"SignExtendedOp1", flags->SignExtendedOp1,
"SignExtendedDws", flags->SignExtendedDws);
}
static PyObject *_pybddisasm_build_op_reg(ND_OPDESC_REGISTER *reg)
{
return Py_BuildValue("{s,s, s,B, s,I, s,I}",
"Type", RegTypeToString(reg->Type),
"Size", reg->Size,
"Reg", reg->Reg,
"Count", reg->Count);
}
static PyObject *_pybddisasm_build_op_memory(ND_OPDESC_MEMORY *mem)
{
PyObject *nd_vsib = Py_BuildValue("{s,B, s,B, s,B}",
"IndexSize", mem->Vsib.IndexSize,
"ElemSize", mem->Vsib.ElemSize,
"ElemCount", mem->Vsib.ElemCount);
PyObject *p = Py_BuildValue("{"
"s,B," // HasSeg
"s,B," // HasBase
"s,B," // HasIndex
"s,B," // HasDisp
"s,B," // HasCompDisp
"s,B," // HasBroadcast
"s,B," // IsRipRel
"s,B," // IsStack
"s,B," // IsShadowStack
"s,B," // IsDirect
"s,B," // IsBitbase
"s,B," // IsAG
"s,B," // IsMib
"s,B," // IsVsib
"s,B," // BaseSize
"s,B," // IndexSize
"s,B," // DispSize
"s,B," // CompDispSize
"s,O," // Vsib
"s,B," // Seg
"s,B," // Base
"s,B," // Index
"s,B," // Scale
"s,K" // Disp
"}",
"HasSeg", mem->HasSeg,
"HasBase", mem->HasBase,
"HasIndex", mem->HasIndex,
"HasDisp", mem->HasDisp,
"HasCompDisp", mem->HasCompDisp,
"HasBroadcast", mem->HasBroadcast,
"IsRipRel", mem->IsRipRel,
"IsStack", mem->IsStack,
"IsShadowStack", mem->IsShadowStack,
"IsDirect", mem->IsDirect,
"IsBitbase", mem->IsBitbase,
"IsAG", mem->IsAG,
"IsMib", mem->IsMib,
"IsVsib", mem->IsVsib,
"BaseSize", mem->BaseSize,
"IndexSize", mem->IndexSize,
"DispSize", mem->DispSize,
"CompDispSize", mem->CompDispSize,
"Vsib", nd_vsib,
"Seg", mem->Seg,
"Base", mem->Base,
"Index", mem->Index,
"Scale", mem->Index,
"Disp", mem->Disp);
Py_XDECREF(nd_vsib);
return p;
}
static PyObject *_pybddisasm_build_op_immediate(ND_OPDESC_IMMEDIATE *imm)
{
return Py_BuildValue("{s,K}", "Imm", imm->Imm);
}
static PyObject *_pybddisasm_build_op_rel_offset(ND_OPDESC_RELOFFSET *rel_offset)
{
return Py_BuildValue("{s,K}", "Rel", rel_offset->Rel);
}
static PyObject *_pybddisasm_build_op_address(ND_OPDESC_ADDRESS *address)
{
return Py_BuildValue("{s,H, s,K}",
"BaseSeg", address->BaseSeg,
"Offset", address->Offset);
}
static PyObject *_pybddisasm_build_op_const(ND_OPDESC_CONSTANT *constant)
{
return Py_BuildValue("{s,K}", "Const", constant->Const);
}
static PyObject *_pybddisasm_build_operand(ND_OPERAND *operand)
{
PyObject *nd_access = _pybddisasm_build_op_access(&operand->Access);
PyObject *nd_flags = _pybddisasm_build_op_flags(&operand->Flags);
PyObject *nd_operand = NULL;
switch (operand->Type)
{
case ND_OP_REG:
nd_operand = _pybddisasm_build_op_reg(&operand->Info.Register);
break;
case ND_OP_MEM:
nd_operand = _pybddisasm_build_op_memory(&operand->Info.Memory);
break;
case ND_OP_IMM:
nd_operand = _pybddisasm_build_op_immediate(&operand->Info.Immediate);
break;
case ND_OP_OFFS:
nd_operand = _pybddisasm_build_op_rel_offset(&operand->Info.RelativeOffset);
break;
case ND_OP_ADDR:
nd_operand = _pybddisasm_build_op_address(&operand->Info.Address);
break;
case ND_OP_CONST:
nd_operand = _pybddisasm_build_op_const(&operand->Info.Constant);
break;
case ND_OP_BANK:
nd_operand = Py_BuildValue("{}");
break;
default:
PyErr_SetString(PyExc_RuntimeError, "invalid operand type...");
Py_RETURN_NONE;
}
PyObject *p = Py_BuildValue("{"
"s,s," // Type
"s,s," // Encoding
"s,I," // Size
"s,I," // RawSize
"s,O," // Access
"s,O," // Flags
"s,O" // Operand
"}",
"Type", OperandTypeToString(operand->Type),
"Encoding", OperandEncodingToString(operand->Encoding),
"Size", operand->Size,
"RawSize", operand->RawSize,
"Access", nd_access,
"Flags", nd_flags,
"Operand", nd_operand);
Py_XDECREF(nd_access);
Py_XDECREF(nd_flags);
Py_XDECREF(nd_operand);
return p;
}
static PyObject *_pybddisasm_build_operands(ND_OPERAND *operands, size_t count)
{
char op_str_format[1024] = {'[', 0};
size_t last = 1;
PyObject *nd_operands[ND_MAX_OPERAND] = {0};
size_t op;
for (op = 0; op < count && last < sizeof(op_str_format); op++)
{
if (op > 0)
{
op_str_format[last++] = ',';
}
op_str_format[last++] = 'O';
nd_operands[op] = _pybddisasm_build_operand(&operands[op]);
}
op_str_format[last] = ']';
PyObject *p = Py_BuildValue(op_str_format,
nd_operands[0],
nd_operands[1],
nd_operands[2],
nd_operands[3],
nd_operands[4],
nd_operands[5],
nd_operands[6],
nd_operands[7],
nd_operands[8],
nd_operands[9]);
for (size_t o = 0; o < op; o++)
{
Py_XDECREF(nd_operands[o]);
}
return p;
}
static PyObject *_pybddisasm_build_exs(INSTRUX *instr)
{
return Py_BuildValue("{"
"s,B," // w
"s,B," // r
"s,B," // x
"s,B," // b
"s,B," // rp
"s,B," // p
"s,B," // m
"s,B," // l
"s,B," // v
"s,B," // vp
"s,B," // bm
"s,B," // e
"s,B," // z
"s,B," // k
"s,B" // s
"}",
"w", instr->Exs.w,
"r", instr->Exs.r,
"x", instr->Exs.x,
"b", instr->Exs.b,
"rp", instr->Exs.rp,
"p", instr->Exs.p,
"m", instr->Exs.m,
"l", instr->Exs.l,
"v", instr->Exs.v,
"vp", instr->Exs.vp,
"bm", instr->Exs.bm,
"e", instr->Exs.e,
"z", instr->Exs.z,
"k", instr->Exs.k,
"s", instr->Exs.s);
}
static PyObject *_pybddisasm_build_address(INSTRUX *instr)
{
return Py_BuildValue("{s,I, s,H}",
"Ip", instr->Address.Ip,
"Cs", instr->Address.Cs);
}
static PyObject *_pybddisasm_build_cpuid_flag(ND_CPUID_FLAG *cpuid_flag)
{
return Py_BuildValue("{"
"s,K," // Flag
"s,I," // Leaf
"s,I," // SubLeaf
"s,B," // Reg
"s,B" // Bit
"}",
"Flag", cpuid_flag->Flag,
"Leaf", cpuid_flag->Leaf,
"SubLeaf", cpuid_flag->SubLeaf,
"Reg", cpuid_flag->Reg,
"Bit", cpuid_flag->Bit);
}
static PyObject *_pybddisasm_build_flags_access(INSTRUX *instr)
{
return Py_BuildValue("{"
"s,B," // RegAccess
"s,I," // Tested
"s,I," // Modified
"s,I," // Set
"s,I," // Cleared
"s,I" // Undefined
"}",
"RegAccess", instr->FlagsAccess.RegAccess,
"Tested", instr->FlagsAccess.Tested,
"Modified", instr->FlagsAccess.Modified,
"Set", instr->FlagsAccess.Set,
"Cleared", instr->FlagsAccess.Cleared,
"Undefined", instr->FlagsAccess.Undefined);
}
static PyObject *_pybddisasm_build_valid_modes(ND_VALID_MODES *valid_modes)
{
return Py_BuildValue("{"
"s,H," // Raw
"s,B," // Ring0
"s,B," // Ring1
"s,B," // Ring2
"s,B," // Ring3
"s,B," // Real
"s,B," // V8086
"s,B," // Protected
"s,B," // Compatibility
"s,B," // Long
"s,B," // Smm
"s,B," // Sgx
"s,B," // Tsx
"s,B," // VmxRoot
"s,B," // VmxNonRoot
"s,B" // VmxOff
"}",
"Raw", valid_modes->Raw,
"Ring0", valid_modes->Ring0,
"Ring1", valid_modes->Ring1,
"Ring2", valid_modes->Ring2,
"Ring3", valid_modes->Ring3,
"Real", valid_modes->Real,
"V8086", valid_modes->V8086,
"Protected", valid_modes->Protected,
"Compatibility", valid_modes->Compat,
"Long", valid_modes->Long,
"Smm", valid_modes->Smm,
"Sgx", valid_modes->Sgx,
"Tsx", valid_modes->Tsx,
"VmxRoot", valid_modes->VmxRoot,
"VmxNonRoot", valid_modes->VmxNonRoot,
"VmxOff", valid_modes->VmxOff);
}
static PyObject *_pybddisasm_build_valid_prefixes(ND_VALID_PREFIXES *valid_prefixes)
{
return Py_BuildValue("{"
"s,H," // Raw
"s,B," // Rep,
"s,B," // RepCond,
"s,B," // Lock,
"s,B," // Hle,
"s,B," // Xacquire,
"s,B," // Xrelease,
"s,B," // Bnd,
"s,B," // Bhint,
"s,B," // HleNoLock,
"s,B" // Dnt,
"}",
"Raw", valid_prefixes->Raw,
"Rep", valid_prefixes->Rep,
"RepCond", valid_prefixes->RepCond,
"Lock", valid_prefixes->Lock,
"Hle", valid_prefixes->Hle,
"Xacquire", valid_prefixes->Xacquire,
"Xrelease", valid_prefixes->Xrelease,
"Bnd", valid_prefixes->Bnd,
"Bhint", valid_prefixes->Bhint,
"HleNoLock", valid_prefixes->HleNoLock,
"Dnt", valid_prefixes->Dnt);
}
static PyObject *_pybddisasm_build_valid_decorators(ND_VALID_DECORATORS *valid_deorators)
{
return Py_BuildValue("{"
"s,H," // Raw
"s,B," // Er
"s,B," // Sae
"s,B," // Zero
"s,B," // Mask
"s,B" // Broadcast
"}",
"Raw", valid_deorators->Raw,
"Er", valid_deorators->Er,
"Sae", valid_deorators->Sae,
"Zero", valid_deorators->Zero,
"Mask", valid_deorators->Mask,
"Broadcast", valid_deorators->Broadcast);
}
static PyObject *_pybddisasm_build_instr_dict(INSTRUX *instr, uint64_t rip)
{
PyObject *nd_rex = _pybddisasm_build_rex(&instr->Rex);
PyObject *nd_modrm = _pybddisasm_build_modrm(&instr->ModRm);
PyObject *nd_sib = _pybddisasm_build_sib(&instr->Sib);
PyObject *nd_drex = _pybddisasm_build_drex(&instr->Drex);
PyObject *nd_op_array = _pybddisasm_build_operands(instr->Operands, instr->OperandsCount);
PyObject *nd_exs = _pybddisasm_build_exs(instr);
PyObject *nd_address = _pybddisasm_build_address(instr);
PyObject *nd_cpuid_flag = _pybddisasm_build_cpuid_flag(&instr->CpuidFlag);
PyObject *nd_valid_modes = _pybddisasm_build_valid_modes(&instr->ValidModes);
PyObject *nd_valid_prefixes = _pybddisasm_build_valid_prefixes(&instr->ValidPrefixes);
PyObject *nd_valid_decorators = _pybddisasm_build_valid_decorators(&instr->ValidDecorators);
char instr_text[ND_MIN_BUF_SIZE] = {0};
NDSTATUS status = nd_to_text(instr, rip, sizeof(instr_text), instr_text);
if (!ND_SUCCESS(status))
{
strcpy(instr_text, "<error decoding>");
}
PyObject *nd_flags_access = _pybddisasm_build_flags_access(instr);
PyObject *p = Py_BuildValue("{"
"s,B," // DefCode
"s,B," // DefData
"s,B," // DefStack
"s,B," // EncMode
"s,B," // VexMode
"s,B," // AddrMode,
"s,B," // OpMode,
"s,B," // EfOpMode,
"s,B," // VecMode,
"s,B," // EfVecMode,
"s,B," // HasRex,
"s,B," // HasVex,
"s,B," // HasXop,
"s,B," // HasEvex,
"s,B," // HasOpSize,
"s,B," // HasAddrSize,
"s,B," // HasLock,
"s,B," // HasRepnzXacquireBnd,
"s,B," // HasRepRepzXrelease,
"s,B," // HasSeg,
"s,B," // IsRepeated,
"s,B," // IsXacquireEnabled,
"s,B," // IsXreleaseEnabled,
"s,B," // IsRipRelative,
"s,B," // IsCetTracked,
"s,B," // HasModRm,
"s,B," // HasSib,
"s,B," // HasDrex,
"s,B," // HasDisp,
"s,B," // HasAddr,
"s,B," // HasMoffset,
"s,B," // HasImm1,
"s,B," // HasImm2,
"s,B," // HasImm3,
"s,B," // HasRelOffs,
"s,B," // HasSseImm,
"s,B," // HasCompDisp,
"s,B," // HasBroadcast,
"s,B," // HasMask,
"s,B," // HasZero,
"s,B," // HasEr,
"s,B," // HasSae,
"s,B," // SignDisp,
"s,B," // HasMandatory66,
"s,B," // HasMandatoryF2,
"s,B," // HasMandatoryF3,
"s,B," // Length,
"s,B," // WordLength,
"s,B," // PrefLength,
"s,B," // OpLength,
"s,B," // DispLength,
"s,B," // AddrLength,
"s,B," // MoffsetLength,
"s,B," // Imm1Length,
"s,B," // Imm2Length,
"s,B," // Imm3Length,
"s,B," // RelOffsLength,
"s,B," // OpOffset,
"s,B," // MainOpOffset,
"s,B," // DispOffset,
"s,B," // AddrOffset,
"s,B," // MoffsetOffset,
"s,B," // Imm1Offset,
"s,B," // Imm2Offset,
"s,B," // Imm3Offset,
"s,B," // RelOffsOffset,
"s,B," // SseImmOffset,
"s,B," // ModRmOffset,
"s,B," // StackWords,
"s,B," // Rep,
"s,B," // Seg,
"s,O," // Rex,
"s,O," // ModRm,
"s,O," // Sib,
"s,O," // Drex,
"s,O," // Exs,
"s,O," // Address,
"s,K," // Moffset,
"s,I," // Displacement,
"s,I," // RelativeOffset,
"s,K," // Immediate1,
"s,B," // Immediate2,
"s,B," // Immediate3,
"s,B," // SseImmediate,
"s,B," // SseCondition,
"s,B," // Condition,
"s,B," // Predicate,
"s,B," // OperandsCount,
"s,B," // ExpOperandsCount,
"s,H," // OperandsEncodingMap,
"s,O," // Operands,
"s,B," // RipAccess,
"s,B," // StackAccess,
"s,B," // MemoryAccess,
"s,O," // FlagsAccess,
"s,s," // TupleType,
"s,s," // RoundingMode,
"s,I," // Attributes,
"s,I," // Iclass,
"s,I," // Category,
"s,I," // IsaSet,
"s,O," // CpuidFlag,
"s,O," // ValidModes,
"s,O," // ValidPrefixes,
"s,O," // ValidDecorators,
"s,s," // Mnemonic,
"s,y#," // OpCodeBytes,
"s,B," // PrimaryOpCode,
"s,y#," // InstructionBytes,
"s,s" // NdToText
"}",
"DefCode", instr->DefCode,
"DefData", instr->DefData,
"DefStack", instr->DefStack,
"EncMode", instr->EncMode,
"VexMode", instr->VexMode,
"AddrMode", instr->AddrMode,
"OpMode", instr->OpMode,
"EfOpMode", instr->EfOpMode,
"VecMode", instr->VecMode,
"EfVecMode", instr->EfVecMode,
"HasRex", instr->HasRex,
"HasVex", instr->HasVex,
"HasXop", instr->HasXop,
"HasEvex", instr->HasEvex,
"HasOpSize", instr->HasOpSize,
"HasAddrSize", instr->HasAddrSize,
"HasLock", instr->HasLock,
"HasRepnzXacquireBnd", instr->HasRepnzXacquireBnd,
"HasRepRepzXrelease", instr->HasRepRepzXrelease,
"HasSeg", instr->HasSeg,
"IsRepeated", instr->IsRepeated,
"IsXacquireEnabled", instr->IsXacquireEnabled,
"IsXreleaseEnabled", instr->IsXreleaseEnabled,
"IsRipRelative", instr->IsRipRelative,
"IsCetTracked", instr->IsCetTracked,
"HasModRm", instr->HasModRm,
"HasSib", instr->HasSib,
"HasDrex", instr->HasDrex,
"HasDisp", instr->HasDisp,
"HasAddr", instr->HasAddr,
"HasMoffset", instr->HasMoffset,
"HasImm1", instr->HasImm1,
"HasImm2", instr->HasImm2,
"HasImm3", instr->HasImm3,
"HasRelOffs", instr->HasRelOffs,
"HasSseImm", instr->HasSseImm,
"HasCompDisp", instr->HasCompDisp,
"HasBroadcast", instr->HasBroadcast,
"HasMask", instr->HasMask,
"HasZero", instr->HasZero,
"HasEr", instr->HasEr,
"HasSae", instr->HasSae,
"SignDisp", instr->SignDisp,
"HasMandatory66", instr->HasMandatory66,
"HasMandatoryF2", instr->HasMandatoryF2,
"HasMandatoryF3", instr->HasMandatoryF3,
"Length", instr->Length,
"WordLength", instr->WordLength,
"PrefLength", instr->PrefLength,
"OpLength", instr->OpLength,
"DispLength", instr->DispLength,
"AddrLength", instr->AddrLength,
"MoffsetLength", instr->MoffsetLength,
"Imm1Length", instr->Imm1Length,
"Imm2Length", instr->Imm2Length,
"Imm3Length", instr->Imm3Length,
"RelOffsLength", instr->RelOffsLength,
"OpOffset", instr->OpOffset,
"MainOpOffset", instr->MainOpOffset,
"DispOffset", instr->DispOffset,
"AddrOffset", instr->AddrOffset,
"MoffsetOffset", instr->MoffsetOffset,
"Imm1Offset", instr->Imm1Offset,
"Imm2Offset", instr->Imm2Offset,
"Imm3Offset", instr->Imm3Offset,
"RelOffsOffset", instr->RelOffsOffset,
"SseImmOffset", instr->SseImmOffset,
"ModRmOffset", instr->ModRmOffset,
"StackWords", instr->StackWords,
"Rep", instr->Rep,
"Seg", instr->Seg,
"Rex", nd_rex,
"ModRm", nd_modrm,
"Sib", nd_sib,
"Drex", nd_drex,
"Exs", nd_exs,
"Address", nd_address,
"Moffset", instr->Moffset,
"Displacement", instr->Displacement,
"RelativeOffset", instr->RelativeOffset,
"Immediate1", instr->Immediate1,
"Immediate2", instr->Immediate2,
"Immediate3", instr->Immediate3,
"SseImmediate", instr->SseImmediate,
"SseCondition", instr->SseCondition,
"Condition", instr->Condition,
"Predicate", instr->Predicate,
"OperandsCount", instr->OperandsCount,
"ExpOperandsCount", instr->ExpOperandsCount,
"OperandsEncodingMap", instr->OperandsEncodingMap,
"Operands", nd_op_array,
"RipAccess", instr->RipAccess,
"StackAccess", instr->StackAccess,
"MemoryAccess", instr->MemoryAccess,
"FlagsAccess", nd_flags_access,
"TupleType", TupleTypeToString(instr->TupleType),
"RoundingMode", RoundingModeToString(instr->RoundingMode),
"Attributes", instr->Attributes,
"Iclass", instr->Iclass,
"Category", instr->Category,
"IsaSet", instr->IsaSet,
"CpuidFlag", nd_cpuid_flag,
"ValidModes", nd_valid_modes,
"ValidPrefixes", nd_valid_prefixes,
"ValidDecorators", nd_valid_decorators,
"Mnemonic", instr->Mnemonic,
"OpCodeBytes", instr->OpCodeBytes, sizeof(instr->OpCodeBytes),
"PrimaryOpCode", instr->PrimaryOpCode,
"InstructionBytes", instr->InstructionBytes, instr->Length,
"Text", instr_text);
Py_XDECREF(nd_rex);
Py_XDECREF(nd_modrm);
Py_XDECREF(nd_sib);
Py_XDECREF(nd_drex);
Py_XDECREF(nd_op_array);
Py_XDECREF(nd_exs);
Py_XDECREF(nd_address);
Py_XDECREF(nd_cpuid_flag);
Py_XDECREF(nd_valid_modes);
Py_XDECREF(nd_valid_prefixes);
Py_XDECREF(nd_valid_decorators);
Py_XDECREF(nd_flags_access);
return p;
}
static uint8_t _pybddisasm_py_code_to_disasm(uint8_t code)
{
if (16 == code)
{
return ND_CODE_16;
}
else if (32 == code)
{
return ND_CODE_32;
}
else if (64 == code)
{
return ND_CODE_64;
}
PyErr_Format(PyExc_ValueError, "Invalid code: %d (expected 16|32|64)\n", code);
return 0;
}
static uint8_t _pybddisasm_py_data_to_disasm(uint8_t data)
{
if (16 == data)
{
return ND_DATA_16;
}
else if (32 == data)
{
return ND_DATA_32;
}
else if (64 == data)
{
return ND_DATA_64;
}
PyErr_Format(PyExc_ValueError, "Invalid data: %d (expected 16|32|64)\n", data);
return 0;
}
static uint8_t _pybddisasm_py_stack_to_disasm(uint8_t stack)
{
if (16 == stack)
{
return ND_STACK_16;
}
else if (32 == stack)
{
return ND_STACK_32;
}
else if (64 == stack)
{
return ND_STACK_64;
}
PyErr_Format(PyExc_ValueError, "Invalid stack: %d (expected 16|32|64)\n", stack);
return 0;
}
static char *_pybddisasm_get_contiguous_buffer(Py_buffer *view)
{
char *buffer = NULL;
if (PyBuffer_IsContiguous(view, 'C'))
{
return view->buf;
}
buffer = (char *)malloc(sizeof(char) * view->len);
if (!buffer)
{
PyErr_SetString(PyExc_ValueError, "failed to allocate memory for contiguous buffer!");
return NULL;
}
if (PyBuffer_ToContiguous(buffer, view, view->len, 'C') < 0)
{
PyErr_SetString(PyExc_ValueError, "PyBuffer_ToContiguous failed!");
free(buffer);
return NULL;
}
return buffer;
}
static void _pybddisasm_release_contiguous_buffer(Py_buffer *view, char *buffer)
{
if (!PyBuffer_IsContiguous(view, 'C'))
{
free(buffer);
}
}
static PyObject *pybddisasm_decode_ex(PyObject *self, PyObject *args)
{
char *buffer = NULL;
uint64_t rip = 0;
uint8_t code, data;
Py_buffer view;
(void)self;
if (!PyArg_ParseTuple(args, "y*BB|K", &view, &code, &data, &rip))
{
PyErr_SetString(PyExc_ValueError, "invalid arguments. expected: <buffer[byte-like object]> <code> <data> <rip>");
Py_RETURN_NONE;
}
buffer = _pybddisasm_get_contiguous_buffer(&view);
if (!buffer)
{
Py_RETURN_NONE;
}
code = _pybddisasm_py_code_to_disasm(code);
data = _pybddisasm_py_data_to_disasm(data);
if (PyErr_Occurred())
{
Py_RETURN_NONE;
}
INSTRUX instr;
NDSTATUS status = nd_decode_ex(&instr, buffer, view.len, code, data);
if (!ND_SUCCESS(status))
{
Py_RETURN_NONE;
}
_pybddisasm_release_contiguous_buffer(&view, buffer);
PyBuffer_Release(&view);
return _pybddisasm_build_instr_dict(&instr, rip);
}
static PyObject *pybddisasm_decode_ex2(PyObject *self, PyObject *args)
{
char *str_vend = NULL;
char *buffer = NULL;
uint64_t rip = 0;
uint8_t code, data, stack, vend;
Py_buffer view;
(void)self;
if (!PyArg_ParseTuple(args, "y*BBBs|K", &view, &code, &data, &stack, &str_vend, &rip))
{
PyErr_SetString(PyExc_ValueError, "invalid arguments. expected: <buffer[byte-like object]> <code> <data> <stack> <vendor> <rip>");
Py_RETURN_NONE;
}
buffer = _pybddisasm_get_contiguous_buffer(&view);
if (!buffer)
{
Py_RETURN_NONE;
}
if (0 == strcmp(str_vend, "any"))
{
vend = ND_VEND_ANY;
}
else if (0 == strcmp(str_vend, "intel"))
{
vend = ND_VEND_INTEL;
}
else if (0 == strcmp(str_vend, "amd"))
{
vend = ND_VEND_AMD;
}
else if (0 == strcmp(str_vend, "geode"))
{
vend = ND_VEND_GEODE;
}
else if (0 == strcmp(str_vend, "cyrix"))
{
vend = ND_VEND_CYRIX;
}
else
{
PyErr_Format(PyExc_ValueError, "invalid vendor: '%s'", str_vend);
Py_RETURN_NONE;
}
code = _pybddisasm_py_code_to_disasm(code);
data = _pybddisasm_py_data_to_disasm(data);
stack = _pybddisasm_py_stack_to_disasm(stack);
if (PyErr_Occurred())
{
Py_RETURN_NONE;
}
INSTRUX instr;
NDSTATUS status = nd_decode_ex2(&instr, buffer, view.len, code, data, stack, vend);
if (!ND_SUCCESS(status))
{
Py_RETURN_NONE;
}
_pybddisasm_release_contiguous_buffer(&view, buffer);
PyBuffer_Release(&view);
return _pybddisasm_build_instr_dict(&instr, rip);
}
static PyObject *pybddisasm_to_text(PyObject *self, PyObject *args)
{
char *buffer = NULL;
uint64_t rip = 0;
uint8_t code, data;
Py_buffer view;
(void)self;
if (!PyArg_ParseTuple(args, "y*BB|K", &view, &code, &data, &rip))
{
PyErr_SetString(PyExc_ValueError, "invalid arguments. expected: <buffer[byte-like object]> <code> <data> <rip>");
Py_RETURN_NONE;
}
buffer = _pybddisasm_get_contiguous_buffer(&view);
if (!buffer)
{
Py_RETURN_NONE;
}
code = _pybddisasm_py_code_to_disasm(code);
data = _pybddisasm_py_data_to_disasm(data);
if (PyErr_Occurred())
{
Py_RETURN_NONE;
}
INSTRUX instr;
NDSTATUS status = nd_decode_ex(&instr, buffer, view.len, code, data);
if (!ND_SUCCESS(status))
{
Py_RETURN_NONE;
}
char instr_text[ND_MIN_BUF_SIZE] = {0};
status = nd_to_text(&instr, rip, sizeof(instr_text), instr_text);
if (!ND_SUCCESS(status))
{
Py_RETURN_NONE;
}
_pybddisasm_release_contiguous_buffer(&view, buffer);
PyBuffer_Release(&view);
return Py_BuildValue("{s,s,s,y#}", "text", instr_text, "bytes", instr.InstructionBytes, instr.Length);
}
static PyMethodDef module_methods[] = {
{"nd_decode_ex", pybddisasm_decode_ex, METH_VARARGS, pybddisasm_decode_ex_docstring},
{"nd_decode_ex2", pybddisasm_decode_ex2, METH_VARARGS, pybddisasm_decode_ex2_docstring},
{"nd_decode", pybddisasm_decode_ex, METH_VARARGS, pybddisasm_decode_docstring},
{"nd_to_text", pybddisasm_to_text, METH_VARARGS, pybddisasm_to_text_docstring},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef pybddisasm =
{
PyModuleDef_HEAD_INIT,
"pybddisasm", // name of module
module_docstring,
-1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables
module_methods
};
PyMODINIT_FUNC PyInit__pybddisasm(void)
{
static_assert(sizeof(INSTRUX) == LIBRARY_INSTRUX_SIZE, "The size of INSTRUX is not compatible with pybddisasm!");
return PyModule_Create(&pybddisasm);
}