Как найти методы в байт-коде AVM2? - PullRequest
5 голосов
/ 03 ноября 2010

Я играл с байт-кодом ABC и надеялся, что кто-нибудь сможет прояснить ситуацию для меня. У меня есть простой флэш-файл, который помещает клип на сцену и имеет крошечный скрипт для обновления своей позиции в каждом кадре. Код выглядит примерно так:

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 класса. К сожалению, поле 'name' в информации о методе никогда не используется компилятором. Все методы имеют пустую строку в качестве имени (показана выше как безымянная функция в ### 2).

Как флеш-плеер связывает мультинаимен с неназванным методом? Как представляется, в спецификации AVM2 этого нет.

Я знаю, что это возможно, потому что коммерческие декомпиляторы, такие как sothink, могут определить имя метода. Я просто не уверен, как они это делают, или как код мог когда-либо работать.

Ответы [ 3 ]

5 голосов
/ 04 ноября 2010

Я не уверен, почему ваш декомпилятор показывает метод как (анонимный).

Вот дамп 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 имеет одну черту (moveit) вида Trait_Method, что означает, что черта имеет ссылку на метод (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
}

Несколько упрощенный ответ, но я надеюсь, что он устраняет некоторые проблемы.

0 голосов
/ 04 ноября 2010

Оказывается, что имена методов являются многоименными, хранящимися в признаках класса; проблема усугубляется тем, что я искал имена признаков в таблице строк, а не в таблице с несколькими именами. К сожалению.

Кажется, однако, что поле имени метода является избыточным в файле ABC.

0 голосов
/ 04 ноября 2010

я изучаю as3swf и as3abc libs точно в данный момент), а getlex упоминается дважды в as3abc lib:

package com.codeazur.as3abc.factories
    public function create(code:int):AbstractOperation
        switch (code) {//in real life this switch block is really huge
             case Opcodes.GetLex:    return new MultinameOperation(code);
        }

и:

package com.codeazur.as3abc.data.bytecode
public class Opcodes

public static const GetLex:uint = 0x60;
_opNames[ GetLex ] = "GetLex";

так, как я понимаюэто просто ключевое слово внутри AVM2.и более подробно о вашем вопросе: я думаю здесь:

getlex (flash.events.Event);GetProperty (ENTER_FRAME);getlex (внутренний .moveit);
callpropvoid (addEventListener, 2);

мы можем видеть своего рода добавление прослушивателя событий (или, может быть, я просто сумасшедший) и еще одну вещь, которую стоит упомянуть: ваша бывшая функция moveit единственная, которая принимает Eventкак параметр, так что это не сложно назвать именно так.И, кстати: как ты попал внутрь AVM2?может быть, функция настолько внутренняя, что ее имя видно только в том случае, если вы являетесь объектом этого класса;)?
и вот ссылка на некоторый байт-код avm2 от Adobe

...