2

Friends

Im with a little problem. Im trying to create a delphi Dll with a form in RAD Studio, but i don't know how to make it load with DllMain. I want to inject this Dll in a third-party process at runtime after.

I created the Dll project with the form without problems, but i can't find nothing good related to "how to load it with DllMain", or at least the tutorials/things i found doesn't helped me (or i'm just dumb). Can someone help me? Give me some hint or a site/video where i can learn it?

I really appreciate your time guys! =)

BlueOrange
  • 21
  • 1
  • DLLMain is called by Windows when the DLL is being loaded. You never call it yourself. – Ken White Feb 16 '21 at 22:59
  • Yes, but i want to load my form in the third-party process in case of DLL_PROCESS_ATTACH. – BlueOrange Feb 16 '21 at 23:25
  • What you want to do doesn't matter - you can't call DLLMain yourself. – Ken White Feb 17 '21 at 00:03
  • 1
    It is NOT safe to call UI functions in `DllMain()` anyway. See [DllMain Best Practices](https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices): "*You should never perform the following tasks from within DllMain: ... Call functions in User32.dll or Gdi32.dll. Some functions load another DLL, which may not be initialized.*" Guess which library `CreateWindow/Ex()` is in? Hint: `user32.dll`. So, DO NOT try to display a UI Form in `DllMain()` directly. – Remy Lebeau Feb 17 '21 at 01:00
  • Nevertheless, if you were to follow best practices, you could write your code in your unit's initialization section. – Sertac Akyuz Feb 17 '21 at 01:07
  • http://www.rvelthuis.de/articles/articles-dlls.html – Delphi Coder Feb 17 '21 at 02:09
  • @SertacAkyuz that is not any safer. In a DLL, unit initializations are called in the context of `DllMain()` – Remy Lebeau Feb 17 '21 at 03:13
  • You COULD have `DllMain()` start a thread (just don't wait on it!) and then create the Form inside that thread. Another option would be to have `DllMain()` install a hook that the injector could then send a signal to after the DLL is loaded, and that signal handler could then create the Form. – Remy Lebeau Feb 17 '21 at 03:15
  • I would suggest same as Remy, install a hook to some api that you know is called and load your form there and then unhook or set some global variable. – Remko Feb 17 '21 at 09:54
  • @Remy - I know, that's why I commented. And that's why I added "if you were to follow best practices", referring to what you mentioned in your previous comment. – Sertac Akyuz Feb 17 '21 at 15:50
  • Don't forget to upvote the answers that help ya, dude. – Samuel Andrade Feb 17 '21 at 16:30

1 Answers1

2

You could use assembly to inject the ebp-based stack into some variables. Here is an example:

library Project1;

uses
  System.SysUtils,
  Windows,
  System.Classes;

var
  hInstDLL: THandle;
  fdwReason: DWORD;
  lpReserved: DWORD;
begin
  asm
    push eax; // Save the current eax
    mov eax, [ebp+$8] // Put into eax the first argument of the current function (DLLMain)
    mov [hInstDLL], eax; // Put into hInstDLL this argument
    mov eax, [ebp+$c] // Load into eax the second argument
    mov [fdwReason], eax; // Save to fdwReason
    mov eax, [ebp+$10] // Put into eax the last argument
    mov [lpReserved], eax; // Put into lpReserved (unnecessery)
    pop eax; // Restore the original eax value
  end;

  if fdwReason = 1 {DLL_PROCESS_ATTACH} then
  begin
    // Do your stuff;
  end;
end.
  • Just to explain: Windows functions use the common stack ([esp+x]) to pass and receive paramters, Delphi move esp into ebp in the very beginning of any function, So, at first, Delphi doesn't expect any paramter to its EntryPoint, but stills adjust the stack, so we can take it. :) – Samuel Andrade Feb 17 '21 at 16:29
  • I don't understand how your answer is related to the question. Could you explain? – fpiette Feb 17 '21 at 17:13
  • This code merely gains access to the parameters that the OS passes into the DLL. Delphi provides [`DllProc`](http://docwiki.embarcadero.com/Libraries/en/SysInit.DllProc)/[`DllProcEx`](http://docwiki.embarcadero.com/Libraries/en/SysInit.DllProcEx) callbacks for that purpose (though you do have to call them manually for `DLL_PROCESS_ATTACH`). But, this doesn't answer the underlying issue being asked about - how to create a Form when the DLL is loaded into a process. The DPR's code is already executed in response to `DLL_PROCESS_ATTACH`, there is no need to check for `fdwReason = 1` manually. – Remy Lebeau Feb 17 '21 at 18:35
  • Also, I think this code shown is only for 32bit, it would fail miserably under 64bit, which has a completely different call stack layout for parameters. – Remy Lebeau Feb 17 '21 at 18:40
  • If you replace the "// Do your stuff" by the create form code, it will do exactily what he wants. I understood that he wants to inject the DLL into some process then the process will run the DLLMain and he wants to choose what the DLLMain doest when it was attached. – Samuel Andrade Feb 17 '21 at 19:02