Einzelnen Beitrag anzeigen

eric_draven

Registriert seit: 26. Jul 2007
15 Beiträge
 
#1

Problem bei dynamischem Aufruf einer DLL mit Übergabe von Pointern ala Win32API

  Alt 14. Mär 2011, 18:14
Hallo,
viele APIs basieren darauf, dass man der aufgerufenen DLL Funktion einen Pointer (PChar) und eine Länge übergibt. Die Funktion schreibt dann direkt auf die Adresse der Variablen im .DATA Segment.
Ein Beispiel hierfür ist z.B. GetWindowsDirectoryA(lpBuffer: PChar; uSize: UINT): UINT in der kernel32.dll
Etwas ähnliches versuche ich auch, ich habe hier versucht, genau diese Funktion nachzubauen, um mein Problem zu verdeutlichen.
Mein Problem ist: Die Adresse, die ich übergeben bekomme weicht aus irgendeinem Grund immer um einige Byte von der tatsächlichen ab ?!?
Ich werde noch bald wahnsinnig und hoffe, hier kann mir geholfen werden
Ich habe versucht, das Ganze mit etwas Code zu verdeutlichen, da es nicht ganz nicht einfach zu erklären ist:
(Das ist mein erster Beitrag, bitte steinigt mich nicht, falls ich im falschen Channel bin oder etwas nicht perfekt formatiert ist )

Der Code des "Callers":
Delphi-Quellcode:
function DynamicDllCallName(Dll: String; const Name: String; HasResult: Boolean; var Returned: Cardinal; const Parameters: array of Pointer): Boolean;
var
  prc: Pointer;
  x, n: Integer;
  p: Pointer;
  dllh: THandle;
begin
  dllh := GetModuleHandle(PChar(Dll));
  if dllh = 0 then dllh := LoadLibrary(PChar(Dll));
  if dllh <> 0 then begin
    prc := GetProcAddress(dllh, PChar(Name));
    if Assigned(prc) then begin
      n := High(Parameters);
      if n > -1 then begin
        x := n;
        repeat
          p := Parameters[x];
          asm
            PUSH p //Parameterpointer auf den Stack
            //bei stdcall, räumt die aufgerufene Funkion den Stack auf (POP nicht notwendig)
          end;
          Dec(x);
        until x = -1;
      end;
      asm
        CALL prc //Funktionsaufruf
      end;
      if HasResult then begin
        asm
          MOV p, EAX //Ergebnispointer aus EAX Register
        end;
        Returned := Cardinal(p);
      end else begin
        Returned := 0;
      end;
    end else begin
      Returned := 0;
    end;
    Result := Assigned(prc);
  end else begin
    Result := false;
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
Var lpBuffer : PChar;
    parameters: array of Pointer;
    returned: Cardinal;
begin
  GetMem(lpBuffer, 255);
  Label1.Caption := Format ('@lpBuffer:%p', [@lpBuffer]); //Ergibt bei mir: 0012F610
  SetLength(parameters, 2);
  parameters[0] := Pointer(lpBuffer);
  parameters[1] := Pointer(255);
  //function GetWindowsDirectory(lpBuffer: PChar; uSize: UINT): UINT; stdcall;
// DynamicDllCallName('C:\windows\system32\kernel32.dll', 'GetWindowsDirectoryA', true, returned, parameters);
  DynamicDllCallName('C:\DLL_Dynamisch_PChar\project1.dll', 'GetWindowsDirectoryA', true, returned, parameters);
  Label2.Caption := lpBuffer;
  Freemem(lpBuffer);
end;
und die DLL:
Delphi-Quellcode:
library Project1;
uses
  SysUtils,
  Windows;

{$R *.res}

function GetWindowsDirectoryA(lpBuffer : PChar; uSize : UINT) : UINT; stdcall;
Begin
  OutputDebugString(PChar(Format('Project1.dll->GetWindowsDirectoryA(%p,%d)',[@lpBuffer, uSize])));
  //@lpBuffer ist 0012F5AC, laut Project1.exe ist es aber 0012F610
  lpBuffer := 'test';
  Result := 0;
End;

Exports GetWindowsDirectoryA;


begin
end.
Die Zeile im Caller mit dem Aufruf der original kernel32.dll Funktion ist auskommentiert, mit diesem funktioniert es aber.
Im unteren Codeschnipsel steht mein Kommentar, wo das Problem liegt:
//@lpBuffer ist 0012F5AC, laut Project1.exe ist es aber 0012F610
Die Variable uSize wird z.B. korrekt übergeben.
0012F610 ist die korrekte Adresse, wenn ich die Variable nicht mit FreeMem freigebe und als global deklariere, kann ich den Bereich mit OllyDbg erfolgreich ansehen & ändern, um ihn z.B. per Button wieder aufs Label zu geben.
Bin für jede Hilfe dankbar !

Geändert von eric_draven (14. Mär 2011 um 19:37 Uhr) Grund: Zeile hinzugefügt
  Mit Zitat antworten Zitat