Appeler une api en asm avec delphi

Soyez le premier à donner votre avis sur cette source.

Vue 7 005 fois - Téléchargée 1 266 fois

Description

Ce code permet d'appeler n'importe quelle api (stdCall) sans avoir à connaitre ses paramètres. Il n'est pas si compliqué. Il y a encore quelques problèmes à résoudre comme comment faire fonctionner iFlags pour la msgbox ... mais c ma première source en ASM.

Source / Exemple :


//FAIT PAR DEADLYPREDATOR LE 3 MAI 2005 - À UTILISER À VOS RISQUES
unit frmMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    txtGetTickCount: TEdit;
    btnGetTickCount: TButton;
    Label1: TLabel;
    GroupBox1: TGroupBox;
    btnMsgBox: TButton;
    Label2: TLabel;
    txtMsg: TEdit;
    Label3: TLabel;
    txtTitle: TEdit;
    optMsgInfo: TRadioButton;
    optMsgAlerte: TRadioButton;
    chkMsgYesNo: TCheckBox;
    lMsgRep: TLabel;
    optMsgCritique: TRadioButton;
    optMsgNormal: TRadioButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnGetTickCountClick(Sender: TObject);
    procedure btnMsgBoxClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

// Variables qui vont contenir le handle des DLLs, jusqu'à leur déchargement
iKernel32,iUser32: Cardinal;
// -----

// Variables qui vont contenir l'adresse des APIs, jusqu'au déchargement des DLLs
pGetTickCount,pMessageBox: Pointer;
// -----

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
//Chargement des DLLs
iKernel32:=LoadLibrary('Kernel32.dll');// La variable stoke le handle de la DLL, on va en avoir besoin
iUser32:=LoadLibrary('User32.dll');    // ^^^^
//Recherche de l'adresse des APIs
pGetTickCount:=GetProcAddress(iKernel32,'GetTickCount');// Voilà à quoi sert le handle. Si l'API n'est pas trouvée, le pointer est nul (=nil)
pMessageBox:=GetProcAddress(iUser32,'MessageBoxA');     // ^^^^
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
//Déchargement des DLLs
FreeLibrary(iKernel32);// Libération de la dll
FreeLibrary(iUser32);  // ^^^^
end;

procedure TForm1.btnGetTickCountClick(Sender: TObject);
var
iRetVal: Cardinal;//Pour plus tard
begin
{Appel de GetTickCount

Dans delphi : function GetTickCount () : Integer; stdcall; external 'kernel32' name 'GetTickCount'

Bon, on a la DLL chargée et l'adresse de l'API voulue, le plus difficile reste à venir ...
Je ne vous ferez pas un cours ASM 101 car moi même je n'y connait RIEN presque
Vous ne comprenez ce que vous écrivez, pas grave.
}
  asm//Dit à Delphi qu'on commence un bloc d'instructions ASM

  CALL pGetTickCount //On appel le pointeur de l'API, obtenu par GetProcAddress
  MOV iRetVal,EAX //En gros, on met le résultat de l'API dans la variable Delphi "iRetVal", pour des types complexes, cela sera peut-être un pointeur

  end;//Dit à Delphi que le bloc d'instructions ASM est fini

//Maintenant, on a le résultat de GetTickCount. Sauf que c'était trop facile.
//GetTickCount ne requiert aucun paramètre. Donc pas vraiment de problèmes
txtGetTickCount.Text:=IntToStr(iRetVal);//Conversion en string et affichage dans la textbox

end;

procedure TForm1.btnMsgBoxClick(Sender: TObject);
var
iRetVal: Cardinal;//Pour plus tard
iFlags: Cardinal;//Options d'apparence de la msgbox
sTexte, sTitre:PChar;//Pour plus tard
begin
lMsgRep.Caption:='';//on efface la réponse ...
if(optMsgAlerte.Checked=true) then iFlags:=MB_ICONEXCLAMATION;//préparation des paramètres de l'apparence de la msgbox
if(optMsgCritique.Checked=true) then iFlags:=MB_ICONASTERISK; //^^^^
if(optMsgInfo.Checked=true) then iFlags:=MB_ICONQUESTION;     //^^^^
if(chkMsgYesNo.Checked=true) then iFlags:=+MB_YESNO;          //^^^^

sTexte:=PChar(txtMsg.Text);    //Il faut convertir le texte en pchar avant
sTitre:=PChar(txtTitle.Text);  //^^^^

{Appel de MessageBoxA

Dans delphi : function GetTickCount () : Integer; stdcall; external 'kernel32' name 'GetTickCount'

Maintenant, c'est une fonction plus complexe avec des paramètres.
On place chaque paramètre avec PUSH
ATTENTION!!!! LES PARAMÈTRES DOIVENT ÊTRE DONNÉ À L'INVERSE, DE DROITE À GAUCHE!!!
SI PAR EXEMPLE function x(a;b;c;d)
on push dans cette ordre d, c, b, a
Cette méthode ne permet que de fonctionner avec les api qui utilise la convention d'appel appelée stdcall, soit toutes les APIs de windows et la grande majoritée des autres
}
  asm//Dit à Delphi qu'on commence un bloc d'instructions ASM

  PUSH 0//Tout les paramètres pusher dans l'ordre inverse
  PUSH sTitre//^^^^
  PUSH sTexte//^^^^
  PUSH 0//iFlags//^^^^ --> iFlags ne fonctionne pas encore, je ne sais pas pourquoi mais la valeur doit être convertie avant mais en quoi?

  CALL pMessageBox //On appel le pointeur de l'API, obtenu par GetProcAddress
  MOV iRetVal,EAX //En gros, on met le résultat de l'API dans la variable Delphi "iRetVal", pour des types complexes, cela sera peut-être un pointeur

  end;//Dit à Delphi que le bloc d'instructions ASM est fini

if(iRetVal=7) then lMsgRep.Caption:='vous avez répondu non';//^va fonctionner quand iFlag va fonctionner
if(iRetVal=6) then lMsgRep.Caption:='vous avez répondu oui';//^^^^
end;

end.

Conclusion :


Merci. J'aimerais en faire une API qu'on pourrais utiliser pour appeler d'autres API. Ça pourrait servir.

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cs_grandvizir
Messages postés
1237
Date d'inscription
samedi 8 novembre 2003
Statut
Membre
Dernière intervention
3 septembre 2006
8 -
Salut DeadlyPredator. J'ai une petite remarque.

Sachant que Kernel et compagnie sont déjà chargés automatiquement par l'application, je ne pense pas qu'il soit nécessaire de les recharger. Autant utiliser directement l'opérateur Arobase pour récupérer l'adresse de la procédure désirée.

Exemple:

program Project1;
uses Windows, SysUtils, Dialogs;
{$R *.res}

var TickAsm, TickPascal : integer;
Address : Pointer;
begin
//APPEL EN ASSEMBLEUR
Address:=@GetTickCount;
asm
CALL Address
MOV TickAsm, EAX
end;

//APPEL EN PASCAL
TickPascal:=GetTickCount;

//LES DEUX RESULTATS SONT PAREILS
ShowMessage(Format('%d = %d',[TickAsm, TickPascal]));
end.

Cela dit le code est bon. C'est juste une autre manière de faire.
cs_sarko
Messages postés
2
Date d'inscription
mardi 28 janvier 2003
Statut
Membre
Dernière intervention
19 novembre 2010
-
Bonjour ,
a propos du non fonctionnement de iflags ,cette
variable doit etre sur le premier push.
Le 4eme push serait le numero de fenetre /??
N'oublie pas le probleme des icones et attention aux codes
interdits .
Bon courage

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.