Change your views: OS X tags exploited

Apple windows insider

SANS - Survey on application security programs

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

Top three mobile application threats

More from The Register

next story
OpenBSD founder wants to bin buggy OpenSSL library, launches fork
One Heartbleed vuln was too many for Theo de Raadt
Got Windows 8.1 Update yet? Get ready for YET ANOTHER ONE – rumor
Leaker claims big release due this fall as Microsoft herds us into the CLOUD
This time it's 'Personal': new Office 365 sub covers just two devices
Redmond also brings Office into Google's back yard
Ubuntu 14.04 LTS: Great changes, but sssh don't mention the...
Why HELLO Amazon! You weren't here last time
Patch iOS, OS X now: PDFs, JPEGs, URLs, web pages can pwn your kit
Plus: iThings and desktops at risk of NEW SSL attack flaw
Next Windows obsolescence panic is 450 days from … NOW!
The clock is ticking louder for Windows Server 2003 R2 users
Batten down the hatches, Ubuntu 14.04 LTS due in TWO DAYS
Admins dab straining server brows in advance of Trusty Tahr's long-term support landing
Red Hat to ship RHEL 7 release candidate with a taste of container tech
Grab 'near-final' version of next Enterprise Linux next week
Apple inaugurates free OS X beta program for world+dog
Prerelease software now open to anyone, not just developers – as long as you keep quiet
prev story


Securing web applications made simple and scalable
In this whitepaper learn how automated security testing can provide a simple and scalable way to protect your web applications.
3 Big data security analytics techniques
Applying these Big Data security analytics techniques can help you make your business safer by detecting attacks early, before significant damage is done.
The benefits of software based PBX
Why you should break free from your proprietary PBX and how to leverage your existing server hardware.
Mainstay ROI - Does application security pay?
In this whitepaper learn how you and your enterprise might benefit from better software security.
Combat fraud and increase customer satisfaction
Based on their experience using HP ArcSight Enterprise Security Manager for IT security operations, Finansbank moved to HP ArcSight ESM for fraud management.