When creating a reverse engineering project, how to make the project more convenient to use and easy to expand, as well as compiler identification, can greatly improve our daily development efficiency and code quality. This article mainly describes how to use Theos' tweak project to create a project that can be recognized by the Xcode compiler, as well as the commonly used configurations in the project.
https://www.onezen.cc/2017/09/16/iosrevert/revdevconfig.html
After setting up the environment, create the corresponding tweak project
Create an Xcode static library project based on the name of the tweak project created earlier, and then mix the tweak and the created Xcode project together.
Create a Config folder (New Group Without Folder) in the Xcode project, and place the Makefile, corresponding plist file, and control configuration file in this directory without copying. Then create the corresponding folder in Xcode, then replace all the suffixes of the generated .xm
files with .xmi
, and put them in the outermost layer of the project as the only entry class
Set Tweak.xmi in the Xcode compiler to recognize the type as Objective-C++
Set the XcodeTheos header file to allow the compiler to recognize logos syntax. The address of the corresponding header file: https://github.com/onezens/Xcode-Theos. After importing the project, create a global header file and put the header file in In tweak.xmi
, I found that the code inside was black and was not recognized by the compiler. At this time, after closing the project and reopening it, I found that it would be re-recognized by Xcode.
Then set the XcodeTheos
macro to let Xcode recognize the logos macro.
After setting it up together, start writing the logos hook code. If everything is normal, you will find that writing the logos code in Xcode is super smooth, and the Xcode compiler will prompt success.
First modify the compilation file of Makefile When creating a file with the corresponding logos syntax in the future, always name it as an xmi file and write it into the Makefile.
WeChatBot_FILES = Tweak.xm
=> 修改为:
WeChatBot_FILES = Tweak.xmi
There is a problem with the header file reference path in the project, causing compilation to fail.
➜ WeChatBot git:(master) ✗ make
> Making all for tweak WeChatBot…
==> Preprocessing Tweak.xmi…
Tweak.xmi:2:9: fatal error: 'wechatbot-prefix-header.h' file not found
#import "wechatbot-prefix-header.h"
^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
make[3]: *** [/Users/wz/Documents/GitHub/WeChatBot/.theos/obj/debug/armv7/Tweak.mii] Error 1
make[2]: *** [/Users/wz/Documents/GitHub/WeChatBot/.theos/obj/debug/armv7/WeChatBot.dylib] Error 2
make[1]: *** [internal-library-all_] Error 2
make: *** [WeChatBot.all.tweak.variables] Error 2
It was found that it was a header file. The reason for the introduction was to set the header file directory in the Makefile.
#头文件
WeChatBot_OBJCFLAGS += -I./WeChatBot/Headers/wechatHeaders/
WeChatBot_OBJCFLAGS += -I./WeChatBot/Headers/
If you use the latest version of theos, we will find that compiling the .xmi
file will include the following error
➜ WeChatBot git:(master) ✗ make
> Making all for tweak WeChatBot…
==> Preprocessing Tweak.xmi…
==> Compiling Tweak.xmi (arm64)…
Tweak.xmi:18:104: error: use of undeclared identifier 'MSHookMessageEx'
{Class _logos_class$_ungrouped$MicroMessengerAppDelegate = objc_getClass("MicroMessengerAppDelegate"); MSHookMessageEx(_logos_class$_ungro...
^
1 error generated.
make[3]: *** [/Users/wz/Documents/GitHub/WeChatBot/.theos/obj/debug/arm64/Tweak.xmi.ca6fefe9.o] Error 1
make[2]: *** [/Users/wz/Documents/GitHub/WeChatBot/.theos/obj/debug/arm64/WeChatBot.dylib] Error 2
make[1]: *** [internal-library-all_] Error 2
make: *** [WeChatBot.all.tweak.variables] Error 2
Solution:
.xmi
to .xi
files, and import the header file #include <substrate.h>
https://github.com/onezens/theos.git
to replace the original version for compilationSolve the problem of compilation warnings and error reports
➜ WeChatBot git:(master) ✗ make
> Making all for tweak WeChatBot…
==> Preprocessing Tweak.xmi…
==> Compiling Tweak.xmi (arm64)…
Tweak.xmi:8:4: error: 'UIAlertView' is deprecated: first deprecated in iOS 9.0 - UIAlertView is deprecated. Use UIAlertController with a preferredStyle
of UIAlertControllerStyleAlert instead [-Werror,-Wdeprecated-declarations]
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Works for hook" message:__null delegate:__null cancelButtonTitle:@"cancel" otherBu...
^
/opt/theos/sdks/iPhoneOS11.2.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAlertView.h:26:12: note: 'UIAlertView' has been explicitly marked
deprecated here
@interface UIAlertView : UIView
^
Tweak.xmi:8:27: error: 'UIAlertView' is deprecated: first deprecated in iOS 9.0 - UIAlertView is deprecated. Use UIAlertController with a
preferredStyle of UIAlertControllerStyleAlert instead [-Werror,-Wdeprecated-declarations]
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Works for hook" message:__null delegate:__null cancelButtonTitle:@"cancel" otherBu...
^
/opt/theos/sdks/iPhoneOS11.2.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIAlertView.h:26:12: note: 'UIAlertView' has been explicitly marked
deprecated here
@interface UIAlertView : UIView
^
2 errors generated.
make[3]: *** [/Users/wz/Documents/GitHub/WeChatBot/.theos/obj/debug/arm64/Tweak.xmi.6c3ff448.o] Error 1
make[2]: *** [/Users/wz/Documents/GitHub/WeChatBot/.theos/obj/debug/arm64/WeChatBot.dylib] Error 2
make[1]: *** [internal-library-all_] Error 2
make: *** [WeChatBot.all.tweak.variables] Error 2
Solution:
TARGET = iphone:11.2:7.0
#忽略OC警告
WeChatBot_OBJCFLAGS += -Wno-deprecated-declarations
#导入系统的frameworks
WeChatBot_FRAMEWORKS = Foundation UIKit
#导入系统库
WeChatBot_LIBRARIES = stdc++ c++
#导入第三方Frameworks, 动态库需特殊处理
WeChatBot_LDFLAGS += -F./Libraries/dynamic -F./Libraries/static # 识别的库实现
WeChatBot_CFLAGS += -F./Libraries/dynamic -F./Libraries/static # 头文件识别
WeChatBot_FRAMEWORKS += WCBFWStatic WCBFWDynamic
#导入第三方lib
WeChatBot_LDFLAGS += -L./Libraries/dynamic -L./Libraries/static # 识别的库实现
WeChatBot_CFLAGS += -I./Libraries/include # 头文件识别
WeChatBot_LIBRARIES += WCBStatic WCBDyLib
include places all the header files of .a and .dylib libraries. dynamic places all the dynamic library folders. The dynamic libraries are put together to facilitate script processing. static prevents all static library folders.
When we added the dynamic library to the project, we found that running our tweak plug-in did not work in the host APP. The log prompt information was:
Apr 9 15:55:28 wz5 WeChat[5329] <Error>: MS:Error: dlopen(/Library/MobileSubstrate/DynamicLibraries/WeChatBot.dylib, 9): Library not loaded: @rpath/WCBFWDynamic.framework/WCBFWDynamic
Referenced from: /Library/MobileSubstrate/DynamicLibraries/WeChatBot.dylib
Reason: image not found
It can be seen from the log information that the host is in its own bundle and is not loaded into our dynamic library, so the function of our entire plug-in does not take effect.
View the generated dynamic library:
➜ WeChatBot git:(master) ✗ otool -L .theos/_/Library/MobileSubstrate/DynamicLibraries/WeChatBot.dylib
.theos/_/Library/MobileSubstrate/DynamicLibraries/WeChatBot.dylib:
/Library/MobileSubstrate/DynamicLibraries/WeChatBot.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1450.14.0)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1450.14.0)
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 3698.33.6)
@rpath/WCBFWDynamic.framework/WCBFWDynamic (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.1)
@rpath/libWCBDyLib.dylib (compatibility version 0.0.0, current version 0.0.0)
/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
We found that the dynamic library of the tweak project depends on rpath, which is the bundle path of the host, so we need to change this path.
The solution is to change the dynamic library dependency path through a script:
TWEAK_NAME=WeChatBot
cydiaLibPath=/Library/MobileSubstrate/DynamicLibraries/$TWEAK_NAME
dylibPath=Libraries/dynamic
oriDylibPath=$dylibPath/ori
tweakLayoutPath=layout$cydiaLibPath
echo $tweakLayoutPath
if [[ ! -d $oriDylibPath ]]; then
mkdir $oriDylibPath
fi
if [[ ! -d $tweakLayoutPath ]]; then
mkdir $tweakLayoutPath
fi
checkDylibID() {
path=$1
libFullPath=$2
ckLibId=$(otool -L $path | grep rpath)
if [[ -n $ckLibId ]]; then
cp -r $libFullPath $oriDylibPath
ckLibId=${ckLibId%' ('*}
ckLibId=${ckLibId#*/}
install_name_tool -id $cydiaLibPath/$ckLibId $path
otool -L $path
fi
cp -r $libFullPath $tweakLayoutPath
}
for file in $dylibPath/*; do
if [[ $file =~ ".dylib" ]]; then
checkDylibID $file $file
elif [[ $file =~ ".framework" ]]; then
name=${file##*/}
name=${name%.*}
checkDylibID $file/$name $file
fi
done
Before each package, run this script and view the information after the package is completed:
➜ WeChatBot git:(master) ✗ otool -L .theos/_/Library/MobileSubstrate/DynamicLibraries/WeChatBot.dylib
.theos/_/Library/MobileSubstrate/DynamicLibraries/WeChatBot.dylib:
/Library/MobileSubstrate/DynamicLibraries/WeChatBot.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1450.14.0)
/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 1450.14.0)
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 3698.33.6)
/Library/MobileSubstrate/DynamicLibraries/WeChatBot/WCBFWDynamic.framework/WCBFWDynamic (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.1)
/Library/MobileSubstrate/DynamicLibraries/WeChatBot/libWCBDyLib.dylib (compatibility version 0.0.0, current version 0.0.0)
/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.0.0)
Simplify commonly used commands and improve daily development efficiency
before-package::
sh bin/check_dynamic_lib.sh #动态库处理脚本
cp ./bin/postinst .theos/_/DEBIAN/
cp ./bin/postrm .theos/_/DEBIAN/
chmod 755 .theos/_/DEBIAN/postinst
chmod 755 .theos/_/DEBIAN/postrm
after-install::
install.exec "killall -9 SpringBoard"
p::
make package
c::
make clean
i::
make
make p
make install
The postinst script is a script that is executed before each deb package installation. The postrm script is a script that is executed after each deb package installation is completed.
Note: You need to modify the execution permissions of these two before packaging.
chmod 755 .theos/_/DEBIAN/postinst
chmod 755 .theos/_/DEBIAN/postrm
Related script description: http://iphonedevwiki.net/index.php/Packaging
Application scenario: Install the plug-in in Cydia, and display the back button postrm script & delete the control dependency:
#!/bin/bash
declare -a cydia
cydia=($CYDIA)
if [[ ${CYDIA+@} ]]; then
eval "echo 'finish:open' >&${cydia[0]}"
else
echo "uninstall wk completed!"
echo ""
fi
killall -9 WeChat
exit 0
Parameter description:
Acceptable parameters for finish
# return - normal behaviour (return to cydia)
# reopen - exit cydia
# restart - reload springboard
# reload - reload springboard
# reboot - reboot device
Map the file to the mobile device through the layout directory in the project root directory, and then read the resource file
#define kWCBImgSrcPath @"/Library/AppSupport/WeChatBot/imgs"
UIImage *img = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/wcb_icon.png", kWCBImgSrcPath]];
NSLog(@"[WeChatBot] img: %@", img);
UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
[imgView sizeToFit];
imgView.center = CGPointMake(46, 60);
[self.window addSubview:imgView];
#用于编译的SDK和支持的ios最低版本
TARGET = iphone:11.2:9.0
#用于调试的设备地址
THEOS_DEVICE_IP = localhost
THEOS_DEVICE_PORT = 2222
# 打包命名不一样,正式包不会输出log等
DEBUG = 1
# 采用ARC内存管理
WeChatBot_CFLAGS = -fobjc-arc
#忽略OC警告,避免警告导致编译不过
WeChatBot_OBJCFLAGS += -Wno-deprecated-declarations -Wno-unused-variable
Package: cc.onezen.wechatbot #包名
Name: WeChatBot
Depends: mobilesubstrate #依赖库和依赖插件,如果需要插件在cydia安装后不重启springboard可以删掉,否则每次重新
Version: 0.0.1
Architecture: iphoneos-arm
Description: An awesome MobileSubstrate tweak!
Maintainer: wz
Author: wz
Section: Tweaks #cydia源中的分类
Icon: file:///Library/AppSupport/WeChatBot/imgs/wcb_icon.png #icon
git address: https://github.com/onezens/WeChatBot