Skip to content
/ typedef Public

unpack structs, unions, and arrays

License

Notifications You must be signed in to change notification settings

bnbdr/typedef

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

typedef

Conveniently handle structs, unions, and arrays

Installation

pip install typedef

Usage*

from typedef import *

Features

Defining structs, unions and arrays similarly to C

SIZE_LIST = struct([
    (DWORD, 'alignment'),
    (WORD[4], 'sizes')              # array of 4 words
])

VERSION = struct([
    (DWORD, 'build_version'),
    (WORD, 'major'),
    (WORD, 'minor')
])
FLAGS = union([
    (BYTE[4], 'bytes'),             
    (DWORD, 'dw')
])
HEADER = struct([ 
    (VERSION, 'file_version'),      # using existing definitions
    (FLAGS, 'flags'),
    struct([                    
        (WORD, 'size'),
        (WORD, 'offset')
    ], 'inner_struct'),             # define nested definitions
    struct([ 
        (DWORD, 'checksum'),
        (DWORD, 'machine')
    ])                              # define anonymous nested definitions
])

Implicit alignment or explicit pragma pack support

with pragma.pack(1):            # using context manager 
    # define structs here...
...
pragma.pack.push(4)             # explicitly pushing and popping
# define structs here...
...
pragma.pack.pop()               

Convenient initialization

ver = VERSION()  # using default values for each type
buffer = '\xbb\x01\x02\x03'    # using string buffer (`bytes` on py3)
ver = VERSION(buffer) 
iobuffer = StringIO('\xbb\x01\x02\x03')    # using `StringIO` (`BytesIO` on py3)
ver = VERSION(iobuffer) 
in_file = open('{some_path}','rb')    # using files
ver = VERSION(in_file) 
data_dict = { 'build_version': 9600, 'major': 8, 'minor':1 }   # using dictionary for structs
ver = VERSION(data_dict) 
data_list = ['\x01\x02', 3, 5]   # using list for arrays
size_list = SIZE_LIST({'sizes':data_list}) 

Class-like access to attributes

if ver.major > 3:
    ...
for name, value in ver:       # iterating over struct/union instance
    ...
for index, value in size_list.sizes:       # iterating over array instance
    ...
wanted_sizes = size_list.sizes[2:3]       # getting slice of array instance
...

Conveniently update values

>>> ver.minor = 3
>>> ver
00 00 00 00 00 00 03 00
...
>>> ver.major = '\x01\xFF'
>>> ver
00 00 00 00 01 ff 03 00
...
size_list.sizes = [1,2]
...

Initialize types using file and sync it on every change

# file must have read/write access, and contain enough buffer to initialize the type
in_file = open('{some_path}','r+b')    
ver = VERSION(in_file,mode=F_SYNC) 

Easily get the updated byte-string of a type:

>>> bytes(ver)
b'\x00\x00\x00\x00\x01\xff\x03\x00'

Allow types that rely on machine architecture

ARCH_DEP = struct([
    (SIZE_T, 'size'),
    (PVOID, 'pointer')
])

>>> s_32bit = ARCH_DEP('\x00\x00\x00\x00\xFF\xFF\xFF\xFF', target=Arch.x86)
>>> s_64bit = ARCH_DEP('\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF', target=Arch.x64)
>>> s_32bit.size              
0                             
>>> hex(s_32bit.pointer)      
'0xffffffff'                  
>>> s_64bit.size              
0                             
>>> hex(s_64bit.pointer)      
'0xffffffffffffffff'          

Endian, signed

 U = union([
    (DWORD, 'unsignedLittle'),
    (~DWORD, 'signedLittle'),
    (+DWORD, 'unsignedBig'),
    (+~DWORD, 'signedBig')
])

Get size of instance:

>>> sizeof(ver)
8

Examples

  1. dump instance as json using TypeEncoder
  2. parse the pe-file header

Limitations

  1. union initialization is limited to buffers or files
  2. no flexible arrays
  3. no nested arrays
  4. no forward declation

External dependencies

none

Compatability**

  • Python 2.7.8
  • Python 3.5.2

License

This project is licensed under the MIT License - see the LICENSE file for details

Remarks

* Be mindful of name collision with the stdlib struct
** Tested using the specified versions; probably will work on any 2.7.x version and any 3.x