Foreign blame the skillful in Delphi call does not declare function

Recommended for you: Get network issues from WhatsUp Gold. Not end users.

A while ago, a period of Win32Asm, research to the later found Win32 ASM actually and C version of the paper. Even the packaging of 32ASM structure similar to VCL database framework a simple version, but up with no interest, no continued in-depth, alas! Found that increasing age, people are more and more lazy.

Rest for a long time, after at sixes and sevens things messed with a heap of, finally found a can be useful things, then joyfully ran to record your blog that backup.

We all know that in Delphi, VC etc. this kind of static checking form language, if you want to use a function, we must first clarify the function structure, and then call the compiler can compile, generate data to make calls according to the function structure declaration. This class of functions such as MessageBox, are provided in the Windows, the time of the call can edit the code according to the statement. For the use of Delphi that use static pre compiled check it, This method is very simple to apply, But if the hypothesis, We need to design a scripting language, Then the script language, We need to call functions in a DLL, So we have to design a Delphi similar to the pre declaration mode, Invoke then the script, Even to the extent that, Can not advance statement, But according to the parameters and the function name to call this function in DLL, Then we write in script at this time., We in the Delphi is not the function structure of the prior statement. According to the conventional to invoke the nature is not feasible, if the function corresponding to each DLL to declare a function from outside, this is not possible, because DLL is not controllable, we do not know the user scripts need to call the DLL function call what, and what in DLL. Then, how do we come to call the DLL, make it realize available in the script. We first analyze the script, first call will need to know the DLL name, then enter the function name, and then is the function parameter, a, is that we have DLL can get DllHandle, DLLHandle and the name of the function, we can get the address of the function CodeAddr.

That is to say we design a script, the script may enter the following:

dll=DllObject('user32.dll');
dll.MessageBoxW(0,'asf','afd',64);

Then we can get in Delphi is the MessageBoxW address and the function parameter to enter, but we did not declare the function. Our goal now is to put the script to parse out and correct to call MessageBoxW in Delphi. Also as mentioned by not declare the function address calling function.

In fact, a function call in any language, is almost, but is the parameter passing and calls and parameter passing, and a lot of models, such as Delphi has Register, Stdcall, Safecall, cdecl, C also has the call mode, Delphi Register mode in the corresponding C fastcall. It is these parameter passing mode due to different parameters into the stack is not the same, Register is preferred by the register, and then into the stack, stdcall and cdecl are directly onto the stack, and the stack order are the parameters into the stack from right to left, the only difference is that the stdcall is not their own management stack when a function is called automatically clean up after the completion stack space, whereas cdecl requires the caller ourselves to clean up the stack space. SafeCall is in stdcall mode and the Com exception handling etc. We generally in the Dll parameter passing modes are stdcall and cdecl, so, here only for the two to be processed.

Then the task is the parameters on the stack, then the call function addresses on the OK. So the important parameters of any is the stack, call address, this is the most simple.

Now we need to analyze the parameters of the stack, we all know that in the 32 bit system, for transmission to 4 bytes, so the parameters basically pass are 4 byte mode, then we are byte, char, wchar, Boolean and other types of needs into 4 bytes to be transmitted, Int64, double occupies 8 bytes, we need to push the 2 4 bytes into. So now we can design two data structures are used to handle the conversion of these types

tva=record
    case Integer of
    0: (vi: Integer);
    1: (vb: Boolean);
    2: (vc: Char);
    3: (vac: AnsiChar);
    4: (vf: Single);
    5: (vd: DWORD);
  end;

  tpint64dbl = record
    case Integer of
      0: (value: int64);
      1: (vdouble: Double);
      2:
        (
          High: DWORD;
          low: DWORD
        )

  end;

TVA structure is designed to be less than 4 bytes 4 bytes into parameters and Push, and tpint64dbl is 8 bytes of Int64 and double into 2 4 bytes of stack, tpint64dbl stack in pressure, pressing low low byte, and then press High high 4 bytes. So these basic parameters can be one one onto the stack. Then some special types of fields, such as object, string, Record stack model and complex types of data, that we only know a little Win32 assembler can know, the stack of these parameters are actually offset address stack, so, the address and then onto the stack on the line.

Then the processing mode can be as follows:

If the parameter is a String, then directly

      st := Params[i];

      tmp := Integer(PChar(st));
      asm
        push tmp
      end;

If Object, then Delphi is in direct address

Then the transmission parameters of the model, we can use for downto 0 in accordance with the rules of the tail of the stack

If the version of Delphi we can directly use array of TValue as a parameter, then the function call mode can be as follows

function InvokeRtti(codeptr: Pointer;Params: array of TValue): Integer;overload;
var
  i: Integer;
  type
    tva=record
      case Integer of
      0: (vi: Integer);
      1: (vb: Boolean);
      2: (vc: Char);
      3: (vac: AnsiChar);
      4: (vf: Single);
      5: (vd: DWORD);
    end;
    tpint64dbl = record
      case Integer of
        0: (value: int64);
        1: (vdouble: Double);
        2:
         (
           High: DWORD;
           low: DWORD
         )
    end;
var
  p64: tpint64dbl;
  v: tva;
  tmp: Integer;
  st: string;
begin
  for i := High(Params) downto 0 do
  begin
    case Params[i].TypeInfo.Kind of
    tkInteger:
      begin
        tmp := Params[i].AsInteger;
        asm
          push tmp
        end;
      end;
    tkChar:
    begin
       v.vac := params[i].AsType<AnsiChar>;
       asm
          push v
       end;
    end;
    tkWChar:
    begin
      v.vc := Params[i].AsType<Char>;
      asm
          push v
      end;
    end;
    tkFloat:
      begin
        v.vf := Params[i].AsType<Single>;
        asm
          push v
        end;
      end;
    tkInt64:
      begin
        p64.value := Params[i].AsInt64;
        asm
          lea ecx,p64
          push [ecx][4] //Lower byte, repress the high byte
          push [ecx][0]
        end;
      end;
    tkRecord,tkClass:
      begin
        tmp := Integer(Params[i].GetReferenceToRawData);
        asm
          push tmp
        end;
      end;
    tkString,tkUString:
      begin
        st := Params[i].AsString;
        tmp := Integer(PChar(st));
        asm
          push tmp
        end;
      end;
    end;
  end;
  tmp := Integer(codeptr);
  asm
    call tmp
    mov  result,eax
  end;

end;


Method of use

h := LoadLibrary('user32.dll');
  if h <> 0 then
    fh := GetProcAddress(h,'MessageBoxW');
if fh <> nil then
  begin
  InvokeRtti(fh,[TValue.From(Handle),'asf','234',64])

  end;


If it is a low version, can be composed of Variant to realize the following

function Invoke(codeptr: Pointer;Params: array of Variant): Integer;overload;
var
  i: Integer;
  type
    tva=record
      case Integer of
      0: (vi: Integer);
      1: (vb: Boolean);
      2: (vc: Char);
      3: (vac: AnsiChar);
      4: (vf: Single);
      5: (vd: DWORD);
    end;
    tpint64dbl = record
      case Integer of
        0: (value: int64);
        1: (vdouble: Double);
        2:
         (
           High: DWORD;
           low: DWORD
         )
    end;
var
  p64: tpint64dbl;
  v: tva;
  tmp: Integer;
  st: string;
  ast: AnsiString;
  vtype: TVarType;
begin
  for i := High(Params) downto 0 do
  begin
    vtype := VarType(Params[i]);
    case vtype of
    varUString:
      begin
        st := Params[i];
        tmp := Integer(PChar(st));
        asm
          push tmp
        end;
      end;
    varString:
      begin
        st := Params[i];
        ast := AnsiString(st);
        tmp := Integer(PAnsiChar(ast));
        asm
          push tmp
        end;
      end;
    varInteger,varSmallint,varWord,varByte:
      begin
        v.vi := Params[i];
        asm
          push v
        end;
      end;
    varLongWord:
      begin
        v.vd := Params[i];
        asm
          push v
        end;
      end;
    varSingle:
      begin
        v.vf := Params[i];
        asm
          push v
        end;
      end;
    varDouble:
      begin
        p64.vdouble := Params[i];
        asm
          lea ecx,p64
          push [ecx][4] //Lower byte, repress the high byte
          push [ecx][0]
        end;
      end;
    varInt64:
      begin
        p64.value := Params[i];
        asm
          lea ecx,p64
          push [ecx][4] //Lower byte, repress the high byte
          push [ecx][0]
        end;
      end;
    end;
  end;
  tmp := Integer(codeptr);
  asm
    call tmp
    mov  result,eax
  end;

end;


Usage is similar to the following:

procedure Showmsg(msg: string;tmp: Double); stdcall;
begin
  ShowMessage(msg+floattostr(tmp));
end;

var
  tmp: Single;
begin
  tmp := 13234.24;
  Invoke(@Showmsg,['asfsf',tmp])

end;


So basically the function is complete, but this method has not a good question, that is to call the function returns a result, unpredictable, returns are both of type integer, and the results can not determine the return address is integer or is or is he the type. In addition, this method is not comprehensive, parameter if you want to use a comprehensive please assembly reference Delphi corresponding to the function call transfer process corresponding to the correction.


Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Posted by Maxwell at January 09, 2014 - 6:44 PM