越狱开发2-Tweak入门

Tweak入门,以及微信插件重签名

2016-11-13 | 阅读

Theos是越狱开发的主要工具,我们一般使用Theos中的tweak来为目标程序添加小插件,通过替换或者增加方法,达到自己的特殊目的。

安装 Theos

设置 Theos 安装目录 :

export THEOS=~/theos

下载

git clone --recursive git://github.com/DHowett/theos.git $THEOS

下载后, 去修改环境变量 :

export THEOS=~/theos
export PATH=$THEOS/bin:$PATH
export THEOS_DEVICE_IP=xx.xx.xx.xx THEOS_DEVICE_PORT=22

IP地址和端口号可以不填,可以在具体项目的配置文件中进行配置.

但是 Substrate 没有跟随Theos一起打包, 所以要安装CydiaSubstrate : 在越狱机上, 将/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate 传输到电脑上得$THEOS/lib , 并且改名为 libsubstrate.dylib . 同时将头文件 /Library/Frameworks/CydiaSubstrate.framework/Headers/CydiaSubstrate.h 传输到 $THEOS/include , 并改名为 substrate.h :

安装 dpkg-deb , deb是越狱开发安装包的标准格式, dpkg-deb是一种操作deb文件的工具 , 将 $THEOS/bin/dm.pl重命名为 dkpg-deb , 并赋予可执行的权限.

使用Theos

使用 New Instance Creator 即NIC来创建一个新的项目 :

$THEOS/bin/nic.pl

这里使用时, 我们可以看到NIC有几个项目模板供我们选择 :

➜  Testing $THEOS/bin/nic.pl
NIC 2.0 - New Instance Creator
------------------------------
  [1.] iphone/activator_event
  [2.] iphone/application_modern
  [3.] iphone/cydget
  [4.] iphone/flipswitch_switch
  [5.] iphone/framework
  [6.] iphone/ios7_notification_center_widget
  [7.] iphone/library
  [8.] iphone/notification_center_widget
  [9.] iphone/preference_bundle_modern
  [10.] iphone/tool
  [11.] iphone/tweak
  [12.] iphone/xpc_service
Choose a Template (required): 2
Project Name (required): HelloWorld
Package Name [com.yourcompany.helloworld]: org.lxm.helloworld
Author/Maintainer Name [罗贤明]: 
[iphone/application_modern] Class name prefix (two or more characters) [XX]: CN
Instantiating iphone/application_modern in helloworld/...
Done.

创建好项目后,就会创建一个HelloWorld的文件夹在当前目录下, 下面并有相应地目录结构.

这里就算安装完成了, 然后使用

make package 来打包一个包, 使用 make install 来安装一个包

Tweak

Theos中, 我们主要开发的时 Tweak,Tweak主要是去注入到一个APP中,通过OC语言的动态性来替换方法,以实现对APP改写.

使用 nip创建一个Tweak :

Choose a Template (required): 11
Project Name (required): QiyeWeixin
Package Name [com.yourcompany.qiyeweixin]: com.lxm.qiyeweixinplugin
Author/Maintainer Name [罗贤明]: 
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.tencent.ww  # 需要注入的app的bunldid
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: SpringBoard // 安装Tweak 后需要重启的应用.
Instantiating iphone/tweak in qiyeweixin/...
Done.

查看 Tweak生成的目录 , 有4个文件 :

  • Makefile : 该文件指定工程用到的文件,框架和库等信息. 将这个过程自动化.
  • xxx.plist : 与APP中的 Info.plist类似, 记录一些配置信息, 描述 tweak的作用范围.
  • control ,记录了 deb包管理系统所需的基本信息, 会被打包到 deb 包中.
  • Tweak.xm : 默认的源文件, x表示支持Logos语法,m表示支持OC语法.

Logos语法

  • %hook : 指定要hook的Class, 必须以%end结尾 .
  • %log : 要在%hook内使用, 表示打印信息到 syslog , 可以以 %log([(<type>)<expr>,...]) 格式追加打印信息.
  • %orig : 在%hook 内使用,表示执行被勾住的函数的原始代码.
  • %group ,组, 用来组合%hook ,必须配合%init使用才能生效组中的替换方法. 如 %group xxx ... %end ,要以end结尾,没有显示声明的 hook都被放在了_ungrouped中.
  • %init , 用来初始化某个group , 必须放在 %hook,参数为 group 名, 如 %init(_ungrouped).
  • %subclass : 创建一个新的类, 但是不支持属性, 只能通过关联对象来实现。
  • %property : 创建一个属性, 可以放在上面的subclass中,写法与 @property相同, 但是实现是用的关联对象.
  • %ctor , 初始化钩子, 如果不显式定义, 则默认实现 :

      %ctor{
          %init;
      }
    
  • %new , 给现有的类添加方法,与 class_addMethod相同. 必须放在%hook中, 即没有声明%new的都视为替换方法, 声明了new才视为新增方法.

简单写一个输出helloworld的示例 :

%hook AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
	UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"helloworld" message:@"helloworld!!!" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
        [alertView show];
	return %orig;
}
%end

使用 make package , make install 安装, 然后在桌面重启后,就进入应用可以看到效果了.

Tweak中导入其他库, 要在Makefile中, 编写 :

QiyeWeixin_FRAMEWORKS = CoreLocation UIKit CoreGraphics AVFoundation

以引入这些库, 但是引入这些库后 , 在 Tweak.xm的代码中,依然会报错, 找不到这些库中的类与方法, 所以要创建一个头文件,以引入这些库, 但是不能在Tweak.xm文件中来 #import <CoreLocation/CLLocation.h> ,必须放在一个单独的头文件中.

Theos编译时,会进行严格的编译校验,所以一些如类型转换的警告,都会导致编译出错,要使用 -w 忽略所有警告 :

#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"

// 写在这个中间的代码,都不会被编译器提示-Wdeprecated-declarations类型的警告
dispatch_queue_tcurrentQueue =dispatch_get_current_queue();

#pragma clang diagnostic pop

关于动态库注入

Tweak在越狱环境上的运行,是通过动态库注入,而我们想要做一个APP的插件版,即二次打包应用,一般通过动态库注入一些自己的逻辑,这一节介绍一下动态库注入相关的知识.

之前介绍了 cycript注入动态库的方式,这必须要在越狱环境下才能实现。二次打包动态库的注入,是通过修改可执行文件的Load Commands来实现的. 在Load Commands中增加一个LC_LOAD_DYLIB , 写入dylib路径,这样程序执行的时候, 就会编译这个 LC_LOAD_DYLIB 找到要注入的 dylib,加载动态库 .

我们使用 MachoOView查看app可执行文件中Load Commnads的结构 :

可以发现,这里有很多的LC_LOAD_DYLIB ,所以我们把一个自己的dylib放到APP的目录下,然后修改二进制文件,以让APP加载这个动态库。这个动态库也是需要签名的,使用对app重签名的方式对这个动态库进行签名。

动态库的注入,可以使用这个工具 insert_dylib脚本.

insert_dylib --all-yes @executable_path/test.dylib Payload/WeChat.app/WeChat

@executable_path/test.dylib 表示动态库的加载路径,@executable_path 表示可执行文件所在的路径, 所以我们要把动态库放到可执行文件一级的目录.

Tweak在非越狱环境下的使用.

二次打包:制作一个动态库, 动态库注入到可执行文件, 重签名。而我们学习使用Tweak的目的,就是第一步,制作动态库.在我们编写好Tweak后,就可以在项目文件夹下发现一个.theos的隐藏文件夹, 在这个文件夹下,.theos/obj/debug 中,可以发现编译后的动态库文件.

但直接使用这个动态库文件,是无法在非越狱环境上使用的, 原因很简单, Tweak默认依赖于越狱环境,打包出来的动态库,依赖于越狱环境下的CydiaSubstrate.framework/CydiaSubstrate 这个库,也就是上面我们提到的一个库. 可以通过otool -L QiyeWeixin.dylib 查看依赖,发现 :

/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate (compatibility version 0.0.0, current version 0.0.0)

Theos会在编译动态库时, 会这个动态库添加上这一条依赖,所以要想在非越狱环境上运行,还得把CydiaSubstrate库也跟着打包到APP中.

当然Theos提供了解决方案 :

MakefileTweak_Name=XXXX下添加以下两行 :

SUBSTRATE ?= yes
instance_USE_SUBSTRATE = $(SUBSTRATE)

把上面的instance替换成你的TweakName,在上面的这个例子中就是XXXX

然后打包使用命令:

make SUBSTRATE=no

这样Theos打包的时候,会将依赖的CydiaSubstrate中的符号加载到最终生成的动态库中,不再依赖CydiaSubstrate库.

重签名 二次打包

重签名,需要下载ipa包, 并解压。

  1. 如果是来自appstroe的应用,必须先破壳.
  2. 编写一个Entitlements.plist , 企业证书的签名,必须声明该应用要对哪些服务进行签名,如使用共享keychain等等. 这里是一个例子 :

     <?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>application-identifier</key>
         <string> xxxxxx.com.xxx.xxxx </string>
         <key>com.apple.developer.team-identifier</key>
         <string>xxxxx</string>
         <key>get-task-allow</key>
         <false/>
         <key>keychain-access-groups</key>
         <array>
             <string>xxxxxx.com.xxx.xxxx</string>
         </array>
     </dict>
     </plist>
    

    这里会说明企业版app签名使用的证书,也就是你重签名后要用的证书.这个文件不用放到打包的app中.

  3. 下载企业证书对应的 provisioning profiles ,并将其改名为embedded.mobileprovision ,放置到app的可执行文件的目录中.
  4. 修改bundleID , 即修改info.plist中得bundleID.
  5. 删除原有签名文件,即_CodingSign文件夹
  6. 对app进行重签名:

      codesign -f -s "iPhone Distribution: xxxx..." --entitlements Entitlements.plist Payload/wework.app
    

    注意,需要对插件和watch扩展也进行签名,framework 也需要签名。

  7. 打包APP :

     xcrun -sdk iphoneos PackageApplication -v Payload/wework.app -o ~/xxx.ipa
    

第6步签名, 再补充一下签名时可能会用到的一些命令 :

# 查看当前系统中可用的所有签名证书
security find-identity -v -p codesigning  
# 签名, 可以加 -f 参数 以覆盖签名
codesign -s 'iPhone Developer: Thomas Kollbach (7TPNXN7G6K)' Example.app
# 查看签名状态
codesign -vv -d Example.app
# 另外一种方式来查看签名
ldid -e Demo.app/demo

最后,发布企业版应用

企业版应用的发布, 需要一个plist文件, 以记录APP的信息:

<?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>items</key>  
	    <array>  
	        <dict>  
	            <key>assets</key>  
	            <array>  
	                <dict>  
	                    <key>kind</key>  
	                    <string>software-package</string>  
	                    <key>url</key>  
	                    <string>http://xxx/xxx.ipa</string>  
	                </dict>  
	            </array>  
	            <key>metadata</key>  
	            <dict>  
	                <key>bundle-identifier</key>  
	                <string>com.fnst.smartwork</string>  
	                <key>bundle-version</key>  
	                <string>1.0</string>  
	                <key>kind</key>  
	                <string>software</string>  
	                <key>title</key>  
	                <string>xxx.ipa</string>  
	            </dict>  
	        </dict>  
	    </array>  
	</dict>  
	</plist>  

而下载企业版APP的链接,是 itms-services://?action=download-manifest&url=https://resource.luoxianming.cn/qiyeweixin.plist 这种形式, 注意 plist的链接必须是https的,而下载的app的地址可以是http的 .

项目示例

这里是一个小的尝试, Tweak企业微信, 以修改定位地址,保证自己签到签退无压力 , 可以在github上查看代码。