Örnek vermek gerekirse:
Kod: Tümünü seç
type
TMyClass = class(TObject)
private
FValue: Longword;
public
function GetValue(Handle: Longword): Longword; stdcall;
end;
function TMyClass.GetValue(Handle: Longword): Longword;
begin
Result:= Self.FValue;
end;
Ben de bunun üzerine daha nefis bir yöntem hackledim. Hackledim diyorum çünkü başka bir componentin uyguladığı yöntemi aldım. Componentin source'u olmadığından debugger'a güvendim. Assembler modunda trace ederek adamların yöntemini çözdüm. Aslında oldukça basit ve zekice bir yöntemdi...
Adamlar Self pointer'ın içeriğini önceden bellekte saklıyor, daha sonra bu pointer'ı stack a push edip method call gerçekleştiriyor. Bunun için şuna benzer bir wrapper yazmışlar.
Kod: Tümünü seç
pop edx // Handle parametresi stack'ten alınıyor.
mov eax, Self
push eax // İlk parametre olarak Self stack'e koyuluyor.
push edx // Handle parametresi stack'e koyuluyor.
jmp TMyClass.GetValue // method jump yapılıyor.
Bu jump kodunu neden static vermedik diyecek olursanız, wrapper stub kodunu oluşturup bellekte yer ayırıyoruz. Ayrılan bellek adresi hep aynı olmadığından jump offset te hep değişecektir. Bu yüzden stub koduna yer ayırdıktan sonra hesaplanması gerekir.
Ben stub'ı şu şekilde oluşturmayı tercih ettim:
Kod: Tümünü seç
type
TStubRecord = packed record
pop_edx: Byte;
mov_eax: Byte;
SelfPtr: Pointer;
push_eax: Byte;
push_edx: Byte;
jmp_near: Byte;
MethodOffset: Pointer;
end;
procedure CreateStub;
begin
// Stub'a bellek ayır.
GetMem(FStub, SizeOf(TStubRecord));
with TStubRecord(FStub^) do
begin
// Burada instruction opcode'larını yazıyoruz.
pop_edx:= $5A; // Pop EDX
mov_eax:= $B8; // Mov EAX, FFunction
// Self'i de koyduk.
SelfPtr:= FSelfPtr;
push_eax:= $50; // Push EAX
push_edx:= $52; // Push EDX
jmp_near:= $E9; // Jmp FMethodPtr
// Method'a sıçrama adresini hesaplar
MethodOffset:= Pointer(Integer(FMethodPtr) - Integer(FStub) -
SizeOf(TStubRecord));
end;
end;