Как редактировать таблицы виртуальных и динамических методов?
Как редактировать таблицы виртуальных и динамических методов?
unitEditorVMTandDMTTables;
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.