From 4f182b2c11e83927212ec8ed16bc0decb7da38aa Mon Sep 17 00:00:00 2001 From: Andrei KISARI Date: Thu, 22 Jun 2023 14:54:41 +0300 Subject: [PATCH] Use SWIG to create bindings between C and Python. --- bindings/pybddisasm/LICENSE | 2 +- bindings/pybddisasm/MANIFEST.in | 4 + bindings/pybddisasm/README.md | 18 +- bindings/pybddisasm/_pybddisasm/_pybddisasm.c | 1199 ----------------- bindings/pybddisasm/_pybddisasm/pybddisasm.c | 24 - bindings/pybddisasm/_pybddisasm/pybddisasm.h | 20 - bindings/pybddisasm/pybddisasm/__init__.py | 5 +- bindings/pybddisasm/pybddisasm/__main__.py | 11 - bindings/pybddisasm/pybddisasm/app.py | 15 - bindings/pybddisasm/pybddisasm/bddisasm.py | 71 - bindings/pybddisasm/pybddisasm/core.py | 52 - bindings/pybddisasm/pybddisasm/helpers.py | 156 --- bindings/pybddisasm/pybddisasm/pybddisasm.c | 96 ++ bindings/pybddisasm/pybddisasm/pybddisasm.h | 25 + bindings/pybddisasm/pybddisasm/pybddisasm.i | 177 +++ bindings/pybddisasm/setup.py | 67 +- bindings/pybddisasm/tests/nd_decode.py | 125 ++ bindings/pybddisasm/tests/nd_get_version.py | 26 + 18 files changed, 505 insertions(+), 1588 deletions(-) delete mode 100644 bindings/pybddisasm/_pybddisasm/_pybddisasm.c delete mode 100644 bindings/pybddisasm/_pybddisasm/pybddisasm.c delete mode 100644 bindings/pybddisasm/_pybddisasm/pybddisasm.h delete mode 100644 bindings/pybddisasm/pybddisasm/__main__.py delete mode 100644 bindings/pybddisasm/pybddisasm/app.py delete mode 100644 bindings/pybddisasm/pybddisasm/bddisasm.py delete mode 100644 bindings/pybddisasm/pybddisasm/core.py delete mode 100644 bindings/pybddisasm/pybddisasm/helpers.py create mode 100644 bindings/pybddisasm/pybddisasm/pybddisasm.c create mode 100644 bindings/pybddisasm/pybddisasm/pybddisasm.h create mode 100644 bindings/pybddisasm/pybddisasm/pybddisasm.i create mode 100644 bindings/pybddisasm/tests/nd_decode.py create mode 100644 bindings/pybddisasm/tests/nd_get_version.py diff --git a/bindings/pybddisasm/LICENSE b/bindings/pybddisasm/LICENSE index 7652714..25194e5 100644 --- a/bindings/pybddisasm/LICENSE +++ b/bindings/pybddisasm/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2020 Bitdefender + Copyright 2023 Bitdefender Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/bindings/pybddisasm/MANIFEST.in b/bindings/pybddisasm/MANIFEST.in index fa60c52..163caf1 100644 --- a/bindings/pybddisasm/MANIFEST.in +++ b/bindings/pybddisasm/MANIFEST.in @@ -4,3 +4,7 @@ include *.md # Include the license file include LICENSE +# Exclude SWIG/C files +global-exclude pybddisasm/*.c +global-exclude pybddisasm/*.i + diff --git a/bindings/pybddisasm/README.md b/bindings/pybddisasm/README.md index 7645dba..908f164 100644 --- a/bindings/pybddisasm/README.md +++ b/bindings/pybddisasm/README.md @@ -11,30 +11,30 @@ python3 setup.py install ## Usage -Use it by importing the pybddisasm.disasm module: +Use it by importing the pybddisasm module: ```python -from pybddisasm.bddisasm import * +import pybddisasm -instr = nd_decode_ex2(buff, arch, arch, arch, vendor, current_rip) +ret, instr = pybddisasm.nd_decode_ex(code, def_code, def_data, def_stack) ``` ## Example ```python -from pybddisasm.bddisasm import * -from sys import * +import pybddisasm -buff = b"\x55\x48\x8b\x05\xb8\x13\x00\x00" +code = b"\x55\x48\x8b\x05\xb8\x13\x00\x00" offset = 0 -while offset < getsizeof(buff): - instr = nd_decode_ex2(buff[offset:], 64, 64, 64) +while offset < len(code): + _, instr = pybddisasm.nd_decode_ex(code[offset:], len(code[offset:]), pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64) if instr is None: break - print(instr.Text) + _, text = pybddisasm.nd_to_text(instr, 0x0) + print(text) offset += instr.Length ``` diff --git a/bindings/pybddisasm/_pybddisasm/_pybddisasm.c b/bindings/pybddisasm/_pybddisasm/_pybddisasm.c deleted file mode 100644 index 63292c6..0000000 --- a/bindings/pybddisasm/_pybddisasm/_pybddisasm.c +++ /dev/null @@ -1,1199 +0,0 @@ -/* - * Copyright (c) 2020 Bitdefender - * SPDX-License-Identifier: Apache-2.0 - */ -#define _SIGNAL_H -#include -#include -#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_QV: return "QV"; - 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, ""); - } - - 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: "); - 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: "); - 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: "); - 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); -} diff --git a/bindings/pybddisasm/_pybddisasm/pybddisasm.c b/bindings/pybddisasm/_pybddisasm/pybddisasm.c deleted file mode 100644 index 1daea82..0000000 --- a/bindings/pybddisasm/_pybddisasm/pybddisasm.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2020 Bitdefender - * SPDX-License-Identifier: Apache-2.0 - */ -#include "pybddisasm.h" -#include - - -int nd_decode_ex(INSTRUX *instrux, void *code, size_t size, int def_code, int def_data) -{ - return NdDecodeEx(instrux, code, size, def_code, def_data); -} - - -int nd_decode_ex2(INSTRUX *instrux, void *code, size_t size, int def_code, int def_data, int def_stack, int prefered_vendor) -{ - return NdDecodeEx2(instrux, code, size, def_code, def_data, def_stack, prefered_vendor); -} - - -int nd_to_text(INSTRUX *instrux, size_t rip, size_t bufsize, char *buf) -{ - return NdToText(instrux, rip, bufsize, buf); -} diff --git a/bindings/pybddisasm/_pybddisasm/pybddisasm.h b/bindings/pybddisasm/_pybddisasm/pybddisasm.h deleted file mode 100644 index c28141e..0000000 --- a/bindings/pybddisasm/_pybddisasm/pybddisasm.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2020 Bitdefender - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef _PYBDDISASM_H_ -#define _PYBDDISASM_H_ - -#include -#include -#include - -#include "bddisasm.h" - -int nd_decode_ex(INSTRUX *instrux, void *code, size_t size, int def_code, int def_data); - -int nd_decode_ex2(INSTRUX *instrux, void *code, size_t size, int def_code, int def_data, int def_stack, int prefered_vendor); - -int nd_to_text(INSTRUX *instrux, size_t rip, size_t bufsize, char *buf); - -#endif // _PYBDDISASM_H_ diff --git a/bindings/pybddisasm/pybddisasm/__init__.py b/bindings/pybddisasm/pybddisasm/__init__.py index 0a59b28..f59fc8a 100644 --- a/bindings/pybddisasm/pybddisasm/__init__.py +++ b/bindings/pybddisasm/pybddisasm/__init__.py @@ -1,7 +1,6 @@ # -# Copyright (c) 2020 Bitdefender +# Copyright (c) 2023 Bitdefender # SPDX-License-Identifier: Apache-2.0 # -from pybddisasm.bddisasm import NdInstruction, nd_decode, nd_decode_ex, nd_decode_ex2, nd_to_text -from pybddisasm.helpers import disassemble_file, disassemble_hexstring, print_instruction +from pybddisasm.pybddisasm import * diff --git a/bindings/pybddisasm/pybddisasm/__main__.py b/bindings/pybddisasm/pybddisasm/__main__.py deleted file mode 100644 index 8bbc5c4..0000000 --- a/bindings/pybddisasm/pybddisasm/__main__.py +++ /dev/null @@ -1,11 +0,0 @@ -# -# Copyright (c) 2020 Bitdefender -# SPDX-License-Identifier: Apache-2.0 -# -"""Early initialization and main entry point.""" - -from pybddisasm.core import main - -if __name__ == "__main__": - main() - diff --git a/bindings/pybddisasm/pybddisasm/app.py b/bindings/pybddisasm/pybddisasm/app.py deleted file mode 100644 index bf363a2..0000000 --- a/bindings/pybddisasm/pybddisasm/app.py +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright (c) 2020 Bitdefender -# SPDX-License-Identifier: Apache-2.0 -# -from pybddisasm.bddisasm import * -from pybddisasm.helpers import * - - -def run(args): - if args.file: - return disassemble_file(args.file, offset=args.offset, size=args.size, rip=args.rip, - arch=args.arch, highlight=args.highlight, ext_info=args.ext_info) - elif args.hexstring: - return disassemble_hexstring(args.hexstring, offset=args.offset, size=args.size, rip=args.rip, - arch=args.arch, highlight=args.highlight, ext_info=args.ext_info) diff --git a/bindings/pybddisasm/pybddisasm/bddisasm.py b/bindings/pybddisasm/pybddisasm/bddisasm.py deleted file mode 100644 index 13b8bca..0000000 --- a/bindings/pybddisasm/pybddisasm/bddisasm.py +++ /dev/null @@ -1,71 +0,0 @@ -# -# Copyright (c) 2020 Bitdefender -# SPDX-License-Identifier: Apache-2.0 -# -"""Interface for disassembling code.""" - -import _pybddisasm - -class NdInstruction(dict): - """Magic wrapper around a dictionary, that makes all the keys available - through dot notation (recursively). Examples: - - instruction['Length'] is now instruction.Length - instruction['InstructionBytes'] is now instruction.InstructionBytes - - You can still access the fileds the old way.""" - def __init__(self, *args, **kwargs): - super(NdInstruction, self).__init__(*args, **kwargs) - self.__dict__ = self - - # now set all the dict children to be the same - for key in self.__dict__: - if not isinstance(self.__dict__[key], dict): - continue - - self.__dict__[key] = NdInstruction(self.__dict__[key]) - - if 'Operands' in self.__dict__ and isinstance(self.Operands, dict): - for op in self.Operands: - self.Operands[op] = NdInstruction(self.Operands[op]) - - -def nd_to_text(code, arch_code_size, arch_data_size=0, rip=0): - if not arch_data_size: - arch_data_size = arch_code_size - - return _pybddisasm.nd_to_text(code, arch_code_size, arch_data_size, rip) - - -def nd_decode(code, arch_code_size, arch_data_size=0, rip=0): - if not arch_data_size: - arch_data_size = arch_code_size - - instruction = _pybddisasm.nd_decode_ex(code, arch_code_size, arch_data_size, rip) - - if not instruction: - return None - - return NdInstruction(instruction) - - -def nd_decode_ex(code, arch_code_size, arch_data_size=0, rip=0): - if not arch_data_size: - arch_data_size = arch_code_size - - instruction = _pybddisasm.nd_decode_ex(code, arch_code_size, arch_data_size, rip) - - if not instruction: - return None - - return NdInstruction(instruction) - - -def nd_decode_ex2(code, arch_code_size, arch_data_size, arch_stack_size, vendor='intel', rip=0): - instruction = _pybddisasm.nd_decode_ex2(code, arch_code_size, arch_data_size, - arch_stack_size, vendor, rip) - - if not instruction: - return None - - return NdInstruction(instruction) diff --git a/bindings/pybddisasm/pybddisasm/core.py b/bindings/pybddisasm/pybddisasm/core.py deleted file mode 100644 index 0d57793..0000000 --- a/bindings/pybddisasm/pybddisasm/core.py +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright (c) 2020 Bitdefender -# SPDX-License-Identifier: Apache-2.0 -# -"""Early initialization and main entry point.""" - -import sys -import argparse -import pybddisasm - - -def _auto_int(x): - return int(x, 0) - - -def _get_argparser(): - """Get the argpase parser.""" - parser = argparse.ArgumentParser(prog='pybddisasm') - - parser.add_argument('-b', '--arch', choices=[16, 32, 64], default=64, type=int) - - group = parser.add_mutually_exclusive_group() - group.add_argument('-f', '--file', dest='file') - group.add_argument('--hex', dest='hexstring', nargs='*') - - parser.add_argument('-r', '--rip', dest='rip', default=0, type=_auto_int, - help='Disassemble considering the given RIP.') - parser.add_argument('--offset', dest='offset', default=0, type=_auto_int, - help='Disassemble starting at the given offset. Only valid for --file option.') - parser.add_argument('--size', dest='size', default=0, type=_auto_int, - help='Disassemble only the given size. Only valid for --file option.') - parser.add_argument('-c', '--highlight', dest='highlight', action='store_true', - help='Color the instruction bytes by group (opcode, prefix, etc).') - parser.add_argument('-e', '--ext-info', dest='ext_info', action='store_true') - parser.add_argument('--vendor', dest='vendor', - choices=['intel', 'amd', 'cyrix', 'geode', 'any'], default='any') - - return parser - - -def main(): - """Parse the args and run the app.""" - parser = _get_argparser() - - args = parser.parse_args(sys.argv[1:]) - - if not args.file and not args.hexstring: - parser.print_usage() - return 1 - - from pybddisasm import app - app.run(args) diff --git a/bindings/pybddisasm/pybddisasm/helpers.py b/bindings/pybddisasm/pybddisasm/helpers.py deleted file mode 100644 index 7812f44..0000000 --- a/bindings/pybddisasm/pybddisasm/helpers.py +++ /dev/null @@ -1,156 +0,0 @@ -# -# Copyright (c) 2020 Bitdefender -# SPDX-License-Identifier: Apache-2.0 -# -import os -import sys - -from pybddisasm.bddisasm import * - -try: - from termcolor import colored -except: - colored = None - - -_SPACES = [ - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', -] - - -def print_internal(string, foreground=None, highlight=True): - no_colors = (foreground is None) or (not highlight) - - if not colored or no_colors: - sys.stdout.write(string) - else: - text = colored(string, foreground) - sys.stdout.write(text) - - -def print_instruction(instruction, rip, highlight=False, ext_info=False): - k = 0 - - print_internal('%016x ' % rip) - - # prefixes - for ibyte in range(0, instruction.PrefLength): - print_internal('%02x' % instruction.InstructionBytes[ibyte]) - - # opcodes - k += instruction.PrefLength - for ibyte in range(k, k + instruction.OpLength): - print_internal('%02x' % instruction.InstructionBytes[ibyte], 'green', highlight) - - # modrm and sib - k += instruction.OpLength - for ibyte in range(k, k + instruction.HasModRm + instruction.HasSib): - print_internal('%02x' % instruction.InstructionBytes[ibyte], 'yellow', highlight) - - # displacement - k += instruction.HasModRm + instruction.HasSib - for ibyte in range(k, k + instruction.DispLength): - print_internal('%02x' % instruction.InstructionBytes[ibyte], 'blue', highlight) - - # relative offset/moffset/immediates - rest = instruction.Imm1Length + instruction.Imm2Length + instruction.RelOffsLength + \ - instruction.MoffsetLength + instruction.HasSseImm + instruction.AddrLength - - k += instruction.DispLength - for ibyte in range(k, k + rest): - print_internal('%02x' % instruction.InstructionBytes[ibyte], 'red', highlight) - - # the rest of the bytes - k += rest - for ibyte in range(k, instruction.Length): - print_internal('%02x' % instruction.InstructionBytes[ibyte]) - - print_internal('%s' % _SPACES[16 - instruction.Length]) - print_internal('%s' % instruction.Text) - - if ext_info: - print_internal('\n') - print_internal('%r' % instruction) - - print_internal('\n') - - -def disassemble_file(filepath, offset=0, size=0, rip=0, arch=64, - highlight=True, vendor='any', ext_info=False): - if not filepath: - return - - with open(filepath, 'rb') as f: - total = 0 - file_size = os.path.getsize(filepath) - - if not size: - size = file_size - - while offset < file_size and total < size: - to_read = file_size - offset - if to_read > 15: - to_read = 15 - - f.seek(offset, 0) - buff = f.read(to_read) - - current_rip = rip + total - - instr = nd_decode_ex2(buff, arch, arch, arch, vendor, current_rip) - if instr: - print_instruction(instr, current_rip, highlight, ext_info) - offset += instr['Length'] - total += instr['Length'] - else: - sys.stdout.write('%016x %02x %s db 0x%02x' % (current_rip, buff[0], - _SPACES[15], buff[0])) - - if str.isalpha(chr(buff[0])): - sys.stdout.write(str(buff[0])) - - sys.stdout.write('\n') - - offset += 1 - total += 1 - - -def disassemble_hexstring(hexstring, offset=0, size=0, rip=0, arch=64, - highlight=True, vendor='any', ext_info=False): - if not hexstring: - return - - buff = bytes.fromhex(''.join(hexstring)) - - total = 0 - if not size: - size = len(buff) - - while total < size: - current_rip = rip + total - - instr = nd_decode_ex2(buff[total:total+16], arch, arch, arch, vendor, current_rip) - if instr: - print_instruction(instr, current_rip, highlight, ext_info) - offset += instr['Length'] - total += instr['Length'] - else: - sys.stdout.write('%016x %02x %s db 0x%02x\n' % (current_rip, buff[offset], - _SPACES[15], buff[offset])) - offset += 1 - total += 1 diff --git a/bindings/pybddisasm/pybddisasm/pybddisasm.c b/bindings/pybddisasm/pybddisasm/pybddisasm.c new file mode 100644 index 0000000..9a3b1f0 --- /dev/null +++ b/bindings/pybddisasm/pybddisasm/pybddisasm.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Bitdefender + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "pybddisasm.h" + + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + +int nd_vsnprintf_s(char *buffer, size_t size, size_t count, const char *format, va_list argptr) +{ + return vsnprintf(buffer, size, format, argptr); +} + +void * nd_memset(void *s, int c, size_t n) +{ + return memset(s, c, n); +} + +void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, char **build_date, char **build_time) +{ + NdGetVersion(major, minor, revision, build_date, build_time); +} + +NDSTATUS nd_decode(INSTRUX *__output_instr, const ND_UINT8 *code, ND_UINT8 def_code, ND_UINT8 def_data) +{ + return NdDecode(__output_instr, code, def_code, def_data); +} + +NDSTATUS nd_decode_ex(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_UINT8 def_code, ND_UINT8 def_data) +{ + return NdDecodeEx(__output_instr, code, size, def_code, def_data); +} + +NDSTATUS nd_decode_ex2(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_UINT8 def_code, ND_UINT8 def_data, + ND_UINT8 def_stack, ND_UINT8 prefered_vendor) +{ + return NdDecodeEx2(__output_instr, code, size, def_code, def_data, def_stack, prefered_vendor); +} + +NDSTATUS nd_decode_with_context(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_CONTEXT *context) +{ + return NdDecodeWithContext(__output_instr, code, size, context); +} + +NDSTATUS nd_to_text(const INSTRUX *__input_instr, ND_UINT64 rip, ND_UINT32 buffer_size, char *__output_buffer) +{ + return NdToText(__input_instr, rip, buffer_size, __output_buffer); +} + +ND_BOOL nd_is_instrux_rip_relative(const INSTRUX *__input_instr) +{ + return NdIsInstruxRipRelative(__input_instr); +} + +NDSTATUS nd_get_full_access_map(const INSTRUX *__input_instr, ND_ACCESS_MAP *__output_access_map) +{ + return NdGetFullAccessMap(__input_instr, __output_access_map); +} + +NDSTATUS nd_get_operand_rlut(const INSTRUX *__input_instr, ND_OPERAND_RLUT *__output_rlut) +{ + return NdGetOperandRlut(__input_instr, __output_rlut); +} + +void nd_init_context(ND_CONTEXT *__input_context) +{ + NdInitContext(__input_context); +} + +ND_UINT8 *nd_get_instrux_bytes(const INSTRUX *__input_instr, size_t *__output_convert_length) +{ + *__output_convert_length = sizeof(__input_instr->InstructionBytes); + return (ND_UINT8 *)__input_instr->InstructionBytes; +} + +ND_UINT8 *nd_get_intrux_op_code_bytes(const INSTRUX *__input_instr, size_t *__output_convert_length) +{ + *__output_convert_length = sizeof(__input_instr->OpCodeBytes); + return (ND_UINT8 *)__input_instr->OpCodeBytes; +} + + +ND_OPERAND *nd_get_intrux_operands(const INSTRUX *__input_instr, size_t *__output_convert_length) +{ + *__output_convert_length = ARRAY_SIZE(__input_instr->Operands); + return (ND_OPERAND *)__input_instr->Operands; +} diff --git a/bindings/pybddisasm/pybddisasm/pybddisasm.h b/bindings/pybddisasm/pybddisasm/pybddisasm.h new file mode 100644 index 0000000..152274d --- /dev/null +++ b/bindings/pybddisasm/pybddisasm/pybddisasm.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Bitdefender + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _PYBDDISASM_H_ +#define _PYBDDISASM_H_ + +#include "bddisasm.h" + +void nd_get_version(ND_UINT32 *major, ND_UINT32 *minor, ND_UINT32 *revision, char **build_date, char **build_time); +NDSTATUS nd_decode(INSTRUX *__output_instr, const ND_UINT8 *code, ND_UINT8 def_code, ND_UINT8 def_data); +NDSTATUS nd_decode_ex(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_UINT8 def_code, ND_UINT8 def_data); +NDSTATUS nd_decode_ex2(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_UINT8 def_code, ND_UINT8 def_data, + ND_UINT8 def_stack, ND_UINT8 prefered_vendor); +NDSTATUS nd_decode_with_context(INSTRUX *__output_instr, const ND_UINT8 *code, ND_SIZET size, ND_CONTEXT *context); +NDSTATUS nd_to_text(const INSTRUX *__input_instr, ND_UINT64 rip, ND_UINT32 buffer_size, char *__output_buffer); +ND_BOOL nd_is_instrux_rip_relative(const INSTRUX *__input_instr); +NDSTATUS nd_get_full_access_map(const INSTRUX *__input_instr, ND_ACCESS_MAP *__output_access_map); +NDSTATUS nd_get_operand_rlut(const INSTRUX *__input_instr, ND_OPERAND_RLUT *__output_rlut); +void nd_init_context(ND_CONTEXT *__input_context); +ND_UINT8 *nd_get_instrux_bytes(const INSTRUX *__input_instr, size_t *__output_convert_length); +ND_UINT8 *nd_get_intrux_op_code_bytes(const INSTRUX *__input_instr, size_t *__output_convert_length); +ND_OPERAND *nd_get_intrux_operands(const INSTRUX *__input_instr, size_t *__output_convert_length); + +#endif // !_PYBDDISASM_H_ diff --git a/bindings/pybddisasm/pybddisasm/pybddisasm.i b/bindings/pybddisasm/pybddisasm/pybddisasm.i new file mode 100644 index 0000000..6308397 --- /dev/null +++ b/bindings/pybddisasm/pybddisasm/pybddisasm.i @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2023 Bitdefender + * SPDX-License-Identifier: Apache-2.0 + */ +%module (package="pybddisasm", moduleimport="import $module") pybddisasm +%{ + #define SWIG_FILE_WITH_INIT + + #include "pybddisasm.h" + + #include "bddisasm.h" + #include "constants.h" + #include "cpuidflags.h" + #include "disasmstatus.h" + #include "disasmtypes.h" + #include "registers.h" + #include "version.h" + +%} + +%include "typemaps.i" +%include "stdint.i" + +%{ + #define ND_ARCH_X64 + static PyObject * __uint8_to_pylist(uint8_t *arr, size_t size) + { + PyObject *list = PyList_New(size); + for (uint8_t idx = 0; idx < size; idx++) { + PyObject *obj = PyInt_FromLong(arr[idx]); + PyList_SetItem(list, idx, obj); + } + + return list; + } + + static PyObject * __nd_operand_to_pylist(ND_OPERAND *arr, size_t size) + { + PyObject *list = PyList_New(size); + + for (uint8_t idx = 0; idx < size; idx++) { + PyObject *obj = SWIG_NewPointerObj(&arr[idx], SWIGTYPE_p__ND_OPERAND, 0); + PyList_SetItem(list, idx, obj); + } + + return list; + } +%} + +%typemap(in,numinputs=0) ND_UINT32 * (ND_UINT32 tmp) %{ + $1 = &tmp; +%} + +%typemap(argout) ND_UINT32 * (PyObject* obj) %{ + obj = PyLong_FromLong(*$1); + $result = SWIG_Python_AppendOutput($result,obj); +%} + +%typemap(freearg) ND_UINT32 * %{ + +%} + +%typemap(in,numinputs=0) char** (char* tmp) %{ + $1 = &tmp; +%} + +%typemap(argout) char** (PyObject* obj) %{ + obj = PyUnicode_FromString(*$1); + $result = SWIG_Python_AppendOutput($result,obj); +%} + +%typemap(freearg) char** %{ + +%} + + +%typemap(in, numinputs = 0) (ND_UINT32 buffer_size, char *__output_buffer) { + $1 = ND_MIN_BUF_SIZE; + $2 = (char *)malloc($1 * sizeof(char)); +} + +%typemap(freearg) (ND_UINT32 buffer_size, char *__output_buffer) { + free($2); +} + +%typemap(argout) char *__output_buffer { + // TODO: check if function failed + PyObject *o, *o2, *o3; + o = PyString_FromString($1); + if ((!$result) || ($result == Py_None)) { + $result = o; + } else { + if (!PyTuple_Check($result)) { + PyObject *o2 = $result; + $result = PyTuple_New(1); + PyTuple_SetItem($result,0,o2); + } + o3 = PyTuple_New(1); + PyTuple_SetItem(o3,0,o); + o2 = $result; + $result = PySequence_Concat(o2,o3); + Py_DECREF(o2); + Py_DECREF(o3); + } +} + +%typemap(in, numinputs=0) INSTRUX * __output_instr { + $1 = malloc(sizeof(INSTRUX)); + +} + +%typemap(freearg) INSTRUX * __output_instr { +} + +%typemap(argout) INSTRUX * __output_instr { + %append_output(SWIG_NewPointerObj($1,$1_descriptor,SWIG_POINTER_OWN)); +} + +%typemap(in,numinputs=0,noblock=1) size_t *__output_convert_length { + size_t tmp_len; + $1 = &tmp_len; +} + +%typemap(out) ND_UINT8 * { + size_t size = tmp_len; + $result = __uint8_to_pylist($1, size); +} + +%typemap(out) ND_OPERAND * { + size_t size = tmp_len; + $result = __nd_operand_to_pylist($1, size); +} + +%typemap(in, numinputs = 1) (const ND_UINT8 *) { + Py_buffer view; + + if (!(PyObject_CheckBuffer($input) || PyBytes_Check($input) || PyByteArray_Check($input))) { + SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " + "$argnum"" of type '" "$type""'"); + } + + if (PyObject_GetBuffer($input, &view, 0) != 0) { + SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " + "$argnum"" of type '" "$type""'"); + } + + $1 = (uint8_t *)malloc(sizeof(uint8_t) * view.len); + if (!($1)) { + SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " + "$argnum"" of type '" "$type""'"); + } + + if (PyBuffer_ToContiguous($1, &view, view.len, 'C') != 0) { + SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " + "$argnum"" of type '" "$type""'"); + } + + PyBuffer_Release(&view); +} + +%typemap(freearg) (const ND_UINT8 *) { + free($1); +} + +%define __x86_64__ +%enddef + + +%include "bddisasm.h" +%include "constants.h" +%include "cpuidflags.h" +%include "disasmstatus.h" +%include "disasmtypes.h" +%include "registers.h" +%include "version.h" + +%include "pybddisasm.h" diff --git a/bindings/pybddisasm/setup.py b/bindings/pybddisasm/setup.py index 591777a..2ceede3 100644 --- a/bindings/pybddisasm/setup.py +++ b/bindings/pybddisasm/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2020 Bitdefender +# Copyright (c) 2023 Bitdefender # SPDX-License-Identifier: Apache-2.0 # @@ -11,16 +11,32 @@ import re from setuptools import find_packages, setup, Command, Extension, Distribution from codecs import open -VERSION = (0, 1, 3) +VERSION = (0, 3, 0) LIBRARY_VERSION = (1, 37, 0) -LIBRARY_INSTRUX_SIZE = 856 +DIR_INCLUDE = '../../inc' -packages = ['pybddisasm'] -requires = ['setuptools'] here = os.path.abspath(os.path.dirname(__file__)) -def _check_library_version(): - version_header = '../../inc/version.h' +__swig_opts = ['-I%s' % (DIR_INCLUDE)] +__extra_compile_args = ['-march=westmere'] +__sources = ['pybddisasm/pybddisasm.c', 'pybddisasm/pybddisasm.i'] +__libraries = ['bddisasm'] +__library_dirs = ['../../build', '../../bin/x64/Release'] +__packages = ['pybddisasm'] +__requires = ['setuptools'] + + +class BinaryDistribution(Distribution): + def has_ext_modules(arg): + return True + + def is_pure(self): + return False + + +def __fn_validate_compatibility(): + print(os.getcwd()) + version_header = '%s/version.h' % (DIR_INCLUDE) with open(version_header, 'r') as file: data = file.read() @@ -46,21 +62,15 @@ def _check_library_version(): if int(major) != LIBRARY_VERSION[0] or int(minor) != LIBRARY_VERSION[1] or int(revision) != LIBRARY_VERSION[2]: print('error: The version of the library is not compatible with the pybddisasm!') print('error: Library : %s.%s.%s - pybddisasm : %d.%d.%d' % (major, minor, revision, LIBRARY_VERSION[0], - LIBRARY_VERSION[1], LIBRARY_VERSION[2])) + LIBRARY_VERSION[1], LIBRARY_VERSION[2])) sys.exit(1) -_check_library_version() + +__fn_validate_compatibility() with open('README.md', 'r', 'utf-8') as f: readme = f.read() -class BinaryDistribution(Distribution): - def has_ext_modules(arg): - return True - - def is_pure(self): - return False - setup( name="pybddisasm", version='.'.join(map(str, VERSION)), @@ -69,31 +79,34 @@ setup( long_description = readme, long_description_content_type = "text/markdown", url = "https://github.com/bitdefender/bddisasm", - packages=packages, license="Apache Software License", - package_data={'': ['LICENSE', 'NOTICE'], 'pybddisasm': ['*.pem']}, + package_data={'': ['LICENSE', 'NOTICE'], 'pybddisasm': ['pybddisasm/pybddisasm.py']}, package_dir={'pybddisasm': 'pybddisasm'}, platforms = ["Windows", "Linux"], + packages=__packages, include_package_data=True, + py_modules = ["pybddisasm"], python_requires=">=3.5", setup_requires=['wheel'], - install_requires=requires, + install_requires=__requires, zip_safe=False, classifiers=[ - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'License :: OSI Approved :: Apache Software License', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux' ], ext_modules = [Extension("_pybddisasm", - extra_compile_args = ["-march=westmere"], - sources = ["_pybddisasm/_pybddisasm.c", "_pybddisasm/pybddisasm.c"], - define_macros = [('AMD64', None), ('LIBRARY_INSTRUX_SIZE', LIBRARY_INSTRUX_SIZE)], - include_dirs = ['../../inc'], - libraries = ['bddisasm'], - library_dirs = ['/usr/local/lib', '../../build', '../../bin/x64/Release'])], + swig_opts = __swig_opts, + extra_compile_args = __extra_compile_args, + sources = __sources, + define_macros = [('AMD64', None)], + include_dirs = [DIR_INCLUDE], + libraries = __libraries, + library_dirs = __library_dirs)], distclass=BinaryDistribution ) diff --git a/bindings/pybddisasm/tests/nd_decode.py b/bindings/pybddisasm/tests/nd_decode.py new file mode 100644 index 0000000..a0625b5 --- /dev/null +++ b/bindings/pybddisasm/tests/nd_decode.py @@ -0,0 +1,125 @@ +# +# Copyright (c) 2023 Bitdefender +# SPDX-License-Identifier: Apache-2.0 +# +import sys +import unittest +import pybddisasm + +class TestNdDecode(unittest.TestCase): + def test_nd_decode_bytes(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = b"\x48\x8b\x05\xb8\x13\x00\x00" + ret, instrux = pybddisasm.nd_decode(instr_bytes, pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, len(instr_bytes)): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + def test_nd_decode_bytes_array(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = bytearray(b'\x48\x8b\x05\xb8\x13\x00\x00') + ret, instrux = pybddisasm.nd_decode(instr_bytes, pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, instrux.Length): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + + def test_nd_decode_memory_view(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = memoryview(bytearray(b'\x48\x8b\x05\xb8\x13\x00\x00')) + ret, instrux = pybddisasm.nd_decode(instr_bytes, pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, instrux.Length): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + def test_nd_decode_ex_bytes(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = b"\x48\x8b\x05\xb8\x13\x00\x00" + ret, instrux = pybddisasm.nd_decode_ex(instr_bytes, len(instr_bytes), pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, instrux.Length): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + def test_nd_decode_ex_bytes_array(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = bytearray(b'\x48\x8b\x05\xb8\x13\x00\x00') + ret, instrux = pybddisasm.nd_decode_ex(instr_bytes, len(instr_bytes), pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, instrux.Length): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + + def test_nd_decode_ex_memory_view(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = memoryview(bytearray(b'\x48\x8b\x05\xb8\x13\x00\x00')) + ret, instrux = pybddisasm.nd_decode_ex(instr_bytes, len(instr_bytes), pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, instrux.Length): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + def test_nd_decode_ex2_bytes(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = b"\x48\x8b\x05\xb8\x13\x00\x00" + ret, instrux = pybddisasm.nd_decode_ex2(instr_bytes, len(instr_bytes), pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64, + pybddisasm.ND_STACK_64, pybddisasm.ND_VEND_INTEL); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, instrux.Length): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + def test_nd_decode_ex2_bytes_array(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = bytearray(b'\x48\x8b\x05\xb8\x13\x00\x00') + ret, instrux = pybddisasm.nd_decode_ex2(instr_bytes, len(instr_bytes), pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64, + pybddisasm.ND_STACK_64,pybddisasm.ND_VEND_INTEL); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, instrux.Length): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + + def test_nd_decode_ex2_memory_view(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = memoryview(bytearray(b'\x48\x8b\x05\xb8\x13\x00\x00')) + ret, instrux = pybddisasm.nd_decode_ex2(instr_bytes, len(instr_bytes), pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64, + pybddisasm.ND_STACK_64,pybddisasm.ND_VEND_INTEL); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + + for idx in range(0, instrux.Length): + self.assertEqual(pybddisasm.nd_get_instrux_bytes(instrux)[idx], instr_bytes[idx]) + + def test_nd_rip_relative(self): + # mov rax,QWORD PTR [rip+0x13b8] + instr_bytes = memoryview(bytearray(b'\x48\x8b\x05\xb8\x13\x00\x00')) + ret, instrux = pybddisasm.nd_decode_ex2(instr_bytes, len(instr_bytes), pybddisasm.ND_CODE_64, pybddisasm.ND_DATA_64, + pybddisasm.ND_STACK_64,pybddisasm.ND_VEND_INTEL); + + self.assertIsInstance(ret, int, "'return-value' is not instance of 'int'") + self.assertEqual(ret, 0, "'return-value' is not equal to 0") + +if __name__ == '__main__': + unittest.main() diff --git a/bindings/pybddisasm/tests/nd_get_version.py b/bindings/pybddisasm/tests/nd_get_version.py new file mode 100644 index 0000000..2301ee4 --- /dev/null +++ b/bindings/pybddisasm/tests/nd_get_version.py @@ -0,0 +1,26 @@ +# +# Copyright (c) 2023 Bitdefender +# SPDX-License-Identifier: Apache-2.0 +# +import sys +import unittest + +import pybddisasm + +class TestNdGetVersion(unittest.TestCase): + def test_nd_get_version_exception(self): + self.assertRaises(Exception, pybddisasm.nd_get_version()) + + def test_nd_get_version_output(self): + major, minor, revision, build_date, build_time = pybddisasm.nd_get_version() + + print("\nversion = %ld.%ld.%ld (%s, %s)\n" % (major, minor, revision, build_date, build_time)) + + self.assertIsInstance(major, int, "'Major' is not instance of 'int'") + self.assertIsInstance(minor, int, "'Minor' is not instance of 'int'") + self.assertIsInstance(revision, int, "'Revision' is not instance of 'int'") + self.assertIsInstance(build_date, str, "'BuildDate' is not instance of 'str'") + self.assertIsInstance(build_time, str, "'BuildDate' is not instance of 'str'") + +if __name__ == '__main__': + unittest.main()