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
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

Posted: Sat Apr 05, 2008 10:09 pm
by Fluid Byte
Indeed!
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.
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.