首页 07-Hook
文章
取消

07-Hook

安装签名工具ldid

  • 安装Homebrew
1
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • 利用brew安装ldid
1
$ brew install ldid

修改环境变量

1
2
ls -l
ls -al // 查看目录文件(详细)
1
2
3
4
5
6
7
8
9
10
viw ~/.bash_profile
// 输入i
export THEOS=~/theos
export PATH=$THEOS/bin:$PATH
// 退出
esc
:wq
// 配置环境有可能无效,需要执行一下.bash_profile
让.bash_profile配置的环境表里立即生效(或者重新打开终端)
$ source ~/.bash_profile

注意: source .bash_profile有可能出错

rm -f ~/.bash_profile.swp

source .bash_profile

下载theos

1
2
// --recursive: 递归下载,会把依赖也下载下来
git clone --recursive https://github.com/theos/theos.git $THEOS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ cd ~/Desktop
$ nic.pl
NIC 2.0 - New Instance Creator
------------------------------
  [1.] iphone/activator_event
  [2.] iphone/activator_listener
  [3.] iphone/application_modern
  [4.] iphone/application_swift
  [5.] iphone/cydget
  [6.] iphone/flipswitch_switch
  [7.] iphone/framework
  [8.] iphone/library
  [9.] iphone/notification_center_widget
  [10.] iphone/notification_center_widget-7up
  [11.] iphone/preference_bundle_modern
  [12.] iphone/theme
  [13.] iphone/tool
  [14.] iphone/tool_swift
  [15.] iphone/tweak
  [16.] iphone/tweak_with_simple_preferences
  [17.] iphone/xpc_service
Choose a Template (required): 15
Project Name (required): tingtweak
Package Name [com.yourcompany.tingtweak]: com.jovins.tingtweak
Author/Maintainer Name [Jovins]:
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.gemd.iting
[iphone/tweak] List of applications to terminate upon installation (space-separated. '_' for none) [SpringBoard]: Springboard
Instantiating iphone/tweak in springboardtest/...
Done.

填写项目信息

  • Project Name: 项目名称
  • Package Name: 项目ID(随便写,如: com.jovins.tingtweak)
  • Author/Maintainer Name: 作者,直接回车默认就行(默认电脑用户名)
  • [iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]
    • 需要修改的App的Bundle identifier (喜马拉雅FM的是com.gemd.iting)
    • 可以通过Cycript查看App的Bunlde Identifier
  • iphone/tweak] List of applications to terminate upon installation: 直接回车

编辑Makefile

  • 在前面加入环境变量,写清楚通过那个IP和端口访问手机
    • THEOS_DEVICE_IP
    • THEOS_DEVICE_PORT
1
2
3
4
5
6
7
8
9
 
export THEOS_DEVICE_IP=127.0.0.1 
export THEOS_DEVICE_PORT=10010
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = ting_tweak
ting_tweak_FILES = Tweak.xm
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
    install.exec "killall -9 SpringBoard"
  • 如果不希望每个项目的Makefile都编写IP和端口环境变量,也可以添加到用户配置文件中。

    • 编辑完毕后source ~/.bash_profile让配置生效(或重启终端)
    1
    2
    3
    4
    5
    6
    
    $ vim ~/.bash_profile
    export THEOS=~/theos
    export PATH=$THEOS/bin:$PATH
    export THEOS_DEVICE_IP=127.0.0.1
    export THEOS_DEVICE_PORT=10010
    $ source ~/.bash_profile
    

编写代码

  • 打开Tweak.x文件
1
2
3
4
5
6
7
8
9
10
11
%hook XMAdAnimationView
- (id)initWithImageUrl:(id)arg1 title:(id)arg2 iconType:(long long)arg3
jumpType:(long long)arg4
{
return nil; }
%end
%hook XMSoundPatchPosterView
- (id)initWithFrame:(struct CGRect)arg1
{
return nil; }
%end

编译-打包-安装

  • 编译

    1
    
    make
    
  • 打包成deb

    1
    
    make package
    
  • 安装(默认会自动重启SpringBoard)

    1
    
    make install
    

可能遇到的错误

  • 1.make package的错误

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    $ make package
    Can't locate IO/Compress/Lzma.pm in @INC (you may need to install the
    IO::Compress::Lzma module) (@INC contains: /Library/Perl/5.18/darwin-
    thread-multi-2level /Library/Perl/5.18 /Network/Library/Perl/5.18/darwin-
    thread-multi-2level /Network/Library/Perl/5.18 /Library/Perl/Updates/5.18.2
    /System/Library/Perl/5.18/darwin-thread-multi-2level
    /System/Library/Perl/5.18 /System/Library/Perl/Extras/5.18/darwin-thread-
    multi-2level /System/Library/Perl/Extras/5.18 .) at
    /Users/mj/theos/bin/dm.pl line 12.
    BEGIN failed--compilation aborted at /Users/mj/theos/bin/dm.pl line 12.
    make: *** [internal-package] Error 2
    
    • 是因为打包压缩方式有问题,改成gzip压缩就行

      • 修改dm.pl文件,将#号注释掉下面两句

        1
        2
        3
        
        $ vim $THEOS/vendor/dm.pl/dm.pl
        #use IO::Compress::Lzma;
        #use IO::Compress::Xz;
        
      • 修改deb.mk文件第6行的压缩方式为gzip

        1
        2
        
        $ vim $THEOS/makefiles/package/deb.mk
        _THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= gzip
        
  • 2.make的错误

    1
    2
    3
    4
    
    $ make
    Error: You do not have an SDK in
    /Library/Developer/CommandLineTools/Platforms/iPhoneOS.platform/Developer/S
    DKs
    
    • 是因为多个xcode导致路径有可能安装了好几个xcode,需要指定一下Xcode

      1
      2
      
      $ sudo xcode-select --switch
      /Applications/Xcode.app/Contents/Developer/
      
    1
    2
    3
    
    $ make
    > Making all for tweak xxx...
    make[2]: Nothing to be done for `internal-library-compile'.
    
    • 是因为之前已经变异过,有缓存导致的,clean一下即可

      1
      2
      
      $ make clean
      $ make
      

练习

  • 将iPhone桌面的更新红色数字去掉
1
2
3
4
5
6
7
8
9
10
11
12
13
14
export THEOS_DEVICE_IP=127.0.0.1
export THEOS_DEVICE_PORT=10010

TARGET := iphone:clang:latest:7.0
INSTALL_TARGET_PROCESSES = SpringBoard

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = tweak_sb

tweak_sb_FILES = Tweak.x
tweak_sb_CFLAGS = -fobjc-arc

include $(THEOS_MAKE_PATH)/tweak.mk
1
2
3
4
5
6
7
8
%hook SBIconBadgeView

- (id)init
{
	return nil;
}

%end
1
2
3
4
5
tweak_sb $ make
tweak_sb $ make package
tweak_sb $ make install
或者
tweak_sb $ make && make package && make install
  • 给微信的"发现"界面增加2行功能
#define ADUserDefaults [NSUserDefaults standardUserDefaults]
#define ADAutoKey @"ad_auto_key"
#define ADFile(path) @"/Library/PreferenceLoader/Preferences/ADWeChat/" #path

%hook FindFriendEntryViewController

// 一共多少组
- (long long)numberOfSectionsInTableView:(id)tableView {
	return %orig + 1;
}

// 每组多少行
- (long long)tableView:(id)tableView numberOfRowsInSection:(long long)section {

	if (section == [self numberOfSectionsInTableView:tableView] - 1) {
		return 2;
	} else {
		return %orig;
	}
}

// cell内容布局
- (id)tableView:(id)tableView cellForRowAtIndexPath:(id)indexPath {
	if ([indexPath section] != [self numberOfSectionsInTableView:tableView] - 1) {
		return %orig;
	}

	static NSString *cellId = [indexPath row] == 0 ? @"autoCellId" : @"exitCellId";
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
		cell.backgroundColor = [UIColor whiteColor];
		cell.imageView.image = [UIImage imageWithContentsOfFile:ADFile(AppIcon@2x.png)];
    }

	if ([indexPath row] == 0) {
	    cell.textLabel.text = @"自动抢红包";

	    UISwitch *switchView = [[UISwitch alloc] init];
    	[switchView addTarget:self action:@selector(ad_valueChange:) forControlEvents:UIControlEventValueChanged];
    	switchView.on = [ADUserDefaults boolForKey:ADAutoKey];
		cell.accessoryView = switchView;
	} else if ([indexPath row] == 1) {
	    cell.textLabel.text = @"退出微信";
	}
	
	return cell;
}

// 自动抢红包按钮打开/关闭(如果是新方法, 需要加上%new)
%new 
- (void)ad_valueChange:(UISwitch *)switchView {
    [ADUserDefaults setBool:switchView.isOn forKey:ADAutoKey];
    [ADUserDefaults synchronize];
}

// 返回cell的高度
- (double)tableView:(id)tableView heightForRowAtIndexPath:(id)indexPath {
	if ([indexPath section] != [self numberOfSectionsInTableView:tableView] - 1) {
		return %orig;
	}

	return 44;
}

// 选中cell
- (void)tableView:(id)tableView didSelectRowAtIndexPath:(id)indexPath {
	if ([indexPath section] != [self numberOfSectionsInTableView:tableView] - 1) {
		%orig;
		return;
	}

	[tableView deselectRowAtIndexPath:indexPath animated:YES];
	if ([indexPath row] == 1) {
		// exit(); // 这种方式有卡顿,不推荐
		abort(); // 终止进程, 使用这种方式退出无卡顿
	}
}
1
$ make package debug=0 // release版本
  • 去掉内涵段子的广告
    • 首页的广告
    • 评论区的广告
%hook SSTipModel

- (id)initWithDictionary:(id)arg1 location:(long long)arg2 {
	return nil;
}
	
%end
  
%hook EssayDetailTipModel

- (id)initWithDictionary:(id)arg1 error:(id *)arg2 
{
	return nil;  
}  
  
%end 
  • 腾讯视频广告
// 去掉启动页广告
@interface TADSplashWindow
- (void)hideSplash;	
@end
%hook TADSplashWindow

- (void)showSplash
{
   [self hideSplash];
}  
  
%end  
// 去掉视频广告
%hook QNBPlayerVideoAdsViewController

- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 
withParentViewController:(id)arg3 withPageViewController:(id)arg4
withAddToParentViewControllerNow:(_Bool)arg5 
{
	return nil;
}

- (id)initWithEventProxy:(id)arg1 withPlayerInfo:(id)arg2 
withParentViewController:(id)arg3 withParentEventViewController:(id)arg4
withAddToParentViewControllerNow:(_Bool)arg5 
{
	return nil;
}

%end

theos资料查询

  • 目录结构: https://github.com/theos/theos/wiki/Structure

  • 环境变量: http://iphonedevwiki.net/index.php/Theos

  • Logos语法: http://iphonedevwiki.net/index.php/Logos

    • %hook%end : hook一个类的开始和结束

    • %log: 打印方法调用详情

      • 可以通过Xcode -> Window -> Devices and Simulators查看日志
    • HBDebuglog: 跟NSLog类似

    • %new: 添加一个新的方法

    • %c(className):生成一个Class对象,比如%c(NSObject),类似于NSStringFromClass()、objc_getClass()

    • %orig : 函数原来的代码逻辑

    • %ctor: 加载动态库时调用

    • %dtor: 在程序退出时调用

    • logify.pl : 可以将一个头文件快速转换成已经包含打印信息的xm文件

      1
      
      logify.pl xx.h > xx.xm
      
  • 如果有额外的资源文件(比如图片),放在项目的layout文件夹中,对应着文件夹中,对应着手机的根路径/

theos-tweak的实现过程

  • 编写Tweak代码
  • $ make : 编译Tweak代码为动态库(*.dylib)
  • $ make package : 将dylib打包为deb文件
  • $ make install : 将deb文件传送到手机上,通过Cydia安装deb
  • 插件将会安装在/Library/MobileSubstrate/DynamicLibraries文件夹中
    • *.dylib: 编译后的Tweak代码
    • *.plist: 存放着需要hook的APP ID
  • 当打开App时
    • Cydia Substrate(Cydia已自动安装的插件)会让App去加载对应的dylib
    • 修改App内存中的代码逻辑,去执行dylib中的函数代码
  • 所以,theos的tweak并不会对App原来的可执行文件进行修改,仅仅是修改了内存中的代码逻辑
  • 疑问
    • 未脱壳的App是否支持tweak?
      • 支持,因为是在内存中实现的,并没有修改.app包中的可执行文件
    • tweak效果是否永久性的?
      • 取决于tweak中用到的App代码是否被修改过
    • 未越狱的手机是否支持tweak?
      • 不支持
    • 能不能对Swift/C函数进行tweak?
      • 可以,方式跟OC不一样
    • 能不能对游戏项目进行tweak?
      • 可以
      • 但是游戏大多是通过C++/C编写的,而且类名、函数名会进行混淆操作

logify.pl注意点

  • 生成的xm文件

    1
    2
    
    // > 覆盖,>> 追加
    $ logify.pl BaseTest.h > Test.h
    
  • logify.pl生成的xm文件,you很多时候是编译不通过的,需要进行一些处理

    • 删掉__weak
    • 删掉inout
    • 删掉协议,比如
      • 或者声明一下一些信息@protocol TestDelegate
    • 删掉- (void).cxx_destruct { %log; %orig; }
    • 删掉HBLogDebug(@” = 0x%x”, (unsigned int)r);
    • 替换类型为void,比如将XXPerson *替换为 *void **
      • 或者声明一下类信息@class XXPerson

命令行工具

  • 权限

    • 给可执行文件签上一定的权限,让它可以访问其他App的可执行文件。

    • 权限: entitlements

    1
    2
    3
    
    // > 代表覆盖文件,>> 代表追加
    // 导出可执行文件权限
    $ ldid -e TestCL > TestCL.entitilements 
    
    • SpringBoard拥有所有访问权限,可以通过获取SpringBoard赋给可执行文件访问权限。
    1
    2
    3
    4
    
    // 导出SpringBoard可执行文件权限
    $ ldid -e SpringBoard > SpringBoard.entitilements 
    // 将权限赋给TestCL
    $ ldid -SSpringBoard.entitilements TestCL
    
本文由作者按照 CC BY 4.0 进行授权

06-脱壳

08-动态调试