return res
+StringClass = _AVMClass('(no name idx)', 'String')
+
+
class SWFInterpreter(object):
def __init__(self, file_contents):
+ self._patched_functions = {}
code_tag = next(tag
for tag_code, tag in _extract_tags(file_contents)
if tag_code == 82)
u30() # namespace_idx
name_idx = u30()
self.multinames.append(self.constant_strings[name_idx])
+ elif kind == 0x09:
+ name_idx = u30()
+ u30()
+ self.multinames.append(self.constant_strings[name_idx])
else:
self.multinames.append(_Multiname(kind))
for _c2 in range(MULTINAME_SIZES[kind]):
assert p + code_reader.tell() == len(code_tag)
+ def patch_function(self, avm_class, func_name, f):
+ self._patched_functions[(avm_class, func_name)] = f
+
def extract_class(self, class_name):
try:
return self._classes_by_name[class_name]
raise ExtractorError('Class %r not found' % class_name)
def extract_function(self, avm_class, func_name):
+ p = self._patched_functions.get((avm_class, func_name))
+ if p:
+ return p
if func_name in avm_class.method_pyfunctions:
return avm_class.method_pyfunctions[func_name]
if func_name in self._classes_by_name:
self._classes_by_name, avm_class.variables])
while True:
opcode = _read_byte(coder)
- if opcode == 17: # iftrue
+ if opcode == 16: # jump
+ offset = s24()
+ coder.seek(coder.tell() + offset)
+ elif opcode == 17: # iftrue
offset = s24()
value = stack.pop()
if value:
value = stack.pop()
if not value:
coder.seek(coder.tell() + offset)
+ elif opcode == 19: # ifeq
+ offset = s24()
+ value2 = stack.pop()
+ value1 = stack.pop()
+ if value2 == value1:
+ coder.seek(coder.tell() + offset)
+ elif opcode == 20: # ifne
+ offset = s24()
+ value2 = stack.pop()
+ value1 = stack.pop()
+ if value2 != value1:
+ coder.seek(coder.tell() + offset)
+ elif opcode == 32: # pushnull
+ stack.append(None)
elif opcode == 36: # pushbyte
v = _read_byte(coder)
stack.append(v)
+ elif opcode == 38: # pushtrue
+ stack.append(True)
+ elif opcode == 39: # pushfalse
+ stack.append(False)
elif opcode == 42: # dup
value = stack[-1]
stack.append(value)
res = args[0].join(obj)
stack.append(res)
continue
+ elif obj == StringClass:
+ if mname == 'String':
+ assert len(args) == 1
+ assert isinstance(args[0], (int, compat_str))
+ res = compat_str(args[0])
+ stack.append(res)
+ continue
+ else:
+ raise NotImplementedError(
+ 'Function String.%s is not yet implemented'
+ % mname)
raise NotImplementedError(
'Unsupported property %r on %r'
% (mname, obj))
+ elif opcode == 71: # returnvoid
+ res = None
+ return res
elif opcode == 72: # returnvalue
res = stack.pop()
return res
args = list(reversed(
[stack.pop() for _ in range(arg_count)]))
obj = stack.pop()
+ if isinstance(obj, _AVMClass_Object):
+ func = self.extract_function(obj.avm_class, mname)
+ res = func(args)
+ assert res is None
+ continue
+ if isinstance(obj, _ScopeDict):
+ assert mname in obj.avm_class.method_names
+ func = self.extract_function(obj.avm_class, mname)
+ res = func(args)
+ assert res is None
+ continue
if mname == 'reverse':
assert isinstance(obj, list)
obj.reverse()
break
else:
res = scopes[0]
- stack.append(res[mname])
+ if mname not in res and mname == 'String':
+ stack.append(StringClass)
+ else:
+ stack.append(res[mname])
elif opcode == 94: # findproperty
index = u30()
mname = self.multinames[index]
pname = self.multinames[index]
if pname == 'length':
obj = stack.pop()
- assert isinstance(obj, list)
+ assert isinstance(obj, (compat_str, list))
stack.append(len(obj))
+ elif isinstance(pname, compat_str): # Member access
+ obj = stack.pop()
+ assert isinstance(obj, (dict, _ScopeDict)), \
+ 'Accessing member %r on %r' % (pname, obj)
+ res = obj.get(pname, None)
+ stack.append(res)
else: # Assume attribute access
idx = stack.pop()
assert isinstance(idx, int)
value1 = stack.pop()
res = value1 % value2
stack.append(res)
+ elif opcode == 171: # equals
+ value2 = stack.pop()
+ value1 = stack.pop()
+ result = value1 == value2
+ stack.append(result)
elif opcode == 175: # greaterequals
value2 = stack.pop()
value1 = stack.pop()