Objective-CS: Difference between revisions

From iPhone Development Wiki
m (Cynder moved page Clang-logos to Objective-CS: lets try and figure all this out)
(Update with the info about the continuation project.)
 
Line 1: Line 1:
Clang-logos is an Objective-C extension for hooking class methods at runtime via MobileSubstrate. It is developed by [[User:eswick|Evan Swick]].
== Overview ==
 
Objective-CS is an Objective-C extension for hooking class methods at runtime via MobileSubstrate.  
 
A few notable features are:
* Instance Variable (ivar) hooking is now as simple as using them normally. No more MSHookIvar.
* It ships with clangd and thus offers modern language server features in common editors (autocomplete, etc)
 
It is an alternative to the logos preprocessor that is particularly notable for being implemented within LLVM itself.
This allows it to implement some things Perl would '''very heavily''' struggle with.
 
The [https://github.com/eswick/objective-cs "Objective-CS"] project ''appears'' to be an iteration upon the original [https://github.com/eswick/clang-logos clang-logos] project.
 
It was theorized, specified, and implemented by [[User:eswick|Evan Swick]] in 2014-2015 as a fork of LLVM's clang compiler.  


== Overview ==
Development has been continued of the project via the [https://github.com/DragonBuild/llvm-objcs llvm-objcs] compiler and associated tooling listed below. As of Sep 4, 2023,
it builds with the latest version of the `next` branch on Apple's LLVM fork


Clang-logos builds upon the original Logos preprocessor, but brings quite a few features that the original Logos preprocessor isn't capable of. This is because clang-logos, as indicated by its name, is part of Clang, giving it the full power of the compiler. It isn't a preprocessor; hook code is compiled directly from Objective-C to LLVM IR.
=== Documentation ===


Using Clang allows us to do many things that Perl is not capable of. Most notably, clang-logos can emulate instance variables. Using @synthesize inside of an @hook container will generate getters and setters for an object, using Objective-C associative references. Non-object types such as structs and scalars (int, float, etc) are automatically wrapped in NSValue (this is transparent to the user).
Documentation for the Objective-CS specification is available via the `dragon` docs: https://dragon.cynder.me/en/latest/objcs.html


Clang-logos also inserts code to calculate the offset of instance variables at runtime, for ivars referenced within an @hook container. This eliminates the need for MSHookIvar.
=== Specification ===


[https://github.com/DragonBuild/Objective-CS This github repo] tracks the currently implemented specification for llvm-objcs. It is currently unchanged from the original specification proposed by eswick.


Clang-logos is still under development, and many features are yet to come. The information below is subject to change.
== Getting Started ==


== Building clang-logos ==
=== Installing ===


Building clang-logos is the same as building normal Clang. The source can be downloaded from [https://github.com/eswick/clang-logos eswick's GitHub].
Compiled toolchains for Intel and Apple Silicon macOS machines are available at https://github.com/DragonBuild/llvm-objcs/releases/tag/llvm-objcs-0.1.0-llvm-17.0.0


See [http://clang.llvm.org/get_started.html the official documentation] for instructions on building.
[[dragon]], if you use it, offers the `dragon lo setup` command which will install and configure the appropriate toolchain for your system.  


== Usage ==
''For theos it is unclear to me how you would install this currently as IIRC it uses xcrun to find the toolchain if it finds that command? Need to check l8r''


=== Examples ===
=== Usage ===


Clang-logos syntax is slightly different than original Logos.
Objective-CS syntax is slightly different than original Logos.


For proper usage, header of the class you're hooking should be in an external file, separate from the file containing the hooks. This header typically comes from [[class-dump]].
For proper usage, header of the class you're hooking should be in an external file, separate from the file containing the hooks. This header typically comes from [https://{{SERVERNAME}}/index.php/Reverse_Engineering_Tools#Class.2FMetadata_Dumping_tools a class dumping website or tool].


<source lang="objc">
<syntaxhighlight lang="objc">
// SBIconView.h
// SBIconView.h
@interface SBIconView : UIView { // Ivar declarations are no longer completely useless! (see below)
 
SBIcon *_icon;
@interface SBIconView : UIView
SBIconLabelView *_labelView;
{
....
    BOOL _allowsLabelArea; // Declare ivars we want to "hook" (access) here
    CGFloat _iconImageAlpha; // This replaces the need for swapping to ObjC++ and wrangling the MSHookIvar API.
}
}


+ (struct CGSize)defaultIconImageSize;
-(void)configureForLabelAllowed:(BOOL)allowed;
- (id)initWithDefaultSize;
- (BOOL)isInDock;
...


</source>
@end
 
</syntaxhighlight>


The hooking code should go in a normal Objective-C file, with an extension of .m / .mm
The hooking code should go in a normal Objective-C file, with an extension of .m / .mm
Line 46: Line 61:
#import "SBIconView.h"
#import "SBIconView.h"


@interface SBIconView () // Declare a class extension; this is where your new declarations go
// Declare a class category; this is where your new declarations go.
// You can add them in the original header, too, but this convention is cleaner.
@interface SBIconView ()


// Add our property
@property (nonatomic, retain) UIView *indicatorView;
@property (nonatomic, retain) UIView *indicatorView;


@new // Methods declared after @new are added to the class at runtime
@new // Methods declared after @new are added to the class at runtime
- (void)updateIndicatorVisibility;
- (void)myAwesomeNewInstanceMethod;


@end
@end




@hook SBIconView // Start a new hook
@hook SBIconView
@synthesize indicatorView; // Generates getters and setters for the new property, "indicatorView"


- (id)initWithDefaultSize {
-(void)myAwesomeNewInstanceMethod
{
self = @orig(); // Call the original method; parentheses *must* be specified
  NSLog(@"Hello from Objective-CS!");
if (self) {
// Initialize our newly added property
self.indicatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
self.indicatorView.backgroundColor = [UIColor blackColor];
CGSize defaultSize = [[self class] defaultIconImageSize];
self.indicatorView.center = CGPointMake(defaultSize.width / 2, defaultSize.height + self.indicatorView.bounds.size.height);
...
}
return self;
}
}


 
-(void)configureForLabelAllowed:(BOOL)allowed
// This method was declared as 'new' in our class extension
{
- (void)updateIndicatorVisibility {
    @orig(NO);
self.indicatorView.hidden = ![self isInDock];
    // All we have to do to 'hook' these ivars :)
}
    _allowsLabelArea = NO;
 
    _iconImageAlpha = 0.5;
- (void)layoutSubviews {
    [self myAwesomeNewInstanceMethod];
@orig();
[self updateIndicatorVisibility]; // Call our new method
 
if ([self isInDock]) {
_labelView.hidden = true; // _labelView is an ivar! MSHookIvar no longer needed; the compiler inserts code to find the offset automatically
}else{
_labelView.hidden = false;
}
}
}


@end
@end
</source>
</source>
=== Running clang-logos ===
Compiling clang-logos source code is the same as compiling normal Objective-C, with one exception; the '-fobjc-logos' flag must be specified. When linking source compiled with clang-logos, it must be linked against libsubstrate.

Latest revision as of 08:46, 4 September 2023

Overview

Objective-CS is an Objective-C extension for hooking class methods at runtime via MobileSubstrate.

A few notable features are:

  • Instance Variable (ivar) hooking is now as simple as using them normally. No more MSHookIvar.
  • It ships with clangd and thus offers modern language server features in common editors (autocomplete, etc)

It is an alternative to the logos preprocessor that is particularly notable for being implemented within LLVM itself. This allows it to implement some things Perl would very heavily struggle with.

The "Objective-CS" project appears to be an iteration upon the original clang-logos project.

It was theorized, specified, and implemented by Evan Swick in 2014-2015 as a fork of LLVM's clang compiler.

Development has been continued of the project via the llvm-objcs compiler and associated tooling listed below. As of Sep 4, 2023, it builds with the latest version of the `next` branch on Apple's LLVM fork

Documentation

Documentation for the Objective-CS specification is available via the `dragon` docs: https://dragon.cynder.me/en/latest/objcs.html

Specification

This github repo tracks the currently implemented specification for llvm-objcs. It is currently unchanged from the original specification proposed by eswick.

Getting Started

Installing

Compiled toolchains for Intel and Apple Silicon macOS machines are available at https://github.com/DragonBuild/llvm-objcs/releases/tag/llvm-objcs-0.1.0-llvm-17.0.0

dragon, if you use it, offers the `dragon lo setup` command which will install and configure the appropriate toolchain for your system.

For theos it is unclear to me how you would install this currently as IIRC it uses xcrun to find the toolchain if it finds that command? Need to check l8r

Usage

Objective-CS syntax is slightly different than original Logos.

For proper usage, header of the class you're hooking should be in an external file, separate from the file containing the hooks. This header typically comes from a class dumping website or tool.

// SBIconView.h

@interface SBIconView : UIView
{
    BOOL _allowsLabelArea; // Declare ivars we want to "hook" (access) here
    CGFloat _iconImageAlpha; // This replaces the need for swapping to ObjC++ and wrangling the MSHookIvar API.
}

-(void)configureForLabelAllowed:(BOOL)allowed;

@end

The hooking code should go in a normal Objective-C file, with an extension of .m / .mm

#import "SBIconView.h"

// Declare a class category; this is where your new declarations go. 
// You can add them in the original header, too, but this convention is cleaner.
@interface SBIconView () 

// Add our property
@property (nonatomic, retain) UIView *indicatorView;

@new // Methods declared after @new are added to the class at runtime
- (void)myAwesomeNewInstanceMethod;

@end


@hook SBIconView

-(void)myAwesomeNewInstanceMethod
{
  NSLog(@"Hello from Objective-CS!");
}

-(void)configureForLabelAllowed:(BOOL)allowed
{
    @orig(NO);
    // All we have to do to 'hook' these ivars :)
    _allowsLabelArea = NO;
    _iconImageAlpha = 0.5;
    [self myAwesomeNewInstanceMethod];
}

@end