diff options
Diffstat (limited to '')
| -rw-r--r-- | README | 5 | ||||
| -rw-r--r-- | classy.py | 63 | 
2 files changed, 47 insertions, 21 deletions
| @@ -38,6 +38,7 @@ Supported so far:     - Overrides are shown at the top of the original method body     - Renames and argument list changes are propagated from original methods       to overrides (Though not vice versa yet) +   - Pure virtuals are supported  That's all for now, I think... @@ -51,8 +52,6 @@ Current Todo:  - Named arguments to methods  - Return types for methods  - Const methods -- Improve vtable end detection heuristics -- Support pure virtuals.  - Handle IDA chooser history/defaults correctly everywhere  - Better keybindings  - Rename class menu item @@ -70,7 +69,7 @@ Caveats:  - Probably won't work as well with non-CodeWarrior stuff.  Notes: -- When autocreating virtual methods, start with the base class!! +- When creating virtual methods, start with the base class!!    Otherwise, you might end up defining an override as a virtual    method. And that would be bad. @@ -194,7 +194,9 @@ class Class(object):  	def find_vtable_end(self):  		check = self.vtable + 4 -		while Dword(check + 4) != 0: +		while True: +			value = Dword(check + 4) +			if value < 0x80000000 or value > 0x817FFFFF: break  			check += 4  		print('Inferred vtable as %08x .. %08x' % (self.vtable, check)) @@ -307,6 +309,7 @@ class Method(object):  	def is_null(self): return False  	def is_virtual(self): return False +	def has_code(self): return True  	def rename(self, name):  		self.name = name @@ -315,22 +318,23 @@ class Method(object):  	def refresh(self):  		MakeName(self.ea, "%s__%s%s" % (self.name, self.owner.mangled_name, self.mangled_args)) -		# figure out if any virtual xrefs include us -		# a bit slow, but who cares -		call_dict = db.virtual_calls -		func = idaapi.get_func(self.ea) -		check = func.startEA -		end = func.endEA +		if self.has_code(): +			# figure out if any virtual xrefs include us +			# a bit slow, but who cares +			call_dict = db.virtual_calls +			func = idaapi.get_func(self.ea) +			check = func.startEA +			end = func.endEA -		done_already = {} +			done_already = {} -		while check <= end: -			if check in call_dict: -				method = call_dict[check] -				if method not in done_already: -					method.refresh_comment() -					done_already[method] = True -			check += 4 +			while check <= end: +				if check in call_dict: +					method = call_dict[check] +					if method not in done_already: +						method.refresh_comment() +						done_already[method] = True +				check += 4  	def unlink(self, orphan=False):  		if self.name == '__ct': @@ -437,13 +441,20 @@ class VirtualMethod(Method):  		SetFunctionCmt(self.ea, self.get_comment(), 0) +class PureVirtualMethod(VirtualMethod): +	def has_code(self): return False + +	def __init__(self, owner, name, vt_offset): +		VirtualMethod.__init__(self, owner, name, owner.vtable+vt_offset, vt_offset) +	 +	def refresh_comment(self): +		MakeComm(self.ea, self.get_comment()) + +  class OverrideMethod(VirtualMethod):  	def __init__(self, owner, name, ea, vt_offset, base):  		VirtualMethod.__init__(self, owner, name, ea, vt_offset) -		if ea == BADADDR || ea == 0: -			raise ValueError("An override method can't be pure!!") -  		self.base = base  		self.original = (hasattr(base, 'original') and base.original) or base  		self.copy_signature(self.original) @@ -547,6 +558,10 @@ def get_current_function():  		func = idaapi.get_func(Dword(ea))  	if func is None: +		# otherwise, might be entered into the method DB (as a pure virtual?) +		if ea in db.known_methods: +			return ea +  		# and if it's still none ...  		Warning('Place the cursor on top of a function.')  		raise ValueError @@ -728,7 +743,19 @@ def register_virtual_method():  		Warning('This class does not have a virtual table defined.')  		return +	# check for pure virtuals and handle them separately +	current_ea = idaapi.get_screen_ea() +	if Dword(current_ea) == 0 and current_ea > cls.vtable and current_ea <= cls.vtable_end: +		offset = current_ea - cls.vtable + +		name = idaapi.askstr(idaapi.HIST_IDENT, 'vf%02X' % offset, 'Enter a name for this pure virtual') +		method = PureVirtualMethod(cls, name, offset) +		method.refresh() +		Refresh() +		return +  	ea = get_current_function() +  	unlink_method_if_exists(ea)  	# try to find it within the vtable | 
