m (→Late hooking) |
m (Mail filter.) |
||
(33 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
Find me on saurik's [[IRC]] server, [https://twitter.com/uroboro845 Twitter], [http://www.reddit.com/user/uroboro Reddit], [https://github.com/uroboro Github], [http://stackoverflow.com/users/1429562/uroboro StackOverflow]. | Find me on saurik's [[IRC]] server, [https://twitter.com/uroboro845 Twitter], [http://www.reddit.com/user/uroboro Reddit], [https://github.com/uroboro Github], [http://stackoverflow.com/users/1429562/uroboro StackOverflow] or send me an [mailto:[email protected] email]. | ||
Made [https://github.com/uroboro/UnlockEvents UnlockEvents] and [https://github.com/uroboro/FlipNC FlipNC]. | Made [https://github.com/uroboro/UnlockEvents UnlockEvents] and [https://github.com/uroboro/FlipNC FlipNC]. | ||
Line 7: | Line 7: | ||
Some [[NIC]] templates [https://github.com/uroboro/nicTemplates here]. | Some [[NIC]] templates [https://github.com/uroboro/nicTemplates here]. | ||
And a repository there: uroboro.github.io/repo. | And a repository there: [https://cydia.saurik.com/api/share#?source=https://uroboro.github.io/repo/ uroboro.github.io/repo]. | ||
'''DISCLAIMER: All code written in this page is to be considered experimental and untested. The author shall not be held responsible or liable for any undesired consequences, including, but not limited to, data loss, property damage, time travel, the singularity, suffered by you as a result of any error in such code. You also agree that you will not use these code snippets for any purposes prohibited by United States law, including, without limitation, the development, design, manufacture, or production of nuclear, missile, or chemical or biological weapons.''' | |||
== "Interesting" links == | == "Interesting" links == | ||
* [https://developer.apple.com/library/ | * [https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html Object ownership]. | ||
* [https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html Memory management]. | |||
* [https://www.reddit.com/r/jailbreak/comments/3bcwdk/tutorial_lets_secure_ssh_a_bit_more/ Securing SSH] - [https://bitbucket.org/lordscotland/sshconnect/overview SSHConnect]. | |||
== | == Hooking everything == | ||
While previously it was possible to provide no filter or an empty one, this is no longer the case, both by [[Cydia Substrate]] requiring one and not it being empty. So the solution is based on another requirement that is not very documented: Cydia Substrate will only hook binaries that are linked with [[Security.framework]]. The following filter will suffice for this purpose but please reduce the hooking target of your tweak as much as possible. | |||
{| | |||
|+ com.your.tweak.plist | |||
|- valign="top" | |||
| | |||
{{Collapse|1=<source lang="javascript">{ | |||
Filter = { | |||
Bundles = ( | |||
"com.apple.Security" | |||
) | |||
} | |||
} | |||
</source>|2=NeXTSTEP style}} | |||
|| | |||
{{Collapse|1=<source lang="xml"> | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
<plist version="1.0"> | |||
<dict> | |||
<key>Filter</key> | |||
<dict> | |||
<key>Bundles</key> | |||
<array> | |||
<string>com.apple.Security</string> | |||
</array> | |||
</dict> | |||
</dict> | |||
</plist> | |||
</source>|2=XML style}} | |||
|} | |||
== Late hooking == | |||
=== | === UI usage === | ||
If you need to use UI elements, you have to wait until the application is ready. | |||
==== Using callbacks ==== | |||
<source lang="objc"> | |||
static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { | static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { | ||
// UI is available, use UIKit here | |||
#if BEFORE_IOS_8 | |||
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Alert" | |||
message:@"This is an alert." | |||
delegate:nil | |||
cancelButtonTitle:@"I'm ok with this" | |||
otherButtonTitles:nil]; | |||
[alert show]; | |||
#else | |||
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Alert" | |||
message:@"This is an alert." | |||
preferredStyle:UIAlertControllerStyleAlert]; | |||
[alert addAction:[UIAlertAction actionWithTitle:@"I'm ok with this" | |||
style:UIAlertActionStyleDefault | |||
handler:^(UIAlertAction * action) {}]]; | |||
[[UIWindow keyWindow].rootViewController presentViewController:alert animated:YES completion:^{}]; | |||
#endif | |||
} | } | ||
static void * observer = NULL; | |||
%ctor { | %ctor { | ||
CFNotificationCenterAddObserver( | |||
CFNotificationCenterGetLocalCenter(), | |||
&observer, | |||
notificationCallback, | |||
(CFStringRef)UIApplicationDidFinishLaunchingNotification, | |||
NULL, | |||
CFNotificationSuspensionBehaviorCoalesce | |||
); | |||
} | |||
// | // Remove observer upon unloading the dylib | ||
%dtor { | |||
CFNotificationCenterRemoveObserver( | |||
CFNotificationCenterGetLocalCenter(), | |||
&observer, | |||
(CFStringRef)UIApplicationDidFinishLaunchingNotification, | |||
NULL | |||
); | |||
} | } | ||
</source> | </source> | ||
=== | ==== Using blocks ==== | ||
<source lang="objc"> | <source lang="objc"> | ||
static id observer; | |||
%ctor { | |||
observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification | |||
object:nil queue:[NSOperationQueue mainQueue] | |||
usingBlock:^(NSNotification *notification) { | |||
// UI is available, use UIKit here | |||
#if BEFORE_IOS_8 | |||
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Alert" | |||
message:@"This is an alert." | |||
delegate:nil | |||
cancelButtonTitle:@"I'm ok with this" | |||
otherButtonTitles:nil]; | |||
@ | [alert show]; | ||
#else | |||
@ | UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Alert" | ||
message:@"This is an alert." | |||
preferredStyle:UIAlertControllerStyleAlert]; | |||
[alert addAction:[UIAlertAction actionWithTitle:@"I'm ok with this" | |||
style:UIAlertActionStyleDefault | |||
handler:^(UIAlertAction * action) {}]]; | |||
[[UIWindow keyWindow].rootViewController presentViewController:alert animated:YES completion:^{}]; | |||
#endif | |||
} | |||
]; | |||
} | } | ||
// Remove observer upon unloading the dylib | |||
%dtor { | |||
[[NSNotificationCenter defaultCenter] removeObserver:observer]; | |||
} | } | ||
</source> | |||
=== Dynamic bundle loading === | |||
Same applies if a class you want to hook is dynamically loaded by a bundle. | |||
''To do: read [https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/dyld.3.html this] and make this procedure more robust.'' | |||
==== Using callbacks ==== | |||
<source lang="objc"> | <source lang="objc"> | ||
static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { | |||
if ([((NSDictionary *)userInfo)[NSLoadedClasses] containsObject:@"targetClass"]) { | |||
// Target class has been loaded | |||
} | |||
} | } | ||
%ctor { | %ctor { | ||
CFNotificationCenterAddObserver( | |||
CFNotificationCenterGetLocalCenter(), NULL, | |||
notificationCallback, | |||
(CFStringRef)NSBundleDidLoadNotification, | |||
NULL, CFNotificationSuspensionBehaviorCoalesce); | |||
} | } | ||
</source> | </source> | ||
==== Using blocks ==== | |||
<source lang="objc"> | <source lang="objc"> | ||
static id observer; | |||
%ctor { | |||
observer = [[NSNotificationCenter defaultCenter] addObserverForName:NSBundleDidLoadNotification | |||
object:nil queue:[NSOperationQueue mainQueue] | |||
usingBlock:^(NSNotification *notification) { | |||
if ([notification.userInfo[NSLoadedClasses] containsObject:@"targetClass"]) { | |||
// Target class has been loaded | |||
} | |||
} | |||
]; | |||
} | } | ||
% | //if a destructor existed or you don't need to track the notification anymore | ||
[[NSNotificationCenter defaultCenter] | %dtor { | ||
[[NSNotificationCenter defaultCenter] removeObserver:observer]; | |||
} | } | ||
</source> | </source> | ||
Line 290: | Line 251: | ||
{| class="wikitable" | {| class="wikitable" | ||
|+ com.your.tweak.plist | |+ com.your.tweak.plist | ||
! | ! NeXTSTEP style !! XML style | ||
|- valign="top" | |- valign="top" | ||
| | | | ||
<source lang="javascript">{ | <source lang="javascript">{ | ||
entry = { | |||
cell = PSSwitchCell; | |||
defaults = "com.your.tweak"; | |||
label = "Your Tweak"; | |||
key = enabled; | |||
default = 1; | |||
icon = "/Applications/Preferences.app/[email protected]"; | |||
PostNotification = "com.your.tweak/preferences.changed"; | |||
}; | |||
} | } | ||
</source> | </source> | ||
Line 336: | Line 297: | ||
{| | {| | ||
|+ com.your.tweak.plist | |+ com.your.tweak.plist | ||
! | ! NeXTSTEP style !! XML style | ||
|- valign="top" | |- valign="top" | ||
| | | | ||
<source lang="javascript">{ | <source lang="javascript">{ | ||
entry = { | |||
cell = PSSwitchCell; | |||
defaults = "com.your.tweak"; | |||
label = "Your Tweak"; | |||
key = enabled; | |||
default = 1; | |||
icon = "/Applications/Preferences.app/[email protected]"; | |||
PostNotification = "com.your.tweak/preferences.changed"; | |||
}; | |||
} | } | ||
</source> | </source> | ||
Line 377: | Line 338: | ||
</plist> | </plist> | ||
</source> | </source> | ||
|} | |||
Maybe collapsing? | |||
{| | |||
|+ com.your.tweak.plist | |||
|- valign="top" | |||
| | |||
{{Collapse|1=<source lang="javascript">{ | |||
entry = { | |||
cell = PSSwitchCell; | |||
defaults = "com.your.tweak"; | |||
label = "Your Tweak"; | |||
key = enabled; | |||
default = 1; | |||
icon = "/Applications/Preferences.app/[email protected]"; | |||
PostNotification = "com.your.tweak/preferences.changed"; | |||
}; | |||
} | |||
</source>|2=NeXTSTEP style}} | |||
|| | |||
{{Collapse|1=<source lang="xml"> | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
<plist version="1.0"> | |||
<dict> | |||
<key>entry</key> | |||
<dict> | |||
<key>cell</key> | |||
<string>PSSwitchCell</string> | |||
<key>defaults</key> | |||
<string>com.your.tweak</string> | |||
<key>label</key> | |||
<string>Your Tweak</string> | |||
<key>key</key> | |||
<string>enabled</string> | |||
<key>default</key> | |||
<true/> | |||
<key>icon</key> | |||
<string>/Applications/Preferences.app/[email protected]</string> | |||
<key>PostNotification</key> | |||
<string>com.your.tweak/preferences.changed</string> | |||
</dict> | |||
</dict> | |||
</plist> | |||
</source>|2=XML style}} | |||
|} | |} |
Latest revision as of 05:06, 30 January 2018
Find me on saurik's IRC server, Twitter, Reddit, Github, StackOverflow or send me an email.
Made UnlockEvents and FlipNC.
If you are looking for notifications within a process, give NotificationExplorer a look.
And a repository there: uroboro.github.io/repo.
DISCLAIMER: All code written in this page is to be considered experimental and untested. The author shall not be held responsible or liable for any undesired consequences, including, but not limited to, data loss, property damage, time travel, the singularity, suffered by you as a result of any error in such code. You also agree that you will not use these code snippets for any purposes prohibited by United States law, including, without limitation, the development, design, manufacture, or production of nuclear, missile, or chemical or biological weapons.
"Interesting" links
Hooking everything
While previously it was possible to provide no filter or an empty one, this is no longer the case, both by Cydia Substrate requiring one and not it being empty. So the solution is based on another requirement that is not very documented: Cydia Substrate will only hook binaries that are linked with Security.framework. The following filter will suffice for this purpose but please reduce the hooking target of your tweak as much as possible.
|
|
Late hooking
UI usage
If you need to use UI elements, you have to wait until the application is ready.
Using callbacks
static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
// UI is available, use UIKit here
#if BEFORE_IOS_8
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Alert"
message:@"This is an alert."
delegate:nil
cancelButtonTitle:@"I'm ok with this"
otherButtonTitles:nil];
[alert show];
#else
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Alert"
message:@"This is an alert."
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"I'm ok with this"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {}]];
[[UIWindow keyWindow].rootViewController presentViewController:alert animated:YES completion:^{}];
#endif
}
static void * observer = NULL;
%ctor {
CFNotificationCenterAddObserver(
CFNotificationCenterGetLocalCenter(),
&observer,
notificationCallback,
(CFStringRef)UIApplicationDidFinishLaunchingNotification,
NULL,
CFNotificationSuspensionBehaviorCoalesce
);
}
// Remove observer upon unloading the dylib
%dtor {
CFNotificationCenterRemoveObserver(
CFNotificationCenterGetLocalCenter(),
&observer,
(CFStringRef)UIApplicationDidFinishLaunchingNotification,
NULL
);
}
Using blocks
static id observer;
%ctor {
observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification
object:nil queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notification) {
// UI is available, use UIKit here
#if BEFORE_IOS_8
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Alert"
message:@"This is an alert."
delegate:nil
cancelButtonTitle:@"I'm ok with this"
otherButtonTitles:nil];
[alert show];
#else
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Alert"
message:@"This is an alert."
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"I'm ok with this"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {}]];
[[UIWindow keyWindow].rootViewController presentViewController:alert animated:YES completion:^{}];
#endif
}
];
}
// Remove observer upon unloading the dylib
%dtor {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}
Dynamic bundle loading
Same applies if a class you want to hook is dynamically loaded by a bundle.
To do: read this and make this procedure more robust.
Using callbacks
static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
if ([((NSDictionary *)userInfo)[NSLoadedClasses] containsObject:@"targetClass"]) {
// Target class has been loaded
}
}
%ctor {
CFNotificationCenterAddObserver(
CFNotificationCenterGetLocalCenter(), NULL,
notificationCallback,
(CFStringRef)NSBundleDidLoadNotification,
NULL, CFNotificationSuspensionBehaviorCoalesce);
}
Using blocks
static id observer;
%ctor {
observer = [[NSNotificationCenter defaultCenter] addObserverForName:NSBundleDidLoadNotification
object:nil queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notification) {
if ([notification.userInfo[NSLoadedClasses] containsObject:@"targetClass"]) {
// Target class has been loaded
}
}
];
}
//if a destructor existed or you don't need to track the notification anymore
%dtor {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}
Other Stuff
Similar Wanted Pages:
Test Zone
Wondering what looks better:
To "wikitable"...
NeXTSTEP style | XML style |
---|---|
{
entry = {
cell = PSSwitchCell;
defaults = "com.your.tweak";
label = "Your Tweak";
key = enabled;
default = 1;
icon = "/Applications/Preferences.app/[email protected]";
PostNotification = "com.your.tweak/preferences.changed";
};
}
|
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>entry</key>
<dict>
<key>cell</key>
<string>PSSwitchCell</string>
<key>defaults</key>
<string>com.your.tweak</string>
<key>label</key>
<string>Your Tweak</string>
<key>key</key>
<string>enabled</string>
<key>default</key>
<true/>
<key>icon</key>
<string>/Applications/Preferences.app/[email protected]</string>
<key>PostNotification</key>
<string>com.your.tweak/preferences.changed</string>
</dict>
</dict>
</plist>
|
or not to "wikitable"...
NeXTSTEP style | XML style |
---|---|
{
entry = {
cell = PSSwitchCell;
defaults = "com.your.tweak";
label = "Your Tweak";
key = enabled;
default = 1;
icon = "/Applications/Preferences.app/[email protected]";
PostNotification = "com.your.tweak/preferences.changed";
};
}
|
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>entry</key>
<dict>
<key>cell</key>
<string>PSSwitchCell</string>
<key>defaults</key>
<string>com.your.tweak</string>
<key>label</key>
<string>Your Tweak</string>
<key>key</key>
<string>enabled</string>
<key>default</key>
<true/>
<key>icon</key>
<string>/Applications/Preferences.app/[email protected]</string>
<key>PostNotification</key>
<string>com.your.tweak/preferences.changed</string>
</dict>
</dict>
</plist>
|
Maybe collapsing?
|
|