Disassembling Binary File with Python on Mac

By | August 7, 2020

I’m currently doing some exploration towards PE32 on my macOS. Some of interesting surface analysis, some of deep analysis. But sometimes, I need only to see what kind of instructions in a small chunk of PE32. It was begin with the this blog, that discussing PE32 using Python pefile module by Ero Carrera.

Installing pefile using pip was straight thru.

Even with a limited documentation, I can explore what properties and methods are available from this module. Using python dir() function, I can see and guess each methods and properties.

output of python dir() function for pefile module

If I want to know what is the object in pefile module, such as PE above, then I can use python help() function. For example, when I typed

help (pefile.PE)

then this screen showed up:

output of python help() function for Class pefile.PE

Or I just simply want to know where did pip3 put this module in my drive. I used print(pefile.__file__)

print (pefile.__file__) to show the full path location

Knowing this module, I thought I can create my own unpacker when analyzing packed malware. Something like PEiD and tools based on it such as here. In usage example, the author mentioned pydasm can be used to disassemble bytes in Entry Point.

I was interested in observing PyDASM due to its simplicity as mentioned in here. It is basically python wrapper of LibDASM. But, this is old project that might not be suitable for macOS.

pydasm Github Project
libdasm Github Project

Following several tutorials to install the module from here using svn, and here using git, just made me stumbled and wondering whether the code still compatible with recent OS. I chose to follow the git-way.

❯ git clone https://github.com/axcheron/libdasm.git
Cloning into 'libdasm'...
remote: Enumerating objects: 77, done.
remote: Total 77 (delta 0), reused 0 (delta 0), pack-reused 77
Unpacking objects: 100% (77/77), done.

❯ python3 setup.py build_ext
running build_ext
building 'pydasm' extension
creating build
creating build/temp.macosx-10.9-x86_64-3.8
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -I/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8 -I/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8 -c ../libdasm.c -o build/temp.macosx-10.9-x86_64-3.8/../libdasm.o
In file included from ../libdasm.c:15:
../opcode_tables.h:445:34: warning: use of logical '||' with constant operand [-Wconstant-logical-operand]
/*0F 7C*/{ INSTRUCTION_TYPE_OTHER||TYPE_3,NULL,  FLAGS_NONE,                  FLAGS_NONE,                FLAGS_NONE,   0, 0, 0, 0, 0 },
                                 ^ ~~~~~~
../opcode_tables.h:445:34: note: use '|' for a bitwise operation
/*0F 7C*/{ INSTRUCTION_TYPE_OTHER||TYPE_3,NULL,  FLAGS_NONE,                  FLAGS_NONE,                FLAGS_NONE,   0, 0, 0, 0, 0 },
                                 ^~~~~~~~
                                 |
../opcode_tables.h:446:34: warning: use of logical '||' with constant operand [-Wconstant-logical-operand]
/*0F 7D*/{ INSTRUCTION_TYPE_OTHER||TYPE_3,NULL,  FLAGS_NONE,                  FLAGS_NONE,                FLAGS_NONE,   0, 0, 0, 0, 0 },
                                 ^ ~~~~~~
../opcode_tables.h:446:34: note: use '|' for a bitwise operation
/*0F 7D*/{ INSTRUCTION_TYPE_OTHER||TYPE_3,NULL,  FLAGS_NONE,                  FLAGS_NONE,                FLAGS_NONE,   0, 0, 0, 0, 0 },
                                 ^~~~~~~~
                                 |
2 warnings generated.
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -I/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8 -I/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8 -c pydasm.c -o build/temp.macosx-10.9-x86_64-3.8/pydasm.o
pydasm.c:251:28: warning: implicit declaration of function 'PyString_FromString' is invalid in C99 [-Wimplicit-function-declaration]
    PyObject *pClassName = PyString_FromString(class_name);
                           ^
pydasm.c:251:15: warning: incompatible integer to pointer conversion initializing 'PyObject *' (aka 'struct _object *') with an expression of type
      'int' [-Wint-conversion]
    PyObject *pClassName = PyString_FromString(class_name);
              ^            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pydasm.c:253:14: warning: implicit declaration of function 'PyClass_New' is invalid in C99 [-Wimplicit-function-declaration]
    pClass = PyClass_New(NULL, pClassDict, pClassName);
             ^
pydasm.c:253:12: warning: incompatible integer to pointer conversion assigning to 'PyObject *' (aka 'struct _object *') from 'int' [-Wint-conversion]
    pClass = PyClass_New(NULL, pClassDict, pClassName);
           ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pydasm.c:275:42: warning: implicit declaration of function 'PyString_FromString' is invalid in C99 [-Wimplicit-function-declaration]
    assign_attribute(pPInst, "mnemonic", PyString_FromString(pinst->mnemonic));
                                         ^
pydasm.c:275:42: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'PyObject *' (aka 'struct _object *')
      [-Wint-conversion]
    assign_attribute(pPInst, "mnemonic", PyString_FromString(pinst->mnemonic));
                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pydasm.c:201:60: note: passing argument to parameter 'attr' here
void assign_attribute(PyObject *obj, char *name, PyObject *attr)
                                                           ^
pydasm.c:304:5: warning: implicit declaration of function 'PyString_AsStringAndSize' is invalid in C99 [-Wimplicit-function-declaration]
    PyString_AsStringAndSize(
    ^
pydasm.c:461:5: warning: implicit declaration of function 'PyString_AsStringAndSize' is invalid in C99 [-Wimplicit-function-declaration]
    PyString_AsStringAndSize(pBuffer, &data, &data_length);
    ^
pydasm.c:534:12: warning: implicit declaration of function 'PyString_FromStringAndSize' is invalid in C99 [-Wimplicit-function-declaration]
    pStr = PyString_FromStringAndSize(data, strlen(data));    
           ^
pydasm.c:534:10: warning: incompatible integer to pointer conversion assigning to 'PyObject *' (aka 'struct _object *') from 'int' [-Wint-conversion]
    pStr = PyString_FromStringAndSize(data, strlen(data));    
         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pydasm.c:584:12: warning: implicit declaration of function 'PyString_FromStringAndSize' is invalid in C99 [-Wimplicit-function-declaration]
    pStr = PyString_FromStringAndSize(data, strlen(data));
           ^
pydasm.c:584:10: warning: incompatible integer to pointer conversion assigning to 'PyObject *' (aka 'struct _object *') from 'int' [-Wint-conversion]
    pStr = PyString_FromStringAndSize(data, strlen(data));
         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pydasm.c:653:12: warning: implicit declaration of function 'PyString_FromStringAndSize' is invalid in C99 [-Wimplicit-function-declaration]
    pStr = PyString_FromStringAndSize(data, strlen(data));
           ^
pydasm.c:653:10: warning: incompatible integer to pointer conversion assigning to 'PyObject *' (aka 'struct _object *') from 'int' [-Wint-conversion]
    pStr = PyString_FromStringAndSize(data, strlen(data));
         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pydasm.c:716:12: warning: implicit declaration of function 'Py_InitModule' is invalid in C99 [-Wimplicit-function-declaration]
        pModule = Py_InitModule("pydasm", pydasmMethods);
                  ^
pydasm.c:716:10: warning: incompatible integer to pointer conversion assigning to 'PyObject *' (aka 'struct _object *') from 'int' [-Wint-conversion]
        pModule = Py_InitModule("pydasm", pydasmMethods);
                ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pydasm.c:736:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
pydasm.c:741:20: warning: incompatible pointer types passing 'char *' to parameter of type 'const wchar_t *' (aka 'const int *')
      [-Wincompatible-pointer-types]
        Py_SetProgramName(argv[0]);
                          ^~~~~~~
/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8/pylifecycle.h:38:51: note: passing argument to parameter here
PyAPI_FUNC(void) Py_SetProgramName(const wchar_t *);
                                                  ^
18 warnings generated.
creating build/lib.macosx-10.9-x86_64-3.8
gcc -bundle -undefined dynamic_lookup -arch x86_64 -g build/temp.macosx-10.9-x86_64-3.8/../libdasm.o build/temp.macosx-10.9-x86_64-3.8/pydasm.o -o build/lib.macosx-10.9-x86_64-3.8/pydasm.cpython-38-darwin.so

❯ file build/lib.macosx-10.9-x86_64-3.8/pydasm.cpython-38-darwin.so 
build/lib.macosx-10.9-x86_64-3.8/pydasm.cpython-38-darwin.so: Mach-O 64-bit bundle x86_64

Warnings, but no errors. Then I copied the file pydasm.cpython-38-darwin.so to the same folder where pefile.py was installed.

copying pydasm bundled to python module folder

But my python is not recognizing the file. Following this blog, the sys.path is correct. But still python is not recognizing the pydasm module. Not even detecting the existence of pydasm. May be I missed something?

I also followed this StackOverflow recommendation, but still no luck.

Then, I was told by Yohanes Nugroho to use Capstone by Nguyen Anh, a disassembly framework introduced at BlackHat 2014.

Reading the presentation slide, I think it is simple to use. It supports multiple processors, including for IBM Z-series, that is the Mainframe. Support multiple OSes 16bit,32bit, and 64bit. And of course, wrapper for 9 programming languages, that includes python.

I simply installed this python module using pip.

pip3 install capstone

It works like a charm. Imported and evaluated this module with dir(), and it met my expectation.

Followed some python examples in their website, and observed what other classes, methods, that can be used to get an output just like disassembler I use, I made short python script such this:

small code to disassembly PE32

And the output is here:

output of the script above

Well, I’m happy with this Capstone Disassembly Framework. Will explore more about this.

Leave a ReplyCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.