我一直在玩 ABC 字节码,希望有人能帮我解决一个困惑。我有一个简单的 Flash 文件,它在舞台上放置一个剪辑,并有一个小脚本来更新它在每一帧上的位置。代码看起来像:
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class RedCircle extends MovieClip
{
public function RedCircle()
{
this.addEventListener(Event.ENTER_FRAME, moveit);
}
function moveit(e:Event)
{
this.x -=1;
}
}
}
编译成类似的东西:
protected package protected RedCircle
{
class RedCircle extends flash.display.MovieClip
{
static () : Void
{
getlocal_0();
pushscope();
returnvoid();
}
RedCircle () : Void
{
getlocal_0();
pushscope();
getlocal_0();
constructsuper(0);
getlocal_0();
getlex(flash.events.Event);
getproperty(ENTER_FRAME);
getlex(internal .moveit); // ###1
callpropvoid(addEventListener, 2);
returnvoid();
}
function (anonymous) (flash.events.Event param1) : Void // ###2
{
getlocal_0();
pushscope();
getlocal_0();
getlocal_0();
getproperty(x);
decrement();
setproperty(x);
returnvoid();
}
}
}
我的问题是“getlex”操作是如何工作的(我用###1 标记了它)。它被传递一个引用类的“moveit”方法的多名称。不幸的是,方法信息中的“名称”字段似乎永远不会被编译器使用。所有方法都以空字符串作为其名称(如上图 ###2 处的未命名函数所示)。
Flash 播放器如何将多名称链接到未命名方法? AVM2 规范中似乎没有这方面的规定。
我知道这是可能的,因为像 sothink 这样的商业反编译器设法确定方法名称。我只是不确定他们是如何做到的,或者代码如何工作。
最佳答案
我不确定为什么您的反编译器将该方法显示为(匿名)。
这是 abcData 的转储:
abcFile{
minor_version (17): 16
major_version (19): 46
constant_pool{
int_count (21): 0
[0]: zero (not included in abcFile)
uint_count (22): 0
[0]: zero (not included in abcFile)
double_count (23): 0
[0]: NaN (not included in abcFile)
string_count (24): 17
string_info[0]{
name: * (not included in abcFile)
}
string_info[1]{
size (25): 12
name (26): "flash.events"
}
string_info[2]{
size (38): 5
name (39): "Event"
}
string_info[3]{
size (44): 0
name (45): ""
}
string_info[4]{
size (45): 9
name (46): "RedCircle"
}
string_info[5]{
size (55): 13
name (56): "flash.display"
}
string_info[6]{
size (69): 9
name (70): "MovieClip"
}
string_info[7]{
size (79): 6
name (80): "moveit"
}
string_info[8]{
size (86): 11
name (87): "ENTER_FRAME"
}
string_info[9]{
size (98): 16
name (99): "addEventListener"
}
string_info[10]{
size (115): 1
name (116): "x"
}
string_info[11]{
size (117): 6
name (118): "Object"
}
string_info[12]{
size (124): 15
name (125): "EventDispatcher"
}
string_info[13]{
size (140): 13
name (141): "DisplayObject"
}
string_info[14]{
size (154): 17
name (155): "InteractiveObject"
}
string_info[15]{
size (172): 22
name (173): "DisplayObjectContainer"
}
string_info[16]{
size (195): 6
name (196): "Sprite"
}
namespace_count (202): 6
namespace_info[0]{
kind: * (not included in abcFile)
}
namespace_info[1]{
kind (203): CONSTANT_PackageNamespace
name (204): 1
}
namespace_info[2]{
kind (205): CONSTANT_PackageNamespace
name (206): 3
}
namespace_info[3]{
kind (207): CONSTANT_PackageNamespace
name (208): 5
}
namespace_info[4]{
kind (209): CONSTANT_ProtectedNamespace
name (210): 4
}
namespace_info[5]{
kind (211): CONSTANT_PackageInternalNs
name (212): 3
}
ns_set_count (213): 0
ns_set_info[0]{
ns: 0 (not included in abcFile)
}
multiname_count (214): 14
multiname_info[0]{
kind: 0 (not included in abcFile)
}
multiname_info[1]{
kind (216): CONSTANT_QName
multiname_kind_QNAME{
ns (216): 1
name (217): 2 ("Event")
}
}
multiname_info[2]{
kind (219): CONSTANT_QName
multiname_kind_QNAME{
ns (219): 2
name (220): 4 ("RedCircle")
}
}
multiname_info[3]{
kind (222): CONSTANT_QName
multiname_kind_QNAME{
ns (222): 3
name (223): 6 ("MovieClip")
}
}
multiname_info[4]{
kind (225): CONSTANT_QName
multiname_kind_QNAME{
ns (225): 5
name (226): 7 ("moveit")
}
}
multiname_info[5]{
kind (228): CONSTANT_QName
multiname_kind_QNAME{
ns (228): 2
name (229): 8 ("ENTER_FRAME")
}
}
multiname_info[6]{
kind (231): CONSTANT_QName
multiname_kind_QNAME{
ns (231): 2
name (232): 9 ("addEventListener")
}
}
multiname_info[7]{
kind (234): CONSTANT_QName
multiname_kind_QNAME{
ns (234): 2
name (235): 10 ("x")
}
}
multiname_info[8]{
kind (237): CONSTANT_QName
multiname_kind_QNAME{
ns (237): 2
name (238): 11 ("Object")
}
}
multiname_info[9]{
kind (240): CONSTANT_QName
multiname_kind_QNAME{
ns (240): 1
name (241): 12 ("EventDispatcher")
}
}
multiname_info[10]{
kind (243): CONSTANT_QName
multiname_kind_QNAME{
ns (243): 3
name (244): 13 ("DisplayObject")
}
}
multiname_info[11]{
kind (246): CONSTANT_QName
multiname_kind_QNAME{
ns (246): 3
name (247): 14 ("InteractiveObject")
}
}
multiname_info[12]{
kind (249): CONSTANT_QName
multiname_kind_QNAME{
ns (249): 3
name (250): 15 ("DisplayObjectContainer")
}
}
multiname_info[13]{
kind (252): CONSTANT_QName
multiname_kind_QNAME{
ns (252): 3
name (253): 16 ("Sprite")
}
}
}
method_count (254): 4
method_info[0]{
param_count (255): 0
return_type (256): 0
name (257): 0
flags (258): 0
NEED_ARGUMENTS (0x01): false
NEED_ACTIVATION (0x02): false
NEED_REST (0x04): false
HAS_OPTIONAL (0x08): false
SET_DXNS (0x40): false
HAS_PARAM_NAMES (0x80): false
}
method_info[1]{
param_count (259): 0
return_type (260): 0
name (261): 0
flags (262): 0
NEED_ARGUMENTS (0x01): false
NEED_ACTIVATION (0x02): false
NEED_REST (0x04): false
HAS_OPTIONAL (0x08): false
SET_DXNS (0x40): false
HAS_PARAM_NAMES (0x80): false
}
method_info[2]{
param_count (263): 1
return_type (264): 0
param_type[0] (265): 1
name (266): 0
flags (267): 0
NEED_ARGUMENTS (0x01): false
NEED_ACTIVATION (0x02): false
NEED_REST (0x04): false
HAS_OPTIONAL (0x08): false
SET_DXNS (0x40): false
HAS_PARAM_NAMES (0x80): false
}
method_info[3]{
param_count (268): 0
return_type (269): 0
name (270): 0
flags (271): 0
NEED_ARGUMENTS (0x01): false
NEED_ACTIVATION (0x02): false
NEED_REST (0x04): false
HAS_OPTIONAL (0x08): false
SET_DXNS (0x40): false
HAS_PARAM_NAMES (0x80): false
}
metadata_count (272): 0
class_count (273): 1
instance_info[0]{
name (274): 2 (RedCircle)
super_name (275): 3 (MovieClip)
flags (276): 9
CONSTANT_ClassSealed (0x01): true
CONSTANT_ClassFinal (0x02): false
CONSTANT_ClassInterface (0x04): false
CONSTANT_ClassProtectedNs (0x08): true
protectedNs (277): 4
intrf_count (278): 0
iinit (279): 1
trait_count (280): 1
traits_info[0]{
name (281): 4 (moveit)
kind (282): Trait_Method
ATTR_Final (0x1): false
ATTR_Override (0x2): false
ATTR_Metadata (0x4): false
trait_method{
disp_id (283): 0
method (284): 2
}
}
}
class_info[0]{
cinit (285): 0
trait_count (286): 0
}
script_count (287): 1
init (288): 3
trait_count (289): 1
traits_info[0]{
name (290): 2 (RedCircle)
kind (291): Trait_Class
ATTR_Metadata (0x4): false
trait_class{
slot_id (292): 1
classi (293): 0
}
}
method_body_count (294): 4
method_body_info[0]{
method (295): 0
max_stack (296): 1
local_count (297): 1
init_scope_depth (298): 9
max_scope_depth (299): 10
code_length (300): 3
208 0xD0 (301) getlocal_0
48 0x30 (302) pushscope
71 0x47 (303) returnvoid
exception_count (304): 0
trait_count (305): 0
}
method_body_info[1]{
method (306): 1
max_stack (307): 3
local_count (308): 1
init_scope_depth (309): 10
max_scope_depth (310): 11
code_length (311): 17
208 0xD0 (312) getlocal_0
48 0x30 (313) pushscope
208 0xD0 (314) getlocal_0
73 0x49 (315) constructsuper
arg_count: 0
208 0xD0 (317) getlocal_0
96 0x60 (318) getlex
index: 1 (Event)
102 0x66 (320) getproperty
index: 5 (ENTER_FRAME)
208 0xD0 (322) getlocal_0
102 0x66 (323) getproperty
index: 4 (moveit)
79 0x4F (325) callpropvoid
index: 6 (addEventListener)
arg_count: 2
71 0x47 (328) returnvoid
exception_count (329): 0
trait_count (330): 0
}
method_body_info[2]{
method (331): 2
max_stack (332): 3
local_count (333): 2
init_scope_depth (334): 10
max_scope_depth (335): 11
code_length (336): 10
208 0xD0 (337) getlocal_0
48 0x30 (338) pushscope
208 0xD0 (339) getlocal_0
208 0xD0 (340) getlocal_0
102 0x66 (341) getproperty
index: 7
147 0x93 (343) decrement
97 0x61 (344) setproperty
index: 7
71 0x47 (346) returnvoid
exception_count (347): 0
trait_count (348): 0
}
method_body_info[3]{
method (349): 3
max_stack (350): 2
local_count (351): 1
init_scope_depth (352): 1
max_scope_depth (353): 9
code_length (354): 39
208 0xD0 (355) getlocal_0
48 0x30 (356) pushscope
101 0x65 (357) getscopeobject
index: 0
96 0x60 (359) getlex
index: 8
48 0x30 (361) pushscope
96 0x60 (362) getlex
index: 9
48 0x30 (364) pushscope
96 0x60 (365) getlex
index: 10
48 0x30 (367) pushscope
96 0x60 (368) getlex
index: 11
48 0x30 (370) pushscope
96 0x60 (371) getlex
index: 12
48 0x30 (373) pushscope
96 0x60 (374) getlex
index: 13
48 0x30 (376) pushscope
96 0x60 (377) getlex
index: 3
48 0x30 (379) pushscope
96 0x60 (380) getlex
index: 3
88 0x58 (382) newclass
index: 0
29 0x1D (384) popscope
29 0x1D (385) popscope
29 0x1D (386) popscope
29 0x1D (387) popscope
29 0x1D (388) popscope
29 0x1D (389) popscope
29 0x1D (390) popscope
104 0x68 (391) initproperty
index: 2
71 0x47 (393) returnvoid
exception_count (394): 0
trait_count (395): 0
}
}
您在这里感兴趣的是 instance_info[0]。这是一个类的运行时实例的定义,这里是 RedCircle。实例具有各种类型的特征数组。 RedCircle 有一个 Trait_Method 类型的特征 (moveit),这意味着该特征具有对方法 (2) 的引用。
因此,如果您跳到 method_body_info[1](RedCircle 的构造函数),您可以在第 323 字节看到 getProperty 被调用,索引为 4。
102 0x66 (323) getproperty
index: 4 (moveit)
这是对多名称常量池的引用。
multiname_info[4]{
kind (225): CONSTANT_QName
multiname_kind_QNAME{
ns (225): 5
name (226): 7 ("moveit")
}
}
在调用方法时,它会在实例的特征中查找名称索引。
traits_info[0]{
name (281): 4 (moveit)
kind (282): Trait_Method
ATTR_Final (0x1): false
ATTR_Override (0x2): false
ATTR_Metadata (0x4): false
trait_method{
disp_id (283): 0
method (284): 2
}
}
然后调用相关方法。
method_info[2]{
param_count (263): 1
return_type (264): 0
param_type[0] (265): 1
name (266): 0
flags (267): 0
NEED_ARGUMENTS (0x01): false
NEED_ACTIVATION (0x02): false
NEED_REST (0x04): false
HAS_OPTIONAL (0x08): false
SET_DXNS (0x40): false
HAS_PARAM_NAMES (0x80): false
}
method_body_info[2]{
method (331): 2
max_stack (332): 3
local_count (333): 2
init_scope_depth (334): 10
max_scope_depth (335): 11
code_length (336): 10
208 0xD0 (337) getlocal_0
48 0x30 (338) pushscope
208 0xD0 (339) getlocal_0
208 0xD0 (340) getlocal_0
102 0x66 (341) getproperty
index: 7 (x)
147 0x93 (343) decrement
97 0x61 (344) setproperty
index: 7 (x)
71 0x47 (346) returnvoid
exception_count (347): 0
trait_count (348): 0
}
一个稍微简化的答案,但我希望它能解决一些问题。
关于flash - 如何在 AVM2 字节码中找到方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4089291/