home *** CD-ROM | disk | FTP | other *** search
/ Chip 1999 March / Chip_1999-03_cd.bin / zkuste / delphi / INFO / DI9811YA.ZIP / DelRun.pas next >
Pascal/Delphi Source File  |  1998-04-30  |  9KB  |  309 lines

  1. (******************************************************************************)
  2. (* Unit Name:   DelRun                                                        *)
  3. (* Description: Detect whether the current process is running under the       *)
  4. (*              control of Delphi under Windows 95 and NT.                    *)
  5. (* Author:      Yorai Aminov                                                  *)
  6. (* Created:     30 April 1998                                                 *)
  7. (*                                                                            *)
  8. (* Copyright (c) 1998 Yorai Aminov                                            *)
  9. (******************************************************************************)
  10. unit DelRun;
  11.  
  12. interface
  13.  
  14. uses
  15.   Windows, Classes, SysUtils;
  16.  
  17. function RunningUnderDelphi: Boolean;
  18.  
  19. implementation
  20.  
  21. { NtQueryInformation constants }
  22.  
  23. const
  24.   ProcessBasicInformation = 0;
  25.  
  26. { NtQueryInformation types }
  27.  
  28. type
  29.   TProcessBasicInformation = packed record
  30.     ExitStatus: Integer;
  31.     PebBaseAddress: Pointer;
  32.     AffinityMask: Integer;
  33.     BasePriority: Integer;
  34.     UniqueProcessID: Integer;
  35.     InheritedFromUniqueProcessID: Integer;
  36.   end;
  37.  
  38.   TNtQueryInformationProcess =
  39.     function(hProcess: THandle; ProcessInformationClass: Integer;
  40.       var ProcessInformation; ProcessInformationLength: Integer;
  41.       var ReturnLength: Integer): Integer; stdcall;
  42.  
  43. { NT IsDebuggerPresent prototype }
  44.  
  45. type
  46.   TIsDebuggerPresent = function: BOOL; stdcall;
  47.  
  48. { Retrieve parent process ID from NtQueryInformation }
  49.  
  50. function GetParentProcessIDForNT: Integer;
  51. var
  52.   hNTDLL: Integer;
  53.   NtQueryInformationProcess: TNtQueryInformationProcess;
  54.   PBI: TProcessBasicInformation;
  55.   ReturnLength: Integer;
  56. begin
  57.   Result := 0;
  58.   // Attempt to load NTDLL
  59.   hNTDLL := LoadLibrary('NTDLL.DLL');
  60.   if hNTDLL <> 0 then
  61.   begin
  62.     // Retrieve address of NtQueryInformationProcess
  63.     NtQueryInformationProcess := GetProcAddress(hNTDLL, 'NtQueryInformationProcess');
  64.     if Assigned(NTQueryInformationProcess) then
  65.     begin
  66.       // Call NtQueryInformationProcess
  67.       NtQueryInformationProcess(GetCurrentProcess, ProcessBasicInformation,
  68.         PBI, SizeOf(PBI), ReturnLength);
  69.       // Return parent process ID
  70.       Result := PBI.InheritedFromUniqueProcessID;
  71.     end;
  72.     // Release NTDLL
  73.     FreeLibrary(hNTDLL);
  74.   end;
  75. end;
  76.  
  77. { Check for debugger under NT }
  78.  
  79. function IsDebuggerPresentForNT: Boolean;
  80. var
  81.   Kernel32: THandle;
  82.   FIsDebuggerPresent: TIsDebuggerPresent;
  83. begin
  84.   Result := False;
  85.   // Attempt to load KERNEL32
  86.   Kernel32 := LoadLibrary('KERNEL32.DLL');
  87.   if Kernel32 <> 0 then
  88.   begin
  89.     // Retrieve address of IsDebuggerPresent
  90.     FIsDebuggerPresent := GetProcAddress(Kernel32, 'IsDebuggerPresent');
  91.     // Return True if a debugger is present
  92.     if Assigned(FIsDebuggerPresent) then
  93.       Result := FIsDebuggerPresent;
  94.     // Release KERNEL32
  95.     FreeLibrary(Kernel32);
  96.   end;
  97. end;
  98.  
  99. { ToolHelp32 constants }
  100.  
  101. const
  102.   TH32CS_SNAPPROCESS  = $00000002;
  103.  
  104. { ToolHelp32 types }
  105.  
  106. type
  107.   PProcessEntry32 = ^TProcessEntry32;
  108.   TProcessEntry32 = record
  109.     dwSize: DWORD;
  110.     cntUsage: DWORD;
  111.     th32ProcessID: DWORD;
  112.     th32DefaultHeapID: DWORD;
  113.     th32ModuleID: DWORD;
  114.     cntThreads: DWORD;
  115.     th32ParentProcessID: DWORD;
  116.     pcPriClassBase: Longint;
  117.     dwFlags: DWORD;
  118.     szExeFile: array[0..MAX_PATH - 1] of Char;// Path
  119.   end;
  120.  
  121. { ToolHelp32 function prototypes }
  122.  
  123. type
  124.   TCreateToolhelp32Snapshot =
  125.     function(dwFlags, th32ProcessID: DWORD): THandle; stdcall;
  126.   TProcess32First =
  127.     function(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; stdcall;
  128.   TProcess32Next =
  129.     function(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; stdcall;
  130.  
  131.  
  132. function GetParentProcessIDForWindows: Integer;
  133. var
  134.   Kernel32: THandle;
  135.   CreateToolhelp32Snapshot: TCreateToolhelp32Snapshot;
  136.   Process32First: TProcess32First;
  137.   Process32Next: TProcess32Next;
  138.   Snapshot: THandle;
  139.   Entry: TProcessEntry32;
  140.   WalkResult: Boolean;
  141.   ID: Integer;
  142. begin
  143.   Result := 0;
  144.   // Attempt to load KERNEL32
  145.   Kernel32 := LoadLibrary('KERNEL32.DLL');
  146.   if Kernel32 <> 0 then
  147.   begin
  148.     // Retrieve ToolHelp32 function addresses
  149.     CreateToolhelp32Snapshot :=
  150.       GetProcAddress(Kernel32, 'CreateToolhelp32Snapshot');
  151.     Process32First := GetProcAddress(Kernel32, 'Process32First');
  152.     Process32Next := GetProcAddress(Kernel32, 'Process32Next');
  153.     if Assigned(CreateToolhelp32Snapshot) and
  154.        Assigned(Process32First) and
  155.        Assigned(Process32Next) then
  156.     begin
  157.       // Retrieve current process ID for comparison
  158.       ID := GetCurrentProcessId;
  159.       // Create processes snapshot
  160.       Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  161.       if Snapshot <> -1 then
  162.       begin
  163.         // Start walking list of processes
  164.         Entry.dwSize := SizeOf(TProcessEntry32);
  165.         WalkResult := Process32First(Snapshot, Entry);
  166.         // Walk through entire list until result can be determined
  167.         while (GetLastError <> ERROR_NO_MORE_FILES) and (Result = 0) do
  168.         begin
  169.           if WalkResult then
  170.           begin
  171.             // If this is the current process, return its parent
  172.             if Entry.th32ProcessID = ID then
  173.               Result := Entry.th32ParentProcessID;
  174.           end;
  175.           // Move to next item in the process list
  176.           Entry.dwSize := SizeOf(TProcessEntry32);
  177.           WalkResult := Process32Next(Snapshot, Entry);
  178.         end;
  179.         // Release handle to the snapshot
  180.         CloseHandle(Snapshot);
  181.       end;
  182.     end;
  183.     // Release KERNEL32
  184.     FreeLibrary(Kernel32);
  185.   end;
  186. end;
  187.  
  188. { Process database constants }
  189.  
  190. const
  191.   fDebugSingle        = $00000001;
  192.  
  193. { Process database types }
  194.  
  195. type
  196.   PProcessDatabase = ^TProcessDatabase;
  197.   TProcessDatabase = packed record
  198.     DontCare1: array[0..7] of Integer;
  199.     Flags: Integer;
  200.     DontCare2: array[0..11] of Integer;
  201.     DebugeeCB: Integer;
  202.     DontCare3: array[0..22] of Integer;
  203.     DontCare4: Word;
  204.   end;
  205.  
  206. function IsDebuggerPresentForWindows: Boolean;
  207. var
  208.   PDB: PProcessDatabase;
  209.   TID: Integer;
  210.   Obsfucator: Integer;
  211. begin
  212.   Result := False;
  213.   Obsfucator := 0;
  214.   TID := GetCurrentThreadID;
  215.   // Calculate Obsfucator
  216.   asm
  217.     MOV     EAX, FS:[18h]
  218.     SUB     EAX, 10h
  219.     XOR     EAX, [TID]
  220.     MOV     [Obsfucator], EAX
  221.     // Obsfucator := (@TIB - $10) xor GetCurrentThreadID
  222.   end;
  223.   if Obsfucator <> 0 then
  224.   begin
  225.     // Retriece pointer to the PDB
  226.     PDB := Pointer(GetCurrentProcessID xor Obsfucator);
  227.     // Return True if process is being debugged
  228.     Result := (PDB^.Flags and fDebugSingle) <> 0;
  229.   end;
  230. end;
  231.  
  232. function GetParentProcessID: Integer;
  233. var
  234.   OSVersionInfo: TOSVersionInfo;
  235. begin
  236.   // Get version information
  237.   OSVersionInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  238.   GetVersionEx(OSVersionInfo);
  239.   // If Windows 95 or NT 5.0+, use ToolHelp32
  240.   if (OSVersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT) and
  241.      (OSVersionInfo.dwMajorVersion < 5) then
  242.     Result := GetParentProcessIDForNT else
  243.     Result := GetParentProcessIDForWindows;
  244. end;
  245.  
  246. function IsDebuggerPresent: Boolean;
  247. var
  248.   OSVersionInfo: TOSVersionInfo;
  249. begin
  250.   // Get version information
  251.   OSVersionInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  252.   GetVersionEx(OSVersionInfo);
  253.   // If Windows 95, use PDB. Otherwise, use NT's IsDebuggerPresent
  254.   if OSVersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then
  255.     Result := IsDebuggerPresentForNT else
  256.     Result := IsDebuggerPresentForWindows;
  257. end;
  258.  
  259. procedure EnumWindowsProc(Window: THandle; LParam: Integer); stdcall;
  260. var
  261.   ClassName: string;
  262. begin
  263.   // Allocate space for class name
  264.   SetLength(ClassName, 255);
  265.   // Retrieve window's class name
  266.   GetClassName(Window, PChar(ClassName), 255);
  267.   // Reallocate string length
  268.   SetLength(ClassName, StrLen(PChar(ClassName)));
  269.   // If window belongs to an instance of Delphi, add to list
  270.   if ClassName = 'TAppBuilder' then
  271.     TList(LParam).Add(Pointer(Window));
  272. end;
  273.  
  274. function RunningUnderDelphi: Boolean;
  275. var
  276.   List: TList;
  277.   i: Integer;
  278.   ID, ParentID: Integer;
  279. begin
  280.   Result := False;
  281.   // Retrieve ID for the parent process
  282.   ParentID := GetParentProcessID;
  283.   // If ID found and being debugged, check for Delphi
  284.   if (ParentID <> 0) and (IsDebuggerPresent) then
  285.   begin
  286.     // Create a list of window handles
  287.     List := TList.Create;
  288.     // Fill list with window handles for instances of Delphi
  289.     EnumWindows(@EnumWindowsProc, Integer(List));
  290.     // Check Delphi instances
  291.     for i := 0 to List.Count - 1 do
  292.     begin
  293.       // Get process ID for the Delphi window
  294.       GetWindowThreadProcessID(Integer(List[i]), @ID);
  295.       // Compare IDs
  296.       if ID = ParentID then
  297.       begin
  298.         // The process parent ID is Delphi's process ID
  299.         Result := True;
  300.         Break;
  301.       end;
  302.     end;
  303.     // Free list
  304.     List.Free;
  305.   end;
  306. end;
  307.  
  308. end.
  309.