home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1996 November / PCO96_11.ISO / filesbbs / taskmon.arj / PASCAL / TASKDLL0.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-08-23  |  12.3 KB  |  301 lines

  1. unit taskdll0;
  2.  
  3. // NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE!
  4. //
  5. // In order to recompile this DLL you will need at the minimum REBASE.EXE (a
  6. // utility supplied in the Windows SDK) and a hex editor.  Alternatively, if
  7. // the Delphi compiler has undocumented switches that allow you to load DLL's
  8. // successfully above the 2GB line (hex addresses > $80000000), then that will
  9. // be more convenient.  (The $IMAGEBASE directive alone does not do the job in
  10. // my experience because we cannot mark segments as "SHARED" in the Delphi2
  11. // environment.) Specifically, the "DATA", ".idata", and "BSS" segments must be
  12. // marked "Shareable" and the DLL's base address must be placed in an unused
  13. // address above $80000000 (The compiled DLL is rebased to $BFF70000 - the same
  14. // as KERNEL32.DLL - the Windows loader will move it to a more appropriate
  15. // free shared area).
  16. //
  17. // Modification of this code, especially in the callbacks, must be made very
  18. // carefully.  Be prepared to reboot your machine often.  This is not a problem
  19. // with the FH95 library, but it is the nature of the beast.  You are, after all,
  20. // altering the Win32 API flow and CreateProcessA and ExitProcess are fundamental
  21. // to your operating system!
  22. //
  23. // NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE! - NOTE!
  24.  
  25. interface
  26.  
  27. uses
  28.   Windows, SysUtils, Messages;
  29.  
  30. {$I TASKMONI.PAS}
  31.  
  32. // Standard exported functions for use by TASKMON.EXE
  33. function InitTaskDLL: Boolean; stdcall; export;
  34. function InstallHookCreateProcess: Boolean; stdcall; export;
  35. function InstallHookExitProcess: Boolean; stdcall; export;
  36. function UninstallHooks: Boolean; stdcall; export;
  37. function GetItemInLog (FirstItemInList: Boolean): PLogInfo; stdcall; export;
  38. function SetAlarm (SetTheAlarm: Boolean): Boolean; stdcall; export;
  39.  
  40. // Callbacks that will become wrappers around CreateProcessA and ExitProcess.
  41. // These will not be called by TASKMON.EXE but by FH95.DLL and the Windows 95
  42. // operating system.  Note that these prototypes must match EXACTLY the
  43. // prototype for the real Win32 API.
  44. function MyCreateProcessA (lpApplicationName: PAnsiChar;
  45.                            lpCommandLine: PAnsiChar;
  46.                            lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
  47.                            bInheritHandles: BOOL;
  48.                            dwCreationFlags: DWORD;
  49.                            lpEnvironment: Pointer;
  50.                            lpCurrentDirectory: PAnsiChar;
  51.                            const lpStartupInfo: TStartupInfo;
  52.                            var lpProcessInformation: TProcessInformation): WordBool; stdcall; export;
  53. procedure MyExitProcess (uExitCode: UINT); stdcall; export;
  54.  
  55. // A storage object used for storing the starting and ending of tasks.
  56. // TASKMON.EXE will display the task list by reading each item in the list.
  57. type
  58.   PItemListObject = ^TItemListObject;
  59.   TItemListObject = record
  60.     Heap: LongInt;
  61.     List: PByte;
  62.   end;
  63.  
  64. // There are no local variables in the callbacks.  While this is not strictly
  65. // prevented, it does avoid stack overflows if an API has a small stack.
  66. var
  67.   ItemListObject: TItemListObject;        // Stores task starting and ending
  68.                                           // information.  See PLogInfo type.
  69.   lCreateProcessA, lExitProcess: LongInt; // FH95 hook identifiers
  70.   TheAlarmIsSet: Boolean;
  71.   fRC: WordBool;                          // Value returned by CreateProcessA
  72.   StatusMask, Skip, Last: Integer;        // Status variables from FH95.DLL
  73.   LogInfoP: PLogInfo;                     // Information structure about
  74.                                           // tasks starting and ending.
  75.   MainWindow: HWnd;                       // Main window of TASKMON.EXE
  76.  
  77. implementation
  78.  
  79. {$I FUNCHOOK.PAS} // Partial header file for FH95.DLL.
  80.  
  81. function
  82.   GetItemInLog
  83.     (FirstItemInList: Boolean): PLogInfo;
  84. begin
  85.   if FirstItemInList then
  86.     LogInfoP := PLogInfo (SLMFirst (ItemListObject.List))
  87.   else
  88.     LogInfoP := PLogInfo (SLMNext (ItemListObject.List));
  89.   Result := LogInfoP;
  90. end; {GetItemInLog}
  91.  
  92. function
  93.   SetAlarm
  94.     (SetTheAlarm: Boolean): Boolean;
  95. begin
  96.   TheAlarmIsSet := SetTheAlarm;
  97.   Result := TheAlarmIsSet;
  98. end; {SetAlarm}
  99.  
  100. function
  101.   InitTaskDLL: Boolean;
  102. var
  103.   rc: Boolean;
  104. begin
  105.   rc := False;
  106.   // First, remember the window handle for TASKMON.EXE.  Messages will be sent
  107.   // to it by the hook/callbacks.
  108.   MainWindow := FindWindow (Nil, 'Task Monitor for Windows 95');
  109.   // Next, create our storage area.  Note that this will exist in the shareable
  110.   // memory area (hmmm...sounds like a memory-mapped file concept).
  111.   ItemListObject.Heap :=
  112.     SMMCreate (64000, SMM_ATTR_EXTENSIBLE + SMM_ATTR_ZEROINIT);
  113.   if ItemListObject.Heap <> SMM_BAD_HEAP then begin
  114.     ItemListObject.List :=
  115.       SLMCreateEx (SizeOf (TLogInfo), ItemListObject.Heap);
  116.     if ItemListObject.List = Nil then
  117.       SMMDestroy (ItemListObject.Heap)
  118.     else
  119.       rc := True;
  120.   end;
  121.   Result := rc;
  122. end; {InitTaskDLL}
  123.  
  124. function
  125.   InstallHookCreateProcess: Boolean;
  126. var
  127.   pfnHook: TFarProc;
  128.   rc: Boolean;
  129. begin
  130.   rc := False;
  131.   // Note that this is a generic hooking capability.  Virtually all published
  132.   // (and several undocumented) API's can be hooked (the constraint is that
  133.   // there must be enough "room" to establish the hook).  Approximately 40 Win32
  134.   // API's have been successfully hooked by FH95.  See EXESpy95 and INISpy95
  135.   // for further examples.
  136.   if lCreateProcessA = 0 then begin
  137.     // Install the hook/callback for CreateProcessA.
  138.     pfnHook := MakeProcInstance (TFarProc (Addr (MyCreateProcessA)), HInstance);
  139.     lCreateProcessA := FuncHookInstallHookEx ('KERNEL32', 'CreateProcessA', pfnHook, 40, True);
  140.     if lCreateProcessA <> 0 then begin
  141.       rc := True;
  142.       FuncHookConfigureHook (lCreateProcessA, FUNCHOOK_CONFIG_RTNSIZE , 0, 4);
  143.       FuncHookConfigureHook (lCreateProcessA, FUNCHOOK_CONFIG_BRTNSIZE, 0, 4);
  144.       FuncHookConfigureHook (lCreateProcessA, FUNCHOOK_CONFIG_EXITCOND , 0, FUNCHOOK_COND_NE);
  145.       FuncHookConfigureHook (lCreateProcessA, FUNCHOOK_CONFIG_BEXITCOND, 0, FUNCHOOK_COND_NE);
  146.     end;
  147.   end;
  148.   Result := rc;
  149. end; {InstallHookCreateProcess}
  150.  
  151. function
  152.   InstallHookExitProcess: Boolean;
  153. var
  154.   pfnHook: TFarProc;
  155.   rc: Boolean;
  156. begin
  157.   rc := False;
  158.   // Note that this is a generic hooking capability.  Virtually all published
  159.   // (and several undocumented) API's can be hooked (the constraint is that
  160.   // there must be enough "room" to establish the hook).  Approximately 40 Win32
  161.   // API's have been successfully hooked by FH95.  See EXESpy95 and INISpy95
  162.   // for further examples.
  163.   if lExitProcess = 0 then begin
  164.     // Install the hook/callback for ExitProcess.
  165.     pfnHook := MakeProcInstance (TFarProc (Addr (MyExitProcess)), HInstance);
  166.     lExitProcess := FuncHookInstallHookEx ('KERNEL32', 'ExitProcess', pfnHook, 4, True);
  167.     if lExitProcess <> 0 then begin
  168.       rc := True;
  169.       FuncHookConfigureHook (lExitProcess, FUNCHOOK_CONFIG_EXITCOND , 0, FUNCHOOK_COND_STOP);
  170.       FuncHookConfigureHook (lExitProcess, FUNCHOOK_CONFIG_BEXITCOND, 0, FUNCHOOK_COND_STOP);
  171.     end;
  172.   end;
  173.   Result := rc;
  174. end; {InstallHookExitProcess}
  175.  
  176. function
  177.   UninstallHooks: Boolean;
  178. // This routine will remove the hook code in the CreateProcessA and ExitProcess
  179. // API's and destroy the shared memory area.
  180. var
  181.   rc: Boolean;
  182. begin
  183.   if lCreateProcessA <> 0 then
  184.     FuncHookUnInstallHook (lCreateProcessA);
  185.   lCreateProcessA := 0;
  186.   if lExitProcess <> 0 then
  187.     FuncHookUnInstallHook (lExitProcess);
  188.   lExitProcess := 0;
  189.   if ItemListObject.Heap <> SMM_BAD_HEAP then
  190.     rc := SMMDestroy (ItemListObject.Heap);
  191.   ItemListObject.Heap := SMM_BAD_HEAP;
  192.   ItemListObject.List := Nil;
  193.   Result := rc;
  194. end; {UninstallHooks}
  195.  
  196. // The following routines are not called directly by any program.  When they
  197. // have been successfully installed, they become "part of" the Windows 95
  198. // operating system.  As such, they appear in any process space that makes
  199. // use of the hooked API, e.g., CreateProcessA and ExitProcess.  But,
  200. // because they reside in TASKDLL.DLL, we can grab information, add additional
  201. // processing, or change parameters as needed.  In effect, we have "injected"
  202. // TASKDLL.DLL into any and all processes that make use of, in this case,
  203. // CreateProcessA and/or ExitProcess.  This is known as in other words a
  204. // systemwide hook.
  205. function
  206.   MyCreateProcessA
  207.     (lpApplicationName: PAnsiChar;
  208.      lpCommandLine: PAnsiChar;
  209.      lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
  210.      bInheritHandles: BOOL;
  211.      dwCreationFlags: DWORD;
  212.      lpEnvironment: Pointer;
  213.      lpCurrentDirectory: PAnsiChar;
  214.      const lpStartupInfo: TStartupInfo;
  215.      var lpProcessInformation: TProcessInformation): WordBool;
  216. begin
  217.   // Some additional processing - an alert - if the user requests it.
  218.   if TheAlarmIsSet then
  219.     MessageBeep (MB_OK);
  220.   // Remember some internal hook states from FH95.
  221.   StatusMask := FuncHookGetInfo (FUNCHOOK_CMD_STATUS, lCreateProcessA);
  222.   StatusMask := StatusMask and FUNCHOOK_STATUS_MASK;
  223.   // If FH95 commands our callback to perform the "real" API, then do it!
  224.   // The "real" API must be called ONCE AND ONLY ONCE!  (Note - this call
  225.   // may or may not perform the real CreateProcessA; there may be other
  226.   // hooks on the chain waiting for their chance.
  227.   if StatusMask = FUNCHOOK_STATUS_DOIT then
  228.     fRC := CreateProcessA (lpApplicationName, lpCommandLine, lpProcessAttributes,
  229.                            lpThreadAttributes, bInheritHandles, dwCreationFlags,
  230.                            lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  231.                            lpProcessInformation)
  232.   else
  233.     // In this case the "real" API has already been performed but we need to
  234.     // return the results back to the real world.
  235.     fRC := WordBool (FuncHookGetInfo (FUNCHOOK_CMD_LASTRESULT, lCreateProcessA));
  236.   // Now, we will save some information from the CreateProcessA call.
  237.   LogInfoP := PLogInfo (SMMAlloc (ItemListObject.Heap, SizeOf (TLogInfo)));
  238.   if LogInfoP <> Nil then begin
  239.     with LogInfoP^ do begin
  240.       HookType := CREATINGPROCESS;
  241.       ProcessID := lpProcessInformation.dwProcessId;
  242.       if lpCommandLine <> Nil then begin
  243.         Application := SMMAlloc (ItemListObject.Heap, StrLen (lpCommandLine) + 1);
  244.         // Grab the command line parameter; this will be "beautified" later.
  245.         StrCopy (Application, lpCommandLine);
  246.       end;
  247.     end;
  248.     SLMAdd (ItemListObject.List, PByte (LogInfoP));
  249.   end;
  250.   // Notify TASKMON.EXE that its listbox needs refreshing.
  251.   SendMessage (MainWindow, WM_REFRESHMSG, 0, 0);
  252.   Result := fRC;
  253. end; {MyCreateProcessA}
  254.  
  255. procedure
  256.   MyExitProcess
  257.     (uExitCode: UINT);
  258. begin
  259.   // Some additional processing - an alert - if the user requests it.
  260.   if TheAlarmIsSet then
  261.     MessageBeep (MB_OK);
  262.   // First, we will save some information from the ExitProcess call.
  263.   LogInfoP := PLogInfo (SMMAlloc (ItemListObject.Heap, SizeOf (TLogInfo)));
  264.   if LogInfoP <> Nil then begin
  265.     with LogInfoP^ do begin
  266.       HookType := EXITINGPROCESS;
  267.       // In the CreateProcessA hook/callback we saved the ProcessId as part
  268.       // of the parameter list; here we must rely upon FH95 to give us that
  269.       // value.
  270.       ProcessID := FuncHookGetInfo (FUNCHOOK_CMD_PROCESSID, lExitProcess);
  271.       Application := SMMAlloc (ItemListObject.Heap, 20);
  272.       ProcProcessName (ProcessId, Application);
  273.     end;
  274.     SLMAdd (ItemListObject.List, PByte (LogInfoP));
  275.   end;
  276.   // Notify TASKMON.EXE that its listbox needs refreshing.
  277.   SendMessage (MainWindow, WM_REFRESHMSG, 0, 0);
  278.   // Remember some internal hook states from FH95.
  279.   StatusMask := FuncHookGetInfo (FUNCHOOK_CMD_STATUS, lExitProcess);
  280.   Skip := StatusMask and FUNCHOOK_STATUS_MASK;
  281.   if Skip <> FUNCHOOK_STATUS_SKIP then begin
  282.     Last := StatusMask and FUNCHOOK_STATUS_LAST;
  283.     if Last <> 0 then begin
  284.       // If we are the last hook, then we must perform the one and only one
  285.       // API call.
  286.       FuncHookUnlockDeletion (1);
  287.       ExitProcess (uExitCode);
  288.     end
  289.     else
  290.       FuncHookSetInfo (FUNCHOOK_CMD_STATUS, lExitProcess, FUNCHOOK_STATUS_NOTDONE);
  291.   end;
  292. end; {MyExitProcess}
  293.  
  294. initialization
  295.   TheAlarmIsSet := False;
  296.   ItemListObject.Heap := 0;
  297.   ItemListObject.List := Nil;
  298.   lCreateProcessA := 0;
  299.   lExitProcess := 0;
  300. end. {taskdll0}
  301.