Page 1 of 2

How to get the OWNERs name of a process? [Solved]

Posted: Thu Feb 21, 2008 6:17 am
by BigJack
Hi folks,:D
in an attempt to develop a program similar to Windows task-manager, I encountered a problem:
How can I get the owners name (user name) of a running process?
I couldn't find anything helpful in the forum, probably because it is a very specific question. Even google didn't help, except for code examples written in C++ or VB.
Thus far I know how to list all running processes and get their exe-names (thanks to POBSL Process...)

Using PB 4.2 / WindowsXP Pro

Posted: Sat Apr 05, 2008 6:18 pm
by BigJack
I thought it was time to refresh this topic...
Any solutions?

Posted: Sat Apr 05, 2008 7:59 pm
by SFSxOI
might give some clues:

http://www.purebasic.fr/english/viewtop ... cess+owner

http://www.purebasic.fr/english/viewtop ... r&start=15

But...i've seen some API code somewhere that does this, just have to find it.

Posted: Sat Apr 05, 2008 8:20 pm
by Fluid Byte
Everything I found on the web uses Windows Management Instrumentation (WMI) to obtain the user names. I haven't found any code doing it natively with API.

Posted: Sat Apr 05, 2008 8:20 pm
by KarLKoX

Code: Select all

; code      : KarLKoX
; date      : 04/05/2008
; changelog : 1.0 - Initial Release
;
; Note      : activate unicode support

#ANYSIZE_ARRAY              = 1
#OWNER_SECURITY_INFORMATION = $00000001

Enumeration ; SID_NAME_USE
  #SidTypeUser = 1
  #SidTypeGroup
  #SidTypeDomain
  #SidTypeAlias
  #SidTypeWellKnownGroup
  #SidTypeDeletedAccount
  #SidTypeInvalid
  #SidTypeUnknown
  #SidTypeComputer
  #SidTypeLabel
EndEnumeration

Enumeration ; SE_OBJECT_TYPE
  #SE_UNKNOWN_OBJECT_TYPE
  #SE_FILE_OBJECT
  #SE_SERVICE
  #SE_PRINTER
  #SE_REGISTRY_KEY
  #SE_LMSHARE
  #SE_KERNEL_OBJECT
  #SE_WINDOW_OBJECT
  #SE_DS_OBJECT
  #SE_DS_OBJECT_ALL
  #SE_PROVIDER_DEFINED_OBJECT
EndEnumeration

Structure SID
  Revision.b
  SubAuthorityCount.b
  *IdentifierAuthority.SID_IDENTIFIER_AUTHORITY
  SubAuthority.l[#ANYSIZE_ARRAY]
EndStructure

Prototype.l PFNCreateToolhelp32Snapshot(dwFlags.l, th32ProcessID.l)
Prototype.b PFNProcess32First(hSnapshot.l, *lppe.PROCESSENTRY32)
Prototype.b PFNProcess32Next(hSnapshot.l, *lppe.PROCESSENTRY32)
Prototype.b PFNThread32First(hSnapshot.l, *lppe.THREADENTRY32)
Prototype.b PFNThread32Next(hSnapshot.l, *lppe.THREADENTRY32)

Procedure DBG(out.s)
CompilerIf #PB_Compiler_Debugger
  Debug out
CompilerEndIf
EndProcedure

Procedure.l GetPidByName(name.s)
Protected hDLL.l, process_name.s
Protected PEntry.PROCESSENTRY32, hTool32.l
Protected pCreateToolhelp32Snapshot.PFNCreateToolhelp32Snapshot
Protected pProcess32First.PFNProcess32First
Protected pProcess32Next.PFNProcess32Next

  hDLL = OpenLibrary(#PB_Any,"kernel32.dll")
  If hDLL
    ; get function pointer
    pCreateToolhelp32Snapshot = GetFunction(hDLL,"CreateToolhelp32Snapshot")
    pProcess32First = GetFunction(hDLL,"Process32FirstW")
    pProcess32Next = GetFunction(hDLL,"Process32NextW")
  Else
    DBG("GetPidByName:: OpenLibrary failed !")
    ProcedureReturn 0
  EndIf
   
  PEntry\dwSize = SizeOf(PROCESSENTRY32)
  hTool32 = pCreateToolhelp32Snapshot(#TH32CS_SNAPPROCESS, 0)
  pProcess32First(hTool32, @PEntry)
  process_name = Space(#MAX_PATH)
  CopyMemory(@PEntry\szExeFile,@process_name,StringByteLength(process_name))
  If process_name = name 
    ProcedureReturn PEntry\th32ProcessID
  EndIf
  While pProcess32Next(hTool32, @PEntry) > 0
    process_name = Space(#MAX_PATH)
    CopyMemory(@PEntry\szExeFile,@process_name,StringByteLength(process_name))
    If process_name = name
      ProcedureReturn PEntry\th32ProcessID
    EndIf
  Wend
    
  CloseLibrary(hDLL)
  CloseHandle_(pCreateToolhelp32Snapshot)
  
  ProcedureReturn 0
EndProcedure

Macro MAKELANGID(p, s)
  (s << 10 | p)
EndMacro 

; format the errcode to the corresponding message error string
Procedure.s GetLastErrorString(lErrCode.l)
Protected lpMsgBuf.l
Protected out.s = ""
  
  If lErrCode
    FormatMessage_(#FORMAT_MESSAGE_ALLOCATE_BUFFER | #FORMAT_MESSAGE_FROM_SYSTEM, #Null, lErrCode, MAKELANGID(#LANG_NEUTRAL, #SUBLANG_DEFAULT), @lpMsgBuf, 0, #Null)
    out = PeekS(lpMsgBuf)
    LocalFree_(lpMsgBuf)
  EndIf
 
  ProcedureReturn out
EndProcedure 

Procedure.s getOwnerObject(pid.l)
Protected owner.s
Protected *pSidOwner.SID, *pSD.SECURITY_DESCRIPTOR
Protected dwRtnCode.l, bRtnBool.l
Protected AcctName.s, DomainName.s
Protected dwAcctName.l, dwDomainName.l
Protected eUse.l = #SidTypeUnknown

  If pid = #INVALID_HANDLE_VALUE
    DBG("Invalid pid !")
    ProcedureReturn ""
  EndIf
  
  object = OpenProcess_(#READ_CONTROL, #False, pid)
  If object = #INVALID_HANDLE_VALUE
    DBG("Invalid object handle !")
    ProcedureReturn ""
  EndIf
  
  If OpenProcessToken_(GetCurrentProcess_(), #TOKEN_QUERY | #TOKEN_ADJUST_PRIVILEGES, @htok) <= 0
    DBG("OpenProcessToken failed")
    ProcedureReturn ""
  EndIf
  
  ; allocate memory for the SID structure
  *pSidOwner = AllocateMemory(SizeOf(SID))
  If *pSidOwner = 0
    DBG("Can't allocate memory for the SID structure")
    ProcedureReturn ""
  EndIf
  
  ; allocate memory for the security descriptor structure
  *pSD = AllocateMemory(SizeOf(SECURITY_DESCRIPTOR))
  If *pSD = 0
    DBG("Can't allocate memory for the SECURITY_DESCRIPTOR structure")
    ProcedureReturn ""
  EndIf
  
  ; get the owner SID of the object
  dwRtnCode = GetSecurityInfo_(object, #SE_KERNEL_OBJECT, #OWNER_SECURITY_INFORMATION, @*pSidOWner, #Null, #Null, #Null, @*pSD)
  
  ; check GetLastError for GetSecurityInfo error condition
  If dwRtnCode <> #ERROR_SUCCESS
    DBG("GetSecurityInfo error = " + GetLastErrorString(dwRtnCode) )
    ProcedureReturn ""
  EndIf  
  
  ; first call to LookupAccoundSid to get the buffer sizes
  bRtnBool = LookupAccountSid_(#Null, *pSidOwner, AcctName, @dwAcctName, DomainName, @dwDomainName, @eUse)
  
  ; reallocate memory for the buffers
  AcctName = Space(dwAcctName)
  DomainName = Space(dwDomainName)
  
  ; second call to LookupAccountSid to get the account name
  bRtnBool = LookupAccountSid_(#Null, *pSidOwner, AcctName, @dwAcctName, DomainName, @dwDomainName, @eUse)
  
  ; close the process handle
  CloseHandle_(object)
  
  ProcedureReturn AcctName
EndProcedure

Procedure Test()
Protected pid1.l, pid2.l
Protected owner1.s, owner2.s

  ; should be different
  pid1 = GetPidByName("explorer.exe")
  pid2 = GetPidByName("lsass.exe")  
  owner1 = getOwnerObject(pid1)
  owner2 = getOwnerObject(pid2)
  
  MessageRequester("Result", "The Owner of explorer.exe is " + owner1 + " and the owner of lsass.exe is " + owner2 )
EndProcedure

Test()
Hope it helps.

Posted: Sat Apr 05, 2008 8:26 pm
by SFSxOI
Yeah, what karlkox posted, thats the api stuff I was thinking of.

Posted: Sat Apr 05, 2008 8:29 pm
by Fluid Byte
Does it work for you? Although I haven't tested other executables yet I get "Invalid handle" error on both demo .EXE's.

Posted: Sat Apr 05, 2008 9:14 pm
by ABBKlaus
; Note : activate unicode support
i assume this means you have to switch unicode mode on :wink:

Posted: Sat Apr 05, 2008 10:09 pm
by Fluid Byte
Indeed! Image

One more thing ...

For "lsass.exe" it says "Administratoren" and the taskmanager says "SYSTEM". That is the same, isn't it?

Posted: Sat Apr 05, 2008 10:24 pm
by SFSxOI
I've noticed that too, Administrator and System are not the same it turns out. One is an account the other is root level system. Its possible they can both be at the same permission level, but they would still be different and be called Administrator and System. So for "lsass.exe" it might say Administrator because it ran when the administrator logged in with those permissions because the admin long in actually triggered it to run so the admin would be the owner in terms of it running instead of the system running it whereas its a system level access for the process task which would mean that it shows system in task manager. At least from what I can tell.

that make sense? I'm probably wrong or said it wrong, done it before so this would not be the last time :)

Posted: Sat Apr 05, 2008 11:38 pm
by BigJack
Very impressive code you posted - thanks!
But unfortunately it doesn't return any value here.
System: Windows XP Pro SP2
PureBasic 4.2 Beta

Posted: Sun Apr 06, 2008 12:00 am
by SFSxOI
without unicode enabled returns the names of the two processes but never gives the owner and gives two errors in the debug

GetSecurityInfo error = The handle is invalid.
GetSecurityInfo error = The handle is invalid.

This is on Vista so it might not like the SECURITY_DESCRIPTOR in some way. With unicode enabled it gives the owner of explorer.exe correctly (owner 1) but never shows the owner for lsass.exe and still gives one error in the debug GetSecurityInfo error = The handle is invalid.

Posted: Mon Apr 07, 2008 10:27 am
by jpd
Hi,

here a modified code that running in Ansi/Unicode and

solve the Problem described by SFSyOI on Vista.


Code: Select all


; code      : KarLKoX 
; date      : 04/05/2008 
; changelog : 1.0 - Initial Release 
; 
; Note      : activate unicode support 



#ANYSIZE_ARRAY              = 1 
#OWNER_SECURITY_INFORMATION = $00000001 

Enumeration ; SID_NAME_USE 
  #SidTypeUser = 1 
  #SidTypeGroup 
  #SidTypeDomain 
  #SidTypeAlias 
  #SidTypeWellKnownGroup 
  #SidTypeDeletedAccount 
  #SidTypeInvalid 
  #SidTypeUnknown 
  #SidTypeComputer 
  #SidTypeLabel 
EndEnumeration 

Enumeration ; SE_OBJECT_TYPE 
  #SE_UNKNOWN_OBJECT_TYPE 
  #SE_FILE_OBJECT 
  #SE_SERVICE 
  #SE_PRINTER 
  #SE_REGISTRY_KEY 
  #SE_LMSHARE 
  #SE_KERNEL_OBJECT 
  #SE_WINDOW_OBJECT 
  #SE_DS_OBJECT 
  #SE_DS_OBJECT_ALL 
  #SE_PROVIDER_DEFINED_OBJECT 
EndEnumeration 

Structure SID 
  Revision.b 
  SubAuthorityCount.b 
  *IdentifierAuthority.SID_IDENTIFIER_AUTHORITY 
  SubAuthority.l[#ANYSIZE_ARRAY] 
EndStructure 

; ------------------------ Get PID 

#TH32CS_SNAPPROCESS = $2 


Procedure DBG(out.s) 
CompilerIf #PB_Compiler_Debugger 
  Debug out 
CompilerEndIf 
EndProcedure 


Macro MAKELANGID(p, s) 
  (s << 10 | p) 
EndMacro 

; format the errcode to the corresponding message error string 
Procedure.s GetLastErrorString(lErrCode.l) 
Protected lpMsgBuf.l 
Protected out.s = "" 
  
  If lErrCode 
    FormatMessage_(#FORMAT_MESSAGE_ALLOCATE_BUFFER | #FORMAT_MESSAGE_FROM_SYSTEM, #Null, lErrCode, MAKELANGID(#LANG_NEUTRAL, #SUBLANG_DEFAULT), @lpMsgBuf, 0, #Null) 
    out = PeekS(lpMsgBuf) 
    LocalFree_(lpMsgBuf) 
  EndIf 
  
  ProcedureReturn out 
EndProcedure 

Procedure SearchPID(Name.s) 
;-http://www.purebasic.fr/german/viewtopic.php?t=10576&postdays=0&postorder=asc&highlight=processentry33&start=10
  Protected result.l, Snapshot.l, ProcessFound.l, PN$, Process.PROCESSENTRY32 
  Process\dwSize = SizeOf(PROCESSENTRY32) 
  Snapshot = CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS, 0) 
  If Snapshot 
    ProcessFound = Process32First_(Snapshot, Process) 
    While ProcessFound 
      PN$ = UCase(PeekS(@Process\szExeFile, #PB_Any, #PB_Ascii)) 
      If UCase(Name) = GetFilePart(PN$)  
        ProcedureReturn Process\th32ProcessID 
      EndIf 
      ProcessFound = Process32Next_(Snapshot, Process) 
    Wend 
    CloseHandle_(Snapshot) 
  EndIf 
  ProcedureReturn 0
EndProcedure 

Procedure.s getOwnerObject(pid.l) 
Protected owner.s 
Protected *pSidOwner.SID, *pSD.SECURITY_DESCRIPTOR 
Protected dwRtnCode.l, bRtnBool.l 
Protected AcctName.s, DomainName.s 
Protected dwAcctName.l, dwDomainName.l 
Protected eUse.l = #SidTypeUnknown 

  If pid = #INVALID_HANDLE_VALUE 
    DBG("Invalid pid !") 
    ProcedureReturn "" 
  EndIf 
  
  object = OpenProcess_(#READ_CONTROL, #False, pid) 
  If object = #INVALID_HANDLE_VALUE 
    DBG("Invalid object handle !") 
    ProcedureReturn "" 
  EndIf 
  
  If OpenProcessToken_(GetCurrentProcess_(), #TOKEN_QUERY | #TOKEN_ADJUST_PRIVILEGES, @htok) <= 0 
    DBG("OpenProcessToken failed") 
    ProcedureReturn "" 
  EndIf 
  
  ; allocate memory for the SID structure 
  *pSidOwner = AllocateMemory(SizeOf(SID)) 
  If *pSidOwner = 0 
    DBG("Can't allocate memory for the SID structure") 
    ProcedureReturn "" 
  EndIf 
  
  ; allocate memory for the security descriptor structure 
  *pSD = AllocateMemory(SizeOf(SECURITY_DESCRIPTOR)) 
  If *pSD = 0 
    DBG("Can't allocate memory for the SECURITY_DESCRIPTOR structure") 
    ProcedureReturn "" 
  EndIf 
  
  ; get the owner SID of the object 
  dwRtnCode = GetSecurityInfo_(object, #SE_KERNEL_OBJECT, #OWNER_SECURITY_INFORMATION, @*pSidOWner, #Null, #Null, #Null, @*pSD) 
   ; dwRtnCode = GetSecurityInfo_(object, #SE_KERNEL_OBJECT, #OWNER_SECURITY_INFORMATION, @*pSidOWner, #Null, #Null, #Null, @pSD) 
  ; check GetLastError for GetSecurityInfo error condition 
  If dwRtnCode <> #ERROR_SUCCESS 
    DBG("GetSecurityInfo error = " + GetLastErrorString(dwRtnCode) ) 
    ProcedureReturn "" 
  EndIf  
  
  ; first call to LookupAccoundSid to get the buffer sizes 
  bRtnBool = LookupAccountSid_(#Null, *pSidOwner, AcctName, @dwAcctName, DomainName, @dwDomainName, @eUse) 
  
  ; reallocate memory for the buffers 
  AcctName = Space(dwAcctName) 
  DomainName = Space(dwDomainName) 
  
  ; second call to LookupAccountSid to get the account name 
  bRtnBool = LookupAccountSid_(#Null, *pSidOwner, AcctName, @dwAcctName, DomainName, @dwDomainName, @eUse) 
  
  ; close the process handle 
  CloseHandle_(object) 
  
  ProcedureReturn AcctName 
EndProcedure 






Procedure Test() 
Protected pid1.l, pid2.l 
Protected owner1.s, owner2.s 

pid1=SearchPID("explorer.exe")
pid2=SearchPID("lsass.exe")

 
  Debug pid1
  Debug pid2
  owner1 = getOwnerObject(pid1) 
  owner2 = getOwnerObject(pid2) 
  
  MessageRequester("Result", "The Owner of explorer.exe is " + owner1 + " and the owner of lsass.exe is " + owner2 ) 
EndProcedure 

#SE_DEBUG_NAME="SeDebugPrivilege" ; missing constant 

Procedure EnableDebugPrivNT() 
;-http://www.purebasic.fr/english/viewtopic.php?t=31161&highlight=enabledebugprivnt

   DebugValue.LUID; 
   tkp.TOKEN_PRIVILEGES 
    
   ; Retrieve a handle of the access token 
   If Not OpenProcessToken_(GetCurrentProcess_(),#TOKEN_ADJUST_PRIVILEGES|#TOKEN_QUERY,@hToken) 
      ProcedureReturn #False; 
   EndIf 
    
   ; Enable the SE_DEBUG_NAME privilege 
   If Not LookupPrivilegeValue_("",#SE_DEBUG_NAME,@DebugValue) 
      ProcedureReturn #False; 
   EndIf 
    
   NewState.TOKEN_PRIVILEGES 
   NewState\PrivilegeCount=1 
   NewState\Privileges[0]\Luid\HighPart=DebugValue\HighPart 
   NewState\Privileges[0]\Luid\LowPart=DebugValue\LowPart 
   NewState\Privileges[0]\Attributes=#SE_PRIVILEGE_ENABLED 
   AdjustTokenPrivileges_(hToken,#False,@NewState,SizeOf(TOKEN_PRIVILEGES),@PreviousState.TOKEN_PRIVILEGES,@ReturnLength) 
    
   If GetLastError_()<>#ERROR_SUCCESS 
      ProcedureReturn #False 
   EndIf 

   ProcedureReturn #True 
EndProcedure



If EnableDebugPrivNT() 

  Debug "privilege loaded..."
  Test() 
 Else
  Debug "privilege not setted...."
 EndIf
 


Posted: Wed Apr 09, 2008 6:19 am
by BigJack
WOW....
absolutely great - and it now return the required values. :D
Thanks for sharing this piece of code...

Re: How to get the OWNERs name of a process? [Solved]

Posted: Fri Sep 20, 2013 11:23 am
by IdeasVacuum
[PB5.20LTS WinXP x86]

jpd's version reports GetSecurityInfo error = The handle is invalid. with Compiler set to Unicode, but delivers the correct names when set to ASCII. The original KarLKoX code works with Unicode only.