mutex owner

delphi package - easy access to kernel objects etc.
Post Reply
digitaldoom
Posts: 10
Joined: Fri Aug 18, 2006 2:36 am

mutex owner

Post by digitaldoom »

Is it possible to find the process owner of a given mutex? If so, how? Thanks!
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Maybe it's possible with some internal native API. Or maybe by making use of the undocumented mutex structure (which may change between different OSs). But to be honest, I'm not sure...
digitaldoom
Posts: 10
Joined: Fri Aug 18, 2006 2:36 am

Post by digitaldoom »

I know it *can* be done as somehow ProcessExplorer lists the mutex of a given process. I just want to do the reverse of that. Having said that when I use madkernel to get at the information it always returns my process as the owner.

When I try to get the handle manually it always says ACCESS DENIED even though I have Admin access and Debug privs.

If I figure it out I'll let you know if you are interested :)
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Hmmmm... How do you define "owner"? ProcessExplorer lists the kernel handles which a specific process has opened (and not closed yet). madKernel does the same thing. However, this information does NOT tell you which process currently "owns" the mutex in that sense that it called WaitForSingleObject on the mutex and succeeded to get access. You know, multiple processes can share the same mutex. But only one of them can "own" it at the same time, although all of them can have a handle open to the same mutex at the same time...
digitaldoom
Posts: 10
Joined: Fri Aug 18, 2006 2:36 am

Post by digitaldoom »

Ideally I would like to list all processes that have a handle to the mutex but just the original .exe that created it would be fine.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Well, listing all processes that have a handle to the mutex is no big problem with madKernel. Just use "Handles(true)" which will return a list of all handles system wide. Be aware, though, that some OSs don't like it much if you try to look at handles of some of their system processes. So you may want to enumerate through processes instead and then enumerate through the handles of each process.
digitaldoom
Posts: 10
Joined: Fri Aug 18, 2006 2:36 am

Post by digitaldoom »

here is the code I am using to get the mutex list:

Code: Select all

procedure ttest.getmutexlist;
var dirhandle: thandle;
    oadir: jwawindows.pobject_attributes;
    status: ntstatus;
    wdir: unicode_string;
    mut: unicode_string;
    name: array[0..17] of widechar;
    mutant: array[0..6] of widechar;
    ctx: ULONG;
    p: PDIRECTORY_BASIC_INFORMATION;
    i: Integer;
    mtx: imutex;
begin
  mutex.Clear;
  if (getwindowsversion < jclsysinfo.wvWinNT31) then
    exit;
  ctx:=0;
  name[0]:='\'; name[1]:='B'; name[2]:='a'; name[3]:='s'; name[4]:='e'; name[5]:='N'; name[6]:='a'; name[7]:='m';
  name[8]:='e'; name[9]:='d'; name[10]:='O'; name[11]:='b'; name[12]:='j'; name[13]:='e'; name[14]:='c'; name[15]:='t';
  name[16]:='s'; name[17]:=#0;
  mutant[0]:='M'; mutant[1]:='u'; mutant[2]:='t'; mutant[3]:='a'; mutant[4]:='n'; mutant[5]:='t'; mutant[6]:=#0;

  jwanative.RtlCreateUnicodeString(@wdir, @name);
  jwanative.RtlCreateUnicodeString(@mut, @mutant);

  new(oadir);
  oadir^.Length:=sizeof(object_attributes);
  oadir^.RootDirectory:=0;
  oadir^.ObjectName:=@wdir;
  oadir^.Attributes:=OBJ_PERMANENT;
  oadir^.SecurityDescriptor:=nil;
  oadir^.SecurityQualityOfService:=nil;
  status:=ZwOpenDirectoryObject(@dirhandle, DIRECTORY_QUERY or DIRECTORY_TRAVERSE, oadir);
  p:=nil;

  try
    getmem(p, 1024);
    while (status = STATUS_SUCCESS) do
      begin
        status:=ZwQueryDirectoryObject(dirhandle, p, 300, true, false, @ctx, nil);
        if (status = STATUS_SUCCESS) then
          if (p^.ObjectTypeName.Buffer[0] = mut.Buffer[0]) then
            begin
              mtx:=madkernel.OpenMutex(p^.ObjectName.Buffer);
              mutex.Add(mtx.Handle.OwnerProcess.ExeFile+#32+p^.ObjectName.Buffer);
              mutexlistcb.Items.add(mtx.Handle.OwnerProcess.ExeFile+#32+p^.ObjectName.Buffer);
            end;
      end;
  finally
    ZwClose(dirhandle);
    dispose(oadir);
    freemem(p);
  end;
In there I have:

Code: Select all

mtx:=madkernel.OpenMutex(p^.ObjectName.Buffer);
              mutex.Add(mtx.Handle.OwnerProcess.ExeFile+#32+p^.ObjectName.Buffer);
              mutexlistcb.Items.add(mtx.Handle.OwnerProcess.ExeFile+#32+p^.ObjectName.Buffer);
the output is:

Code: Select all

Mutex
-----
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe ZonesCacheCounterMutex
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe SHIMLIB_LOG_MUTEX
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe ZonesLockedCacheCounterMutex
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe CTF.LBES.MutexDefaultS-1-5-21-1177238915-573735546-839522115-1003
 0CADFD67AF62496dB34264F000F5624A
 PSched_Perf_Library_Lock_PID_c4
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe WPA_RT_MUTEX
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe c:!documents and settings!daniel!cookies!
 aspnet_state_Perf_Library_Lock_PID_c4
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe WPA_PR_MUTEX
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe {45DB34C3-955C-11D3-ABEF-444553540000} Hook
 PnP_Init_Mutex
 ASP.NET_Perf_Library_Lock_PID_c4
 MSDTC_Perf_Library_Lock_PID_c4
 PerfDisk_Perf_Library_Lock_PID_c4
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe SRDataStore
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe madToolsMsgHandlerMutex$ddc$57009194
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe MidiMapper_modLongMessage_RefCnt
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe MidiMapper_Configure
 ASP.NET_1.1.4322_Perf_Library_Lock_PID_c4
 PerfProc_Perf_Library_Lock_PID_c4
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe MSCTF.Shared.MUTEX.MNN
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe MSCTF.Shared.MUTEX.APG
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe userenv: machine policy mutex
C:\Documents and Settings\daniel\My Documents\Borland Studio Projects\test5.5\test.exe userenv: user policy mutex
 ShimCacheMutex
I don't think my process "owns" all these mutex'
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Well, obviously you are opening all the mutexes listed in BaseNamedObjects. In the moment when you open them your process gets a handle to them. I still don't know if that is what you define as "own".
digitaldoom
Posts: 10
Joined: Fri Aug 18, 2006 2:36 am

Post by digitaldoom »

I want to map the mutex to the original creator of the mutex.
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Well, in that case I have to refer you to my first post in this thread.
Nico Bendlin
Posts: 46
Joined: Fri Apr 28, 2006 1:17 pm

Post by Nico Bendlin »

Maybe this code snippet contains what you want:

Code: Select all

{$ALIGN ON}
{$MINENUMSIZE 4}

type
  TNtStatus = LongInt;
  TClientId = record
    UniqueProcess: Pointer;
    UniqueThread : Pointer;
  end;
  TMutantInformationClass = (
    MutantBasicInformation,  // 0
    MutantOwnerInformation   // 1
  );
  TMutantBasicInformation = record
    CurrentCount  : LongInt;
    OwnedByCaller : Boolean;
    AbandonedState: Boolean;
  end;
  TMutantOwnerInformation = record
    ClientId: TClientId;
  end;

function NtQueryMutant(MutantHandle: THandle;
  MutantInformationClass: TMutantInformationClass; out MutantInformation;
  MutantInformationLength: ULONG; ReturnLength: PULONG): TNtStatus; stdcall;
  external 'ntdll';

var
  Mutex: THandle;
  Basic: TMutantBasicInformation;
  Owner: TMutantOwnerInformation;
  Bytes: ULONG;
begin
  Mutex := OpenMutex(MUTANT_QUERY_STATE, False, 'MutantTest');
  if Mutex <> 0 then
  try
    FillChar(Basic, SizeOf(Basic), 0);
    Bytes := 0;
    ShowMessage('MutantBasicInformation: $' + IntToHex(NtQueryMutant(Mutex,
      MutantBasicInformation, Basic, SizeOf(Basic), @Bytes), 8) +
      #13#10'Basic.CurrentCount: ' + IntToStr(Basic.CurrentCount) +
      #13#10'Basic.OwnedByCaller: ' + BoolToStr(Basic.OwnedByCaller, True) +
      #13#10'Basic.AbandonedState: ' + BoolToStr(Basic.AbandonedState, True) +
      #13#10'Bytes: ' + IntToStr(Bytes));
    FillChar(Owner, SizeOf(Owner), 0);
    Bytes := 0;
    ShowMessage('MutantOwnerInformation: $' + IntToHex(NtQueryMutant(Mutex,
      MutantOwnerInformation, Owner, SizeOf(Owner), @Bytes), 8) +
      #13#10'Owner.ClientId.UniqueProcess: $' +
      IntToHex(NativeUInt(Owner.ClientId.UniqueProcess), SizeOf(Pointer) * 2) +
      #13#10'Owner.ClientId.UniqueThread: $' +
      IntToHex(NativeUInt(Owner.ClientId.UniqueThread), SizeOf(Pointer) * 2) +
      #13#10'Bytes: ' + IntToStr(Bytes));
  finally
    CloseHandle(Mutex);
  end;
end.
Well, I don’t know the Windows version that introduced MutantOwnerInformation.

Note that the "owner" of the Mutex is the thread that called CreateMutex(..., True, ...) or a wait function and not (yet) called ReleaseMutex(...) to release the ownership. Read the Remarks section of ReleaseMutex in MSDN.
Post Reply