asmagill / hammerspoon_asm

Hammerspoon modules in progress...
MIT License
52 stars 12 forks source link

Question about using hs._asm.objc #18

Closed latenitefilms closed 4 years ago

latenitefilms commented 4 years ago

@asmagill - I'm trying to use hs._asm.objc to attempt to access some private functions in one of Final Cut Pro's Frameworks.

I'm using this to load all the required Frameworks:

print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/PluginManager.framework/Versions/B/PluginManager","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/FxPlug.framework/Versions/A/FxPlug","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/Helium.framework/Versions/A/Helium","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/ProCore.framework/Versions/A/ProCore","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/ProChannel.framework/Versions/A/ProChannel","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/StudioSharedResources.framework/Versions/A/StudioSharedResources","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/LunaKit.framework/Versions/A/LunaKit","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/ProInspector.framework/Versions/A/ProInspector","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/ProShapes.framework/Versions/A/ProShapes","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/ProGL.framework/Versions/A/ProGL","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/ProOSC.framework/Versions/A/ProOSC","*")))
print(string.format("Loaded: %s", package.loadlib("/Applications/Final Cut Pro.app/Contents/Frameworks/ProAppsFxSupport.framework/Versions/A/ProAppsFxSupport","*")))
o = require("hs._asm.objc")

...which works as expected. But when I try and use hs._asm.objc to access these private functions, I get an error:

> o.class("PAEMD5Value")("alloc")("initFromString:", "test")
2020-03-07 20:09:33: 20:09:33    LuaSkin:     @ = [PAEMD5Value alloc] with 0 arguments
2020-03-07 20:09:33:                          @ = [<PAEMD5Value> initFromString:] with 1 arguments
/Users/chrishocking/.hammerspoon/hs/_asm/objc/init.lua:65: bad argument #3 to 'fn' (hs._asm.objc.id expected, got string)
stack traceback:
    [C]: in function 'hs._asm.objc.objc_msgSend'
    /Users/chrishocking/.hammerspoon/hs/_asm/objc/init.lua:65: in function </Users/chrishocking/.hammerspoon/hs/_asm/objc/init.lua:56>
    (...tail calls...)
    [C]: in function 'xpcall'
    ...app/Contents/Resources/extensions/hs/_coresetup/init.lua:467: in function <...app/Contents/Resources/extensions/hs/_coresetup/init.lua:447>

> o.class("NSString")("alloc")("initWithUTF8String:", "hello")
2020-03-07 20:11:33: 20:11:33                 @ = [NSString alloc] with 0 arguments
2020-03-07 20:11:33:                          @ = [<NSPlaceholderString> initWithUTF8String:] with 1 arguments
hs._asm.objc.id: NSTaggedPointerString (0x7c52fc8772282ac9)

Any ideas what I'm doing wrong?

asmagill commented 4 years ago

Ok, first the objc module is... dangerous. Useful for examining things but please, please, please do not even slightly consider using it in production because: a) it completely ignores all return type qualifiers about assign/copy/weak/etc. and treats every return value as strong b) it has no concept whatsoever of structures and is useful only for methods which return actual objects or single value entities (numbers, boolean, etc.) or void c) no concept of pointers (c-strings are an exception iff the return type can be known to be (unsigned) char * or void *) d) will let you do dangerous and dumb things.

Whenever I use it, I plan on having to restart Hammerspoon or even reboot the computer soon.

Ok, with those qualifiers out of the way, it is an interesting way to poke at things and "see what they do"...

Glancing at what you've show above, it looks like you're pretty much on the right track, but remember, and method that takes a string, is expecting an NSString, so you'd have to do something like

o.class("PAEMD5Value")("alloc")("initFromString:", o.class("NSString")("stringWithUTF8String:", "my lua string"))

You can also assign things to variables, so...

n = o.class("NSString")("alloc")("initWithUTF8String:", "hello")
p = o.class("PAEMD5Value")("alloc")("initFromString:", n)

Don't forget to check out the metatables for the various types as well to learn about known methods, ivars, etc. There is limited ability to actually manipulate the ivars, but remember that in most non private cases, an ivar just backs a property, so for an ivar of _abc, look for methods abc and setAbc:

By default it also logs all of the interpretation of objective-c messages via LuaSkin's logDebug, so you may want to temporarily change the log level (with hs.luaSkinLog.level) or recompile with DEBUG_msgSend commented out in objc.h.

latenitefilms commented 4 years ago

Legend, thanks heaps for the fast reply! HUGELY appreciated!

Yes, completely understood this is dangerous and can allow me to do really dumb things - duly noted!

I'm just going to use hs._asm.objc to experiment within Hammerspoon - this definitely won't be used within CommandPost.