diff options
Diffstat (limited to '')
-rw-r--r-- | optdump.py | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/optdump.py b/optdump.py new file mode 100644 index 0000000..b1bb42e --- /dev/null +++ b/optdump.py @@ -0,0 +1,386 @@ +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) |