MWCC/optdump.py

387 lines
11 KiB
Python

import json
'''
HOW TO GENERATE:
'''
def play_with_addr(ea):
if ea == 0:
return None
e = ida_name.get_name_expr(0, 0, ea, BADADDR)
e = e[13:-2]
return e
class String:
name: str
value: str
@staticmethod
def from_ea(ea):
if ea == 0:
return None
else:
s = String()
s.name = get_name(ea)
v = get_bytes(ea, 1024)
v = v[:v.find(b'\0')]
s.value = v.decode('ascii')
return s
def encode(self):
if self.name.startswith('a'):
return self.value
else:
return dict(name=self.name, value=self.value)
class Param:
name: str
flags: int
myname: String
@staticmethod
def from_ea(ea):
print('reading param %08x' % ea)
which = get_wide_byte(ea)
next_ea = get_wide_dword(ea + 6)
p = PARAM_CLASSES[which]()
p.populate_from_ea(ea)
return p, next_ea
def populate_from_ea(self, ea):
self.name = get_name(ea)
self.flags = get_wide_byte(ea + 1)
self.myname = String.from_ea(get_wide_dword(ea + 2))
def encode(self):
d = dict(_name=self.name, flags=self.flags)
if self.myname is not None:
d['myname'] = self.myname
return d
@staticmethod
def list_from_ea(ea):
lst = []
while ea != 0:
param, next_ea = Param.from_ea(ea)
lst.append(param)
ea = next_ea
return lst
class FTypeCreatorParam(Param):
def populate_from_ea(self, ea):
super(FTypeCreatorParam, self).populate_from_ea(ea)
self.fc = play_with_addr(get_wide_dword(ea + 10))
self.iscreator = get_wide_byte(ea + 14)
def encode(self):
d = super(FTypeCreatorParam, self).encode()
d['_type'] = 'FTypeCreator'
d['fc'] = self.fc
d['iscreator'] = self.iscreator
return d
class FilePathParam(Param):
def populate_from_ea(self, ea):
super(FilePathParam, self).populate_from_ea(ea)
self.fflags = get_wide_byte(ea + 10)
self.defaultstr = String.from_ea(get_wide_dword(ea + 11))
self.filename = play_with_addr(get_wide_dword(ea + 15))
self.maxlen = get_wide_dword(ea + 19)
def encode(self):
d = super(FilePathParam, self).encode()
d['_type'] = 'FilePath'
d['fflags'] = self.fflags
d['defaultstr'] = self.defaultstr
d['filename'] = self.filename
d['maxlen'] = self.maxlen
return d
class NumberParam(Param):
def populate_from_ea(self, ea):
super(NumberParam, self).populate_from_ea(ea)
self.size = get_wide_byte(ea + 10)
self.fit = get_wide_byte(ea + 11)
self.lo = get_wide_dword(ea + 12)
self.hi = get_wide_dword(ea + 16)
self.num = play_with_addr(get_wide_dword(ea + 20))
def encode(self):
d = super(NumberParam, self).encode()
d['_type'] = 'Number'
d['size'] = self.size
d['fit'] = self.fit
d['lo'] = self.lo
d['hi'] = self.hi
d['num'] = self.num
return d
class StringParam(Param):
def populate_from_ea(self, ea):
super(StringParam, self).populate_from_ea(ea)
self.maxlen = get_wide_word(ea + 10)
self.pstring = get_wide_byte(ea + 12)
self.str = play_with_addr(get_wide_dword(ea + 13))
def encode(self):
d = super(StringParam, self).encode()
d['_type'] = 'String'
d['maxlen'] = self.maxlen
d['pstring'] = self.pstring
d['str'] = self.str
return d
class IdParam(StringParam):
def populate_from_ea(self, ea):
super(IdParam, self).populate_from_ea(ea)
def encode(self):
d = super(IdParam, self).encode()
d['_type'] = 'Id'
return d
class SymParam(StringParam):
def populate_from_ea(self, ea):
super(SymParam, self).populate_from_ea(ea)
def encode(self):
d = super(SymParam, self).encode()
d['_type'] = 'Sym'
return d
class OnOffParam(Param):
def populate_from_ea(self, ea):
super(OnOffParam, self).populate_from_ea(ea)
self.var = play_with_addr(get_wide_dword(ea + 10))
def encode(self):
d = super(OnOffParam, self).encode()
d['_type'] = 'OnOff'
d['var'] = self.var
return d
class OffOnParam(Param):
def populate_from_ea(self, ea):
super(OffOnParam, self).populate_from_ea(ea)
self.var = play_with_addr(get_wide_dword(ea + 10))
def encode(self):
d = super(OffOnParam, self).encode()
d['_type'] = 'OffOn'
d['var'] = self.var
return d
class MaskParam(Param):
def populate_from_ea(self, ea):
super(MaskParam, self).populate_from_ea(ea)
self.size = get_wide_byte(ea + 10)
self.ormask = get_wide_dword(ea + 11)
self.andmask = get_wide_dword(ea + 15)
self.num = play_with_addr(get_wide_dword(ea + 19))
def encode(self):
d = super(MaskParam, self).encode()
d['_type'] = 'Mask'
d['size'] = self.size
d['ormask'] = self.ormask
d['andmask'] = self.andmask
d['num'] = self.num
return d
class ToggleParam(Param):
def populate_from_ea(self, ea):
super(ToggleParam, self).populate_from_ea(ea)
self.size = get_wide_byte(ea + 10)
self.mask = get_wide_dword(ea + 11)
self.num = play_with_addr(get_wide_dword(ea + 15))
def encode(self):
d = super(ToggleParam, self).encode()
d['_type'] = 'Toggle'
d['size'] = self.size
d['mask'] = self.mask
d['num'] = self.num
return d
class SetParam(Param):
def populate_from_ea(self, ea):
super(SetParam, self).populate_from_ea(ea)
self.size = get_wide_byte(ea + 10)
self.value = get_wide_dword(ea + 11)
self.num = play_with_addr(get_wide_dword(ea + 15))
def encode(self):
d = super(SetParam, self).encode()
d['_type'] = 'Set'
d['size'] = self.size
d['value'] = self.value
d['num'] = self.num
return d
class SetStringParam(Param):
def populate_from_ea(self, ea):
super(SetStringParam, self).populate_from_ea(ea)
self.value = get_wide_dword(ea + 10)
self.pstring = get_wide_byte(ea + 14)
self.var = play_with_addr(get_wide_dword(ea + 15))
def encode(self):
d = super(SetStringParam, self).encode()
d['_type'] = 'SetString'
d['value'] = self.value
d['pstring'] = self.pstring
d['var'] = self.var
return d
class GenericParam(Param):
def populate_from_ea(self, ea):
super(GenericParam, self).populate_from_ea(ea)
self.parse = play_with_addr(get_wide_dword(ea + 10))
# self.var = play_with_addr(get_wide_dword(ea + 14))
var = get_wide_dword(ea + 14)
if get_name(var).startswith('a'):
self.var = String.from_ea(var)
else:
self.var = var
self.help = String.from_ea(get_wide_dword(ea + 18))
def encode(self):
d = super(GenericParam, self).encode()
d['_type'] = 'Generic'
d['parse'] = self.parse
d['var'] = self.var
d['help'] = self.help
return d
class IfArgParam(Param):
def populate_from_ea(self, ea):
super(IfArgParam, self).populate_from_ea(ea)
self.parg = Param.list_from_ea(get_wide_dword(ea + 10))
self.helpa = String.from_ea(get_wide_dword(ea + 14))
self.pnone = Param.list_from_ea(get_wide_dword(ea + 18))
self.helpn = String.from_ea(get_wide_dword(ea + 22))
def encode(self):
d = super(IfArgParam, self).encode()
d['_type'] = 'IfArg'
d['parg'] = self.parg
d['helpa'] = self.helpa
d['pnone'] = self.pnone
d['helpn'] = self.helpn
return d
class SettingParam(Param):
def populate_from_ea(self, ea):
super(SettingParam, self).populate_from_ea(ea)
self.parse = play_with_addr(get_wide_dword(ea + 10))
self.valuename = String.from_ea(get_wide_dword(ea + 14))
def encode(self):
d = super(SettingParam, self).encode()
d['_type'] = 'Setting'
d['parse'] = self.parse
d['valuename'] = self.valuename
return d
PARAM_CLASSES = [
Param,
FTypeCreatorParam,
FilePathParam,
NumberParam,
StringParam,
IdParam,
SymParam,
OnOffParam,
OffOnParam,
MaskParam,
ToggleParam,
SetParam,
SetStringParam,
GenericParam,
IfArgParam,
SettingParam
]
class Option:
name: str
names: String
avail: int
sub: 'OptionList'
conflicts: 'OptionList'
help: String
@staticmethod
def from_ea(ea):
if ea == 0:
return None
else:
o = Option()
o.name = get_name(ea)
o.names = String.from_ea(get_wide_dword(ea))
o.avail = get_wide_dword(ea + 4)
o.param = Param.list_from_ea(get_wide_dword(ea + 8))
o.sub = OptionList.from_ea(get_wide_dword(ea + 12))
o.conflicts = OptionList.from_ea(get_wide_dword(ea + 16), shallow=True)
o.help = String.from_ea(get_wide_dword(ea + 20))
return o
@staticmethod
def read_list(list_ea, shallow=False):
lst = []
while True:
ea = get_wide_dword(list_ea)
if ea == 0:
break
if shallow:
lst.append(get_name(ea))
else:
lst.append(Option.from_ea(ea))
list_ea += 4
return lst
def encode(self):
d = dict(_name=self.name, names=self.names, avail=self.avail, param=self.param, help=self.help)
if self.sub is not None:
d['sub'] = self.sub
if self.conflicts is not None:
d['conflicts'] = self.conflicts
return d
class OptionList:
@staticmethod
def from_ea(ea, shallow=False):
if ea == 0:
return None
else:
ol = OptionList()
ol.name = get_name(ea)
ol.help = String.from_ea(get_wide_dword(ea))
ol.flags = get_wide_dword(ea + 4)
list_ea = get_wide_dword(ea + 8)
if list_ea != 0:
ol.list_name = get_name(list_ea)
ol.list = Option.read_list(list_ea, shallow)
return ol
def dump(self):
print(f'OptionList({self.name})')
def encode(self):
d = dict(_name=self.name, flags=self.flags, _list_name=self.list_name, list=self.list)
if self.help is not None:
d['help'] = self.help
return d
def get_optlist_eas():
ea = get_name_ea_simple('_optLists')
lists = []
while True:
list_ea = get_wide_dword(ea)
if list_ea == 0:
break
# list_name = get_name(list_ea)
lists.append(list_ea)
ea += 4
return lists
optlists = []
for ea in get_optlist_eas():
optlists.append(OptionList.from_ea(ea))
def enc(obj):
if hasattr(obj, 'encode'):
return obj.encode()
else:
raise TypeError
with open('/Users/ash/src/mwcc/opts.json', 'w') as f:
json.dump(optlists, f, sort_keys=True, indent=4, default=enc)