Use SWIG to create bindings between C and Python.

pull/80/head
Andrei KISARI 10 months ago
parent 096b583c25
commit 4f182b2c11

@ -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.

@ -4,3 +4,7 @@ include *.md
# Include the license file
include LICENSE
# Exclude SWIG/C files
global-exclude pybddisasm/*.c
global-exclude pybddisasm/*.i

@ -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
```

File diff suppressed because it is too large Load Diff

@ -1,24 +0,0 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include "pybddisasm.h"
#include <stdlib.h>
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);
}

@ -1,20 +0,0 @@
/*
* Copyright (c) 2020 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _PYBDDISASM_H_
#define _PYBDDISASM_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#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_

@ -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 *

@ -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()

@ -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)

@ -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)

@ -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)

@ -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

@ -0,0 +1,96 @@
/*
* Copyright (c) 2023 Bitdefender
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#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;
}

@ -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_

@ -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"

@ -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
)

@ -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()

@ -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()
Loading…
Cancel
Save