Skip to content
trolldbois edited this page Jul 8, 2011 · 3 revisions

It’s easy to add new structures (check ctypeslib or do it by hand or check sslsnoop on github)

a) Your class must extend haystack.model.LoadableMembers.
b) You must give your class a completed _fields_ (with one _ ), like all ctypes.Structure
c) You can add an expectedValues dict() to your class to refine your search
d) call model.registerModule(sys.modules[__name__])

Advanced use : You can override methods to fine tune some validation or loading

The global algoritm :

a)  A ctypes structure is mapped at a memory address.
b)  The method loadMembers id called.
c)  The method isValid is called on self.
d)  A validation test is done for each members, it's expected values and memory space validity (pointers) are tested.
    The validation does not recurse.
e)  Each members is then 'loaded' to local space.
    If the value is a pointer or a model.LoadableMembers type, it's recursively Loaded. ( and validated).
    If the recursive loading fails, the calls fails. bye-bye.
f) see next offset, goto a)

Extension examples :

@ see sslsnoop in the Pypi repo. openssl and nss structures are generated.

@ see ctypes-kernel on my github. Linux kernel structure are generated. (VMM is abitch)

Pseudo Example :

from haystack.model import LoadableMembers, RangeValue, NotNull

class OpenSSLStruct(LoadableMembers):
  pass

class RSA(OpenSSLStruct):
  ''' rsa/rsa.h '''
  _fields_ = [
  ("pad",  ctypes.c_int),
  ("version",  ctypes.c_long),
  ("meth",ctypes.POINTER(BIGNUM)),#const RSA_METHOD *meth;
  ("engine",ctypes.POINTER(ENGINE)),#ENGINE *engine;
  ('n', ctypes.POINTER(BIGNUM) ), ## still in ssh memap
  ('e', ctypes.POINTER(BIGNUM) ), ## still in ssh memap
  ('d', ctypes.POINTER(BIGNUM) ), ## still in ssh memap
  ('p', ctypes.POINTER(BIGNUM) ), ## still in ssh memap
  ('q', ctypes.POINTER(BIGNUM) ), ## still in ssh memap
  ('dmp1', ctypes.POINTER(BIGNUM) ),
  ('dmq1', ctypes.POINTER(BIGNUM) ),
  ('iqmp', ctypes.POINTER(BIGNUM) ),
  ("ex_data", CRYPTO_EX_DATA ),
  ("references", ctypes.c_int),
  ("flags", ctypes.c_int),
  ("_method_mod_n", ctypes.POINTER(BN_MONT_CTX) ),
  ("_method_mod_p", ctypes.POINTER(BN_MONT_CTX) ),
  ("_method_mod_q", ctypes.POINTER(BN_MONT_CTX) ),
  ("bignum_data",ctypes.POINTER(ctypes.c_ubyte)), ## moue c_char_p ou POINTER(c_char) ?
  ("blinding",ctypes.POINTER(BIGNUM)),#BN_BLINDING *blinding;
  ("mt_blinding",ctypes.POINTER(BIGNUM))#BN_BLINDING *mt_blinding;
  ]
  expectedValues={
    "pad": [0],
    "version": [0],
    "references": RangeValue(0,0xfff),
    "n": [NotNull],
    "e": [NotNull],
    "d": [NotNull],
    "p": [NotNull],
    "q": [NotNull],
    "dmp1": [NotNull],
    "dmq1": [NotNull],
    "iqmp": [NotNull]
  }
  def loadMembers(self, mappings, maxDepth):
    print 'example'
    if not LoadableMembers.loadMembers(self, mappings, maxDepth):
      log.debug('RSA not loaded')
      return False
    return True

# register to haystack
model.registerModule(sys.modules[__name__])
Clone this wiki locally