Al crear un proyecto de ingeniería inversa, cómo hacer que el proyecto sea más conveniente de usar y fácil de expandir, así como la identificación del compilador, pueden mejorar en gran medida nuestra eficiencia de desarrollo diario y la calidad del código. Este artículo describe principalmente cómo usar el proyecto tweak de Theos para crear un proyecto que pueda ser reconocido por el compilador Xcode, así como las configuraciones comúnmente utilizadas en el proyecto.
https://www.onezen.cc/2017/09/16/iosrevert/revdevconfig.html
Después de configurar el entorno, cree el proyecto de modificación correspondiente.
Cree un proyecto de biblioteca estática de Xcode basado en el nombre del proyecto de ajuste creado anteriormente y luego mezcle el ajuste y el proyecto de Xcode creado.
Cree una carpeta de configuración (Nuevo grupo sin carpeta) en el proyecto Xcode y coloque el Makefile, el archivo plist correspondiente y el archivo de configuración de control en este directorio sin copiar. Luego cree la carpeta correspondiente en Xcode, luego reemplace todos los sufijos de los archivos .xm
generados con .xmi
y colóquelos en la capa más externa del proyecto como la única clase de entrada.
Configure Tweak.xmi en el compilador de Xcode para reconocer el tipo como Objective-C++
Configure el archivo de encabezado de XcodeTheos para permitir que el compilador reconozca la sintaxis de los logotipos. La dirección del archivo de encabezado correspondiente: https://github.com/onezens/Xcode-Theos. Después de importar el proyecto, cree un archivo de encabezado global y coloque el encabezado. archivo en En tweak.xmi
, descubrí que el código dentro era negro y el compilador no lo reconoció. En este momento, después de cerrar el proyecto y volver a abrirlo, descubrí que Xcode lo volvería a reconocer.
Luego configure la macro XcodeTheos
para permitir que Xcode reconozca la macro del logotipo.
Después de configurarlo juntos, comience a escribir el código de enlace de logotipos. Si todo es normal, encontrará que escribir el código de logotipos en Xcode es muy sencillo y el compilador de Xcode le indicará que se realizó correctamente.
Primero modifique el archivo de compilación de Makefile Cuando cree un archivo con la sintaxis de logotipos correspondiente en el futuro, nómbrelo siempre como archivo xmi y escríbalo en el Makefile.
WeChatBot_FILES = Tweak.xm
=> 修改为:
WeChatBot_FILES = Tweak.xmi
Hay un problema con la ruta de referencia del archivo de encabezado en el proyecto, lo que provoca que falle la compilación.
➜ 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
Se descubrió que era un archivo de encabezado. El motivo de la introducción fue establecer el directorio del archivo de encabezado en Makefile.
#头文件
WeChatBot_OBJCFLAGS += -I./WeChatBot/Headers/wechatHeaders/
WeChatBot_OBJCFLAGS += -I./WeChatBot/Headers/
Si utiliza la última versión de theos, encontraremos que al compilar el archivo .xmi
se incluirá el siguiente 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
Solución:
.xmi
a .xi
e importe el archivo de encabezado #include <substrate.h>
https://github.com/onezens/theos.git
para reemplazar la versión original para la compilaciónResuelva el problema de las advertencias de compilación y los informes de errores.
➜ 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
Solución:
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 coloca todos los archivos de encabezado de las bibliotecas .a y .dylib. Dynamic coloca todas las carpetas de la biblioteca dinámica. Las bibliotecas dinámicas se reúnen para facilitar el procesamiento de secuencias de comandos estáticas.
Cuando agregamos la biblioteca dinámica al proyecto, descubrimos que la ejecución de nuestro complemento de modificación no funcionaba en la aplicación host. La información del mensaje de registro era:
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
Se puede ver en la información de registro que el host está en su propio paquete y no está cargado en nuestra biblioteca dinámica, por lo que la función de todo nuestro complemento no tiene efecto.
Ver la biblioteca dinámica generada:
➜ 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)
Descubrimos que la biblioteca dinámica del proyecto de modificación depende de rpath, que es la ruta del paquete del host, por lo que debemos cambiar esta ruta.
La solución es cambiar la ruta de dependencia de la biblioteca dinámica mediante un 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
Antes de cada paquete, ejecute este script y vea la información una vez completado el paquete:
➜ 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)
Simplifique los comandos de uso común y mejore la eficiencia del desarrollo diario
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
El script postinst es un script que se ejecuta antes de cada instalación del paquete deb. El script postrm es un script que se ejecuta después de que se completa la instalación de cada paquete deb.
Nota: Debe modificar los permisos de ejecución de estos dos antes del empaquetado.
chmod 755 .theos/_/DEBIAN/postinst
chmod 755 .theos/_/DEBIAN/postrm
Descripción del script relacionado: http://iphonedevwiki.net/index.php/Packaging
Escenario de aplicación: instale el complemento en Cydia, muestre el script postrm del botón Atrás y elimine la dependencia de control:
#!/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
Descripción del parámetro:
Acceptable parameters for finish
# return - normal behaviour (return to cydia)
# reopen - exit cydia
# restart - reload springboard
# reload - reload springboard
# reboot - reboot device
Asigne el archivo al dispositivo móvil a través del directorio de diseño en el directorio raíz del proyecto y luego lea el archivo de recursos
#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
dirección de git: https://github.com/onezens/WeChatBot