Creating threads

Posted on 2004-09-24
Last Modified: 2011-09-20
Hello, what is a good way to make a function or procedure run after your program has been closed?
Question by:delphcon5
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
LVL 12

Expert Comment

ID: 12141682
1) OnClose event
2) in Application.OnTerminate
3) catch WM_QUERYENDSESSION and WM_ENDSESSION for shudown/restart
LVL 22

Expert Comment

by:Ferruccio Accalai
ID: 12141693
From the program itself or from outside?

Author Comment

ID: 12141931
from the program, or from outside like making a dll file, anything would work, can you inject a dll into a process like explorer?
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Accepted Solution

php4delphi earned 125 total points
ID: 12146428
program dllinject;


 Author  : Rezmond
 URL     :
 Email   :
 Relesed : Friday 11th Oct 2002
 Version : 1.00

 Freeware for non commerical use

 Note this only works under NT

 This program demonstrates how to inject a DLL into a remote process

 When working with code in a target you must be
 carefull with the variables you use

 How this program works!

  The CreateRemoteThread procedure will make the target process
  create a thread an execute it.

  What we simply do is use VirtualAllocEx to allocate some extra memory in
  the target process

  The next step is to copy our code ( in this case InjectedProc )
  into that memory.

  We then get the target process to execute that code

   In order to pass parameters to the remote thread we must
   copy the data over to the remote process  with  VirtualAllocEx
   and WriteProcessMemory.
   We cannot referance local variables in our inject application from the remote process

 Writing Remote Thread code :
  When writing code that will be injected to a remote process you must be carefull
  that you do not make any referances to local variables determined by your app
  This include function calls!! if you wish to call functions
  you must load the libraries first using LoadLibrary and GetProcAddress

  For example writing
    MessageBox( 0, 'hey\0','hey\0' , 0);
  in the thread we want to inject would cause an error

  Your best bet is to use the inline assembler when coding.
  Delphi code is not always safe

  procs in 'procs.pas';


 this structure contains pointers to variables
 that will be passed to and used by the InjectedProc
  TInjectDllData = record
    pLoadLibrary     : pointer;  //pointer to the loadLibrary function
    pGetProcAddress  : pointer;  //pointer to the GetProcAddress function
    pGetModuleHandle : pointer;  //pointer to the GetModulhandle function
    lib_name     : pointer;      //pointer to the name of the dll we will load

procedure InjectedProc( parameter : Pointer ) ; stdcall;
var InjectDllData : TInjectDllData;
  InjectDllData :=  TInjectDllData(parameter^);
   push InjectDllData.lib_name
   call InjectDllData.pLoadLibrary
   you could easily call a function inside the library we just loaded

 this basically allocates some memory in the target process
 is then uses create remote thread to execute it
 it will then wait for the code to finish executing
 once finished it will free the memory used.
function InjectDllToTarget(dllName : string; TargetProcessID : DWORD ; code : pointer; CodeSize : integer ): boolean;
  InitDataAddr , WriteAddr : pointer;
  hProcess  , ThreadHandle : Thandle;
  BytesWritten , TheadID : DWORD;
  InitData : TInjectDllData;
 result := false;

 // it would probably be a good idea to set these
 // from the IAT rather than assuming kernel32.dll
 // is loaded in the same place in the remote process
 InitData.pLoadLibrary      := GetProcAddress(LoadLibrary('kernel32.dll'), 'LoadLibraryA');
 InitData.pGetProcAddress   := GetProcAddress(LoadLibrary('kernel32.dll'), 'GetProcAddress');
 InitData.pGetModuleHandle  := GetProcAddress(LoadLibrary('kernel32.dll'), 'GetModuleHandleA');

 hProcess := OpenProcess( PROCESS_ALL_ACCESS, FALSE, TargetProcessID );
 if (hProcess = 0) then exit;

// write the initdata strucutre to the remote prcess
 InitDataAddr := VirtualAllocEx(hProcess , 0, sizeof(InitData)  , MEM_COMMIT , PAGE_READWRITE) ;
 if ( InitDataAddr <> nil) then
  WriteProcessMemory(hProcess , InitDataAddr , (@InitData) , sizeof(InitData) , BytesWritten );
 end ;

 // alocate and write the dll name to the remote process
 InitData.lib_name := VirtualAllocEx(hProcess , 0, length(dllName) + 5  , MEM_COMMIT , PAGE_READWRITE) ;
 if ( InitData.lib_name <> nil) then
    WriteProcessMemory(hProcess ,  InitData.lib_name , pchar(dllName) , length(dllName) , BytesWritten );
 end ;

// write our proc that loads the dll into the remote process
// then execute it
 WriteAddr := VirtualAllocEx(hProcess , 0, CodeSize , MEM_COMMIT , PAGE_READWRITE) ;
 if (WriteAddr <> nil) then
   WriteProcessMemory(hProcess , WriteAddr , code , CodeSize , BytesWritten );

   if BytesWritten = CodeSize then
      ThreadHandle := CreateRemoteThread( hProcess , nil , 0, WriteAddr , InitDataAddr ,0 , TheadID );

     WaitForSingleObject( ThreadHandle , INFINITE);  //wait for the thread to execute

      VirtualFreeEx( hProcess , WriteAddr ,   0 , MEM_RELEASE); // free the memory we allocated
      result := true;

 // free the memory we allocated for the dll name
 VirtualFreeEx( hProcess , InitDataAddr ,  0 , MEM_RELEASE);
 VirtualFreeEx( hProcess , InitData.lib_name ,  0 , MEM_RELEASE);

var InitData : TInjectDllData;
   PID       : Dword;
   dll_to_inject : string;

 GetDebugPrivs; // give us debug privalages

 dll_to_inject := 'wsock.dll'; //just an example, it can be anything

  for the perous of this demo we will just inject into
  our own process but PID could be any process we want
  PID := GetCurrentProcessID();

 if  InjectDllToTarget(dll_to_inject, PID , @InjectedProc , 1000)  then
   writeLn('Dll Injected' )
    writeLn('Dll Inject failed');

 writeLn('Press enter to exit');


unit procs;


uses windows;

  Author : Rezmond
  URL    :
  Email  :

  Freeware for non commerical use

  ToolHelp Wrappper functions
  As well as a procedure to get Debug Privalages under win NT

   TH32CS_SnapProcess = 2;

type  TProcessEntry32 = record
      dwSize              : DWORD;
      cntUsage            : DWORD;
      th32ProcessID       : DWORD;
      th32DefaultHeapID   : DWORD;
      th32ModuleID        : DWORD;
      cntThreads          : DWORD;
      th32ParentProcessID : DWORD;
      pcPriClassBase      : integer;
      dwFlags             : DWORD;
      szExeFile           : array [0..MAX_PATH-1] of char;

 function CreateToolhelp32Snapshot (dwFlags,th32ProcessID: cardinal) : cardinal;
 function Process32First(hSnapshot: cardinal; var lppe: TProcessEntry32) : bool;
 function Process32Next(hSnapshot: cardinal; var lppe: TProcessEntry32) : bool;
 function FindProcess( Name : string) : dword;
 procedure GetDebugPrivs;
 procedure killbyPID( PID : DWORD);

procedure killbyPID( PID : DWORD);
var hp : THANDLE;
 hp := OpenProcess( PROCESS_TERMINATE , false, PID) ;

Const SE_DEBUG_NAME = 'SeDebugPrivilege' ;

procedure GetDebugPrivs;
  hToken: THandle;
  tkp: TTokenPrivileges;
  retval: dword;

 if  (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or  TOKEN_QUERY, hToken)) then
     LookupPrivilegeValue(nil, SE_DEBUG_NAME  , tkp.Privileges[0].Luid);
     tkp.PrivilegeCount := 1;
     tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
     AdjustTokenPrivileges(hToken, false, tkp, 0, nil, retval);

function FindProcess( Name : string) : dword;
   FSnapshotHandle : THandle;
   FProcessEntry32 : TProcessEntry32;
   hp : Thandle;

   FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
   ContinueLoop := Process32First(FSnapshotHandle,FProcessEntry32);
   while ContinueLoop do
     if Name = FProcessEntry32.szExeFile  then
           result := FProcessEntry32.th32ProcessID ;

       ContinueLoop := Process32Next(FSnapshotHandle,FProcessEntry32);

 pCreateToolhelp32Snapshot : function (dwFlags,th32ProcessID: cardinal) : cardinal; stdcall = nil;
 pProcess32First :  function (hSnapshot: cardinal; var lppe: TProcessEntry32) : bool; stdcall = nil;
 pProcess32Next  :  function (hSnapshot: cardinal; var lppe: TProcessEntry32) : bool; stdcall = nil;

function TestToolhelpFunctions : boolean;
var c1 : cardinal;
  @pProcess32First          :=GetProcAddress(c1,'Process32First'          );
  @pProcess32Next           :=GetProcAddress(c1,'Process32Next'           );
  result := (@pCreateToolhelp32Snapshot<>nil) and (@pProcess32First<>nil) and (@pProcess32Next<>nil);

 function CreateToolhelp32Snapshot (dwFlags,th32ProcessID: cardinal) : cardinal;
   result := 0;
   if @pCreateToolhelp32Snapshot = nil then if not TestToolhelpFunctions then exit;
   result := pCreateToolhelp32Snapshot( dwFlags , th32ProcessID );

 function Process32First(hSnapshot: cardinal; var lppe: TProcessEntry32) : bool;
   result := false;
   if @pProcess32First = nil then if not TestToolhelpFunctions then exit;
   result := pProcess32First(hSnapshot,lppe);

 function Process32Next(hSnapshot: cardinal; var lppe: TProcessEntry32) : bool;
    result := false;
    if @pProcess32Next = nil then if not TestToolhelpFunctions then exit;
    result := pProcess32Next(hSnapshot,lppe);


Author Comment

ID: 12149464
Is that two ways to do it?

Author Comment

ID: 12149470
Nevermind i got it.

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Correct Component for Shopping Cart. 2 136
Downloading email attachments 2 96
Making delphi communicate with a c# service 16 138
firemonkey Android Listview Sort items 7 107
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

751 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question