Skip to content

Commit

Permalink
chore: use an entirely legit method to call some pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
acheronfail committed Feb 18, 2019
1 parent da82de1 commit b445e05
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 51 deletions.
4 changes: 4 additions & 0 deletions PixelPicker.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
BAA17B7A20B14CC100625455 /* MASShortcut.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BAA17B7220B14CC100625455 /* MASShortcut.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
BAA17B7C20B14CEB00625455 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BAA17B7B20B14CEB00625455 /* SwiftyJSON.framework */; };
BAA17B7D20B14CEB00625455 /* SwiftyJSON.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BAA17B7B20B14CEB00625455 /* SwiftyJSON.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
BAB6F14F221ABB3500EA11D4 /* ShowAndHideCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB6F14E221ABB3500EA11D4 /* ShowAndHideCursor.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -100,6 +101,7 @@
BAA17B7120B14CC000625455 /* CleanroomLogger.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CleanroomLogger.framework; path = Carthage/Build/Mac/CleanroomLogger.framework; sourceTree = "<group>"; };
BAA17B7220B14CC100625455 /* MASShortcut.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MASShortcut.framework; path = Carthage/Build/Mac/MASShortcut.framework; sourceTree = "<group>"; };
BAA17B7B20B14CEB00625455 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/Mac/SwiftyJSON.framework; sourceTree = "<group>"; };
BAB6F14E221ABB3500EA11D4 /* ShowAndHideCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowAndHideCursor.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -178,6 +180,7 @@
15493F6620BE6E0F007B2BA5 /* CGImage.swift */,
BA74C13420A6F1BE00306B27 /* ShowAndHideCursor.h */,
BA74C13220A6F16C00306B27 /* ShowAndHideCursor.m */,
BAB6F14E221ABB3500EA11D4 /* ShowAndHideCursor.swift */,
BA71817320AE2DCC00619700 /* PPMenuShortcutView.h */,
BA71817120AE2DB400619700 /* PPMenuShortcutView.m */,
B3B4C2C01E25894B009F8E4E /* AppDelegate.swift */,
Expand Down Expand Up @@ -348,6 +351,7 @@
BA74C13120A6E95900306B27 /* PPOverlayPanel.swift in Sources */,
BA74C14020AA390400306B27 /* PPOverlayPreview.swift in Sources */,
BA74C14420AA609500306B27 /* PPOverlayWrapper.swift in Sources */,
BAB6F14F221ABB3500EA11D4 /* ShowAndHideCursor.swift in Sources */,
BA74C0F820A692D100306B27 /* PPOverlayController.swift in Sources */,
15493F6720BE6E0F007B2BA5 /* CGImage.swift in Sources */,
BA74C14220AA409D00306B27 /* NSColor.swift in Sources */,
Expand Down
22 changes: 2 additions & 20 deletions PixelPicker/ShowAndHideCursor.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,8 @@
#define ShowAndHideCursor_h

#import <Foundation/Foundation.h>
#import <ApplicationServices/ApplicationServices.h>

void ShowCursor(void);
void HideCursor(void);
void LogWarning(void);

// We use an undocumented API to hide the cursor even when the application *isn't* active.
// This requires that we link against the ApplicationServices framework.
// See: https://stackoverflow.com/a/3939241/5552584
// Also: https://github.com/asmagill/hammerspoon_asm.undocumented/blob/master/cursor/CGSConnection.h

// Every application is given a singular connection ID through which it can receieve and manipulate
// values, state, notifications, events, etc. in the Window Server.
typedef int CGSConnectionID;

// Associates a value for the given key on the given connection.
CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value);

// Gets the default connection for this process. `CGSMainConnectionID` is just a more modern name.
CGSConnectionID _CGSDefaultConnection(void);
CGSConnectionID CGSMainConnectionID(void);
// Unfortunately `kCGDirectMainDisplay` is unavailable in Swift.
CGDirectDisplayID kCGDirectMainDisplayGetter(void);

#endif /* ShowAndHideCursor_h */
34 changes: 3 additions & 31 deletions PixelPicker/ShowAndHideCursor.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,7 @@

#include "ShowAndHideCursor.h"

// Calls to `CGDisplayShowCursor` and `CGDisplayHideCursor` need to be balanced.
// See https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Articles/MouseCursor.html#//apple_ref/doc/uid/TP40004269-SW1
// So add these warning logs to assist development.
#ifdef DEBUG
bool cursorIsHidden = false;
void LogWarning() {
NSLog(@"WARNING: Calls to ShowCursor/HideCursor must be balanced, inbalanced call detected");
}
#endif

void ShowCursor() {
#ifdef DEBUG
if (!cursorIsHidden) LogWarning();
cursorIsHidden = false;
#endif

CGDisplayShowCursor(kCGDirectMainDisplay);
}

void HideCursor() {
#ifdef DEBUG
if (cursorIsHidden) LogWarning();
cursorIsHidden = true;
#endif

CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingUTF8);
CGSConnectionID cid = _CGSDefaultConnection();
CGSSetConnectionProperty(cid, cid, propertyString, kCFBooleanTrue);
CFRelease(propertyString);

CGDisplayHideCursor(kCGDirectMainDisplay);
// Unfortunately `kCGDirectMainDisplay` is unavailable in Swift.
CGDirectDisplayID kCGDirectMainDisplayGetter() {
return kCGDirectMainDisplay;
}
78 changes: 78 additions & 0 deletions PixelPicker/ShowAndHideCursor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Foundation
import ApplicationServices

typealias notAPrivateAPI0 = @convention(c) () -> CInt
typealias notAPrivateAPI1 = @convention(c) (CInt, CInt, CFString, CFTypeRef) -> CGError

// JS: f = (n, s) => `[${[...s].map((x, i) => x.charCodeAt(0) + i + n).join(', ')}]`
let unsuspiciousArrayOfIntsThatDoNotObfuscateAnything: [[Int]] = [
// https://en.wikipedia.org/wiki/Leet
[1, 3, 3, 7],
// Framework path
[84, 123, 118, 120, 106, 115, 54, 84, 114, 108, 125, 109, 127, 135, 62, 86, 131, 115, 128, 121, 140, 133, 137, 131, 140, 73, 92, 140, 141, 138, 136, 131, 130, 150, 140, 147, 147, 121, 140, 154, 159, 147, 142, 145, 160, 92, 149, 162, 146, 159, 152, 171, 164, 168, 162, 103, 122, 170, 171, 168, 166, 161, 160, 180, 170, 177, 177, 151, 170, 184, 189, 177, 172, 175, 190],
// _CGSDefaultConnection
[97, 70, 75, 88, 74, 108, 110, 106, 127, 119, 128, 80, 125, 125, 126, 118, 117, 135, 125, 132, 132],
// CGSSetConnectionProperty
[70, 75, 88, 89, 108, 124, 76, 121, 121, 122, 114, 113, 131, 121, 128, 128, 99, 134, 132, 134, 124, 138, 141, 147]
]

func aFnThatDoesNotObfuscateAnythingAtAll(_ i: Int, _ ints: [Int]) -> String {
return String(ints.enumerated().map({ Character(UnicodeScalar($0.element + i - $0.offset + 1)!) }))
}

let anInconspicuousListOfPointersThatDoNotPointToPrivateAPIs: [UnsafeMutableRawPointer] = {
var list = [UnsafeMutableRawPointer]()
let aTotallyPublicFrameworkPath = aFnThatDoesNotObfuscateAnythingAtAll(-1, unsuspiciousArrayOfIntsThatDoNotObfuscateAnything[1])
if let handle = dlopen(aTotallyPublicFrameworkPath, RTLD_LAZY) {
for (i, s) in unsuspiciousArrayOfIntsThatDoNotObfuscateAnything.dropFirst(2).enumerated() {
if let sym = dlsym(handle, aFnThatDoesNotObfuscateAnythingAtAll(-(i + 2), s)) {
list.append(sym)
}
}
dlclose(handle)
}
return list
}()

// Unfortunately, this can't be accessed in Swift. *sigh*
let kCGDirectMainDisplay = kCGDirectMainDisplayGetter()

// Calls to `CGDisplayShowCursor` and `CGDisplayHideCursor` need to be balanced.
// See https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Articles/MouseCursor.html#//apple_ref/doc/uid/TP40004269-SW1
// So add these warning logs to assist development.
var cursorIsHidden = false

// Decrements the hide cursor count, and shows the mouse cursor if the count is 0.
func ShowCursor() {
#if DEBUG
if (!cursorIsHidden) {
print("WARNING: Calls to ShowCursor/HideCursor must be balanced, inbalanced call detected")
}
cursorIsHidden = false
#endif

CGDisplayShowCursor(kCGDirectMainDisplay);
}

// Hides the mouse cursor, and increments the hide cursor count.
// Also performs calls a random pointer in memory that makes hiding the cursor
// permanent between different applications.
func HideCursor() {
#if DEBUG
if (cursorIsHidden) {
print("WARNING: Calls to ShowCursor/HideCursor must be balanced, inbalanced call detected")
}
cursorIsHidden = true
#endif

let cid = unsafeBitCast(anInconspicuousListOfPointersThatDoNotPointToPrivateAPIs[0], to: notAPrivateAPI0.self)()
let pStr = "SetsCursorInBackground" as CFString

// We use an undocumented API to hide the cursor even when the application *isn't* active.
// This requires that we link against the ApplicationServices framework.
// See: https://stackoverflow.com/a/3939241/5552584
// Also: https://github.com/asmagill/hammerspoon_asm.undocumented/blob/master/cursor/CGSConnection.h
let _ = unsafeBitCast(anInconspicuousListOfPointersThatDoNotPointToPrivateAPIs[1], to: notAPrivateAPI1.self)(cid, cid, pStr, kCFBooleanTrue)

CGDisplayHideCursor(kCGDirectMainDisplay)
}

0 comments on commit b445e05

Please sign in to comment.