Tworzenie listy metod i ich argumentów dostępnych w DLL

0

Witam.
Szukam już od pewnego czasu jak wyciągnąć i stworzyć listę metod które eksportuje DLL ale nie znalazłem żadnego rozwiązania żeby dowiedzieć się jakie parametry przyjmuje taka metoda a znalazłem wiele kopii tego samego kodu który tylko tworzy mi taka listę (http://www.binboy.org/delphi/faq/63/Jak_uzyskac_liste_funkcji_eksportowanych_z_biblioteki_DLL.html)

I drugi problem polega na tym że chciałbym wywołać później te metody dynamicznie, zważając na fakt że typ i ilość argumentów jest zmienna chciałem to zrobić w asm najpierw w pętli push'nąć przykładowe wartości a później wywołać procedurę, ale to nie jest zbyt eleganckie i nie mam pomysłu jak by tu to zrobić fajniejsze.

0

O ile się orientuje, to nie ma możłiwość poznania dokładnej deklaracji procedur i/lub funkcji z dllki. Trzeba posiadać pliki nagłowkowe dostarczone przez twórcę lub jakąś dokumentację tej dllki. Można jedynie spróbować jeszcze sledzić program pod debuggerem i zobaczyć co jest przekazywane do wywołań poszczególnych funkcji. Jednak nie da to wedlug mnie i tak pełnej informacji, która by łatwo pomogła ogarnąć sposób wykorzystania obcej nam dllki :/

0

Jeżeli ta DLL'ka też jest twojej produkcji to zastanów się nad konstrukcją BPL

0

A dało by się pobrać ilość parametrów?

2

Niektóre biblioteki (przede wszystkim te pisane w C++) mogą mieć udekorowane nazwy, z nich można by spróbować wyciągnąć liczbę parametrów.
Natomiast w większości przypadków wyeksportowana zostanie po prostu zwykła nazwa funkcji, z której nic ciekawego nie wynika - musiałbyś pobawić się z jakimś debuggerem (np.IDA) i mozolnie patrzeć na skompilowane źródło każdej funkcji, by poznać liczbę parametrów oraz ich typy.

0

W BPL jest zakodowana nawet cała lista klass z metodami ich parametrami a nawet z deklaracjami publiczny/publiszed.
Zauważ że aby zainstalować w Delphi/Builderze jakąś paletę komponentów czasami wystarczy jeden plik BPL.

0

Dobra, pomyśle jak to ugryźć, a teraz drugi problem,
Chce wywołać taką metodę

procedure ForceDllCall(Path,Method:String;Args:array of DWORD);
var
 proc:function:Integer;stdcall;
 dwDWord:DWORD;
 I:Integer;
 DLLHandle:THandle;
begin
 DLLHandle:=LoadLibrary(PChar(Path));
 if DLLHandle = 0 then ShowMessage('DLL not found');
 @proc := GetProcAddress(DLLHandle,PChar(Method));
 if @proc = nil then ShowMessage('Function not found');
 for I := High(Args) downto Low(Args) do begin
  dwDWord := Args[i];
  asm
   mov eax, dwDWord;
   push eax;
  end; end;
 asm
  call proc
  mov dwDWord, eax; //zwracana wartość z funkcji 
 end;
 FreeLibrary(DLLHandle);
end;

...
//Testowa DLL ma metodę która wyświetla msgbox'a
ForceDllCall('TestDLL.dll','hello',[DWord(PChar('myParam1')),DWord(PChar('myParam2'))]);

Działa poprawnie dla jednego argumentu, aczkolwiek nie chce dostarczać kolejnych wartości parametru (w pętli).
Jak użyłem (ręcznie deklarując) jeszcze rejestr EDX dla drugiego argumentu to działało poprawnie.

asm   
 mov eax, dwDWord1;  
 push eax;
 mov edx, dwDWord2; 
 push edx;
 call proc
end;

jak chciałem użuć samego push dwDWord to wypluwał access violation 0
Ale nie mogę używać kolejnych rejestrów dla nieokreślonej ilości parametrów.

Nie mam pomysłu jak to rozgryźć.

0

Może tak:

Procedure DLLCall(const LibraryFile, MethodName: String; const Args: Array of DWord);
Var Pnt       : PDword;
    ParamCount: uint8;
Label _loop, _call;
Begin
 Pnt        := @Args[0];
 ParamCount := Length(Args);

 { ... }

 Asm
  mov eax, 0
  mov ebx, ParamCount
  mov ecx, Pnt

 _loop:
  cmp eax, ebx
  jge _call

  mov edx, [ecx]
  push edx

  inc eax
  add ecx, sizeof(DWord)
  jmp _loop

 _call:
  call...
 End ['eax', 'ebx', 'ecx', 'edx'];
End;

Btw, nie trzeba stawiać średnika we wstawkach Assemblera.

0

Nie wiem czy to dobrze wkleiłem, ale wywala access violation dla odwołania się na adres 0x02, ponadto musiałem za komentować ['eax', 'ebx', 'ecx', 'edx']; bo nie był zdefiniowany typy tablicy (info od kompilatora), dodam że korzystam z Delphi 2007

Procedure DLLCall(const LibraryFile, MethodName: String; const Args: Array of DWord);
Var
 Pnt       : PDword;
 ParamCount: Integer;
 proc:function:Integer;stdcall;
 dwDWord:DWORD;
 I:Integer;
 DLLHandle:THandle;
Label _loop, _call;
Begin
 Pnt        := @Args[0];
 ParamCount := Length(Args);
 DLLHandle:=LoadLibrary(PChar(LibraryFile));
 if DLLHandle = 0 then ShowMessage('DLL not found');
 @proc := GetProcAddress(DLLHandle,PChar(MethodName));
 if @proc = nil then ShowMessage('Function not found');
 Asm 
  mov eax, 0
  mov ebx, ParamCount
  mov ecx, Pnt
  
  _loop:
   cmp eax, ebx
   jge _call   
   mov edx, [ecx]
   push edx
   inc eax
   add ecx, sizeof(DWord)
   jmp _loop

  _call:
   call proc
 End; //['eax', 'ebx', 'ecx', 'edx'];
End;

PS.
Trzeba by poprawić trochę pisaie postów bo edytor trochę nawala przy kopiowaniu tekstu.

0

Wyłącz wszystkie optymalizacje i spróbuj ponownie, może kompilator alokuje zmienne w rejestrach or somethin'.

0

Nie pomogło ;(

0

Tak właściwie, to w którym miejscu występuje ten access violation?

0

Debugger mi nie pomógł, ale udało mi się ustalić że błąd występuje przy wyjściu z call proc, aczkolwiek nie może być problemów z dll bo wywołując statycznie działa poprawnie.


Postanowiłem przerobić nieco i wysłać coś prostszego, a mianowicie wysyłam 2 Integer'y 555,777 o dziwo działa ale musiałem zmienić

 
 Pnt:=@Args[0]; 
 ParamCount:=Length(Args)-1;

Dll zwraca mi iż pierwszy argument jest równy 1 a drugi 555, manipulowałem rejestrem eax na wstępie ale czy zwiększyłem/zmniejszyłem o 1 drugi argument miał kosmiczne liczby dodam że pierwszy parametr jest tak naprawdę liczba (nie mniejszą niż 0) z rejestru ebx czym jestem zdumiony.

3

@hzmpz Twój pierwszy kod działa poprawnie ale zależy o jaką bibliotekę DLL chodzi np.: wywołanie:

ForceDllCall('user32.dll','MessageBoxA',[0, DWord(PAnsiChar('komunikat')), DWord(PAnsiChar('tytul')), MB_ICONINFORMATION]);

zadziała bez problemu.
Ale dajmy na to torzymy w Delphi bibliotekę (niech bazuje na funkcji MessageBox) przykładowo

function MsgBox(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: Cardinal): Integer; //stdcall;
begin
  result:= MessageBox(hWnd, lpText, lpCaption, uType);
end;

exports MsgBox;

to wywołanie:

ForceDllCall('test.dll','MsgeBox',[0, DWord(PAnsiChar('komunikat')), DWord(PAnsiChar('tytul')), MB_ICONINFORMATION]);

nie zadziała aby zadziałalo trzeba usunąć komentarz przed stdcall w DLL.

0

Wielkie dzięki wszystkim za pomoc, taka mała drobnostka a tyle zmieniła :D

1 użytkowników online, w tym zalogowanych: 0, gości: 1