Created
May 4, 2017 03:21
-
-
Save stek29/ab4b42803c55997c3e5a88516847a526 to your computer and use it in GitHub Desktop.
Frida Script to tweak PIP window alpha level on macOS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const getExport = function (module, name) { | |
const addr = Module.findExportByName(module, name); | |
if (!addr) throw ("Can't find export " + name); | |
else return addr; | |
} | |
const getCGFunction = function (name, returnType, argTypes) { | |
return (new NativeFunction(getExport('CoreGraphics', name), returnType, argTypes)); | |
} | |
const getCFFunction = function (name, returnType, argTypes) { | |
return (new NativeFunction(getExport('CoreFoundation', name), returnType, argTypes)); | |
} | |
const setWindowAlpha = function(windowId, alpha) { | |
// types | |
const CGSConnectionID = 'int'; | |
const CGError = 'uint32'; | |
const CGWindowID = 'uint32'; | |
// constants | |
const kCGErrorSuccess = 0; | |
// private apis | |
const CGSMainConnectionID = getCGFunction('CGSMainConnectionID', CGSConnectionID, []); | |
const CGSSetWindowAlpha = getCGFunction('CGSSetWindowAlpha', CGError, [CGSConnectionID, CGWindowID, 'float']); | |
var err = CGSSetWindowAlpha(CGSMainConnectionID(), windowId, alpha); | |
if (err != kCGErrorSuccess) | |
throw("Can't set alpha for window " + windowID + ", got " + err); | |
} | |
const getWindowAlpha = function(windowId) { | |
// value to be returned | |
var alpha = -1; | |
// types | |
const CFTypeRef = 'pointer'; | |
const CFArrayRef = 'pointer'; | |
const CFAllocatorRef = 'pointer'; | |
const CFIndex = 'long'; | |
const CFArrayCallBacks = 'pointer'; | |
// public apis | |
const CFArrayCreate = getCFFunction('CFArrayCreate', CFArrayRef, [CFAllocatorRef, 'pointer', CFIndex, CFArrayCallBacks]); | |
const CFRelease = getCFFunction('CFRelease', 'void', [CFTypeRef]); | |
const CGWindowListCreateDescriptionFromArray = getCGFunction('CGWindowListCreateDescriptionFromArray', CFArrayRef, [CFArrayRef]); | |
// keys for windowInfo dict | |
const createNSString = function(str) { | |
return ObjC.classes.NSString.stringWithString_(str); | |
} | |
var kCGWindowAlpha = createNSString('kCGWindowAlpha'); | |
// CGWindowID is uint32 => 4 bytes | |
var widPtr = Memory.alloc(4); | |
Memory.writeU32(widPtr, windowId); | |
var widCFArrRef = CFArrayCreate(NULL, widPtr, 1, NULL); | |
var infosPtr = CGWindowListCreateDescriptionFromArray(widCFArrRef); | |
CFRelease(widCFArrRef); | |
var infos = new ObjC.Object(infosPtr); | |
if (infos.count() == 1) { | |
var info = infos.firstObject().retain(); | |
// kCGWindowAlpha is guaranteed to exist | |
var alphaNSNum = info.objectForKey_(kCGWindowAlpha).retain(); | |
alpha = alphaNSNum.floatValue(); | |
alphaNSNum.release(); | |
info.release(); | |
} else { | |
// console.debug("Invalid count: " + infos.count()); | |
alpha = -2; | |
} | |
rpc.exports | |
infos.release(); | |
kCGWindowAlpha.release(); | |
return alpha; | |
} | |
// seems like there could be only one PIP at a time | |
const getPIPWindowID = function() { | |
// value to be returned | |
var windowID = -1; | |
// types | |
const CGWindowID = 'uint32'; | |
const CFArrayRef = 'pointer'; | |
const CGWindowListOption = 'uint32'; | |
// public apis | |
const CGWindowListCopyWindowInfo = getCGFunction('CGWindowListCopyWindowInfo', CFArrayRef, [CGWindowListOption, CGWindowID]); | |
// constants | |
const kCGWindowListOptionOnScreenOnly = (1 << 0); | |
const kCGWindowListExcludeDesktopElements = (1 << 4); | |
const kCGNullWindowID = 0; | |
// helper function | |
const createNSString = function(str) { | |
return ObjC.classes.NSString.stringWithString_(str); | |
} | |
// keys for windowInfo dict | |
// it doesn't seem to be possible to get them | |
// using getCGExport | |
var kCGWindowName = createNSString('kCGWindowName'); | |
var kCGWindowOwnerName = createNSString('kCGWindowOwnerName'); | |
var kCGWindowNumber = createNSString('kCGWindowNumber'); | |
// ones we're looking for | |
var PIPAgentNSS = createNSString('PIPAgent'); | |
var PIPNSS = createNSString('PIP'); | |
var windowInfosPtr = CGWindowListCopyWindowInfo( | |
kCGWindowListOptionOnScreenOnly|kCGWindowListExcludeDesktopElements, | |
kCGNullWindowID | |
); | |
var windowInfos = new ObjC.Object(windowInfosPtr); | |
for (var i = windowInfos.count() - 1; windowID == -1 && i >= 0; i--) { | |
var windowInfo = windowInfos.objectAtIndex_(i).retain(); | |
// Both OwnerName and Name are optional, so nil check is required | |
var ownerNameNSS = windowInfo.objectForKey_(kCGWindowOwnerName); | |
if (ownerNameNSS) ownerNameNSS = ownerNameNSS.retain(); | |
var nameNSS = windowInfo.objectForKey_(kCGWindowName); | |
if (nameNSS) nameNSS = nameNSS.retain(); | |
if (nameNSS && nameNSS.isEqualToString_(PIPNSS) && ownerNameNSS && ownerNameNSS.isEqualToString_(PIPAgentNSS)) { | |
var windowNumberNS = windowInfo.objectForKey_(kCGWindowNumber).retain() | |
windowID = windowNumberNS.intValue() | |
windowNumberNS.release() | |
} | |
if (ownerNameNSS) ownerNameNSS.release(); | |
if (nameNSS) nameNSS.release(); | |
windowInfo.release(); | |
} | |
windowInfos.release(); | |
PIPNSS.release(); | |
PIPAgentNSS.release(); | |
kCGWindowNumber.release(); | |
kCGWindowOwnerName.release(); | |
kCGWindowName.release(); | |
return windowID; | |
} | |
rpc.exports = { | |
getWindowAlpha: getWindowAlpha, | |
setWindowAlpha: setWindowAlpha, | |
getPIPWindowID: getPIPWindowID | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Using
NSRunningApplication runningApplicationsWithBundleIdentifier:
to get PIPAgent's PID would be a good idea