begin process at 2010 09 03 22:04:06
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

API

 > REMPLACER UNE FONCTION D'UNE DLL PAR N'IMPORTE QUELLE AUTRE!

REMPLACER UNE FONCTION D'UNE DLL PAR N'IMPORTE QUELLE AUTRE!


 Information sur la source

Note :
9 / 10 - par 2 personnes
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :API Classé sous :api, hook, dll Niveau :Initié Date de création :07/07/2006 Vu / téléchargé :7 878 / 960

Auteur : Forman

Ecrire un message privé
Commentaire sur cette source (34)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Ce code vous permettra de redéfinir le code d'une fonction importée statiquement par une DLL dans votre programme par une fonction quelconque définie dans votre programme. Il y a très peu à faire pour modifier le code afin qu'il fasse la même chose dans un processus extérieur. La fonction ReplaceAPI de l'unité APIRedirect.pas fait tout le travail:
-Détermination de l'adresse de base où est chargé l'exécutable.
-Exploration de la table des symboles importés jusqu'à trouver la fonction initiale à remplacer
-Recopiage de code machine à partir d'un petit morceau d'assembleur "inline" encadré par 2 nombres magiques pour retrouver le code machine correspondant
-Ce morceau de code "Launcher" est ensuite modifié pour y mettre l'adresse de la nouvelle fonction désirée
-Ajout d'une section exécutable à l'exécutable contenant le code du launcher de la nouvelle fonction
-Et ça marche!

Attention toutefois à respecter SCRUPULEUSEMENT le nombre et le format des paramètres de la nouvelle fonction à remplacer. Et ne pas oublier les conventions d'appels (stdcall, etc...) sinon ça va tout faire planter. Par exemple, si vous jugez que la fonction MessageBox de Windows ne vous convient pas, vous pouvez utiliser:

function MyMessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall;
begin
  <-Code personnel pour remplacer la fonction originale de Microsoft
end;

ReplaceAPI(kernel32,'MessageBox A',@MyMessageBox);

Et le tour est joué!

Je fourni un petit programme d'exemple pour montrer l'utilité d'une telle fonction: il se charge de remplacer l'API GetSysColor de Microsoft par une autre fonction qui permet de changer les couleurs systèmes. Tous les composants VCL non natifs (c'est à dire qui ne sont pas entièrement peints par Windows) sont affectés. Et pas besoin de changer leur couleur!

J'admet que le résultat est visuellement assez pauvre, mais le principe est là.

Source

  • unit APIRedirect;
  • interface
  • uses
  • SysUtils,Windows,ImageHlp,Dialogs;
  • function GetImageBase(
  • Process:THandle; // Handle to a valid process object. Current thread must have PROCESS_VM_READ | PROCESS_VM_OPERATION access to it.
  • Thread:THandle // Handle to a valid thread object. Current thread must have THREAD_GET_CONTEXT access to it.
  • ):Pointer; // Return the image base of the process.
  • function ReplaceAPI(
  • DllName:string; // Name of the DLL containing the procedure or function to replace
  • ProcName:string; // Name of the procedure or function to replace
  • NewProc:Pointer; // Pointer to the new desired procedure. The declaration of this procedure *MUST* be *EXACTLY* the same as the original API.
  • Process:THandle=0; // Handle to a valid process object (or zero for the current process). The caller must have
  • // PROCESS_SUSPEND_RESUME | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION
  • // access to it.
  • Thread:THandle=0 // Handle to a valid thread object (or zero for the current thread). The caller must have
  • // THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION
  • // access to it.
  • ):Boolean;overload; // Return True if the API was successfully patched, false otherwise (for instance, if the process doesnt use the specified
  • // name in his import directory, or if the API was not found in the specified DLL).
  • type
  • PPEB=^TPEB;
  • TPEB=packed record
  • UselessData:array[0..1] of Cardinal; // This is of course not the real definition, but only the ImageBaseAddress field is of interest in our case
  • ImageBaseAddress:POINTER;
  • end;
  • PTEB=^TTEB;
  • TTEB=packed record
  • UselessData:array[0..11] of Cardinal; // This is of course not the real definition, but only the PEB field is of interest in our case
  • PEB:PPEB;
  • end;
  • IMAGE_IMPORT_BY_NAME=packed record
  • Hint:Word;
  • Name:CHAR;
  • end;
  • TImageImportByName=IMAGE_IMPORT_BY_NAME;
  • PImageImportByName=^IMAGE_IMPORT_BY_NAME;
  • IMAGE_THUNK_DATA=packed record
  • ForwarderString: PBYTE;
  • Func: PDWORD;
  • Ordinal: DWORD;
  • AddressOfData:PImageImportByName;
  • end;
  • TImageThunkData=IMAGE_THUNK_DATA;
  • PImageThunkData=^IMAGE_THUNK_DATA;
  • TIIDMisc=packed record
  • case Integer of
  • 0:(Characteristics:DWORD); // 0 for terminating null import descriptor
  • 1:(OriginalFirstThunk:DWORD); // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
  • end;
  • IMAGE_IMPORT_DESCRIPTOR=packed record
  • Misc:TIIDMisc;
  • TimeDateStamp:DWORD;
  • ForwarderChain:DWORD;
  • Name:DWORD;
  • FirstThunk:DWORD;
  • end;
  • TImageImportDescriptor=IMAGE_IMPORT_DESCRIPTOR;
  • PImageImportDescriptor=^IMAGE_IMPORT_DESCRIPTOR;
  • const
  • LOADER_START_MAGIC=$FAFAFAFA; // Magic flags arbitrary defined. These flags will allow us to retrieve
  • LOADER_END_MAGIC=$FEFEFEFE; // code offsets in asm code. Anyway, let us hope the generated machine code doed not
  • LOADER_PROC_MAGIC=$ABABABAB; // contain them! (I havent checked, but the probability is highliy negligible)
  • implementation
  • procedure Launcher; // A launcher for the new procedures. We insert flags to extract only the required code, without whatever Delphi will add
  • // for initialisation and finalisation of the call
  • asm
  • DD LOADER_START_MAGIC; // Flag to indicate start of code
  • PUSH EBP // Store EBP to API caller
  • CALL @START
  • @START: POP EBP
  • SUB EBP, OFFSET @START // Get base EBP
  • MOV EAX, [EBP+@@PROC] // Calculate new proc offset
  • POP EBP // Restore EBP to API caller
  • JMP EAX // JMP to new procedure address (no need to CALL)
  • @@PROC: DD LOADER_PROC_MAGIC; // Flag to indicate absolute address of new proc
  • DD LOADER_END_MAGIC; // Flag to indicate end of code
  • end;
  • function DataPos(Start:Pointer;Data:Cardinal):Cardinal;
  • begin
  • Result:=Cardinal(Start);
  • while PCardinal(Result)^<>Data do
  • Inc(Result);
  • end;
  • procedure GetLauncherCode(var Code:Pointer;var Size:Cardinal;Proc:Pointer);
  • var
  • p:Cardinal;
  • begin
  • p:=DataPos(@Launcher,LOADER_START_MAGIC)+4; // Retrieve position of launching code inside Launcher
  • Size:=DataPos(@Launcher,LOADER_END_MAGIC)-p; // Retrieve end of launching code
  • GetMem(Code,Size);
  • CopyMemory(Code,Pointer(p),Size); // Duplicate launching code
  • p:=DataPos(Code,LOADER_PROC_MAGIC); // Replace the absolute procedure address (which contains LOADER_PROC_MAGIC)...
  • PPointer(p)^:=PPointer(@Proc)^; // ...with the new one
  • end;
  • function GetImageBase(Process:THandle;Thread:THandle):Pointer; // This function uses undocumented APIs. One can find their descriptions there:
  • var // http://undocumented.ntinternals.net/
  • Context:TContext; // There are other (simplier) means to obtain the image base, but this one
  • SelEntry:TLDTEntry; // can extract the image base of other running processes.
  • FSBase:Cardinal;
  • TEB:TTEB;
  • PEB:TPEB;
  • n:Cardinal;
  • begin
  • Context.ContextFlags:=CONTEXT_FULL or CONTEXT_DEBUG_REGISTERS;
  • if not GetThreadContext(Thread,Context) then // See the above link for additional informations
  • RaiseLastOSError;
  • if not GetThreadSelectorEntry(Thread,Context.SegFs,SelEntry) then
  • RaiseLastOSError;
  • with SelEntry do
  • FSBase:=(BaseHi shl 24) or (BaseMid shl 16) or SelEntry.BaseLow;
  • if not VirtualProtectEx(Process,Ptr(FSBase),SizeOf(TEB),PAGE_READWRITE,@n) then
  • RaiseLastOSError;
  • if not ReadProcessMemory(Process,Ptr(FSBase),@TEB,SizeOf(TEB),n) then
  • RaiseLastOSError;
  • if not VirtualProtectEx(Process,TEB.Peb,SizeOf(PEB),PAGE_READWRITE,@n) then
  • RaiseLastOSError;
  • if not ReadProcessMemory(Process,TEB.Peb,@PEB,SizeOf(PEB),n) then
  • RaiseLastOSError;
  • Result:=TEB.Peb.ImageBaseAddress; //That's it, we now have the address at which the process is loaded
  • end;
  • function RedirectAPI(DllName:string;InitialVOffset,NewVOffset,ImageBase:Cardinal;ImageDosHeader:PImageDosHeader;ImageNTHeader:PImageNtHeaders):Boolean;
  • var
  • ImportDirectory:Cardinal;
  • ImageImportDescriptor:PImageImportDescriptor;
  • ImageThunkData:PImageThunkData;
  • begin
  • Result:=False;
  • ImportDirectory:=ImageNTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  • if ImportDirectory=0 then // Well, I think we can find cases where there are no imported libraries...
  • Exit;
  • ImageImportDescriptor:=Ptr(ImageBase+ImportDirectory);
  • while ImageImportDescriptor.Name<>0 do begin // Enumerate imported DLL's
  • if ImageImportDescriptor.Misc.OriginalFirstThunk<>0 then
  • ImageThunkData:=PImageThunkData(ImageBase+ImageImportDescriptor.Misc.OriginalFirstThunk)
  • else
  • ImageThunkData:=PImageThunkData(ImageBase+ImageImportDescriptor.FirstThunk);
  • while ImageThunkData.AddressOfData<>nil do begin // Enumerate procs imported from the DLL
  • if PCardinal(ImageThunkData)^=InitialVOffset then begin // Found the imported proc!
  • PCardinal(ImageThunkData)^:=NewVOffset; // Replace it and leave before Bill Gates notices anything!
  • Result:=True;
  • // Exit; //Apparently, there can be more than one instance of the imported proc in the table. So let's continue just in case...
  • end;
  • Inc(ImageThunkData);
  • end;
  • Inc(ImageImportDescriptor);
  • end;
  • end;
  • function ReplaceAPI(DllName:string;ProcName:string;NewProc:Pointer;Process,Thread:THandle):Boolean;
  • var
  • ImageBase,OldProc,RedirectMem,LauncherCode:Pointer;
  • ImageDosHeader:TImageDosHeader;
  • ImageNTHeader:TImageNtHeaders;
  • n,LauncherSize:Cardinal;
  • Module:HModule;
  • begin
  • if Process=0 then
  • Process:=GetCurrentProcess;
  • if Thread=0 then
  • Thread:=GetCurrentThread
  • else
  • SuspendThread(Thread);
  • try
  • ImageBase:=GetImageBase(Process,Thread);
  • if not ReadProcessMemory(Process,ImageBase,@ImageDosHeader,SizeOf(ImageDosHeader),n) then // The DOS header is located at offset 0...
  • RaiseLastOSError;
  • if not ReadProcessMemory(Process,Ptr(Integer(ImageBase)+ImageDosHeader._lfanew),@ImageNTHeader,SizeOf(ImageNTHeader),n) then
  • RaiseLastOSError; // The NT is located at offset _lfanew...
  • Module:=LoadLibrary(PChar(DllName));
  • OldProc:=GetProcAddress(Module,PChar(ProcName)); // Get the real API address
  • if not Assigned(OldProc) then
  • Assert(False,'Wrong library or procedure name'); // TODO: use Result:=False;Exit;
  • GetLauncherCode(LauncherCode,LauncherSize,NewProc);
  • try
  • RedirectMem:=VirtualAllocEx(Process,nil,LauncherSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE); // Let's add some new code to the module ;-)
  • if not WriteProcessMemory(Process,RedirectMem,LauncherCode,LauncherSize,n) then // Write the launcher code
  • RaiseLastOSError;
  • Result:=RedirectAPI(DllName,Cardinal(OldProc),Cardinal(RedirectMem),Cardinal(ImageBase),@ImageDosHeader,@ImageNTHeader); // OK, here we go, let's modify the headers
  • finally
  • FreeMem(LauncherCode);
  • end;
  • finally
  • ResumeThread(Thread);
  • end;
  • end;
  • end.
unit APIRedirect;

interface

uses
  SysUtils,Windows,ImageHlp,Dialogs;

function GetImageBase(
  Process:THandle;   // Handle to a valid process object. Current thread must have PROCESS_VM_READ | PROCESS_VM_OPERATION access to it.

  Thread:THandle     // Handle to a valid thread object. Current thread must have THREAD_GET_CONTEXT access to it.
  
):Pointer;           // Return the image base of the process.

function ReplaceAPI(
  DllName:string;    // Name of the DLL containing the procedure or function to replace
  
  ProcName:string;   // Name of the procedure or function to replace

  NewProc:Pointer;   // Pointer to the new desired procedure. The declaration of this procedure *MUST* be *EXACTLY* the same as the original API.

  Process:THandle=0; // Handle to a valid process object (or zero for the current process). The caller must have
                     // PROCESS_SUSPEND_RESUME | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION
                     // access to it.

  Thread:THandle=0   // Handle to a valid thread object (or zero for the current thread). The caller must have
                     // THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION
                     // access to it.
  
):Boolean;overload;  // Return True if the API was successfully patched, false otherwise (for instance, if the process doesnt use the specified
                     // name in his import directory, or if the API was not found in the specified DLL).
                     
type
  PPEB=^TPEB;
  TPEB=packed record
    UselessData:array[0..1] of Cardinal;   // This is of course not the real definition, but only the ImageBaseAddress field is of interest in our case
    ImageBaseAddress:POINTER;
  end;

  PTEB=^TTEB;
  TTEB=packed record
    UselessData:array[0..11] of Cardinal;  // This is of course not the real definition, but only the PEB field is of interest in our case
    PEB:PPEB;
  end;

  IMAGE_IMPORT_BY_NAME=packed record
    Hint:Word;
    Name:CHAR;
  end;
  TImageImportByName=IMAGE_IMPORT_BY_NAME;
  PImageImportByName=^IMAGE_IMPORT_BY_NAME;

  IMAGE_THUNK_DATA=packed record
    ForwarderString: PBYTE;
    Func: PDWORD;
    Ordinal: DWORD;
    AddressOfData:PImageImportByName;
  end;
  TImageThunkData=IMAGE_THUNK_DATA;
  PImageThunkData=^IMAGE_THUNK_DATA;

  TIIDMisc=packed record
    case Integer of
      0:(Characteristics:DWORD);    // 0 for terminating null import descriptor
      1:(OriginalFirstThunk:DWORD); // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
  end;

  IMAGE_IMPORT_DESCRIPTOR=packed record
    Misc:TIIDMisc;
    TimeDateStamp:DWORD;
    ForwarderChain:DWORD;
    Name:DWORD;
    FirstThunk:DWORD;
  end;
  TImageImportDescriptor=IMAGE_IMPORT_DESCRIPTOR;
  PImageImportDescriptor=^IMAGE_IMPORT_DESCRIPTOR;

const
  LOADER_START_MAGIC=$FAFAFAFA;   // Magic flags arbitrary defined. These flags will allow us to retrieve
  LOADER_END_MAGIC=$FEFEFEFE;     // code offsets in asm code. Anyway, let us hope the generated machine code doed not
  LOADER_PROC_MAGIC=$ABABABAB;    // contain them! (I havent checked, but the probability is highliy negligible)

implementation

procedure Launcher;  // A launcher for the new procedures. We insert flags to extract only the required code, without whatever Delphi will add
                     // for initialisation and finalisation of the call
asm
              DD   LOADER_START_MAGIC; // Flag to indicate start of code
              PUSH EBP                 // Store EBP to API caller
              CALL @START
@START:       POP  EBP
              SUB  EBP, OFFSET @START  // Get base EBP
              MOV  EAX, [EBP+@@PROC]   // Calculate new proc offset
              POP  EBP                 // Restore EBP to API caller
              JMP  EAX                 // JMP to new procedure address (no need to CALL)
@@PROC:       DD   LOADER_PROC_MAGIC;  // Flag to indicate absolute address of new proc
              DD   LOADER_END_MAGIC;   // Flag to indicate end of code
end;

function DataPos(Start:Pointer;Data:Cardinal):Cardinal;
begin
  Result:=Cardinal(Start);
  while PCardinal(Result)^<>Data do
    Inc(Result);
end;

procedure GetLauncherCode(var Code:Pointer;var Size:Cardinal;Proc:Pointer);
var
  p:Cardinal;
begin
  p:=DataPos(@Launcher,LOADER_START_MAGIC)+4;  // Retrieve position of launching code inside Launcher
  Size:=DataPos(@Launcher,LOADER_END_MAGIC)-p; // Retrieve end of launching code
  GetMem(Code,Size);
  CopyMemory(Code,Pointer(p),Size);            // Duplicate launching code
  p:=DataPos(Code,LOADER_PROC_MAGIC);          // Replace the absolute procedure address (which contains LOADER_PROC_MAGIC)...
  PPointer(p)^:=PPointer(@Proc)^;              // ...with the new one
end;

function GetImageBase(Process:THandle;Thread:THandle):Pointer;  // This function uses undocumented APIs. One can find their descriptions there:
var                                                             //            http://undocumented.ntinternals.net/
  Context:TContext;                                             // There are other (simplier) means to obtain the image base, but this one
  SelEntry:TLDTEntry;                                           // can extract the image base of other running processes.
  FSBase:Cardinal;
  TEB:TTEB;
  PEB:TPEB;
  n:Cardinal;
begin
  Context.ContextFlags:=CONTEXT_FULL or CONTEXT_DEBUG_REGISTERS;
  if not GetThreadContext(Thread,Context) then                  // See the above link for additional informations
    RaiseLastOSError;
  if not GetThreadSelectorEntry(Thread,Context.SegFs,SelEntry) then
    RaiseLastOSError;
  with SelEntry do
    FSBase:=(BaseHi shl 24) or (BaseMid shl 16) or SelEntry.BaseLow;
	if not VirtualProtectEx(Process,Ptr(FSBase),SizeOf(TEB),PAGE_READWRITE,@n) then
    RaiseLastOSError;
  if not ReadProcessMemory(Process,Ptr(FSBase),@TEB,SizeOf(TEB),n) then
    RaiseLastOSError;
	if not VirtualProtectEx(Process,TEB.Peb,SizeOf(PEB),PAGE_READWRITE,@n) then
    RaiseLastOSError;
  if not ReadProcessMemory(Process,TEB.Peb,@PEB,SizeOf(PEB),n) then
    RaiseLastOSError;
  Result:=TEB.Peb.ImageBaseAddress;                             //That's it, we now have the address at which the process is loaded
end;

function RedirectAPI(DllName:string;InitialVOffset,NewVOffset,ImageBase:Cardinal;ImageDosHeader:PImageDosHeader;ImageNTHeader:PImageNtHeaders):Boolean;
var
  ImportDirectory:Cardinal;
  ImageImportDescriptor:PImageImportDescriptor;
  ImageThunkData:PImageThunkData;
begin
  Result:=False;
  ImportDirectory:=ImageNTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  if ImportDirectory=0 then                                             // Well, I think we can find cases where there are no imported libraries...
    Exit;
  ImageImportDescriptor:=Ptr(ImageBase+ImportDirectory);
  while ImageImportDescriptor.Name<>0 do begin                          // Enumerate imported DLL's
    if ImageImportDescriptor.Misc.OriginalFirstThunk<>0 then
      ImageThunkData:=PImageThunkData(ImageBase+ImageImportDescriptor.Misc.OriginalFirstThunk)
    else
      ImageThunkData:=PImageThunkData(ImageBase+ImageImportDescriptor.FirstThunk);
    while ImageThunkData.AddressOfData<>nil do begin                    // Enumerate procs imported from the DLL
      if PCardinal(ImageThunkData)^=InitialVOffset then begin           // Found the imported proc!
        PCardinal(ImageThunkData)^:=NewVOffset;                         // Replace it and leave before Bill Gates notices anything!
        Result:=True;
//        Exit;  //Apparently, there can be more than one instance of the imported proc in the table. So let's continue just in case...
      end;
      Inc(ImageThunkData);
    end;
    Inc(ImageImportDescriptor);
  end;
end;

function ReplaceAPI(DllName:string;ProcName:string;NewProc:Pointer;Process,Thread:THandle):Boolean;
var
  ImageBase,OldProc,RedirectMem,LauncherCode:Pointer;
  ImageDosHeader:TImageDosHeader;
  ImageNTHeader:TImageNtHeaders;
  n,LauncherSize:Cardinal;
  Module:HModule;
begin
  if Process=0 then
    Process:=GetCurrentProcess;
  if Thread=0 then
    Thread:=GetCurrentThread
  else
    SuspendThread(Thread);
  try
    ImageBase:=GetImageBase(Process,Thread);
    if not ReadProcessMemory(Process,ImageBase,@ImageDosHeader,SizeOf(ImageDosHeader),n) then  // The DOS header is located at offset 0...
      RaiseLastOSError;
    if not ReadProcessMemory(Process,Ptr(Integer(ImageBase)+ImageDosHeader._lfanew),@ImageNTHeader,SizeOf(ImageNTHeader),n) then
      RaiseLastOSError;                                                                        // The NT is located at offset _lfanew...
    Module:=LoadLibrary(PChar(DllName));
    OldProc:=GetProcAddress(Module,PChar(ProcName));                                           // Get the real API address
    if not Assigned(OldProc) then
      Assert(False,'Wrong library or procedure name');                                         // TODO: use Result:=False;Exit;
    GetLauncherCode(LauncherCode,LauncherSize,NewProc);
    try
      RedirectMem:=VirtualAllocEx(Process,nil,LauncherSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE); // Let's add some new code to the module    ;-)
      if not WriteProcessMemory(Process,RedirectMem,LauncherCode,LauncherSize,n) then          // Write the launcher code
        RaiseLastOSError;
      Result:=RedirectAPI(DllName,Cardinal(OldProc),Cardinal(RedirectMem),Cardinal(ImageBase),@ImageDosHeader,@ImageNTHeader); // OK, here we go, let's modify the headers
    finally
      FreeMem(LauncherCode);
    end;
  finally
    ResumeThread(Thread);
  end;
end;

end.

 Conclusion

Le code est de moi, je me suis un peu inspiré de cet article, même si ma méthode est un peu différente:
http://www.codeproject.com/useritems/ inject2it.asp

Je préfère aussi prévenir tout de suite: CE N'EST PAS UN VIRUS donc pas la peine que les admins le désactivent. De toute façon j'ai changé le code pour qu'on ne puisse pas injecter du code dans un autre processus.

Le code est de niveau expert, son utilisation de niveau débutant, donc en moyenne initié...

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Sources du même auteur

Source avec Zip TRADUCTION DE DOKAN EN DELPHI: UN DRIVER "USER-MODE" POUR DI...
Source avec Zip Source avec une capture TASK MANAGER EN MODE TEXTE (ÉMULATION MODE 03H)
Source avec Zip Source avec une capture CHRONOMÈTRE POUR LE THÉ
Source avec Zip UTILITAIRE POUR LANCER UN PROGRAMME DEPUIS UN AUTRE COMPTE (...
Source avec Zip Source avec une capture DÉMONSTRATION DE LA GESTION DES OBJETS EN MÉMOIRE PAR DELPHI...

 Sources de la même categorie

Source avec Zip DÉCOUPER UNE FENÊTRE par gta126
Source avec Zip TRANSCRIRE UN FICHIER OPEN FINANCIAL EXCHANGE (OFX) EN FICHI... par jeffem
Source avec Zip Source avec une capture MSXML 4.0 VALIDATION XML / XSD par redtux
Source avec Zip FBRENOMMEADOBJET par fbalien
Source avec Zip NEXTGENS -> UNITÉS DE TYPES ÉVOLUÉS NOUVELLE GÉNÉRATION (DE... par f0xi

 Sources en rapport avec celle ci

SYNCHRONISATION DE THREADS DANS DES DLL par saib
Source avec Zip DYNAMIC LIBRARY LOADER CLASS: GAGNEZ DU TEMPS POUR CHARGER L... par f0xi
Source avec Zip Source avec une capture COMPOSANT TLOG UTILISANT UNE DLL par Bacterius
Source avec Zip Source avec une capture HOOK D'API, INJECTION DE DLL, TABLE D'IMPORT par rt15
Source avec Zip CHARGEMENT D'UNE DLL SANS DLL par DelphiCool

Commentaires et avis

Commentaire de John Dogget le 08/07/2006 10:09:20

Interessant :)
C'est pas ce genre de truc qui est utilisé par certains malwares pour executer des commandes arbitraires ?

Si tu connais un defaut dans une Dll, tu l'appel avec ta méthode personnalisée pour crasher ou prendre le contrôle de l'ordi ...

Commentaire de DRJEROME le 08/07/2006 21:44:43

bien...bien !

Commentaire de elguevel le 09/07/2006 10:15:11

Dégouté ... j'ai commencé à faire une source similaire vendredi et pas eut le temps de la posté que voila c'est fait par quelqu'un d'autre :-(

J'en ai meme parlé y'a quelques jours à une reponse de ce post : http://www.delphifr.com/codes/MONITEUR-RESEAU_38399.aspx

Bon ba on modifira un peu le fonctionnement alors !

Aller bon code, A++ ;-)

Commentaire de elguevel le 10/07/2006 21:42:59

Très bonne source, mais les commentaires auraient pu etre en français (et oui je suis une m**** en anglais).

"De toute façon j'ai changé le code pour qu'on ne puisse pas injecter du code dans un autre processus" <= j'ai changé çà et çà marche pas trop mal, mis à part pour certains process sytème :-) et c'est Fun.

Bravo.

Commentaire de Forman le 10/07/2006 22:03:54

Haha,

je savais que ça allait intéresser du monde     ;-)

A la base j'avais programmé ça exactement comme pour l'exemple: je voulais faire un système de skin complet qui s'intègre automatiquement avec la VCL sans avoir à réécrire quoi que ce soit du code natif de Borland. Donc il fallait (pour que les couleurs restent harmonieuses) que la fonction ColorToRGB (qui permet de passer des couleurs système à leur représentation RGB) soit intégrée le skin. Il y a bien une API qui fait ça (SetSystemColors) mais elle change les couleurs pour TOUTES les fenêtres existantes (y compris les autres programmes)...

Pour injecter du code dans un processus déjà lancé, on peut aussi utiliser CreateRemoteThread      ;-)
C'est quand même beaucoup plus simple!

Un truc que j'ai trouvé assez terrible: il est impossible de trouver dans la MSDN des informations pour détecter à quelle adresse a été chargé le code d'un exécutable... ou alors je ne sais pas chercher!

Une autre utilité de ce code pourrait être de mettre au point un système de cryptage de l'exécutable (pour éviter son désassemblage par exemple). La plupart des désassembleurs seraient bien embarassés pour analyser une table d'import "mouvante"...

Ca m'a aussi donné une idée pour faire un module Delphi pour réaliser un système de classes multi-héritage: en changeant un peu les adresses où pointent les méthodes d'objets, c'est peut-être possible. Ou encore, forcer l'accès à des méthodes d'objet déclarées "private" (qui n'a jamais été confronté au problème lorsqu'il voulait modifier un contrôle natif: certaines méthodes souvent très utiles sont inaccessibles sauf si l'on modifie le source de la VCL...)

Merci pour la note en tout cas, c'est la première fois que je faisais de l'assembleur, ça m'a fait délirer de passer autant de temps sur un morceau de code de 10 lignes      ;-)

Commentaire de elguevel le 10/07/2006 22:38:03

L'assembleur .. et oui c'est certainement les lignes les plus longues à écrire :-D

Sinon j'ai repris ton code mais me suis amusé à modifier d'autre API (sur d'autre process), comme MessageBoxA() (en ré-implantant => WinExec('calc.exe', 3 ).. enfin des trucs marrants, mais il est vrai qu'il y à un filon à exploiter de ce coté-ci et sans pour autant faire des applis de sabotages.

Sinon je ne vois pas qui ne serai pas intéréssé par des sources comme celles-ci ... c'est bandant non ?

Commentaire de elguevel le 10/07/2006 22:39:22

Arf, t'as pas eut ton petit message rouge toi :-D LoL

Commentaire de Forman le 10/07/2006 23:25:51

oui mais je me suis auto-censuré: en théorie la fonction ne marche qu'à l'intérieur du processus qui l'appelle et pas sur les autres ;-)
De toute façon, les différentes façons d'injecter/exécuter du code arbitraire sous zindoz sont devenues tellement nombreuses et  documentées sur le net que je ne vois plus trop l'utilité de censurer... Ca passait encore quand les API non documentées n'étaient pas connues, mais (mort de rire) je suis tombé encore aujourd'hui même sur les sources de windows 2000 en téléchargement sur un site de bitorrent!

Véridique:
http://search.utorrent.com/search.php?q=123&e=http%3a%2f%2fthepiratebay%2eorg%2fsearch%2ephp%3fq%3d&u=1

Commentaire de Forman le 10/07/2006 23:27:45

Oups mauvais copier-coller:
http://static.thepiratebay.org/ms-loveletter.txt
c'est le bon cette fois

Commentaire de Jean_Jean le 11/05/2008 11:58:33

Salut Forman,

Sur un conseil de Cirec, j'ai étudié ton source en vue d'avancer dans la compréhension de la façon dont les couleurs systèmes affectent les contrôles afin de pouvoir les personnaliser.
Un premier jet a été publié ici : http://www.delphifr.com/codes/COULEURS-SYSTEME_46516.aspx

Ton code m'a été très utile pour avancer. du coup, j'ai refait totalement mon source afin d'être plus utile à tous. Malheureusement, il faut que je planche encore dessus car je ne peux encore le publier en l'état (fichier d'aide volumineux >1Mo => images de l'aide à modifier, et aussi codes à finaliser).

Voici le sujet qui me préoccupe : Dans ton explication tu dis :"Tous les composants VCL non natifs (c'est à dire qui ne sont pas entièrement peints par Windows) sont affectés." J'ai pu le vérifier. J'ai essayé d'accéder à Ubuttons de Delphi, mais il est compilé. Par conséquent, on n'a pas accès aux éléments qui sont natifs ou pas de windows. Par exemple, la couleur du texte de SpeedButton est modifié, mais pas celui de Button.
Ce qui veut dire aussi que je ne peux pas par cette méthode modifier directement la couleur de fond de la zone de Titre d'une fenêtre. Dans mon source (2ème version non encore publié) j'utilise pour cela le dessin sur canvas...

Et donc voici ma question : Finalement, il semble que cette méthode fort intéressante ne le soit pas pour un remplacement de couleur puisque :
    1. je ne peux identifier facilement l'élément qui sera affecté du contrôle
    2. je ne peux accéder aux éléments de contrôles natifs windows, par exemple, la zone de titre d'une fenêtre.

Qu'en penses-tu? si tu veux je t'envoi le code et l'aide que je préparre pour la deuxième la publication.

Merci à toi

Jean_Jean

Commentaire de Forman le 12/05/2008 13:45:10

Salut Jean_Jean

Mon code permet de changer la table d'import du processus, comme tu as dû le remarquer. Pour les speedbuttons, la partie "windows" de l'affichage est gérée par une DLL (je ne sais pas exactement laquelle). Cette DLL possède sa propre table d'import, qui n'est pas modifiée par ma fonction, car celle-ci se contente de modifier la table d'import de l'exécutable. Il est probable que la DLL utilise aussi ColorToRGB pour peindre le button, mais comme sa table d'import n'est pas modifiée, c'est la vraie fonction (càd non modifiée) qui est appelée, donc pas de changement de couleur.

Pour que ça fonctionne aussi dans la DLL il faudrait modifier sa table d'import. Pour ça, il faut trouver l'adresse à laquelle elle est chargée (c'est la fonction GetImageBase qui s'en charge pour l'exécutable) et appliquer exactement les mêmes modifications à partir de là.

Je ne connais pas le moyen rigoureux pour trouver l'adresse de chargement d'une DLL. Mais j'ai lu qque part que le handle (de type HLIBRARY) renvoyé par l'API LoadLibrary était en fait cette adresse, toutefois je n'ai jamais vérifié. Ca peut être une première piste.

Une autre piste pourrait être d'essayer de patcher toutes les DLL chargées par l'exécutable. Pour ça tu peux utiliser CreateToolhelp32Snapshot avec TH32CS_SNAPMODULE. Ainsi, avec Module32First/Module32Next tu peux énumérer toutes les DLL chargées dans l'application, et la structure MODULEENTRY32 qui contient le descriptif de chacune possède un champ modBaseAddr qui donne l'adresse de base. Il suffit alors d'appeler ma fonction RedirectAPI pour toutes les DLL énumérées, avec comme paramètre la bonne adresse de base. Evidemment cette solution ne marchera que pour Win NT ou XP je pense.

Ainsi, tu pourras patcher ColorToRGB pour toutes les DLL chargées, en particulier celle qui sert à tracer les boutons. Evidemment, il faut qu'elles utilisent effectivement ColorToRGB pour que ça marche, et pas une autre fonction pour convertir les couleurs.

Il peut y avoir un petit problème ceci dit. Je ne suis pas un expert donc je vais peut-être écrire des bêtises mais j'ai entendu dire que certaines DLL (typiquement user32 et kernel32) qui sont chargées dans la partie haute de la mémoire (du genre au-delà de 0xD0000000, je ne connais pas la valeur exacte) sont chargées un seule fois et partagées entre tous les programmes qui les utilisent. Ca signifie que si tu modifies leur table d'import tu la modifie pour tous les autres processus qui les utilisent. Et étant donné que tu fais pointer la nouvelle table d'import vers une adresse de fonction définie dans un seul processus, cette adresse n'est pas valide pour les autres processus donc tu risques de faire planter tout le système et être obligé de rebooter...

Voilà quelques pistes, j'espère que ça t'aide.

Commentaire de Jean_Jean le 12/05/2008 15:27:25

Merci beaucoup Forman pour toutes ces précisions!

Génial, tu m'a donné du boulot pour des mois au rythme où je programme en ce moment. Je crois que je vais publier mon code en l'état pour la semaine prochaine et réfléchir qu'elle piste je vais approfondir. Je pense que trouver l'adresse d'une DLL chargée ne doit pas être très compliqué bien que je ne l'ai jamais fait. J'ai été surpris de ne pas avoir accès aux sources windows. Si mes souvenirs sont bons, du temps où je programmais en BP7 et BPW, on avait accès aux fenêtres ou aux bitmap de boutons utilisés... Il faudrait demander à Mauricio!

Si tu n'y vois pas d'inconvénient, j'incluerai certains passages de tes explications (je l'ai déjà fait pour ton source) dans mon aide qui va devenir un tuto si ça continue! Il y vraiment des pistes intéresantes dans tout ce que tu écris...

Salutations delphistes!
Jean_Jean

Commentaire de Forman le 12/05/2008 19:11:14

Aïe avant que tu te lances: je viens de faire un essai en patchant GetSysColor pour toutes les DLL utilisées dans le programme de démo de ce source, et apparemment aucune des DLL windows utilisées ne l'utilise...

Voici la liste de celles qui sont utilisées, l'adresse de chargement et un booléen indiquant si elles importent ou non GetSysColor:
Project1.exe : 00400000 TRUE
ntdll.dll : 7C910000 FALSE
kernel32.dll : 7C800000 FALSE
user32.dll : 7E390000 FALSE
GDI32.dll : 77EF0000 FALSE
advapi32.dll : 77DA0000 FALSE
RPCRT4.dll : 77E50000 FALSE
oleaut32.dll : 770E0000 FALSE
msvcrt.dll : 77BE0000 FALSE
ole32.dll : 774A0000 FALSE
version.dll : 77BD0000 FALSE
comctl32.dll : 58B50000 FALSE
IMM32.DLL : 76320000 FALSE
uxtheme.dll : 5B090000 FALSE
msctfime.ime : 75140000 FALSE
comctl32.dll : 77390000 FALSE
SHLWAPI.dll : 77F40000 FALSE

J'ai utilisé cette fonction en remplacement de ma fonction ReplaceAPI originale:

function ReplaceAllImportedAPI(DllName:string;ProcName:string;NewProc:Pointer):Boolean;
var
  ImageBase,OldProc,RedirectMem,LauncherCode:Pointer;
  ImageDosHeader:TImageDosHeader;
  ImageNTHeader:TImageNtHeaders;
  n,LauncherSize:Cardinal;
  Module:HModule;
  h:THandle;
  ME32:TModuleEntry32;
  t:Boolean;
begin
  Result:=False;
  Module:=LoadLibrary(PChar(DllName));
  OldProc:=GetProcAddress(Module,PChar(ProcName));                                           // Get the real API address
  if not Assigned(OldProc) then
    Assert(False,'Wrong library or procedure name');                                         // TODO: use Result:=False;Exit;
  GetLauncherCode(LauncherCode,LauncherSize,NewProc);
  try
    RedirectMem:=VirtualAllocEx(GetCurrentProcess,nil,LauncherSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE); // Let's add some new code to the module    ;-)
    if not WriteProcessMemory(GetCurrentProcess,RedirectMem,LauncherCode,LauncherSize,n) then          // Write the launcher code
      RaiseLastOSError;
    h:=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId);
    if h=0 then
      RaiseLastOSError;
    ZeroMemory(@ME32,SizeOf(ME32));
    ME32.dwSize:=SizeOf(ME32);
    if Module32First(h,ME32) then
      repeat
        ImageBase:=ME32.modBaseAddr;
        if not ReadProcessMemory(GetCurrentProcess,ImageBase,@ImageDosHeader,SizeOf(ImageDosHeader),n) then  // The DOS header is located at offset 0...
          RaiseLastOSError;
        if not ReadProcessMemory(GetCurrentProcess,Ptr(Integer(ImageBase)+ImageDosHeader._lfanew),@ImageNTHeader,SizeOf(ImageNTHeader),n) then
          RaiseLastOSError;                                                                        // The NT is located at offset _lfanew...
        t:=RedirectAPI(DllName,Cardinal(OldProc),Cardinal(RedirectMem),Cardinal(ImageBase),@ImageDosHeader,@ImageNTHeader); // OK, here we go, let's modify the headers
        writeln(t);
        Result:=Result or t;
      until not Module32Next(h,ME32);
    CloseHandle(h);
  finally
    FreeMem(LauncherCode);
  end;
end;

Commentaire de Forman le 12/05/2008 19:13:23

Donc conclusion ça ne fonctionne pas pour changer les couleurs. J'ai aussi essayé de patcher GetSysColorBrush qui fait un peu la même chose mais en renvoyant un HBRUSH pour peindre, mais  là encore ça ne donne rien.

Il semblerait donc qu'il faille utiliser une autre méthode...

Commentaire de Forman le 12/05/2008 19:14:40

Ah oui au fait dans le code que j'ai mis plus haut il faut enlever le WriteLn(t)

Commentaire de Jean_Jean le 12/05/2008 19:58:25

mdr et ouf!
merci de m'avoir prévenu. C'est donc un autre mécanisme qui entre en jeu. je crois que le mieux est de skinner l'ensemble afin de personnaliser en formes et couleurs. Moi qui croyais qu'il y avait une solution API simple et rapide.

Je commençais à me dire qu'il me fallait écrire en assembleur pour récupérer l'adresse mémoire des Dll utilisées par le programme. Mais je vois que tu as résolu la chose avec cette fonction digne de grand Forman!

Au fait, C'est quoi TModuleEntry32? un type que tu as déclaré, je ne le vois pas dans l'aide;

Bien à toi.
Jean_Jean

Commentaire de Forman le 12/05/2008 20:29:59

Ben en fait j'ai trouvé ça sur MSDN:

CreateToolhelp32Snapshot
http://msdn.microsoft.com/en-us/library/ms682489(VS.85).aspx

Module32First
http://msdn.microsoft.com/en-us/library/ms684218(VS.85).aspx

et MODULEENTRY32 (renommé en TModuleEntry32 dans Delphi)
http://msdn.microsoft.com/en-us/library/ms684225(VS.85).aspx

Effectivement, à ce stade je ne vois hélas pas d'autre solution qu'un skinnage à l'ancienne... et c'est toujours un peu pénible à écrire.

Bonne prog
Forman

Commentaire de softkey le 20/10/2008 00:42:48

Bonjour, tous dabord, je trouve cette source vraiment merveilleuse! J'ai un petit soucis par contre. J'essai d'utiliser cette fonction avec l'API 'WTSQuerySessionInformationA' dans la DLL 'Wtsapi32.dll'. Par contre, je n'arrive pas à le faire fonctionner (J'ai toujours l'erreur "Erreur: impossible de localiser l''API à remplacer".

Je mit prend de la manière suivante: ReplaceAPI('wtsapi32','WTSQuerySessionInformationA',@Test1) then begin

Merci !

Commentaire de Forman le 20/10/2008 00:53:02

Bonsoir,

essaie en mettant
ReplaceAPI('wtsapi32.dll','WTSQuerySessionInformationA',@Test1)

Sinon, je ne vois pas pourquoi ça ne marcherait pas... si mes souvenirs sont bons la fonction ReplaceAPI commence par faire un GetProcAddress sur l'API à remplacer, et c'est à ce moment-là que l'erreur que tu mentionnes peut se produire.

Commentaire de softkey le 20/10/2008 03:12:16

Salut, merci pour la réponse. J'avais malheureusement déjà essayé en ajoutant .dll et j'ai le même problème. L'erreur qui est retourné est quand ReplaceAPI = False. Quand je fait un peu de debug, je voit qu'à la ligne 163 du code (celui que tu as posté sur cette page) la condition n'est jamais True, donc c'Est pour ca que ReplaceAPI retourne False. Par contre, je ne comprend pas pourquoi la ligne 163 je retourne jamais True.

Merci encore pour l'aide!

Commentaire de Forman le 20/10/2008 05:16:04

Re,

Est-ce que tu es sûr que le programme dans lequel tu lances ma fonction utilise effectivement l'API WTSQuerySessionInformationA? Il ne suffit pas que tu fasses un import sur la fonction dans l'interface d'une unité (ça doit vraisemblablement être le cas dans ton code qui doit utiliser une unité du type wtsapi32.pas), il faut qu'en plus à un moment donné ton code l'utilise quelque part explicitement (je crois que le linker de Delphi repère les liens vers des procédures qui ne sont pas utilisées et les élimine de la table d'import pour optimiser l'exécutable). Pour être sûr, essaie de rajouter une fonction bidon à un endroit qui utilise l'API avec des paramètres bidons (par exemple dans un événement quelconque qui ne sera jamais déclenché). Vérifie aussi que ce n'est pas de la version WTSQuerySessionInformationW dont il s'agit. Il faut noter aussi que la fonction ne modifie que la table d'import de l'exécutable principal, si tu le fais depuis une DLL qui elle-même utilise WTSQuerySessionInformationA ça modifiera le comportement de l'API pour l'exécutable, pas pour la DLL (je ne sais pas si je suis très clair).

Si ça ne fonctionne toujours pas, je ne vois aucune explication possible, à moins que cette API ait des conventions d'import inhabituelles, mais ça me parait bizarre. Ca voudrait dire que le loader d'exécutable intégré à Windows serait programmé pour reconnaitre ce nom de fonction en particulier, et à appliquer des conventions différentes dans ce cas.

Autre piste: peut-être que la DLL wtsapi32.dll utilise un comportement similaire à celui de ma fonction pour modifier la table d'import des exécutables qui la chargent, par exemple un correctif de sécurité? Mais ça parait quand même improbable, en théorie ça peut causer des ennuis de stabilité de modifier la table d'import si l'exécutable n'a pas été réalisé en connaissance de cause (par exemple s'il inclut une protection antipiratage ou autre qui se base dessus).

Commentaire de softkey le 20/10/2008 17:05:00

Salut, le code est présentement dans une DLL, mais c'est le EXE qui call l'API. Donc à ce niveau tout semble correct. J'ai utiliser le logiciel 'WinAPIOverride32' pour vérifier que le EXE exécute bien la fonction WTSQuerySessionInformationA. Je crois avoir une piste vers le problème. Je me demandais si la DLL n'était pas chargé dynamiquement. Si tel est le cas, de quel manière pourrais-je le déterminer? Y'a t'il un moyen d'utiliser ReplaceAPI si la DLL est chargé dynamiquement? (Genre avec un Timer qui vérifierais la table d'import à tous les 100 ms ou quelquechose du genre?)

Merci beaucoup pour l'aide!

Commentaire de Forman le 20/10/2008 18:40:49

Re-

Ma fonction ne marche qu'avec les importations statiques (qui modifient effectivement la table d'import) et pas avec les importations dynamiques (pour lesquelles la table d'import n'est pas modifiée, l'adresse de la fonction importée pouvant se retrouver n'importe où dans la mémoire de l'exécutable). Dans le cas d'une importation dynamique on pourrait bien sûr faire une recherche toutes les secondes pour déterminer dans la mémoire virtuelle de l'exécutable si l'adresse de l'API apparait quelque part, et la remplacer par une autre adresse, mais ça ne parait pas souhaitable pour deux raisons:
-d'abord ça prend potentiellement beaucoup de temps d'explorer tout l'espace mémoire d'un processus (virtuellement plusieurs gigabytes de mémoire)
-si on est malchanceux on peut tomber sur une valeur égale à celle recherchée, mais qui n'a rien à voir (par exemple un int qui prendrait la même valeur et servirait à autre chose de vital!)

Par contre, rien ne t'empêche de patcher l'API GetProcAdress au moment du lancement de l'exécutable, pour la remplacer par une autre fonction qui, lorsqu'on l'appelle avec le nom 'WTSQuerySessionInformationA', renvoie l'adresse que tu veux (et qui a le même comportement que celle d'origine dans les autres cas). Toutes les API de User32.dll et Kernel32.dll sont chargées de manière statique normalement, donc dans ce cas là ça devrait fonctionner.

Ceci dit après c'est une course contre la vitesse de l'exécutable, car il faut que tu arrives à patcher GetProcAdress avant que celle-ci ne soit utilisée pour charger WTSQuerySessionInformationA. Est-ce que l'exe en question est déjà compilé ou tu en as les sources?

Commentaire de softkey le 20/10/2008 18:53:08

Salut, l'Exe est déjà compilé. Je crois qu'il n'y aurait pas de problème pour patcher GetProcAdress avant que WTSQuerySessionInformationA soit exécuté car cette fonction est utilisé apres 4 ou 5 secondes que l'appli est starté. Donc si je comprend bien, j'utilise ReplaceAPI pour GetProcAdress, et quand je recoit une requête pour charger WTSQuerySessionInformationA, je renvoit un pointeur vers ma nouvelle fonction. Ca serais très logique. Je vais essayer ca et je t'en redonne de nouvelles

Merci beaucoup encore une fois!

Commentaire de Forman le 20/10/2008 19:17:51

De rien.

En ce qui concerne le délai de 4 ou 5 secondes, il se peut quand même que l'API soit chargée avec GetProcAdress bien avant, auquel cas il faut quand même que tu la remplaces très vite!

Peut-être que ça peut être une bonne idée de faire un programme de lancement (qui utilise CreateProcess sur l'exe) avec le flag CREATE_SUSPENDED, patcher GetProcAdress à ce moment-là, puis faire un ResumeThread sur le thread principal du process une fois que c'est patché.

Commentaire de softkey le 20/10/2008 19:31:19

Salut, quand j'essai d'utiliser ReplaceAPI avec GetProcAddress, j'ai le même problème qu'au début (ReplaceAPI retourne False). Est-ce possible que GetProcAddress soit lui aussi dynamique? Je n'ai pas essayé encore de faire un programme de lancement car je voulais commencer par modifier le GetProcAddress, mais ca ne fonctionne pas. Pense-tu qu'avec le programme de lancement ca pourrais changer quelquechose? (Si pour l'instant on met de côté le WTSQuerySessionInformationA).

Merci!

Commentaire de Forman le 20/10/2008 19:38:47

Ca m'étonnerait beaucoup que GetProcAdress soit dynamique! (sinon comment serait-elle chargée?)

Peut-être que le problème vient tout simplement de ta méthode d'injection. Est-ce que tu fais par exemple CreateRemoteThread sur l'adresse de LoadLibrary (avec ta DLL en paramètre) depuis un processus extérieur? Et dans ce cas, est-ce que tu fais le patch dans la procédure "main" de la DLL? Si c'est le cas essaie de lancer un thread depuis le "main" de la DLL qui va s'occuper de patcher les API désirées, car il se peut que le thread "temporaire" qui est créé pour le "main" de la DLL ne dispose pas de toutes les informations utilisées (image base, etc...).

Commentaire de softkey le 20/10/2008 19:45:51

En réalité, je ne fait pas vraiment de méthode d'injection et j'expliquer pourquoi: Le logiciel que je veux modifier s'occupe de loader ma DLL. Donc, si je me trompe pas, c'est lui qui se charge de "l'injection". Présentement je suis en mesure de hooker les message windows de mon EXE (avec SetWindowLong) sans problème. En fesant quelques test, j'ai réussi à hook l'API GetSystemMetrics sans problème. Mais cela ne fonctionne pas avec WTS... et GetProcAddress. Voici le code que j'utilise pour GetProcAddress, peut-être qu'il est là le problème:

Quand ma DLL est loadé par le EXE:

   h:=LoadLibrary(kernel32);
   @GOldGetSysColor:=GetProcAddress(h,'GetProcAddress');
   Assert(Assigned(@GOldGetSysColor));
   if ReplaceAPI(kernel32,'GetProcAddress',@Test1) then begin
        ShowMessage('True')
   end else
   begin
        ShowMessage('False');
   end;

Et voici le reste:

var
  GOldGetSysColor:function(hModule : HMODULE; lpProcName: LPCSTR): Pointer; stdcall;

function Test1(hModule : HMODULE; lpProcName: LPCSTR): Pointer; stdcall;
begin
       Result := GOldGetSysColor(hModule, lpProcName);
end;



Est-ce que je mit prend d'une mauvaise manière?

Merci

Commentaire de Forman le 20/10/2008 20:01:25

Peut-être qu'il faut utiliser 'GetProcAddressA' ou 'GetProcAddressW'? (il faudrait relire la MSDN en détails à ce sujet).

Tu peux aussi essayer d'utiliser un soft du genre Dependency Walker pour voir quelles sont les API qui sont effectivement chargées statiquement par ton exécutable. Il est possible que GetProcAddress ou WTS... soient utilisées non pas directement par l'exécutable, mais par une DLL que l'exécutable utilise... auquel cas il faudrait modifier mon code pour qu'il cherche dans la table d'import de la DLL en question et non pas dans celle de l'exe.

Commentaire de Forman le 20/10/2008 20:02:21

Sinon le code que tu as mis plus haut a l'air parfaitement valide. Quand tu as fait des essais avec GetSystemMetrics, est-ce aue tu as effectivement observé des changements dans le comportement de l'exe?

Commentaire de softkey le 20/10/2008 20:08:49

Oui, pour commencer j'Avais juste mit un ShowMessage dans la procédure et je renvoyais rien (histoire de voir si ca l'Avais réellement un impact) et effectivement il y en avait un. Je viens d'installer Dependency Walker et je voit que Wtsapi32.dll ne semble pas être chargé par l'appli mais bien par: Winscard.dll qui est chargé par rasdlg.dll qui est chargé par wininet.dll qui est chargé par shell32.dll qui est chargé par mon EXE (si j'ai bien compris le tree qui a sorti). Donc j'imagine que si j'utilise ta fonction mentionné plus haut dans les commentaires il y aurait moyen de faire fonctionner le tout?

Merci encore, l'aide est vraiment apprécié!!

Commentaire de Forman le 20/10/2008 20:16:06

Oui ça devrait marcher, si la méthode que j'ai utilisée plus haut (avec CreateToolhelp32Snapshot) énumère bien toutes les DLL chargées. Eventuellement, tu peux faire un ShowMessage avec toutes les DLL trouvées dans la boucle, pour vérifier que Wtsapi32.dll est dans la liste.

Commentaire de softkey le 20/10/2008 20:33:53

Je viens d'essayer avec la fonction ReplaceAllImportedAPI mais malheureusement wtsapi32.dll n'est pas énuméré. N'ayant jamais utilisé Dependency Walker auparavant, je me posais une question: Devant WTSAPI32.dll il y a un sablier, qu'est-ce que ca signifie exactement?

Commentaire de Forman le 20/10/2008 20:56:51

Il y a la réponse ici:
http://www.dependencywalker.com/help/html/interpreting_errors.htm
(voir le paragraphe qui commence par "Delay-load dependencies")

Donc apparemment c'est un import retardé, avec un système que ma fonction ne peut pas patcher tel quel. Finalement, peut-être que ça pourrait marcher en patchant GetProcAdress sur toutes les DLL chargées, et en recommençant à intervalles réguliers (au cas où une nouvelle DLL apparait), voire même en patchant LoadLibrary pour détecter toutes nouvelle DLL qui est chargée... bon courage!

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Hook dll : comment ca marche ? [ par Millenius ] Bonjour, je voudrais hooker un dll.Le clavier et la souris, ca je sais faire.Ce que je voudrais, c pouvoir connaitre les flux de données entrant et so Hook sans dll, c'est possible , mais comment ? [ par jace1975 ] salut &#224; tous je travaille actuellement sur une application, pour me permettre&nbsp;notamment de &nbsp;killer imm&#233;diatement le processus en c A l'aide : utilisation d'une dll delphi par un programme visual visual C++ [ par neo_delphi ] Dans ma DLL sous delphi, j'ai 2 fonctions definies de la facon suivante :function fct1(nb:word; var Tab1:array of word):word;stdcall;function fct2(nb: API Windows [ par michelroc ] Bonjour,J'ai ecris ce code et la reponse est toujours n&#233;gative ?? Y a t-il une erreur dans ce code.Windows XP fam// Savoir si l'&#233;cran de vei Espionner une dll pour récupérer un flot de données [ par gorets ] J'ai un programme qui utilise une fonction plac&#233;e dans une dll. cette dll redirige par une fonction un flux de donn&#233;e vers le port parall&#2 Lien DLL dans un répertoire spécifique [ par dimdidi ] Bonjour,J'utilise delphi 7 sous windowsXP.J'ai&nbsp;plusieurs applications developp&#233;es en delphi qui utilise des DLLs sp&#233;cifiquesJe voudrais erreur dll de fonction [ par saravana ] bonjour a tous j'essaye d'appeler une fonction avec une dll, mais j'ai une erreur estce que quelqun peut me dire si il ya des erreurs dans le source:l [Dll] Inclure des images dans une .Dll et les charger ensuite. [ par JulioDelphi ] Bonjoir ! A mon tour d'avoir un problème sans solution : J'ai une form1 avec un composant TImage posé. (super !) J'ai 20mo d'images à charger dedans. Utiliser l'API BOOL GetSystemPowerStatus pour avoir des infos sur la batterie [ par Yil2201 ] Salut &#224; tous! Voila, j'aimerais cr&#233;er ma propore appli, capable de donner des infos sur la batterie, moins rudimentaire que la fenetre de la ( HELP ) Service de - de 300Ko en utilisant les API [ par Rudy3212 ] Best PigBonjour voila je sais qu'il est possible de faire des application de quelque Ko enfin moins de 300Ko en utilisant les api, mais peut on faire


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Septembre 2010
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
27282930   

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 1,248 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales