theos / logos Goto Github PK
View Code? Open in Web Editor NEWPreprocessor that simplifies Objective-C hooking.
Home Page: https://theos.dev/docs/logos
License: Other
Preprocessor that simplifies Objective-C hooking.
Home Page: https://theos.dev/docs/logos
License: Other
Currently, logos adds that include statement before the first hook line, the only problem with that is that you can't use anything defined in substrate.h (like objective-c runtime stuff) before that line, so any helper functions that are not hooks must be moved after the first hook line.
It's a one line fix, but I thought of letting you know:
- splice(@lines, $firsthookline - 1, 0, "#include <substrate.h>");
+ splice(@lines, 0, 0, "#include <substrate.h>");
It's easy to make a mistake with theos by placing a method-hook under the wrong %hook
class, or adding a typo to a selector name. In this case, the hooks will silently fail, and the methods will not be swizzled, leading to confusion of whether the target methods are being invoked at all.
Instead, theos should loudly fail when I provide an 'invalid hook'. This would catch this bug much earlier in development and reduce headaches.
It would be good to be able to search a specific library for the symbol provided instead of always using MSFindSymbol(NULL, "symbol")
perhaps %hookf(type, "/usr/lib/libname.dylib:symbol"
would make sense
logos picks up false method declarations in the middle of a function.
this:
while (MC.index+(int)hasPlaceHolder < (int)[icons count])
{
SBIcon * neighbor = [icons objectAtIndex:MC.index+(int)hasPlaceHolder];
//...
}
gets turned into this:
while (MC.indexstatic int _logos_meta_method$_ungrouped$SBAppSwitcherController$hasPlaceHolder(Class self, SEL _cmd) < (int)[icons count])
{
SBIcon * neighbor = [icons objectAtIndex:MC.indexstatic int _logos_meta_method$_ungrouped$SBAppSwitcherController$hasPlaceHolder(Class self, SEL _cmd)];
//...
}
%hook H
- (void)format:(NSString *)format, ... {
%orig;
}
%end
Generates the following code:
#line 1 "Tweak.x"
#include <substrate.h>
#if defined(__clang__)
#if __has_feature(objc_arc)
#define _LOGOS_SELF_TYPE_NORMAL __unsafe_unretained
#define _LOGOS_SELF_TYPE_INIT __attribute__((ns_consumed))
#define _LOGOS_SELF_CONST const
#define _LOGOS_RETURN_RETAINED __attribute__((ns_returns_retained))
#else
#define _LOGOS_SELF_TYPE_NORMAL
#define _LOGOS_SELF_TYPE_INIT
#define _LOGOS_SELF_CONST
#define _LOGOS_RETURN_RETAINED
#endif
#else
#define _LOGOS_SELF_TYPE_NORMAL
#define _LOGOS_SELF_TYPE_INIT
#define _LOGOS_SELF_CONST
#define _LOGOS_RETURN_RETAINED
#endif
@class H;
static void (*_logos_orig$_ungrouped$H$format$)(
_LOGOS_SELF_TYPE_NORMAL H *_LOGOS_SELF_CONST, SEL, NSString *);
static void
_logos_method$_ungrouped$H$format$(_LOGOS_SELF_TYPE_NORMAL H *_LOGOS_SELF_CONST,
SEL, NSString *);
#line 1 "Tweak.x"
static void _logos_method$_ungrouped$H$format$(
_LOGOS_SELF_TYPE_NORMAL H *_LOGOS_SELF_CONST __unused self,
SEL __unused _cmd, NSString *format),
... {
_logos_orig$_ungrouped$H$format$(self, _cmd, format);
}
static __attribute__((constructor)) void _logosLocalInit() {
{
Class _logos_class$_ungrouped$H = objc_getClass("H");
MSHookMessageEx(_logos_class$_ungrouped$H, @selector(format:),
(IMP)&_logos_method$_ungrouped$H$format$,
(IMP *)&_logos_orig$_ungrouped$H$format$);
}
}
#line 6 "Tweak.x"
The function prototypes don't contain the , ...
and the function definition itself is wrongly formatted NSString *format), ... {
.
Right now, %subclass treats self as an id
. Logos could create a secret @interface (_logos_interface$_ungrouped$Blah
, maybe?) and use that for self.
[super aMethod]
, where aMethod
is a valid method, in a method.use of undeclared identifier 'super'
.use of undeclared identifier 'super'
.
Succesful compilation.
Par example:
iDUTagCreationAlertCollectionViewController.x:36:13: error: use of undeclared identifier 'super'
self = [super initWithCoder:coder];
^
Nope.
Operating System: macOS 10.15.4
Toolchain Version: …
SDK Version: 13.4
As I know,logify.pl can be used like:
logify.pl 1.h > ~/xxx/Tweak.xm
logify.pl 2.h >> ~/xxx/Tweak.xm
When I found there are around 50 or more functions in file 1.h
,but the target function what I want to record is only one function,how can I use logify.pl to record only one or few functions to Tweak.xm like:
logify.pl [email protected] >> ~/xxx/Tweak.xm
The dylib will crash.
The dylib accesses the float value as expected.
You might see this in the logs:
[NSISRestrictedToZeroMarkerVariable floatValue]: unrecognized selector sent to instance 0x197a33e0
@uroboro believes that this is due to the way %property is generated for CGFloat values and that is wrongly assumed to be of type float. See: https://github.com/theos/theos/blob/master/bin/lib/Logos/Generator/Base/Property.pm for the definition of a %property that is a CGFloat. My code will run perfectly fine on 64-bit devices (iPhone 6s on 9.3.3, iPhone 6s on 10.2, iPad Air on 9.3.2) but fails on 32-bit devices (iPad 4 on 9.3.3).
Operating System: 9.3.3 (iPad3,4 with Home Depot jailbreak)
Toolchain Version: 9.3
SDK Version: 9.3
This will reduce "objc_getClass" calls.
If you write the following hook:
%hook PXAssetFetcher
- (id)fetchAssetsInAssetCollection:(id) withFilterPredicate:(id)
inclusionPredicate:(id) fetchLimit:(NSUInteger) sortDescriptors:(id)
reverseSortOrder:(BOOL) hideHiddenAssets:(BOOL) fetchPropertySets:(id)fetchps {
return %orig;
}
%end
the following (incorrect) code is generated:
MSHookMessageEx(
_logos_class$_ungrouped$PXAssetFetcher,
@selector(fetchAssetsInAssetCollection:: :: :: ::),
(IMP)&_logos_method$_ungrouped$PXAssetFetcher$fetchAssetsInAssetCollection$$$$$$$$,
(IMP *)&_logos_orig$_ungrouped$PXAssetFetcher$fetchAssetsInAssetCollection$$$$$$$$);
The selector should be:
fetchAssetsInAssetCollection:withFilterPredicate:inclusionPredicate:fetchLimit:sortDescriptors:reverseSortOrder:hideHiddenAssets:fetchPropertySets:
Strangely, I can't omit the last label, fetchps
. If omitted, the following error is generated:
Tweak.xm:29:337: error: expected class member or base class name
...BOOL fetchPropertySets):(id) {
^
Tweak.xm:29:336: error: only constructors take base initializers
...BOOL fetchPropertySets):(id) {
^
%log
Error while debugging NSBlock.%log
. (See buildLogCall)When hooking a method which accepts a block as a paramter, Logos dislikes this form of calling the original implementation:
%hook AwesomeClass
- (void)AwesomeMethod:(void (^)(void))awesomeBlock
{
%orig(^{
NSLog(@"Hello");
});
}
%end
However, this works:
%hook AwesomeClass
- (void)AwesomeMethod:(void (^)(void))awesomeBlock
{
%orig(^{ NSLog(@"Hello"); });
}
%end
and putting the block in a variable, works too, obviously.
Logos errors out with this error: "error: missing closing parenthesis"
Attempting to hook a function with a ...
argument will throw a syntax error when you try to call %orig
.
For example, the code:
%hookf (id, objc_msgSend, id self, SEL op, ...)
{
NSLog(@"test");
return %orig;
}
will throw the error:
error: expected expression
return _logos_orig$_ungrouped$objc_msgSend(self, op, ...);
^
Recently, %hook
was updated to support hooking class names with .
in them. %c
does not yet support this
(dd5477a)
Logos should also optimize multiple dynamic lookups with the same image name to increase performance. (e.g. MSGetImageByName should only be called once for two dynamic lookups with the same image name)
The return value of MSGetImageByName/MSFindSymbol should also be compared against NULL before calling MSFindSymbol/MSHookFunction to prevent a possible NULL pointer dereference.
It would make sense to write the snippet
if (%c(SBHomeScreenBackdropView))
%init(SwitcherBackdrop_iOS12);
else
%init(SwitcherBackdrop_iOS11);
as a ternary statement,
%c(SBHomeScreenBackdropView) ? %init(SwitcherBackdrop_iOS12) : %init(SwitcherBackdrop_iOS11);
but that results in errors.
==> Compiling Tweak.xm (arm64)…
Tweak.xm:804:61: error: expected expression
_logos_static_class_lookup$SBHomeScreenBackdropView() ? {Class _logos_class$SwitcherBackdrop_iOS12$...
^
Tweak.xm:804:61: error: expected ':'
_logos_static_class_lookup$SBHomeScreenBackdropView() ? {Class _logos_class$SwitcherBackdrop_iOS12$...
^
:
Tweak.xm:804:59: note: to match this '?'
_logos_static_class_lookup$SBHomeScreenBackdropView() ? {Class _logos_class$SwitcherBackdrop_iOS12$...
^
Tweak.xm:804:61: error: expected expression
_logos_static_class_lookup$SBHomeScreenBackdropView() ? {Class _logos_class$SwitcherBackdrop_iOS12$...
^
3 errors generated.
It seems like Logos outputs a mix between a normal if statement and a ternary operator.
The logs
config param for logos should exist, and support full
, off
, and on
(defaulting to on
). full
will automatically %log all hooked methods. off
will disable (consume) %log
directives.
%property (nonatomic, retain) UITextField * _Nonnull textField;
iDUTagCreationAlertCollectionViewController.x:19:1: error: expected identifier or '('
%property (nonatomic, retain) UITextField * _Nonnull textField;
^
Successful compilation.
iDUTagCreationAlertCollectionViewController.x:19:1: error: expected identifier or '('
%property (nonatomic, retain) UITextField * _Nonnull textField;
^
Nope.
Operating System: macOS 10.15.4
Toolchain Version: …
SDK Version: 13.4
Problem: When specifying a custom setter for a %property
, Logos puts the :
in the generated method name (when it shouldn't).
Code:
%group Foo
%hook NSObject
%property(nonatomic, retain, setter=my_Setter:) id obj;
%end
%end
Error:
file.xm:71:231: error: variable has incomplete type 'void'
...{ return (id)objc_getAssociatedObject(self, (void *)_logos_method$Foo$NSObject$obj); }; __attribute__((used)) static void _logos_method...
^
file.xm:71:267: error: expected ';' after top level declarator
...(void *)_logos_method$Foo$NSObject$obj); }; __attribute__((used)) static void _logos_method$Foo$NSObject$my_Setter:(NSObject * __unuse...
^
;
file.xm:71:278: error: expected ')'
...(void *)_logos_method$Foo$NSObject$obj); }; __attribute__((used)) static void _logos_method$Foo$NSObject$my_Setter:(NSObject * __unuse...
^
file.xm:71:268: note: to match this '('
...(void *)_logos_method$Foo$NSObject$obj); }; __attribute__((used)) static void _logos_method$Foo$NSObject$my_Setter:(NSObject * __unuse...
^
file.xm:71:269: error: C++ requires a type specifier for all declarations
...(void *)_logos_method$Foo$NSObject$obj); }; __attribute__((used)) static void _logos_method$Foo$NSObject$my_Setter:(NSObject * __unuse...
^
file.xm:71:326: error: expected ';' after top level declarator
...static void _logos_method$Foo$NSObject$my_Setter:(NSObject * __unused self, SEL __unused _cmd, id rawValue) { objc_setAssociatedObject(...
^
;
%hook ASDSoftwareUpdatesStore
- (void)reloadFromServerWithCompletionBlock:(void (^)(id data))block { %log; }
%end
Here the output:
https://ghostbin.com/paste/qqma9
Compile the tweak
Mac 0SX 10.2.1
iOS 10.2 (TARGET = iphone:clang:10.2)
%c()
has shortcomings — for instance the compiler has no idea what type it actually is and can’t do type checking on instancetype
methods, forcing use of casts like this:
[(SpringBoard *)[%c(SpringBoard) sharedApplication] doThing];
((SpringBoard *)[%c(SpringBoard) sharedApplication]).isThingDone; // even worse!
Clang supports a weak_import
attribute on classes that allows us to skip the linker trying to find the symbol to link, and allows the symbol to be optional just as %c()
is.
Which would allow much more elegant code, like maybe:
%weakclass SpringBoard;
// …
[[SpringBoard sharedApplication] doThing];
[SpringBoard sharedApplication].isThingDone;
%weakclass X
would expand to:
__attribute__((weak_import))
@interface SpringBoard ()
@end
Of course these weak symbols will be resolved at process launch time/library load time just like every other symbol dyld needs to resolve, so %c()
is still necessary for late-loaded symbols.
Does this work on a category interface? Worst case scenario, we generate a separate file containing flags to pass the linker for weak import, or use this:
asm(".weak_reference _OBJC_CLASS_$_SpringBoard");
According to this thread the attribute method may require a linker flag anyway due to a limitation of the implementation. I’m really hoping this is a bug and that it’s fixed now, so we can use an #if
directive to check the clang version and #error
out if it’s a known broken version.
(Thanks for reporting an issue! Please make sure you click the link above to view the issue guidelines, then fill out the blanks below.)
The tweak does not compile and the error prevents you from doing anything with your code without getting an error
My tweak would compile and I would get an alert when SpringBoard loads
(If it’s long, please paste to https://ghostbin.com/ and insert the link here.)
WillPhone:/var/mobile/sbtest1 root# make package install
/var/mobile/sbtest1/theos/makefiles/targets/Darwin-arm/iphone.mk:43: Targeting iOS 4.0 and higher is not supported with iphone-gcc. Forcing clang.
Making all for tweak sbtest1...
Preprocessing Tweak.xm...
Constants from lexical variables potentially modified elsewhere are deprecated at /private/var/theos/bin/lib/aliased.pm line 42.
Constants from lexical variables potentially modified elsewhere are deprecated at /private/var/theos/bin/lib/aliased.pm line 42.
Constants from lexical variables potentially modified elsewhere are deprecated at /private/var/theos/bin/lib/aliased.pm line 42.
Constants from lexical variables potentially modified elsewhere are deprecated at /private/var/theos/bin/lib/aliased.pm line 42.
Constants from lexical variables potentially modified elsewhere are deprecated at /private/var/theos/bin/lib/aliased.pm line 42.
Constants from lexical variables potentially modified elsewhere are deprecated at /private/var/theos/bin/lib/aliased.pm line 42.
Constants from lexical variables potentially modified elsewhere are deprecated at /private/var/theos/bin/lib/aliased.pm line 42.
Constants from lexical variables potentially modified elsewhere are deprecated at /private/var/theos/bin/lib/aliased.pm line 42.
Can't call method "isNew" on an undefined value at /var/mobile/sbtest1/theos/bin/logos.pl line 382.
make[2]: *** [obj/Tweak.xm.a114fd55.o] Error 255
make[1]: *** [internal-library-all_] Error 2
make: *** [sbtest1.all.tweak.variables] Error 2
WillPhone:/var/mobile/sbtest1 root#
…
Operating System: iOS 8.3
Toolchain Version: 6.1-1
SDK Version: iOS 8.1
After I used logify on my methods and tried to make the tweak, this error occured:
Tweak.x:5: error: %orig does not make sense outside a method
17:22 <@DHowett> that should be being done anyway, come to think of
it. however, it complicates custom class expressions
17:22 <@DHowett> as init can wrap scope
17:22 <@DHowett> (the function cannot be variadic, and i do not know
what classes the user will want to change
17:22 <@DHowett> actually, that's tractable. i think it can be done)
17:23 <@DHowett> (the static function gets generated at the end, after
all. the call can contain all overridden classes)
17:23 <@DHowett> and the prototype and final function as well
I'm trying to make a new property for an ARC project using %property (strong) and I get a compile error of "unrecognized type". It seems like only non-arc types work,
(Thanks for reporting an issue! Please make sure you click the link above to view the issue guidelines, then fill out the blanks below.)
%hook class.name
you should expect it to work like normal.Tweak.xm:1:1: error: cannot use dot operator on a type
Allow you to hook the class that has a dot operator in it.
Tweak.xm:1:1: error: cannot use dot operator on a type
There is a simple fix for it currently using this work around here.
Mac OSX 10.10
iOS 9.2 SDK
(Thanks for reporting an issue! Please make sure you click the link above to view the issue guidelines, then fill out the blanks below.)
I get the error "Experimental shift on scalar is now forbidden at" followed by a string of error messages.
My project to be set up
https://ghostbin.co/paste/yvad2
I'm on iOS 12.4
I replaced the following:
my $functionRetval = shift $args;
my $functionName = shift $args;
with
my $functionRetval = shift @{args};
my $functionName = shift @{args};
Operating System: Windows 10
Toolchain Version: 4.0.3-1
SDK Version: 10.3
I'm gonna ditch the standard issue template because I don't see it fitting.
Defining a property like
%subclass NextUpMediaHeaderView : MediaControlsHeaderView
%property (nonatomic, retain) UIColor *textColor;
...
%end
is fine. However, I'd like to override the setter:
%subclass NextUpMediaHeaderView : MediaControlsHeaderView
%property (nonatomic, retain) UIColor *textColor;
- (void)setTextColor:(UIColor *)color {
%orig;
// some extra stuff being made here
}
...
%end
and this is not possible as it complains about it being redefined.
NextUp.xm:417:17: error: redefinition of
'_logos_method$CustomViews$NextUpMediaHeaderView$setTextColor$'
static void _logos_method$CustomViews$NextUpMediaHeaderView$setTextColor$(...
^
NextUp.xm:367:377: note: previous definition is here
...}__attribute__((used)) static void _logos_method$CustomViews$NextUpMediaHeader...
I know we need to define methods to set and get associated objects when defining a new property, but could it perhaps be tweaked to call a custom setter afterwards if such exists or something?
I'm aware of the obvious solution of defining a method like updateTextColor:
which sets the property and does the extra work. It's just isn't that good looking code, and it would also be confusing for others using already a defined class where this approach is used.
For example, %c(Foo)
should evaluate to
((Foo *) _logos_static_class_lookup$Foo())
instead of just
_logos_static_class_lookup$Foo()
so that type information is not lost, allowing for things like %c(Foo).classProperty
(Sorry I think the issues template doesn't support my issue so I cleared them)
I'm fully aware of the fact that I can %group YOSWAG and %init(YOSWAG);
Can I %group com.apple.springboard and %init([NSBundle mainBundle].bundleIdentifier); ?
Thanks
EDIT:I'm fully aware that this would require a huge refactor.
Having Logos errors follow the same format as clang will make them a bit easier to spot amongst the sea of other colors in the build output, and will also match Xcode’s regexes for error output to ensure it comes up nicely in the warnings tab for people using Theos/Logos via Xcode. (ibtool and some other tools invoked by a typical app build process do the same.)
There should be a way to call %orig
with a different instance variable while not modifying self
.
// Maybe something like this?
%origs(differentInstance); // Call %orig with different self and the original arguments
%origs(differentInstance, NULL, 42, @NO); // Call %orig with different self and arguments
Specifying the class like %init([<class>=<expr>, …]);
, results in the hooked object (self
) being left without type to the compiler. I understand that not assuming any class is the most sane thing to do, but I was wondering if it would be possible to automatically set the object to a known type or to one that conforms to a protocol in order to avoid casting.
I have a few hooks for iOS 11 and 12 (pre 12.2) that hooks the class MediaControlsPanelViewController
in a few of my tweaks. In iOS 12.2 however, this class was renamed to MRPlatterViewController
. All properties and methods seems to be the same. Thus, I would like to reuse the code within the hook, like:
%ctor {
...
Class c;
if (running iOS 12.2)
c = %c(MRPlatterViewController);
else
c = %c(MediaControlsPanelViewController);
%init(MediaControlsPanelViewController = c);
}
This works fine, but inside the actual hooked code, the compiler does no longer know which type self
has.
I realize that it's possible to do something like this:
@protocol PanelViewController<NSObject>
@property (nonatomic, retain) MediaControlsParentContainerView *parentContainerView;
...
@end
@interface MediaControlsPanelViewController : UIViewController <PanelViewController>
@end
@interface MRPlatterViewController : UIViewController <PanelViewController>
@end
and then in the code cast it to an object that conforms to that protocol:
%hook MediaControlsPanelViewController
- (void)viewDidLoad {
%orig;
UIViewController<PanelViewController> *controller = (UIViewController<PanelViewController> *)self;
controller.parentContainerView...
}
...
instead of using self
. I was wondering if it would be possible to automatically set the object to a known type or to one that conforms to a protocol in order to avoid doing this casting. Ideally this would be done in the %ctor
once instead of once in every hooked method.
Once a function is hooked using the Logos syntax (%hook
or %hookf
), it is no longer possible to call the original function from outside of the new function.
%hook SomeClass
// This is a method that is used and hooked by the tweak.
- (id)someMethod:(id)someArg {
// some stuff
return somethingOtherThanOrig;
}
%end
static void MyFunction() {
// I want to call the original implementation but it is not possible to do that after %init.
id value = [SomeClassInstance someMethod:NULL];
// Maybe something like this?
%origff(SomeClassInstance, "someMethod:", NULL);
}
%ctor {
%init;
MyFunction();
}
In CCLoader I have %subclass that implements two protocols, a custom one and one defined in SpringBoardUIServices. That subclass (sometimes) crashes in the constructor function. I'm using the latest theos. Here's the crash log, and the %subclass is also in that project: JonasGessner/CCLoader#12
The %property declaration breaks depending on the position of the asterisk in the declaration, ex. %property (copy) NSObject* myObj
doesn't work but %property (copy) NSObject *myObj
does.
%hook UIView
%property (copy) NSObject* myObj;
%end
perl $THEOS/bin/logos.pl test.xm
to get the logos output.%property (copy) NSObject *myObj
, save the fileThe property declaration is left unprocessed in the output file.
The property declaration should be preprocessed into associated object calls, but isn't if the asterisk isn't directly adjacent to the object name (NSObject * myObj
also fails).
Output of the first perl command:
#line 1 "/Users/thomasfinch/Downloads/test.xm"
#include <substrate.h>
#if defined(__clang__)
#if __has_feature(objc_arc)
#define _LOGOS_SELF_TYPE_NORMAL __unsafe_unretained
#define _LOGOS_SELF_TYPE_INIT __attribute__((ns_consumed))
#define _LOGOS_SELF_CONST const
#define _LOGOS_RETURN_RETAINED __attribute__((ns_returns_retained))
#else
#define _LOGOS_SELF_TYPE_NORMAL
#define _LOGOS_SELF_TYPE_INIT
#define _LOGOS_SELF_CONST
#define _LOGOS_RETURN_RETAINED
#endif
#else
#define _LOGOS_SELF_TYPE_NORMAL
#define _LOGOS_SELF_TYPE_INIT
#define _LOGOS_SELF_CONST
#define _LOGOS_RETURN_RETAINED
#endif
@class UIView;
#line 1 "/Users/thomasfinch/Downloads/test.xm"
%property (copy) NSObject* myObj;
#line 6 "/Users/thomasfinch/Downloads/test.xm"
Output of the second perl command (after change):
#line 1 "/Users/thomasfinch/Downloads/test.xm"
#include <substrate.h>
#if defined(__clang__)
#if __has_feature(objc_arc)
#define _LOGOS_SELF_TYPE_NORMAL __unsafe_unretained
#define _LOGOS_SELF_TYPE_INIT __attribute__((ns_consumed))
#define _LOGOS_SELF_CONST const
#define _LOGOS_RETURN_RETAINED __attribute__((ns_returns_retained))
#else
#define _LOGOS_SELF_TYPE_NORMAL
#define _LOGOS_SELF_TYPE_INIT
#define _LOGOS_SELF_CONST
#define _LOGOS_RETURN_RETAINED
#endif
#else
#define _LOGOS_SELF_TYPE_NORMAL
#define _LOGOS_SELF_TYPE_INIT
#define _LOGOS_SELF_CONST
#define _LOGOS_RETURN_RETAINED
#endif
@class UIView;
#line 1 "/Users/thomasfinch/Downloads/test.xm"
static char _logos_property_key$_ungrouped$UIView$myObj;__attribute__((used)) static NSObject * _logos_method$_ungrouped$UIView$myObj$(UIView* __unused self, SEL __unused _cmd){ return objc_getAssociatedObject(self, &_logos_property_key$_ungrouped$UIView$myObj); }__attribute__((used)) static void _logos_method$_ungrouped$UIView$setMyObj$(UIView* __unused self, SEL __unused _cmd, NSObject * arg){ objc_setAssociatedObject(self, &_logos_property_key$_ungrouped$UIView$myObj, arg, OBJC_ASSOCIATION_COPY); }
static __attribute__((constructor)) void _logosLocalInit() {
{Class _logos_class$_ungrouped$UIView = objc_getClass("UIView"); { class_addMethod(_logos_class$_ungrouped$UIView, @selector(myObj), (IMP)&_logos_method$_ungrouped$UIView$myObj$, [[NSString stringWithFormat:@"%s@:", @encode(NSObject *)] UTF8String]);class_addMethod(_logos_class$_ungrouped$UIView, @selector(setMyObj:), (IMP)&_logos_method$_ungrouped$UIView$setMyObj$, [[NSString stringWithFormat:@"v@:%s", @encode(NSObject *)] UTF8String]);} } }
#line 6 "/Users/thomasfinch/Downloads/test.xm"
This happens regardless of the class being hooked, the object type, or the property type.
Operating System: Mac OS 10.12.3
Toolchain Version: Not quite sure what this means, but using theos commit e94545975dda0c669bbcbed1eba0d7382ba49389
(current master head), clang 800.0.42.1
SDK Version: iOS 10.2 SDK, Xcode 8.2.1
Hi there,
I'm not sure if this is the right place to ask; sorry.
I want to ask, can multiple conditional %init work together in one %ctor? For example,
I have some function hooks as a group, I only want to init this group for certain condition, and other non-grouped hooks get still inited.
I have below code sample:
%ctor {
%init();
if (metCondition) {
%init(SomeGroup)
}
}
Is this allowed? From what I tested, it seems %init(SomeGroup) will override %init(), meaning those ungrouped hooks is not initialized after %init(SomeGroup) is called.
If I am wrong, how can I achieve my goal? Thanks
%hookf
so far allows hooking functions known at compile time or exported at runtime:
%hookf(FILE *, fopen, const char *path, const char *mode) { ...
%hookf(BOOL, "_MGGetBoolAnswer", CFStringRef string) { ...
Taking a runtime value as a function address would allow hooking non-exported functions, simplifying the following example:
void(*old_myFun)(void);
void myFun(void) {
old_myFun();
}
%ctor {
MSHookFunction((void *)unslide(0x123456789), (void *)myFun, (void **)&old_myFun);
}
into:
%hookf(void, myFun, void) {
%orig;
}
%ctor {
%init(myFun = unslide(0x1234567890));
}
The code:
%property (nonatomic) BOOL newProperty;
will throw the warning:
warning: no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed
This warning is unnecessary. The normal objective-c compiler will not throw any warning for:
@property (nonatomic) BOOL newProperty;
example : self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + 1 - (1 * 2), [%c(UIScreen) mainScreen].bounds.size.width, self.frame.size.height);
Compiler returns expression error
Compiles with no problems
==> Compiling Tweak.xm (armv7)…
Tweak.xm:11:85: error: expected expression self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + 1 - (1 * 2), [%c(UIScreen) mainScreen].b...
^
Tweak.xm:11:88: error: unexpected interface name 'UIScreen': expected expression self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + 1 - (1 * 2), [%c(UIScreen) mainScreen].b...
Compiles fine without the brackets around (1 * 2), but obviously will not return the value needed.
Changing the positioning of the bracketed math does not overcome the error
Does not work with objc_getClass
either
Adding an interface for the class will avoid the issue.
Compiling using linux toolchain, 9.2 sdk, most recent theos pull
Not really a bug or anything, just a small feature request.
Would be cool if adding a %property
to a class automatically created an @interface
with the property.
It should be possible to pass arbitrary expressions into a logos macro and have it dedupe and cache them.
Existing %c(classname)
expressions could be converted to use this functionality internally.
Additionally, components within theos itself could use this functionality to trim some of the work they perform (would use this for my internal generator)
Proposed syntax:
%cached(x)
yields a C rvalue that references the result of the computation x
as executed from inside %init;
(or the automatically generated initializer if none exists)
Potential extensions:
Nested cached expressions could be supported to eliminate duplicate work inside of cached expressions themselves. Further, cached expressions that are used only as a subexpression of other cached expressions could be optimized not to escape the scope of %init
Lazy initialization via alternate syntax (with/without thread safety?). Would allow syntax like this to workaround glacial apis:
%cached([[[NSCharacterSet characterSetWithCharactersInString:@"_1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"] invertedSet] retain], lazy)
Hi,
So I just stumbled upon this bug:
%hook ClassToBeHooked
%property (nonatomic, retain) MyClass *baseProperty;
- (void)methodThatAlwaysShouldBeHooked {
%orig;
...
}
%group ConditionalGroup
%property (nonatomic, retain) MyClass *conditionalProperty;
- (void)conditionalMethod {
%orig;
self.conditionalProperty = ...
...
}
%end
%end
%ctor {
%init();
if ([%c(ClassToBeHooked) instancesRespondToSelector:@selector(conditionalMethod:)])
%init(ConditionalGroup);
}
}
This does not work. It computes error messages when building.
==> Compiling Tweak.xm (arm64)…
Tweak.xm:157:917: error: use of undeclared identifier '_logos_class$ConditionalGroup$ClassToBeHooked'; did you mean '_logos_class$_ungrouped$ClassToBeHooked'?
..._typeEncoding); } { char _typeEncoding[1024]; sprintf(_typeEncoding, "%s@:", @encode(SAViewController *)); class_addMethod(_logos_class$ConditionalGroup$ClassToBeHooked, @selector(conditionalProperty), (IMP)&_logos_m...
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_logos_class$_ungrouped$ClassToBeHooked
Tweak.xm:157:16: note: '_logos_class$_ungrouped$ClassToBeHooked' declared here
{Class _logos_class$_ungrouped$ClassToBeHooked = objc_getClass("ClassToBeHooked"); MSHookMessageEx(_logos_class$_ungrouped$ClassToBeHooked, @selector(grabberTongueWillPresent:), (IMP)&_logos_method$_ungrouped...
^
Tweak.xm:157:1164: error: use of undeclared identifier '_logos_class$ConditionalGroup$ClassToBeHooked'; did you mean '_logos_class$_ungrouped$ClassToBeHooked'?
..._typeEncoding); sprintf(_typeEncoding, "v@:%s", @encode(SAViewController *)); class_addMethod(_logos_class$ConditionalGroup$ClassToBeHooked, @selector(setConditionalProperty:), (IMP)&_logos_method$ConditionalGroup$Cl...
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_logos_class$_ungrouped$ClassToBeHooked
Tweak.xm:157:16: note: '_logos_class$_ungrouped$ClassToBeHooked' declared here
{Class _logos_class$_ungrouped$ClassToBeHooked = objc_getClass("ClassToBeHooked"); MSHookMessageEx(_logos_class$_ungrouped$ClassToBeHooked, @selector(grabberTongueWillPresent:), (IMP)&_logos_method$_ungrouped...
^
2 errors generated.
It can be solved by putting the %property
in the original %hook
'ed section and not within the conditional group.
When adding a %property to a hooked class the compiler throws an error, ex:
For:
@interface SBIconController
@property (nonatomic,retain) NSMutableArray *hiddenIcons;
.....
@end
%hook SBIconController
%property (nonatomic,retain) NSMutableArray *hiddenIcons;
....
%end
Result:
error: no matching function for call to 'objc_getAssociatedObject' __attribute__((used)) static NSMutableArray * _logos_method$_ungrouped$SBIconController$hiddenIcons(SBIconController * __unused self, SEL __unused _cmd) { return (NSMutableArray *)objc_getAssociatedObject(self, _logos_method$_ungrouped$SBIconController$hiddenIcons); }; __attribute...
%config(generator=internal);
%hook blah
- (void)thing {
// something...
}
%end
logos.pl blah.xm
An internal Logos error occurs.
The syntax is processed successfully.
blah.xm: error: generator does not implement Method::initializers
N/A
Operating System: OS X 10.11.3
Toolchain Version: Xcode 7.2
SDK Version: iOS 9.2
There's a usage of HBLogDebug
in bin/lib/Logos/Generator/Base/Method.pm which is defined in theos/headers/HBLog.h.
If Logos is truly meant to be decoupled, this logging facility has to be resolved in another manner, either as a builtin definition or a function name passed as a flag when running logos.pl. It should be taken into account that HBLogDebug
is a macro that will end up expanding to os_log_with_type
or CFLog
.
Code such as
%subclass FAFloatyFolderView : FACommonFolderView %end %subclass FACommonFolderView : SBFolderView %end
will generate output:
Class _logos_class$_ungrouped$FACommonFolderView = objc_getClass("FACommonFolderView"); Class _logos_class$_ungrouped$FAFloatyFolderView = objc_allocateClassPair(_logos_class$_ungrouped$FACommonFolderView, "FAFloatyFolderView", 0); Class _logos_class$_ungrouped$FACommonFolderView = objc_allocateClassPair(_logos_class$_ungrouped$SBFolderView, "FACommonFolderView", 0);
Therefore causing FAFloatyFolderView
to be initialized without a superclass, and generating a redundant call to objc_getClass()
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.