iOS - 给现有应用程序(越狱)添加“对象”

21

如何向现有应用程序添加“对象”?

例如,EasyRefresh for Chrome扩展可以在iOS Chrome应用程序内启用一个新按钮,许多其他扩展也是如此。

我如何将一个简单的UIButton添加到Twitter应用程序中?

是否有GitHub项目可以帮助我了解如何完成这个操作?


image

图片来源:ModMyI


谢谢。


这也很有用:http://media.hacking-lab.com/scs3/scs3_pdf/SCS3_2011_Bachmann.pdf - Aleksander Azizi
2个回答

53

这个技巧涉及到一些(非常基础的)反向工程,由几个步骤组成;我将尽可能清晰地解释它们。

零步骤:如果应用程序是从AppStore下载的,则被加密。您需要使用其中一个通常用于破解应用程序的脚本/应用程序进行解密;一个命令行脚本是poedCrack.sh(在其中一个粘贴网站上快速查找即可),一个GUI应用程序是Crakculous(在Cydia中可用)。请注意,这些工具之一是为了轻松(自动)解密而需要的——手动解密方法过于复杂,不适合在StackOverflow答案中介绍,这就是为什么我建议使用这些工具。但是,我绝不鼓励您破解应用程序!(基本上,我要求您不要将这些工具用于其原始用途 :) 如果您想查看手动解密过程,请单击此处

第一步:你需要知道应用程序使用/创建了哪些类。为此,你需要使用class-dump或class-dump-z工具。这个命令行应用程序可以反转应用程序的二进制可执行文件,并为应用程序使用和包含的所有Objective-C类生成接口声明。你可以在这里找到class-dump-z,这是更高级和首选的变体。

第二步:在获得类声明之后,你需要猜测每个类的作用和使用时机(是的,有点困惑)。例如,在通过class-dump-z从上述应用程序Google Chrome生成的一个文件中,你可能会发现类似以下内容:

@interface ChromeUrlToolbar: UIToolbar {
    UISearchBar *urlBar;
}

- (id)initWithFrame:(CGRect)frame;
- (void)loadURL:(NSURL *)url;

@end

嗯,这听起来不错,是吧?你可以看到它的实现有一个initWithFrame:方法(所有UIView子类都有)--为什么不尝试修改它呢?

第三步:对于这个修改,你需要MobileSubstrate。MobileSubstrate是由Cydia的创造者Saurik创建的开发人员库,旨在使代码注入应用程序变得容易。你可以在网上找到一些非常好的教程,包括this one。 所以,你有一个类,想要“hook”它--那么你就写一些像这样的代码:

static IMP __original_init; // A

id __modified_init(id __self, SEL __cmd, CGRect frame) // B
{
    __self = __original_init(__self, __cmd, frame); // C

    // D
    UIButton *newButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [newButton setTitle:@"Chrome Pwned"];
    newButton.frame = CGRectMake(0, 0, 100, 40);
    [__self addSubview:newButton];

    return __self;
}

// E
__attribute__((constructor))
void init()
{
    Class clazz = objc_getClass("ChromeUrlToolbar"); // F
    MSHookMessageEx(clazz, @selector(initWithFrame:), __modified_init, &__original_init); // G
}

解释:让我们从结尾开始。函数init(E)被声明为__attribute__((constructor))。这意味着当我们将这段代码创建成库并加载到Chrome中时,它会自动调用。这正是我们想要的,因为我们希望在启动应用程序之前改变其行为。

在标记为// F的行上,我们捕获了要修改的类对象本身。Objective-C是一种高度动态的语言;这意味着我们可以在运行时获取和修改有关类和对象的信息。在标记为// G的行上,我们使用了MobileSubstrate API最重要的函数:MSHookMessageEx。要理解它的工作原理(而不是它的功能),您必须知道以下内容:Objective-C本身是作为一个纯C库实现的——在引擎盖下,语言本身只是简单的C。因此,在Obejctive-C中发送的每个消息实际上都是一个C函数调用。这些C函数有两个特殊参数:selfcmd——前者是被发送消息的对象的指针,后者是选择器(一个特殊的、唯一的指向正在发送的消息名称的指针)。因此,MSHookMessageEx所做的就是取一个类和一个选择器,找到对应它们的函数的实现,并将该函数与其第3个参数中提供的函数本身(在本例中为__modified_init)交换。为了不丢失数据,它还将该函数返回到其第4个参数中(在这里是__original_init)。

现在,Chrome URL工具栏的初始化已经重定向到我们的函数中,接下来该怎么做呢?其实没什么特别的:首先,我们只需调用原始的初始化函数(注意前两个特殊参数__self和__cmd!),它会像通常一样创建工具栏(这行代码由// C表示)。然后,在// D部分进行实际的修改:我们创建一个UIButton,设置其标题和位置,并将其作为子视图添加到我们刚刚创建的工具栏中。然后,知道这是一个初始化函数后,我们将原始实例与我们注入的按钮代码一起返回。

好了,基本上就是这些;如果您对Objective-C的工作原理以及如何创建酷炫的iOS调整感兴趣,我建议您阅读苹果公司的官方文档,您也可以浏览我的一些开源Cydia调整

希望这能帮到您!


12
你需要了解Objective-C运行时的工作原理,特别是消息传递系统(即调用方法)。具体来说,与其他语言在编译时确定方法不同,Objective-C在运行时确定方法。这允许全局更改特定方法,也就是所谓的方法交换
使用Mobile Substrate库,您可以替换任何方法实现,并甚至调用原始实现。当然,您需要知道方法的名称、参数以及它所属的类。
例如,要修改SpringBoard,您需要知道它包含哪个类和哪个方法。您将需要使用class-dumpclass-dump-z实用程序来执行此操作(class-dump-z更为常用且适用于iOS开发,class-dump更为通用且与旧二进制文件以及64位兼容)。

所以如果要对SpringBoard进行类转储,您需要在Terminal.app中输入以下内容:

class-dump -H /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/CoreServices/SpringBoard.app/SpringBoard -o ~/Desktop/SpringBoard

对于class-dump-z,选项-p将生成@property而不是getter/setter,这更清晰,因此您可能会键入。
class-dump-z -p -H /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/CoreServices/SpringBoard.app/SpringBoard -o ~/Desktop/SpringBoard

这行代码将在您的桌面上创建一个包含SpringBoard所有类定义的文件夹。当然,您可能需要更改路径以适应您的系统(对于最新版本的Xcode,Developer文件夹在Xcode中,因此您需要类似于...的内容。)
/Applications/Xcode/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/CoreServices/SpringBoard.app/SpringBoard

你还可以在互联网上找到已经为你完成此操作的人,适用于大多数现有的框架,这非常方便,只要确保它们适合您的系统版本即可。
对于AppStore应用程序,您首先需要解密它们,因为它们是受保护的。您可能需要自己找到名称和链接,因为这可能违反了Stack Overflow的服务条款,不过使用gdb可以实现这个目的。
为了简化工作,一些工具例如Logos(您可能还需要查看Theos)已被创建,以减少所需的样板代码。还有一个(相当旧的)xcode模板和mobilesubstrate教程提供了很好的帮助。
Logos使得从类classname中挂钩方法method变得容易:
%hook classname //declares the class from your application you're going to override

-(void)method {

    dosomethingnew(); //put all your new code for the method here
    return %orig;     //this calls the original definition of the method
}
%end //end hooking classname

如果您想了解系统中的框架列表及其有用性,请参见此处

最后一件事:流行的调整列表已经开源(尽可能链接到GitHub):

一些小小的调整

最后,看看WeekTweak,他们每周发布一个开源的tweak,你可以通过查看别人的源代码来学习并尝试做自己的东西。如果你礼貌地询问,IRC(irc.saurik.com)的#theos频道也会提供帮助。

1
我已经添加了如何使用“class-dump”或“class-dump-z”的信息,以及各种链接和流行的开源Cydia调整列表,并提供到存储库的链接。 - Olotiar
很好的回答。不过我有点好奇,为什么在 Stack Overflow 上发布解密应用程序存档信息会违反服务条款? - Nate
我不确定是否有这样的工具存在,但大多数方便使用的工具实际上都是用于分发未加密二进制文件的软件破解应用程序,不尊重知识产权。我还相信这违反了AppStore的服务条款,我不想明确地鼓励如何违反你签署的合同。 - Olotiar
不,我了解苹果的合同。但是,你的帖子提到了Stack Overflow的服务条款,我想问一下那个。如果你的意思是“苹果”,你应该编辑帖子来更正。在这里,每个人都应该遵守Stack Overflow的规定,但你不需要签署任何与苹果有关的合同来进行iOS(越狱)开发。 - Nate

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接