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)