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 !