如何安装 tweak
对设备进行越狱
对设备进行越狱是安装 tweak 的首要前提,如果没有越狱设备,并且你不想对自己的设备进行越狱,那么也可以不用继续往下看了。
众所周知,苹果的权限管理是很严格的,在没有越狱的情况下,我们能对设备进行的操控其实是很有限的。而越狱之后我们就可以获得root权限,即最高权限。
现在国内最知名的越狱团队就是盘古与太极了,他们都提供了 windows 版与 mac 版的越狱软件,可以进行一键越狱。
需要注意的是,这两家目前支持越狱的最新版本是 9.0.2 。因此,如果你的设备已经更新到 9.2 了,你可能需要重新找一台比较低版本的设备。
使用工具进行越狱其实很简单,在此也就不赘述了。
CydiaSubstrate
越狱完的设备上面都会多出一个 App,即 Cydia。
Cydia 可以理解为越狱界的 App Store。只不过 App Store 上面的都是经过苹果审核过的应用。而 Cydia 上面的各式各样的 App,tweak都或多或少使用到苹果在 App Store 审核中禁用的功能特性,比如私有方法。
CydiaSubstrate 是 Cydia 的作者的另一个作品,它的主要功能就是对 App 进行 hook,替换 App 中代码的实现,它是绝大部分 tweak 正常工作的基础,Cydia 上的 tweak 都是基于 CydiaSubstrate 的。
一般情况下,越狱完之后就已经安装了 CydiaSubstrate 了,如果你想看到软件包的详细信息,可以直接在 Cydia 当中搜索 Cydia Substrate。
安装 OpenSSH
OpenSSH 会在 iOS 上安装 SSH 服务,以供外界可以远程登录到 iOS 系统当中。
安装 OpenSSH 也很简单,同样在 Cydia 当中搜索 OpenSSH,然后进行安装就行了。
iOS 上的 OpenSSH 的默认用户有 root 和 mobile,默认密码都为 alpine。在这里强烈建议大家对默认密码进行修改,如果没有修改,很多病毒就可以轻易地通过 ssh 以 root 身份远程登录到 iOS 当中,这后果可是非常严重的。
修改密码的步骤:
- 确保你的电脑跟你的 iOS 设备在同一个局域网当中
- 获取 iOS 设备的 IP:设备 -> 无线局域网 -> 查看当前连接的 WIFI 的详细信息,就可以看到设备的 IP
- 在 Mac 上打开终端,执行命令
ssh<span> </span>root@DeveiceIP
,将 DeveiceIP 替换成你的设备 IP - 输入密码进行登录,注意密码是不会回显的,也就是不会显示普通的密码星号,只要继续输入就行了,输入完后按回车
- 登录后,修改root用户密码,执行命令
passwd root
,根据提示输入新密码 - 再修改mobile用户密码,执行
passwd mobile
,根据提示输入新密码
至此,iOS 设备上的环境就配置好了
安装 Theos
Theos 是一个越狱开发工具包,它可以生成 iOS 越狱APP以及tweak等程序的框架,并提供makefile来编译、打包和安装。
安装 Xcode 和 Command Line Tools
会来看这篇教程的,我默认大家都是 iOS 开发者了,所以应该都已经安装了Xcode了,Xcode 就已经附带了 Command Line Tools。
从 Github 下载 Theos
打开命令行,进行如下操作:
xcode-select --install
export THEOS=/opt/theos
如果是这样设置,每次你打开命令行都需要重新设置一下
你也可以编辑/etc/profile文件,把上面那一行添加进去,这样不用每次打开命令行都重新设置一次。
$THEOS/bin/nic.pl
# 如果之前已经安装过 theos,请先删除,然后下载最新版
rm -rf $THEOS
安装Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
安装Theos
bash -c "$(curl -fsSL https://raw.githubusercontent.com/theos/theos/master/bin/install-theos)"
更新Theos
$THEOS/bin/update-theos
安装cmake
brew install make
echo PATH=\"$(brew --prefix make)/libexec/gnubin:\$PATH\" >> ~/.zprofile
正式安装 tweak
根据上面的内容,我们大概知道了,如果要安装一个别人的 tweak,最简单的方法就是直接到 Cydia 上面进行下载并自动安装,但是前提就是你想要安装的这个 tweak 的作者已经将这个 tweak 提交到 cydia 源当中了。
主要修改的是Makefile
文件,使用编辑器打开Makefile文件,可以看到头两行是这样的:
THEOS_DEVICE_IP = localhost
THEOS_DEVICE_PORT = 22
ARCHS = armv7 armv7s arm64 arm64e
ROOTLESS = 1
ifeq ($(ROOTLESS),1)
THEOS_PACKAGE_SCHEME=rootless
endif
ifeq ($(THEOS_PACKAGE_SCHEME), rootless)
TARGET = iphone:clang:latest:15.0
else
TARGET = iphone:clang:latest:12.0
endif
代码混淆
TARGET_CC = /Library/Developer/Toolchains/Hikari.xctoolchain/usr/bin/clang
TARGET_CXX = /Library/Developer/Toolchains/Hikari.xctoolchain/usr/bin/clang++
TARGET_LD = /Library/Developer/Toolchains/Hikari.xctoolchain/usr/bin/clang++
_THEOS_TARGET_CFLAGS += -mllvm -enable-funcwra -mllvm -enable-strcry
include $(THEOS_MAKE_PATH)/tweak.mk
分割字符串 分割字符串
python3 SplitString.py
插件汉化
%hook UILabel
-(void)setText:(NSString *)arg1
{
if([arg1 isEqualToString:@"xxx"])
{
arg1 = @"xxx";
}
%orig(arg1);
}
%end
-(void)respring {
NSString *path = [[NSString alloc]init];
// xinaA15越狱后,二进制可执行文件路径
if([[NSFileManager defaultManager] fileExistsAtPath:@"/var/bin/killall"]) {
path = @"/var/bin/killall";
}
// Fugu15越狱后,rootless型越狱,二进制可执行文件路径
else if ([[NSFileManager defaultManager] fileExistsAtPath:@"/var/jb/usr/bin/killall"]){
path = @"/var/jb/usr/bin/killall";
}
// Unc0ver\Checkra1n等rootful越狱后,二进制可执行文件路径
else {
path = @"/usr/bin/killall";
}
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:path];
[task setArguments:@[@"-9", @"SpringBoard"]];
[task launch];
}
%hook UILabel
//显示不完整,不卡死,格式正确- (BOOL) isEnabled
//显示完整,不卡死,但是格式不对- (void) drawRect:(struct CGRect)arg1
- (void)drawRect:(struct CGRect)arg1
{
%orig;
if([[self text] isEqualToString:@"No Updates Available"])
self.text = @"暂无可用更新";
if([[self text] isEqualToString:@"Installed"])
self.text = @"已安装的应用";
if([[self text] isEqualToString:@"View App IDs"])
{
self.text = @"查看App ID";
self.textAlignment = NSTextAlignmentCenter;
}
if([[self text] isEqualToString:@"Expires in"])
{
self.text = @" 有效期剩余:";
self.textAlignment = NSTextAlignmentCenter;
}
if([[self text] isEqualToString:@"How it works"])
{
if([[self nextResponder] isMemberOfClass:%c(_UINavigationBarLargeTitleView)])
{
self.text = @"自签名工作方法";
self.textColor = [UIColor whiteColor];
self.font = [UIFont boldSystemFontOfSize:20];
}
else
self.text = @"自签名工作方法";
}
if([[self text] isEqualToString:@"News"])
{
if([[self nextResponder] isMemberOfClass:%c(_UINavigationBarLargeTitleView)])
{
self.text = @"新闻";
self.font = [UIFont boldSystemFontOfSize:30];
self.textAlignment = NSTextAlignmentLeft;
}
else if([[self nextResponder] isMemberOfClass:%c(_UINavigationBarContentView)])
{
self.text = @"新闻";
self.font = [UIFont boldSystemFontOfSize:17];
self.textAlignment = NSTextAlignmentCenter;
}
}
}
%end
代码使用方式
-(int) xxxx
{
return xxxx; //你想要的数值
}
-(float) xxxx
{
return xxxx.f; //你想要的数值+ .f
}
-(BOOL) xxxx
{
return true; // return false; 根据不同的情况
}
+ (id)sharedInstance {
return %orig;
}
如果是下面这种函数,目前(指这篇教程)我们无法做出任何修改。
-(void) xxxx
但是如果是 这样的函数,我们是可以修改的
-(void) xxxx:(int) fp8
{
%orig(fp8);
fp8 = xxxx;
}
- (void)setModel:(id)arg1{}
%end
- (void)layoutSubviews{}
%end
- (void)setUserName:(NSString *)userName{
userName = @"123"; //格调
%orig; //在orig顺序上纠结了很久
}
- (void)setVipInfo:(NSString *)vipInfo{
vipInfo = @"无限期会员"; //随你改
%orig;
}
%end
#import <substrate.h>
%hook Profile
-(int) gems
{
return 888888;
}
-(int) level
{
return 88;
}
-(int) gold
{
return 888888;
}
%end
URL请求
%hook NSURL
+ (id)URLWithString:(NSString *)URLString
{
if([URLString containsString:@"https://is.snssdk.com/2/article/information/v23"]|| [URLString containsString:@"/article/information/v26"])
{
NSLog(@"NB啊小老弟,让我改掉这个请求");
URLString = @"https://is.snssdk.com/2/article/fucku/";
}
return %orig;
}
%end
%hook NSURL
+ (id)URLWithString:(id)arg
{
if ([arg hasPrefix:@"url"] ) {
arg = [arg stringByReplacingOccurrencesOfString:@"url" withString:@"url"];
} else if ([arg hasPrefix:@"url"]) {
arg = [arg stringByReplacingOccurrencesOfString:@"url" withString:@"url"];
}
id r = %orig(arg);
return r;
}
%end
文件请求
%hook NSFileManager
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error
{
if([path containsString:@"/Library/MobileSubstrate/DynamicLibraries/"] ||
[path containsString:@"/Library/Application Support/Supercharge"] ||
[path containsString:@"/Library/Application Support/Flex3"])
{
path = @"/Library/";
}
if([path containsString:@"/var/mobile/Library/UserConfiguration/Profiles/PublicInfo/Flex3Patches.plist"])
{
path = @"/var/mobile/Library/";
}
%log;
return %orig;
}
%end
%hook NSURL
+ (NSURL *)fileURLWithPath:(NSString *)path
{
if([path containsString:@"/Library/MobileSubstrate/DynamicLibraries/"] ||
[path containsString:@"/Library/Application Support/Supercharge"] ||
[path containsString:@"/Library/Application Support/Flex3"])
{
path = @"/Library/";
}
%log;
return %orig;
}
%end
%hook NSFileManager
- (BOOL) fileExistsAtPath: (NSString*) path {
NSArray *jbchecks = [NSArray arrayWithObjects:
@"/var/mobile/Library/Caches/com.saurik.Cydia/lists/apt.wxhbts.com_._Release",
nil];
for (NSString *check in jbchecks) {
if ([check isEqualToString: path]) {
return NO;
}
}
return %orig;
}
%end
%hook NSFileManager
//越狱文件检测
- (BOOL)fileExistsAtPath:(NSString *)path
{
if (![WCHLOptions sharedConfig].jbbypass)
return %orig;
NSArray<NSString*>* blacklisted = @[
@"/Applications/Cydia.app",
@"/bin/sh",
@"/bin/bash",
@"/etc/apt",
@"/etc/ssh/sshd_config",
@"/Library/MobileSubstrate/DynamicLibraries",
@"/Library/MobileSubstrate/MobileSubstrate.dylib",
@"/private/var/lib/apt",
@"/private/var/lib/cydia",
@"/private/var/stash",
@"/private/var/tmp/cydia.log",
@"/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
@"/usr/bin/sshd",
@"/usr/bin/ssh",
@"/usr/sbin/sshd",
@"/usr/libexec/sftp-server",
@"/usr/libexec/ssh-keysign",
];
for(NSString* bannedProc in blacklisted)
if([path containsString:bannedProc])
return 0;
return %orig(path);
}
%end
%hook WCFacade
-(bool) isTimelineVideoSightAutoPlayEnable
{
return false;
}
%end;
Flex3 路径
/var/mobile/Library/Application Support/Flex3
#import <SpringBoard/SpringBoard.h>
%hook SpringBoard
-(void)applicationDidFinishLaunching:(id)application {
%orig;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"欢迎使用" message:@"多米诺骨牌源 原创插件" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alert show];
}
%end
<?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.springboard</string>
</array>
</dict>
</dict>
</plist>
在 Mac 下打开终端命令行,并切换到这个仓库的目录,首先确保你的 iOS 设备上的微信是在运行中的,然后执行如下的命令:
清理:make clean
打印详情:make package messages=yes
权限设置:sudo chmod -R 775 *
编译DEB:make package
编译安装:make package install
lzma报错
$ vim $THEOS/makefiles/package/deb.mk
_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= gzip
7zip安装
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install p7zip