Search code examples
delphiassemblyreverse-engineering

Convert ASM to Delphi 7


Unit1.TForm1.Button1Click
    push  0
    push  ebx
    mov   ebx, eax
    ...
    lea   eax,[ebp-4]
    mov   edx,44EB18;`test`
    call  LStrLAsg
    mov   edx,dword ptr [ebp-4]
    mov   eax,dword ptr [ebx+2FC];TForm1.Label1:TLabel
    call  TControl.SetText
    ...

But the Delphi code is simple:

str := 'test';
Label1.Caption := str;

But I wanna use this asm ... end; tag for this. as following code. But I can't compile this code.

asm
  lea         eax,[ebp-4]
  mov         edx, 'test'
  call        @LStrLAsg
  mov         edx,dword ptr [ebp-4]
  mov         eax, TForm1.Label1; TForm1.Label1:TLabel
  call        TControl.SetText
end;

Solution

  • There are several problems with your code, and the biggest one is that TControl.SetText is private. Your code won't assemble, no matter what you try. You will have to use plain Pascal.

    But I'll address the other problems anyway, FYI.

    TL;DR

    Let's start at the beginning:

    lea eax,[ebp-$04]
    

    That tries to take the address of a local variable. You don't know where on the stack this will actually be, so rather use the name. This means you must declare local variables and constants like:

    const
      C: string = 'test'; // In D7, string is AnsiString
    var
      X: string;
    asm
      lea eax,X
      mov edx,C
    

    The assembler will add code to set up the stack frame requried for that.

    But this way, you are discarding eax, which contains the self pointer. You will have to save this first, either in a local variable or by pushing it on the stack:

    var
      LSelf: Pointer;
    asm
      mov LSelf,eax
    

    Later on, you can then use it, e.g. to access the form.

    Then you try to access a hidden System function, _LStrAsg. This is not meant to be used by user code. The compiler has special knowledge about such functions in System.pas. Perhaps it is accessible as

    call System.@LStrAsg
    

    But don't bet on it.

    Then you try to access TForm1.Label1. That is not possible like that in assembler either. You could try something like (untested):

    mov eax,LSelf
    mov eax,[eax].TForm1.Label1
    

    but I am not sure if that works in D7.

    So now we have:

    const
      C: string = 'test'; // In D7, this is an AnsiString, hence _LStrAsg
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      S: string;
      LSelf: Pointer;
    asm
        mov LSelf,eax           // save self pointer
        lea eax,S               // S := C;
        mov edx,C
        call System.@LStrAsg
        mov eax,LSelf           // Self.Label1.Caption := S;
        mov eax,[eax].TForm1.Label1
        mov edx,S
        call TControl.SetText
    end;
    

    But that doesn't compile. The biggest problem is that TControl.SetText is private. You won't be able to access it. I tried several tricks, but to no avail. All of them result in Undeclared identifier: 'SetText'.

    So what is left is to do it without assembler:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Label1.Caption := 'test';
    end;