$theTitle=wp_title(" - ", false); if($theTitle != "") { ?>
About Virtualization, VDI, SBC, Application Compatibility and anything else I feel like
As you know, many kernel32.dll functions, which are working with named objects, like OpenEvent, can be used to work with global and local objects. So what are global and local objects? Global objects are created in session 0 and are actually located in the \BaseNamedObjects directory, while local objects are created in the caller’s session (for example in the \Sessions\5\BaseNamedObjects directory (for session 0, global and local has no meaning since they point to the same object)). MSDN says that you can access only the objects in your own session(via the Local\ prefix) and in session 0 (via the Global\ prefix). But what if you need to access an object in another session? There is nothing in MSDN about it, only this page says “The “Local”, “Global”, and “Session” prefixes are reserved for system use and should not be used as names for kernel objects.” Let’s look at it via WinObj tool:
As you see, we’re now in session 3. \Sessions\3\BaseNamedObjects contains 3 links: Global, which points to \BaseNamedObjects, Local, which just points to itself (\Sessions\3\BaseNamedObjects), and Session, which points to \Sessions\BNOLINKS. Let’s look at the content of the BNOLINKS directory:
Aha, so it seems that this directory just contains the links to the other sessions’ BaseNamedObjects directories (I think, BNOLINKS stands for Base Named Objects Links)! So if you need to access an object in, for example, session 2, you can open it using the Session link: “Session\2\ObjectName“. At first, Session will be resolved to \Sessions\BNOLINKS\2\ObjectName, then \Sessions\BNOLINKS\2 will be resolved to \Sessions\2\BaseNamedObjects\ObjectName, which means, that we’re now accessing object ObjectName of session 2!
Let’s write a simple program, which will create and open objects in other sessions:
At first, we need to get the session list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | type TTSEnum = record SessionId : Cardinal; Name : packed array [0..33] of WideChar; State : DWORD; end; TTSEnumArray = packed array[0..65535] of TTSEnum; PTSEnumArray = ^TTSEnumArray; function WinStationEnumerateW( hServer: THandle; var ppBuffer : PTSEnumArray; var lpCount : DWORD ) : Boolean; stdcall; external 'winsta.dll'; function WinStationFreeMemory(P : Pointer) : Bool; stdcall; external 'winsta.dll'; procedure TForm1.FormCreate(Sender: TObject); var Sessions : PTSEnumArray; Count : DWORD; I : Integer; begin if WinStationEnumerateW(0, Sessions, Count) then try for I := 0 to Count - 1 do CreateCheckBox(I, Sessions^[I].SessionId); finally WinStationFreeMemory(Sessions) end else for I := 0 to 19 do CreateCheckBox(I, I); end; |
Then we can create objects in other sessions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | procedure TForm1.bCreateEventsClick(Sender: TObject); begin ForAllCheckBoxDo(OnCreateEvent); end; procedure TForm1.ForAllCheckBoxDo(Proc: TOnCheckBoxEvent); var I : Integer; begin for I := 0 to ScrollBox1.ControlCount - 1 do if ScrollBox1.Controls[i] is TCheckBox then Proc(ScrollBox1.Controls[i] as TCheckBox); end; procedure TForm1.OnCreateEvent(CheckBox: TCheckBox); begin with CheckBox do if Checked then if CreateEvent(nil, False, False, PChar(Format('Session\%d\MyAppEvent', [Tag]))) <> 0 then Caption := Format('Session %d event created', [Tag]) else Caption := Format('Session %d event creation failed, %s', [Tag, SysErrorMessage(GetLastError())]); end; |
And then we can try to open the objects in other sessions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | procedure TForm1.bOpenEventsClick(Sender: TObject); begin ForAllCheckBoxDo(OnOpenEvent); end; procedure TForm1.OnOpenEvent(CheckBox: TCheckBox); var EventHandle : THandle; begin with CheckBox do if Checked then begin EventHandle := OpenEvent(SYNCHRONIZE, False, PChar(Format('Session\%d\MyAppEvent', [Tag]))); if EventHandle <> 0 then begin CloseHandle(EventHandle); Caption := Format('Session %d event opened', [Tag]); end else Caption := Format('Session %d event open failed, %s', [Tag, SysErrorMessage(GetLastError())]); end; end; |
Session Objects (3221 downloads )
P.S. You can use this technique in any session for any object, which is created in the BaseNamedObjects directory: Event, Mutex, Semaphore, WaitableTimer, Job, FileMapping. Of course, security restrictions apply: you cannot create any object in another session if you do not have access to it. The LocalSystem account can create/access objects in any session, even idle sessions (which have not been initialized yet)
P.P.S. If terminal services are not running, the Session and \Sessions links are not created, so you cannot use them (but you can still use the Global and Local links, which are always created). Actually, there is no sense of using the Session\0\ prefix, since you can just use the Global\ prefix.
These are not the only places where you can create the kernel objects (Check part 2).
3 Responses for "Accessing kernel objects in other sessions part 1"
daNIL,
With this is it possible to rename a mounted easyprint printer to match a standard name (without redirect %session id%) ?
I have to hardcode printername in my application.
David,
Can you please tell me more about your problem? What are you trying to do?
[…] the post Accessing kernel objects in other sessions if you want to learn more about the Object […]
Leave a reply