Page 1 of 1

mutex owner

PostPosted: Mon Oct 06, 2008 1:35 pm
by digitaldoom
Is it possible to find the process owner of a given mutex? If so, how? Thanks!

PostPosted: Wed Oct 08, 2008 8:58 pm
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...

PostPosted: Wed Oct 08, 2008 10:56 pm
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 :)

PostPosted: Thu Oct 09, 2008 6:44 am
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...

PostPosted: Thu Oct 09, 2008 2:27 pm
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.

PostPosted: Thu Oct 09, 2008 4:09 pm
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.

PostPosted: Fri Oct 10, 2008 1:01 am
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'

PostPosted: Fri Oct 10, 2008 8:14 am
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".

PostPosted: Fri Oct 10, 2008 12:30 pm
by digitaldoom
I want to map the mutex to the original creator of the mutex.

PostPosted: Fri Oct 10, 2008 1:36 pm
by madshi
Well, in that case I have to refer you to my first post in this thread.

PostPosted: Mon Nov 17, 2008 5:18 pm
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.