我们在写插件的时候都知道很多时候用到theos去写更为方便
因为theos在线调试后可以直接hook我们需要的东西
比如广告,基址,地址,等各种UIView或者conterller等
今天就记录一下我们theos在写插件的时候用的语法等一些记录
创建项目
首先我们需要创建项目,这些问题我不在强调了
终端输入nic.pl创建tweak项目
创建后我们需要打开tweak.x文件去写代码
注释:
你也可以xcode安装monkeydev直接创建logos插件
这样也是同样的打开xm文件去写代码
xm文件可以写oc,c,swift,logos等代码,但是需要知道xm文件没有代码提示
或者直接删除文件引用m的oc或者swift文件解决
开始记录
%group
%group Groupname
group用于条件初始化或代码组织。分组可用于管理与旧代码的向后兼容性。
以组名开头的hook group。group不能在另一个%group块内。所有未分组的hook都在隐式“_ungrouped” group中。如果没有其他group,则会为您初始化_ungrouped组。您可以使用%init指令手动初始化它。其他组必须使用%init(Groupname)指令初始化。
%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);
}
}
%hook
%hook Classname
为名为类名的类打开一个hook块。
可以在%group块内。
这里有一个微不足道的例子:
%hook SBApplicationController
-(void)uninstallApplication:(SBApplication *)application {
NSLog(@"Hey, we're hooking uninstallApplication:!");
%orig; // Call the original implementation of this method
return;
}
%end
%new
`%new
%new(signature)`
通过在方法定义上方添加此指令,将新方法添加到hook类或子类中。签名是新方法的Objective-C类型编码;如果省略,将生成一个。
必须位于%hook块内。
您还应该在界面中声明新方法,因为Logos不会自动声明。例如:
@interface TheClass (TweakMethods)
-(void)yourNewMethod;
@end
%hook TheClass
%new
-(void)yourNewMethod { /* code */ }
%end
%subclass
%subclass Classname: Superclass
子类块-该类在运行时创建并填充方法。尚未支持ivars(使用关联对象)。对于超类中不存在的方法,需要%new说明符。要实例化新类的对象,您可以使用%c运算符。
可以在%group块内。
这里有一个例子:
%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]);
}
%property
%property (nonatomic|assign|retain|copy|weak|strong|getter|setter) Type name;
将属性添加到%subclass中,就像使用@property添加到正常的Objective-C子类中一样,并在%hook中向现有类添加新属性。
必须位于%subclass或%hook块内。
%end
%end
关闭组/钩子/子类块。
%config
%config(Key=Value);
设置logos标致
%hookf
%hookf(rtype, symbolName, args…) { … }
为名为symbolName的函数生成一个函数钩子。如果名称作为字面字符串传递,则将动态查找该函数。
// Given the function prototype
FILE *fopen(const char *path, const char *mode);
// The hook is thus made
%hookf(FILE *, fopen, const char *path, const char *mode) {
NSLog(@"Hey, we're hooking fopen to deny relative paths!");
if (path[0] != '/') {
return NULL;
}
return %orig; // Call the original implementation of this function
}
人们通常会挂钩其地址在运行时解析的函数,例如MGGetBoolAnswer,例如:
bool (*orig_MGGetBoolAnswer)(CFStringRef);
bool fixed_MGGetBoolAnswer(CFStringRef string)
{
if (CFEqual(string, CFSTR("StarkCapability"))) {
return kCFBooleanTrue;
}
return orig_MGGetBoolAnswer(string);
}
%ctor {
MSHookFunction(((void *)MSFindSymbol(NULL, "_MGGetBoolAnswer")), (void *)fixed_MGGetBoolAnswer, (void **)&orig_MGGetBoolAnswer);
...
}
您还可以做:
%hookf(bool, MGGetBoolAnswer, CFStringRef string)
{
if (CFEqual(string, CFSTR("StarkCapability"))) {
return true;
}
return %orig;
}
%ctor() {
%init(MGGetBoolAnswer = MSFindSymbol(NULL, "_MGGetBoolAnswer"));
}
并将MSFindSymbol(NULL,“_MGGetBoolAnswer”)替换为函数指针的任何表达式。
%ctor
%ctor { … }
生成匿名构造函数(默认优先级)。
%dtor
%dtor { … }
生成一个匿名解构函数(默认优先级)。
%init
%init;
%init([=, …]);
%init(Group[, [+|-]=, …]);
初始化组(或默认组)。不传递组名将初始化“_ungrouped”,传递class=expr参数将在初始化时用给定的表达式替换这些类。+ sigil(如Objective-C中的类方法)可以前置于类名,以替换元类的表达式。如果没有指定,sigil默认为-,以替换类本身。如果没有指定,元类就是从类派生出来的。类名替换对于包含不能用作%hook指令的类名令牌的类,例如空格和点,类名替换特别有用。
Usage:
%hook SomeClass
-(id)init {
return %orig;
}
%end
%ctor {
%init(SomeClass=objc_getClass("class with spaces or dots in the name"));
}
%class
%class Class;
向前宣布一个类。过时%c,但仍然存在。创建一个$Class变量,并使用“_ungrouped”组初始化它。
%c
%c([+|-]Class)
在运行时向Class进行评估。如果指定了+ sigil,它将计算为MetaClass而不是Class。如果没有指定,sigil默认为-,评估为类。
%orig
%orig
%orig(arg1, …)
调用原始挂钩方法。它在%new’d方法中不起作用。奇怪的是,它在子类中工作,因为MobileSubstrate将在钩子时间生成一个超级调用闭包。(如果挂钩方法在我们挂钩的类中不存在,它会创建一个仅调用超类实现的存根。)args传递给原始函数-不包括self和_cmd,Logos会为您这样做。
%log
%log;
%log([(), …]);
将方法参数转储到syslog。%Log中包含的类型参数也将被记录。
文件扩展名
.x文件 将由Logos处理,然后作为 objective-c进行预处理和编译。
.xm文件 将由Logos处理,然后作为 objective-c++进行预处理和编译。
.xi文件 将首先作为 objective-c进行预处理,然后Logos将处理结果,然后进行编译。
.xmi文件 将首先作为 objective-c++进行预处理,然后Logos将处理结果,然后编译。
xi或xmi文件可以在#define宏中使用Logos指令。
默认情况下,Logos预处理器只会在构建时处理一个.xm文件。但是,可以将徽标挂钩代码拆分为多个文件。
首先,主文件必须重命名为.xmi文件。然后,可以使用#include指令包含其他.xm文件。Logos预处理器将在处理之前将这些文件添加到主文件中。
通常,无法在多个徽标文件中初始化钩子组,但有一个变通办法可用于解锁此功能。这是通过将组初始化包装在静态方法中来完成的,然后可以从其他文件调用。
请查看以下代码。它所做的就是在SpringBoard应用程序启动完成后记录一条消息。它位于一个名为TweakGroup的组内,该组在名为InitGroup()的静态函数中初始化。
// Group.xm
#import "Shared.h"
%group TweakGroup
%hook SpringBoard
- (void)applicationDidFinishLaunching:(id)arg1 {
%orig;
NSLog(@"[Group Test] SpringBoard has finished launching");
}
%end
%end
extern "C" void InitGroup() {
%init(TweakGroup);
}
您可能已经注意到,Group.xm的顶部有一个Shared.h的导入。这只是一个头文件,将导入到我们的主Logos文件中,以便我们可以在那里调用该函数:
// Shared.h
extern "C" void InitGroup();
最后,Shared.h可以导入包含构造函数的Logos文件中。调用静态函数将从Group.xm初始化组并运行其hook:
// Tweak.xm
#import "Shared.h"
%ctor {
NSLog(@"[Group Test] Our hook for SpringBoard should show up below this");
InitGroup();
}
如果操作正确且编译没有错误,这应该可以记录两条消息:一条来自构造函数,另一条来自组内的方法。请记住,这不适用于不在组内的hook。
需要注意的几件事:
这在正常的C中不起作用,因此您必须为您的组和构造函数使用.xm文件。
你必须注意你调用初始化的次数,因为Logos将不再告诉你它是否被调用不止一次。
您可以使用logify.pl从头文件创建Logos源文件,该标头文件将记录该标头文件的所有功能。以下是logify.pl生成的非常简单的徽标调整示例
给定一个标题文件:
@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
您可以在$THEOS/bin/logify.pl上找到logify.pl,并以这样使用它:
$THEOS/bin/logify.pl ./SSDownloadAsset.h
打印的结果应该是:
%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
这样,我们就可以轻松的运用我们的tweak进行hook了
更多交流后期会有教程!
请登录后查看评论内容