Delphi World - Как редактировать таблицы виртуальных и динамических методов
Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Как редактировать таблицы виртуальных и динамических методов

Автор: ___ALex___
WEB-сайт: http://pascal.dax.ru

unit EditorVMTandDMTTables;

interface

// функция служит для выяснения существования VMT у класса
// возвращает True, если класс имеет VMT и False - если нет
function IsVMTExist(Cls: TClass): Boolean;

// процедура служит для замены адреса метода в VMT класса со смещением
// Offset(должно быть кратно 4) новым адресом, хранящимся в NewMet
// примечание: перед вызовом этой процедуры проверяйте существование
// VMT у класса функцией IsVMTExist
procedure VirtMethodReplace(Cls: TClass; Offset: LongWord; NewMet: Pointer);
  overload;

// процедура служит для замены адреса метода, хранящегося в OldMet,
// в VMT класса новым адресом, хранящимся в NewMet
// примечание: перед вызовом этой процедуры проверяйте существование
// VMT у класса функцией IsVMTExist
procedure VirtMethodReplace(Cls: TClass; OldMet, NewMet: Pointer); overload;

// функция служит для замены адреса динамического метода класса с индексом,
// хранящимся в Index, новым адресом, хранящимся в NewMet
// возвращает True, если метод с данным индексом найден и False - если нет
function DynMethodReplace(Cls: TClass; Index: Word; NewMet: Pointer): Boolean;
  overload;

// функция служит для замены адреса динамического метода класса, хранящегося
// в OldMet, новым адресом, хранящимся в NewMet
// возвращает True, если метод с данным адресом найден и False - если нет
function DynMethodReplace(Cls: TClass; OldMet, NewMet: Pointer): Boolean;
  overload;

implementation

// функция служит для получения указателя на байт, следующий за адресом
// последнего метода в VMT класса
// возвращает nil в случае, если у класса нет VMT
// функция является "внутренней" в модуле
// (используется другими подпрограммами и не объявлена в секции interface)
// , поэтому используйте её только если
// Вы полностью уверены в своих действиях(она изменяет "рабочие" регистры
// ECX и EDX)

function GetVMTEnd(Cls: TClass): Pointer;
asm
        // Вход: Cls --> EAX
        // Выход: Result --> EAX

        PUSH    EBX
        MOV     ECX, 8
        MOV     EBX, -1
        MOV     EDX, vmtSelfPtr
@@cycle:
        ADD     EDX, 4
        CMP     [EAX + EDX], EAX
        JE      @@vmt_not_found
        JB      @@continue
        CMP     [EAX + EDX], EBX
        JAE     @@continue
        MOV     EBX, [EAX + EDX]
@@continue:
        DEC     ECX
        JNZ     @@cycle
        MOV     EAX, EBX
        JMP     @@exit
@@vmt_not_found:
        XOR     EAX, EAX
@@exit:
        POP     EBX

end;

function IsVMTExist(Cls: TClass): Boolean;
asm
        // Вход: Cls --> EAX
        // Выход: Result --> AL

        CALL    GetVMTEnd
        TEST    EAX, EAX
        JZ      @@vmt_not_found
        MOV     AL, 1
@@vmt_not_found:

end;

procedure VirtMethodReplace(Cls: TClass; Offset: LongWord; NewMet: Pointer);
  overload;
asm
        // Вход: Cls --> EAX, Offset --> EDX, NewMet --> ECX

        MOV     [EAX + EDX], ECX

end;

procedure VirtMethodReplace(Cls: TClass; OldMet, NewMet: Pointer); overload;
asm
        // Вход: Cls --> EAX, OldMet --> EDX, NewMet --> ECX

        PUSH    EDI
        MOV     EDI, EAX
        PUSH    ECX
        PUSH    EDX
        PUSH    EAX
        CALL    GetVMTEnd
        POP     EDX
        SUB     EAX, EDX
        SHR     EAX, 2
        POP     EDX
        POP     ECX
        PUSH    ECX
        MOV     ECX, EAX
        MOV     EAX, EDX
        POP     EDX
        REPNE   SCASD
        JNE     @@OldMet_not_found
        MOV     [EDI - 4], EDX
@@OldMet_not_found:
        POP     EDI

end;

function DynMethodReplace(Cls: TClass; Index: Word; NewMet: Pointer): Boolean;
  overload;
asm
        // Вход: Cls --> EAX, Index --> DX, NewMet --> ECX
        // Выход: Result --> AL

        PUSH    EDI
        PUSH    ESI
        MOV     ESI, ECX
        XOR     EAX, EDX
        XOR     EDX, EAX
        XOR     EAX, EDX
        JMP     @@start
@@cycle:
        MOV     EDX, [EDX]
@@start:
        MOV     EDI, [EDX].vmtDynamicTable
        TEST    EDI, EDI
        JZ      @@get_parent_dmt
        MOVZX   ECX, WORD PTR [EDI]
        PUSH    ECX
        ADD     EDI, 2
        REPNE   SCASW
        JE      @@Index_found
        POP     ECX
@@get_parent_dmt:
        MOV     EDX, [EDX].vmtParent
        TEST    EDX, EDX
        JNZ     @@cycle
        JMP     @@Index_not_found
@@Index_found:
        POP     EAX
        SHL     EAX, 1
        SUB     EAX, ECX
        MOV     [EDI + EAX * 2 - 4], ESI
        MOV     AL, 1
        JMP     @@exit
@@Index_not_found:
        XOR     AL, AL
@@exit:
        POP     ESI
        POP     EDI

end;

function DynMethodReplace(Cls: TClass; OldMet, NewMet: Pointer): Boolean;
  overload;
asm
        // Вход: Cls --> EAX, OldMet --> EDX, NewMet --> ECX
        // Выход: Result --> AL

        PUSH    EDI
        PUSH    ESI
        MOV     ESI, ECX
        XOR     EAX, EDX
        XOR     EDX, EAX
        XOR     EAX, EDX
        JMP     @@start
@@cycle:
        MOV     EDX, [EDX]
@@start:
        MOV     EDI, [EDX].vmtDynamicTable
        TEST    EDI, EDI
        JZ      @@get_parent_dmt
        MOVZX   ECX, WORD PTR [EDI]
        LEA     EDI, EDI + 2 * ECX + 2
        REPNE   SCASD
        JE      @@OldMet_found
@@get_parent_dmt:
        MOV     EDX, [EDX].vmtParent
        TEST    EDX, EDX
        JNZ     @@cycle
        JMP     @@OldMet_not_found
@@OldMet_found:
        MOV     [EDI - 4], ESI
        MOV     AL, 1
        JMP     @@exit
@@OldMet_not_found:
        XOR     AL, AL
@@exit:
        POP     ESI
        POP     EDI

end;

end.
Проект Delphi World © Выпуск 2002 - 2017
Автор проекта: Эксклюзивные курсы программирования