|
|
(20 intermediate revisions by 6 users not shown) |
Line 1: |
Line 1: |
| Logos is a component of the [[Theos]] development suite that allows method hooking code to be written easily and clearly, using a set of special preprocessor directives.
| | {{soft redirect|https://theos.dev/docs/logos}} |
|
| |
|
| == Overview ==
| | This article is obsolete, and has been replaced by the [https://theos.dev/docs/logos theos.dev website]. |
|
| |
|
| The syntax provided by Logos greatly simplifies the development of MobileSubstrate extensions ("tweaks") which can hook other methods throughout the OS.
| | If you need historical installation instructions, you can find the last version of this article [https://iphonedev.wiki/index.php?title=Logos&oldid=5734 here]. |
| In this context, "method hooking" refers to a technique used to replace or modify methods of classes found in other applications on the phone.
| |
| | |
| == Getting Logos ==
| |
| | |
| Logos is distributed with [[Theos]], and you can use Logos' syntax in any Theos-built project without any extra setup. For more information about Theos, visit [[Theos|its page]].
| |
| | |
| == List of Logos Directives ==
| |
| | |
| === Block-level ===
| |
| | |
| The directives in this category open a block of code which must be closed by an %end directive (shown below). These should not exist within functions or methods.
| |
| | |
| ==== %group ====
| |
| | |
| <source lang="logos">
| |
| %group Groupname
| |
| </source>
| |
| | |
| Begin a hook group (for conditional initialization or code organization) with the name ''Groupname''. All ungrouped hooks are in the implicit "_ungrouped" group.
| |
| | |
| | |
| Grouping can be used to manage backwards compatibility with older code:
| |
| | |
| <source lang="logos">
| |
| %group iOS8
| |
| %hook IOS8_SPECIFIC_CLASS
| |
| // your code here
| |
| %end // end hook
| |
| %end // end group ios8
| |
| | |
| %group iOS9
| |
| %hook IOS9_SPECIFIC_CLASS
| |
| // your code here
| |
| %end // end hook
| |
| %end // end group ios9
| |
| | |
| | |
| %ctor {
| |
| if (kCFCoreFoundationVersionNumber > 1200) {
| |
| %init(iOS9);
| |
| } else {
| |
| %init(iOS8);
| |
| }
| |
| }
| |
| </source>
| |
| | |
| ==== %hook ====
| |
| | |
| <source lang="logos">
| |
| %hook Classname
| |
| </source>
| |
| | |
| Open a hook block for the class named ''Classname''.
| |
| | |
| Can be inside a <tt>%group</tt> block.
| |
| | |
| Here's a trivial example:
| |
| | |
| <source lang="logos">
| |
| %hook SBApplicationController
| |
| -(void)uninstallApplication:(SBApplication *)application {
| |
| NSLog(@"Hey, we're hooking uninstallApplication:!");
| |
| %orig; // Call the original implementation of this method
| |
| return;
| |
| }
| |
| %end
| |
| </source>
| |
| | |
| ==== %new ====
| |
| | |
| <source lang="logos">
| |
| %new
| |
| %new(signature)
| |
| </source>
| |
| | |
| Add a new method to a hooked class or subclass. ''signature'' is the Objective-C type encoding for the new method; if it is omitted, one will be generated.
| |
| | |
| Can be inside a <tt>%group</tt> block.
| |
| | |
| ==== %subclass ====
| |
| | |
| <source lang="logos">
| |
| %subclass Classname: Superclass <Protocol list>
| |
| </source>
| |
| | |
| Subclass block - the class is created at runtime and populated with methods. ivars are not yet supported (use associated objects).
| |
| The %new specifier is needed for a method that doesn't exist in the superclass.
| |
| To instantiate an object of the new class, you can use the %c operator.
| |
| | |
| Can be inside a <tt>%group</tt> block.
| |
| | |
| Here's an example:
| |
| | |
| <source lang="logos">
| |
| %subclass MyObject : NSObject
| |
| | |
| - (id)init {
| |
| self = %orig;
| |
| [self setSomeValue:@"value"];
| |
| return self;
| |
| }
| |
| | |
| //the following two new methods act as `@property (nonatomic, retain) id someValue;`
| |
| %new
| |
| - (id)someValue {
| |
| return objc_getAssociatedObject(self, @selector(someValue));
| |
| }
| |
| | |
| %new
| |
| - (void)setSomeValue:(id)value {
| |
| objc_setAssociatedObject(self, @selector(someValue), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
| |
| }
| |
| | |
| %end
| |
| | |
| %ctor {
| |
| MyObject *myObject = [[%c(MyObject) alloc] init];
| |
| NSLog(@"myObject: %@", [myObject someValue]);
| |
| }
| |
| </source>
| |
| | |
| ==== %end ====
| |
| | |
| <source lang="logos">
| |
| %end
| |
| </source>
| |
| | |
| Close a group/hook/subclass block.
| |
| | |
| === Top level ===
| |
| | |
| The directives in this category should not exist within a group/hook/subclass block.
| |
| | |
| ==== %config ====
| |
| | |
| <source lang="logos">
| |
| %config(X=Y);
| |
| </source>
| |
| | |
| Set a logos configuration flag.
| |
| | |
| ===== Configuration Flags =====
| |
| | |
| * generator
| |
| **; MobileSubstrate
| |
| **: generate code that uses [[MobileSubstrate]] for hooking.
| |
| **; internal
| |
| **: generate code that uses only internal Objective-C runtime methods for hooking.
| |
| * warnings
| |
| **; none
| |
| **: suppress all warnings
| |
| **; default
| |
| **: non-fatal warnings
| |
| **; error
| |
| **: make all warnings fatal
| |
| * dump
| |
| **; yaml
| |
| **: dump the internal parse tree in YAML format
| |
| **; <strike>perl</strike>
| |
| **: <strike>dump the internal parse tree in a format suitable for evaluation as perl source.</strike><br /> dump to the perl source feature is removed since [https://github.com/DHowett/theos/commit/a05354a7b9839a5dce48f7c07114f30dd195b537 this commit].
| |
| | |
| ==== %ctor ====
| |
| | |
| <source lang="logos">
| |
| %ctor { … }
| |
| </source>
| |
| | |
| Generate an anonymous constructor (of default priority).
| |
| | |
| === Function level ===
| |
| | |
| The directives in this category should only exist within a function block.
| |
| | |
| ==== %init ====
| |
| | |
| <source lang="logos">
| |
| %init;
| |
| %init([<class>=<expr>, …]);
| |
| %init(Group[, [+|-]<class>=<expr>, …]);
| |
| </source>
| |
| | |
| Initialize a group (or the default group). Passing no group name will initialize "_ungrouped", and passing class=expr arguments will substitute the given expressions for those classes at initialization time. The + sigil (as in class methods in Objective-C) can be prepended to the classname to substitute an expression for the metaclass. If not specified, the sigil defaults to -, to substitute the class itself. If not specified, the metaclass is derived from the class.
| |
| | |
| Usage:
| |
| <source lang="logos">
| |
| | |
| %group SomeGroup
| |
| %hook SomeClass
| |
| -(id)init {
| |
| return %orig;
| |
| }
| |
| %end
| |
| %end
| |
| | |
| %ctor {
| |
| %init(SomeGroup,SomeClass=objc_getClass("OtherClass"));
| |
| }
| |
| </source>
| |
| | |
| ==== %class ====
| |
| | |
| <source lang="logos">
| |
| %class Class;
| |
| </source>
| |
| | |
| {{warning|<tt>%class</tt> is deprecated. Do not use it in new code.}}
| |
| | |
| Forward-declare a class. Outmoded by %c, but still exists. Creates a $Class variable, and initializes it with the "_ungrouped" group.
| |
| | |
| ==== %c ====
| |
| | |
| <source lang="logos">
| |
| %c([+|-]Class)
| |
| </source>
| |
| | |
| Evaluates to <tt>Class</tt> at runtime. If the + sigil is specified, it evaluates to MetaClass instead of Class. If not specified, the sigil defaults to -, evaluating to Class.
| |
| | |
| ==== %orig ====
| |
| | |
| <source lang="logos">
| |
| %orig
| |
| %orig(arg1, …)
| |
| </source>
| |
| | |
| Call the original hooked method. Doesn't function in a <tt>%new</tt>'d method. Works in subclasses, strangely enough, because MobileSubstrate will generate a supercall closure at hook time. (If the hooked method doesn't exist in the class we're hooking, it creates a stub that just calls the superclass implementation.) args is passed to the original function - don't include <tt>self</tt> and <tt>_cmd</tt>, Logos does this for you.
| |
| | |
| ==== %log ==== | |
| | |
| <source lang="logos">
| |
| %log;
| |
| %log([(<type>)<expr>, …]);
| |
| </source>
| |
| | |
| Dump the method arguments to syslog. Typed arguments included in <tt>%log</tt> will be logged as well.
| |
| | |
| == File Extensions for Logos ==
| |
| | |
| {| class="wikitable"
| |
| |-
| |
| ! Extension
| |
| ! Process order
| |
| |-
| |
| | .x
| |
| | will be processed by Logos, then preprocessed and compiled as objective-c.
| |
| |-
| |
| | .xm
| |
| | will be processed by Logos, then preprocessed and compiled as objective-c++.
| |
| |-
| |
| | .xi
| |
| | will be preprocessed as objective-c first, then Logos will process the result, and then it will be compiled.
| |
| |-
| |
| | .xmi
| |
| | will be preprocessed as objective-c++ first, then Logos will process the result, and then it will be compiled.
| |
| |}
| |
| | |
| xi or xmi files can use Logos directives in #define macros.
| |
| | |
| == Splitting Logos Hooking Code Across Multiple Files ==
| |
| | |
| By default, the Logos pre-processor will only process one .xm file at build time. However, it is possible to split the Logos hooking code into multiple files.<br>
| |
| First, the main file has to be renamed to an .xmi file. Then, other .xm files can be included in it using the #include directive. The Logos pre-processor will add those files to the main file before processing it.
| |
| | |
| == logify.pl ==
| |
| | |
| You can use logify.pl to create a Logos source file from a header file that will log all of the functions of that header file. Here is an example of a very simple Logos tweak generated by logify.pl
| |
| | |
| Given a header file:
| |
| | |
| <source lang="logos">
| |
| @interface SSDownloadAsset : NSObject
| |
| - (NSString *)finalizedPath;
| |
| - (NSString *)downloadPath;
| |
| - (NSString *)downloadFileName;
| |
| + (id)assetWithURL:(id)url type:(int)type;
| |
| - (id)initWithURLRequest:(id)urlrequest type:(int)type;
| |
| - (id)initWithURLRequest:(id)urlrequest;
| |
| - (id)_initWithDownloadMetadata:(id)downloadMetadata type:(id)type;
| |
| @end
| |
| </source>
| |
| | |
| You can find logify.pl at $THEOS/bin/logify.pl and you would use it as so:
| |
| | |
| <source lang="bash">
| |
| $THEOS/bin/logify.pl ./SSDownloadAsset.h
| |
| </source>
| |
| | |
| The resulting output should be:
| |
| | |
| <source lang="logos">
| |
| %hook SSDownloadAsset
| |
| - (NSString *)finalizedPath { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }
| |
| - (NSString *)downloadPath { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }
| |
| - (NSString *)downloadFileName { %log; NSString * r = %orig; NSLog(@" = %@", r); return r; }
| |
| + (id)assetWithURL:(id)url type:(int)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }
| |
| - (id)initWithURLRequest:(id)urlrequest type:(int)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }
| |
| - (id)initWithURLRequest:(id)urlrequest { %log; id r = %orig; NSLog(@" = %@", r); return r; }
| |
| - (id)_initWithDownloadMetadata:(id)downloadMetadata type:(id)type { %log; id r = %orig; NSLog(@" = %@", r); return r; }
| |
| %end
| |
| </source>
| |
| | |
| [[Category:Development Tools]]
| |