Change your views: OS X tags exploited

Apple windows insider

Reducing the cost and complexity of web vulnerability management

Mac Secrets Time to conclude our exploration of Apple's mysterious CoreGraphics framework. This time I'll show you how to change the behavior of windows by setting so-called window tags, and I'll exploit window properties to show how to snoop on the windows of another process.

Window tags represent another interesting little corner of the CoreGraphics subsystem. You can think of tags as essentially bit-flags that are associated with each window, but the way in which those bits are set and cleared is somewhat quirky, to say the least.

To set tags, you'd use this routine:

extern CGError CGSSetWindowTags (const CGSConnectionID cid, 
                 CGWindowID wid, int * tag, int tagSize);

In part one of this three-part mini-series I provided an explanation of the wid and cid parameters, which relate to the connection and ID of the window that you're concerned with.

The tag parameter is a pointer to a buffer that holds the tag information you want to set. The window server process allows for up to 64 bits of tag information. Most of the time, you're only concerned with the lower 32 bits in which case you'd point the tag parameter at a 32-bit integer containing the bit flags you want to set, and you'd set the tagSize parameter to 32. To write the higher-order tags, you'd point the tag parameter at a 64-bit quantity and set tagSize to 64.

I emphasize this because some folks think the last parameter should always be 32 - not true. It's usually 32, but I've seen 64 used in plenty of Apple code. If you set tagSize to less than 32, the routine will fail.

I suspect the reason for this rather odd interface is extensibility: it allows the number of tags to be arbitrarily increased without changing the interface. Needless to say, simply passing a 64-bit value would be a lot more straightforward.

To clear one or more tags, you'd use the CGSClearWindowTags routine defined below. In this case, you'd set all the bit flags that you want to clear in the memory pointed to by the tag parameter.

extern CGError CGSClearWindowTags (const CGSConnectionID cid, 
                 CGWindowID wid, int * tag, int tagSize);

Finally, to simply read the existing tag values, you'd use this routine:

extern CGError CGSGetWindowTags (const CGSConnectionID cid, 
                 CGWindowID wid, int * tag, int tagSize);

Note that when setting tag bits, you don't need to call CGSGetWindowTags and "OR in" the bit flags you want before calling CGSSetWindowTags. I've seen code that does this at www.cocoadev.com and it really represents a misunderstanding of how these routines work. The internal OR'ing and AND'ing is done for you - all you need do is supply a mask of the bits you want to set or clear.

All very interesting, but what does this buy us? As an example of what can be done, our demo uses a routine called CGSSetPreventsActivation to determine whether or not a window should activate when it's clicked.

The way this works should be pretty obvious. What's maybe not so obvious is that - internally - CGSSetPreventsActivation is simply a wrapper around CGSSetWindowTags, passing a tag value of 0x00010000 to the inner routine. You'll notice, by the way, that the window can still be activated by Alt-Tab'ing to it, even though it doesn't respond to mouse click activations.

In a similar vein, there are a group of related routines, CGSSetIgnoresCycle, CGSSetIgnoreAsFrontWindow, CGSSetDeferOrdering, CGSSetDeferActivation, which all work by calling CGSSetWindowTags. I don't pretend to understand what they all do - CGSSetIgnoresCycle disables Ctrl-F4 participation, by the way - but I'm on the case. For the terminally curious, the corresponding bit tag mask is show alongside each routine declaration in CGSPrivate.h.

Explore desktop icons

Desktop icons and Exposé thumbnails on display

There's really far too much in CoreGraphics to cover in a few short instalments, but there's one other interesting aspect I want to mention here: properties.

In effect, the window server maintains what you can think of as an NSDictionary object for each connection, and for each window. The per-connection properties stored in this dictionary have interesting key names such as "EnableWindowDoubleBuffering", "DisableDeferredUpdates" . "ClientMayIgnoreEvents" and "ClientIsOppositeEndian". I'd particularly advise you not to fool around with that last one.

You can read and write the connection properties using these two routines:

extern CGError CGSGetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef *outValue);

extern CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value);

The cid and targetCID parameters should normally be identical and obtained from CGSDefaultConnection. That's because only privileged programs like the Dock are able to manipulate the data relating to other connections than their own.

Finally, this month's demo project shows how to retrieve the window titles of all the windows that the Finder has open by using window properties. I would imagine that this is easily possible using AppleScript, but really that's not the point.

The key issue here is to demonstrate some of the undocumented CoreGraphics routines in action. If you step through the code in the debugger, you'll find that there are a surprisingly large number of Finder windows - each desktop icon, for example, is a Finder window. Use Quartz Debug and you'll find the same thing.

By using the undocumented property keys I've provided in CGSPrivate.h many other interesting window attributes can be retrieved.

As ever, this month's demo code can be downloaded from here. ®

New hybrid storage solutions

More from The Register

next story
New 'Cosmos' browser surfs the net by TXT alone
No data plan? No WiFi? No worries ... except sluggish download speed
'Windows 9' LEAK: Microsoft's playing catchup with Linux
Multiple desktops and live tiles in restored Start button star in new vids
iOS 8 release: WebGL now runs everywhere. Hurrah for 3D graphics!
HTML 5's pretty neat ... when your browser supports it
Mathematica hits the Web
Wolfram embraces the cloud, promies private cloud cut of its number-cruncher
Google extends app refund window to two hours
You now have 120 minutes to finish that game instead of 15
Intel: Hey, enterprises, drop everything and DO HADOOP
Big Data analytics projected to run on more servers than any other app
Mozilla shutters Labs, tells nobody it's been dead for five months
Staffer's blog reveals all as projects languish on GitHub
SUSE Linux owner Attachmate gobbled by Micro Focus for $2.3bn
Merger will lead to mainframe and COBOL powerhouse
iOS 8 Healthkit gets a bug SO Apple KILLS it. That's real healthcare!
Not fit for purpose on day of launch, says Cupertino
prev story


Providing a secure and efficient Helpdesk
A single remote control platform for user support is be key to providing an efficient helpdesk. Retain full control over the way in which screen and keystroke data is transmitted.
WIN a very cool portable ZX Spectrum
Win a one-off portable Spectrum built by legendary hardware hacker Ben Heck
Saudi Petroleum chooses Tegile storage solution
A storage solution that addresses company growth and performance for business-critical applications of caseware archive and search along with other key operational systems.
Protecting users from Firesheep and other Sidejacking attacks with SSL
Discussing the vulnerabilities inherent in Wi-Fi networks, and how using TLS/SSL for your entire site will assure security.
Security for virtualized datacentres
Legacy security solutions are inefficient due to the architectural differences between physical and virtual environments.