【交接文档】高鑫

dev_chengFeng
gaoxin 2022-03-14 16:10:23 +08:00
parent 4ed698b567
commit 20dc705f0a
9 changed files with 0 additions and 0 deletions

View File

@ -0,0 +1,84 @@
IOS 马甲包 混淆方案
混淆大概包括游戏AB包混淆Unity库混淆和SDK混淆三大部分。新增了对配置文件的混淆。
混淆要求能够快速便捷的进行重新混淆,目前方案尚不成熟,需要耗费时间手动进行配置。
在混淆开始之前我们先定义一个混淆字段 EncryptKey = "qwerrewq" 这个Key将在我们混淆的流程中反复使用请保证这个Key值在混淆过程中的唯一性。
1、 游戏AB包混淆
苹果机审时可能会对游戏内资源进行比较,比较的内容可能包括文件名和文件内容,所以需要对这两部分进行混淆
文件名混淆:
在Android工程中我们的AB包资源都是按照路径进行存放的但是因为混淆的要求不仅仅包括文件名还包括文件的路径所以为了方便混淆我们直接舍弃了路径将路径分割符 `\' 替换为下划线 `_'所以在IOS的AB资源中我们看不到文件夹所有资源均保存在根目录下。
除了路径我们还加入了向文件名前加入混淆字段的方式这样每次要求我们重新混淆时我们只需要替换文件名前面的混淆字段即可。因为AB包的文件之间会根据文件名有个强关联性。所以文件名的混淆必须做在制作AB包之前所以我们在AB包制作工具中加入了新的选项如下图勾选是否需要混淆后在出现的混淆值字段中填入我们定义好的EncryptKey值并制作AB包即可。
文件内容混淆:
内容混淆采用的是头部混淆的方式在unity制作完AB包后使用工具将EncryptKey值写入所有AB包的头部并在游戏运行加载时使用官方提供的API提供的offset参数如下图跳过AB包前加入的特定字符进行加载。
目前测试头部混淆这种方式是加载最快且有效的方式。其他混淆算法比如异或等等我都尝试过会导致AB包加载时卡顿当然也有可能是我算法写的比较差如果有更好的办法可以分享一下。
在太初行中的自动打包工具(自动化打包->一键导出我们在IOS打包时提供了下面几个功能打包工具的详细说明请查看文档《sdk接入架构及打包》。
三个编辑按钮分别编辑的是ClientConfig工程Version文件夹中对应包的Setting.txtconfig.txt和version.txt文件其中setting文件原来只存在于热更工程中只是用来配置热更的参数现在放在这里的原因是我们要在里面加入一个字段EncryptKey通过这个key值对AB进行内容的混淆。
点击编辑Setting按钮打开Setting文件是一个json结构其他内容请查看《热更新》相关文档。如果没有EncryptKey值则新增如果有则直接修改值为我们准备好的EncryptKey的值。
Setting文件修改完成后点击开始混淆工具将会自动对母包工程中的AB包文件的内容进行混淆。
其他文件:
Resources文件夹当前项目Res文件夹下几乎没有内容而且这个文件夹生成工程时会生成一个文件所以只需要在这个文件夹下加入一些无用内容每次混淆时对这些内容做出一些修改即可。
闪屏图游戏如果没有使用unity自带的闪屏功能的话在生成工程时unity会自动使用默认的一张图作为闪屏图这张图每次生成工程都是一样的所以每次混淆使用一张纯黑色的图进行替换。
2、 Unity库混淆
在漫长的混淆旅途中发行方提供给了我们一个提审方案我将其命名为IOS提审方案v99.1 [HYPERLINK: ]我不知道这是第几版方案了只是希望还没有超过100版。其中大部分太初行已经处理了这里我说下每次混淆都要重新处理的部分
1> global-metadata.dat文件
在导出Xcode工程后我们会在Data/Managed/Metadata/文件夹下找到这个文件具体作用不明反正就是要对他加密混淆而且每次重新混淆的时候都要修改加密这个文件的key值以保证文件与老包的差异性。
加密混淆( global-metadata.dat
峰哥针对这个文件的混淆编写了一个可执行文件LoopEncode放在母包工程JL_Packager中的IOS/Tool/文件夹中其源代码放在IOS/IL2CPP/LoopEncoder其原理就是拿到global-metadata.dat文件通过异或加密的方式重写了文件的内容。
游戏运行时解密libil2cpp.a
加密混淆后我们需要在游戏运行加载时对此文件进行解密加载这个文件的位置是在Unity底层在Xcode工程中则是被封装到了Libraries/libil2cpp.a中所以我们需要对这个文件进行修改。
①新建一个空Xcode工程模板类型为 Static Library并删除所有自动生成的代码。
②在mac上找到游戏使用的Unity引擎右击显示包内容在Contents/il2cpp/文件夹中找到两个文件夹external和libil2cpp复制到新建工程的根目录下。
③在Xcode中右击工程根节点-->Add Files to "***"... 选中我们刚刚复制的libil2cpp文件夹点击Add按钮添加到工程中。
④点击工程根节点选择TARGETS下的选项选则Build Settings在搜索栏中输入Search Paths在Header Search Paths属性中加入 "./libil2cpp"并在User Header Search Paths中加入"./external/boehmgc/include" 和 "./libil2cpp"
⑤ 点击运行按钮显示成功即工程搭建完成。
⑥加载 global-metadata.dat文件的脚本为MetadataLoader.cpp在脚本中加入异或解密的算法将内容还原称我们加密之前的即可。代码详见IOS/IL2CPP/下的工程中的代码。注意代码中的混淆的KEY值需要使用我们开始时定义的EncryptKey值。
⑦运行生成libil2cpp.a文件如果成功可以在日志中找到生成的.a文件的路径打开这个路径复制.a文件到我们母包工程的Libraries文件夹下替换即可。
2> 替换unity引用库的guidIl2CppAttributes.cpp
提审方案中要求我们unity引用库的guid要不一样经讨论unity的引用库主要集中在/Classes/Native/Il2CppAttributes.cpp文件中而且guid的值的特征都比较明显文件中以"GuidAttribute__ctor_"开始的行中包含在引号中的值就是guid于是我们又写了一个工具母包工程/IOS/Tool/GuidReplace.py工具中使用到了Python中的uuid库随机生成guid并替换到母包的cpp文件中。
使用可执行文件实现对unity库的快速混淆
由于libil2cpp.a文件来源于Unity底层并不需要经常替换只需要在每次重新混淆出包时修改混淆key值重新替换即可。但是global-metadata.dat和Il2CppAttributes.cpp文件每次出包都会替换所以这两个文件的混淆操作我们封装成了一个.sh文件保存在打包工程/IOS/Tool/文件夹下这个文件中我们需要将开始时我们定义的EncryptKey配置到下图中红色箭头的位置然后双击运行即可快速对两个文件进行混淆。
每个sh文件对应一个母包目录所以当出现一个新的母包时并需要混淆时则拷贝一个sh文件并修改里面的路径绿色箭头为母包的文件夹名即可。
3、 SDK混淆
这一部分混淆大部要交给渠道方的sdk来做他们要混淆自己的sdk内容我们在拿到混淆的sdk之后需要重新接入也有可能只是替换sdk以及混淆之后方法名。
除了sdk我们还被要求混淆我们自己写的代码文件目前我们自己的文件只包括五个代码文件我们出包流程中有提及我们需要做的就是将文件名前面的混淆字段修改掉同时修改代码中的引用保证引用正确即可。
4、 配置文件的混淆(新增)
在之前的混淆中我们不会对配置文件做任何处理,由于之前配置文件的内容都是明文的,其中还包括一些热更和服务器地址等路径,在提审过程中可能会成为敏感因素,因此我们就加入了配置文件的混淆。
需要混淆的配置文件为files.unity3d, config.txt, version.txt, PackConfig.txt
对于文件名我们依然采用向前加入混淆字段EncryptKey的方式。
内容上:
files.unity3d 由于是个AB包文件所以在之前的AB内容混淆时就已经对这个文件做了混淆方式就是向文件内容前加入混淆字段EncryptKey。
config.txt和version.txt需要我们对明文内容进行混淆所以采用的是异或加密的方式进行的混淆加密字段使用的也是EncryptKey。
PackConfig.txt由于是需要分包之后交给人工配置的文件且不报含敏感信息所以内容上没有做混淆
对配置文件的混淆也都加入到了打包工具中点击同步配置文件时我们将会对config.txtversion.txt和PackConfig.txt的文件名进行混淆并混淆config.txt和version.txt的内容。点击混淆AB包中也加入了对files.unity3d的文件名的混淆。混淆使用的key值均为配置在setting文件中的值。
5、 切小游戏和提审服
在一些情况下IOS混淆要求我们在提审时要在包内展示和正式游戏内容不一样的内容根据需求的不同差异也不同例如在太初行的官包中我们采用的是切提审服的方式提审服内容和正式服内容大致相同只是关闭了除了后台计费点之外的所有充值活动以及部分不允许的功能。而在喜扑渠道的包中要求我们对游戏的UI资源进行替换当然大量替换游戏的UI有时并不可取所以切小游戏的方式出现了。
我们可以随意制作一些简单的单机小游戏,作为提审内容。目前太初行中的小游戏有两个,御剑行和逍遥游,每次混淆时只需要对这两个小游戏中的资源进行替换即可,甚至可以使用正式游戏中的资源。
小游戏/提审服切换正式服的规则:
①将包的唯一性参数化。也就是我们需要一个参数去定位这是哪一个包注意这里的包指的是子包。因为我们出的包有可能是母包所以渠道可以拿这个包分很多子包。如果想要单独控制这些子包的服务器状态就需要获取这些子包的信息这些信息一般由sdk提供。如果sdk没有提供那我们在PackConfig.txt中提供了字段需要渠道方在每次分子包时进行修改。
太初行中的这个唯一参数,我们使用的是 Channel + PackId的方式。Channel指的是我们与服务器约定配置在version文件中的channel字段。packId则是sdk或者发行配置的子包的唯一Id。
②在服务器后台添加一个配置。请服务器同学帮忙在后台添加了一个配置(游戏管理 -- >提审服管理),因为我们希望这个状态的修改交给渠道方控制。
将我们在第一步中准备好的唯一ID配置到后台中同时我们看到在后台中我们可以给这个id配置一个值提审服务器值。我们在出包时都会给包配置一个值Android的VersionCode在IOS中则是build而且我们每次出包都会将这个值+1。所以判断服务器状态的规则当包的versioncode/build小于等于我们在后台配置的服务器值时那么该包连接的是正式服反之则是提审服。
③利用上面的规则,我们就可以在游戏中判断当前的状态进行相应的表现就可以了。
6、 混淆的流程
① 准备小游戏内容或者准备提审服内容
② 确定混淆Key值EncryptKey = "qwerrewq",对
③ 准备热更资源在这一步中我们需要对资源的文件名进行混淆游戏AB包混淆-文件名混淆)。
④ 对Unity中的其他文件进行混淆游戏AB包混淆-其他文件)。
⑤ 准备入口场景并导出Xcode工程。
注意这里在上文中并没有提到
因为我们将AB包和配置文件等都将进行了混淆加密操作所以我们在游戏运行时需要对这些混淆后的文件进行解密操作那么游戏中就需要知道我们混淆的Key值。于是我们在入口场景中加入了下面的配置。每次重新混淆时需要将这个配置改为我们确定的混淆Key值。
⑥ 导出工程后,将相应的内容导入已经准备好的母包中,具体操作请查看 IOS母包搭建 文档。
⑦ 配置自动打包工具修改setting.txt文件中的混淆字段为准备好的EncryptKey值对母包中的AB包文件的内容游戏AB包混淆-文件内容混淆)和配置文件的名称和内容(配置文件的混淆)进行混淆。
⑧ 将混淆之后AB包文件config.txt和version.txt文件上传到CDN并刷新这一步见《热更新》。
⑨ 修改母包工程/IOS/Tool/中的sh文件配置我们母包工程和EncryptKey的值双击运行对unity库文件进行混淆。如果是重新混淆则还需要重新制作libil2cpp.a文件并替换到母包中。Unity库混淆
⑩ SDK混淆修改我们自己的sdk代码的混淆字段的值并接入渠道方重新混淆的SDK。
到此混淆完成,就可以出包测试了。

View File

@ -0,0 +1,65 @@
IOS提审方案v99.1
1.unity引用库的guid要不一样
打出xcode工程扫描guid集中的一个文件可以写工具集中替换2018版本可能是16进制。
具体是哪个文件再确认
2.sdk相关参数每次要不一样尤其是facebook
每次都会更换
3.globalmetadata必须要加密
有FairGuard这个工具可以进行加密再看看有没有免费的方式。
4.wx pay buy charge switch等关键字不能有
处理过,再仔细检查
5.域名绑定的ip要换
只更换过一次下次再换一次需发行方提供新的ip
6.工程路径需要重新打包,要新建工程,进程名称和路径名称都要不一样,名称不要和其他公司名相碰
发行发提供新的sdk我们重新导出新工程并接入
7.老证书要删掉
把所有证书全部删除
8.不能使用webview
没有使用
9.资源文件md5路径换掉
就是我们ab包的资源文件的路径要每次都不一样
10.引擎混淆否则始终以一个unity版本
尝试换个引擎版本试试
11.可视字符32位的要替换通信要加密
通讯已经加密。
可视字符32位指的是代码中不要出现长度为32位的字符串。
12.facebook登录最好去掉
发行去处理
13.客户端日志全部去掉。引擎混淆后可少量c#代码混淆
即将处理日志
14.build id每次重新提从1开始
可以
15.resource目录下的文件如果不需要全部删除
目前确认xcode中的Resources文件夹下的文件只有一个
应该可以删除
16.包体里的链接都要去掉
处理过,再检查
17.混淆尽量用工具,记录过包的混淆方式便于下次出包按同样的方式
18.不能使用base64加密
没使用过
19.meta文件写脚本替换fireid
需要丹哥再确认下
20.所有http请求要加密建议用aes登录ip
修改下传参个数名称。IP修改。 AES加密需要后端支持
*17开头的基本是苹果公司的人在登录审核苹果账号购买的信用卡不能一样

View File

@ -0,0 +1,18 @@
echo "按CPU架构分离.A文件"
lipo libiPhone-lib-il2cpp.a -thin armv7 -output libiPhone-lib-il2cpp-armv7.a
lipo libiPhone-lib-il2cpp.a -thin arm64 -output libiPhone-lib-il2cpp-arm64.a
echo "armv7移除UIWebView"
clang++ -c URLUtility.mm -std=c++11 -stdlib=libc++ -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk
ar -d libiPhone-lib-il2cpp-armv7.a URLUtility.o
ar -q libiPhone-lib-il2cpp-armv7.a URLUtility.o
echo "arm64移除UIWebView"
clang++ -c URLUtility.mm -std=c++11 -stdlib=libc++ -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk
ar -d libiPhone-lib-il2cpp-arm64.a URLUtility.o
ar -q libiPhone-lib-il2cpp-arm64.a URLUtility.o
echo "重新生成.A文件"
lipo -create -output libiPhone-lib-il2cpp_new.a libiPhone-lib-il2cpp-arm64.a libiPhone-lib-il2cpp-armv7.a
rm libiPhone-lib-il2cpp-arm64.a libiPhone-lib-il2cpp-armv7.a URLUtility.o

View File

@ -0,0 +1,28 @@
#include <iostream>
#import <UIKit/UIKit.h>
using namespace std;
namespace core {
template <class type>
class StringStorageDefault {};
template <class type,class type2>
class basic_string {
public:
char *c_str(void);
};
}
void OpenURLInGame(core::basic_string< char,core::StringStorageDefault<char> > const&arg){}
void OpenURL(core::basic_string<char,core::StringStorageDefault<char> >const&arg){
const void *arg2= &arg;
UIApplication *app = [UIApplication sharedApplication];
NSString *urlStr = [NSString stringWithUTF8String:(char *)arg2];
NSURL *url = [NSURL URLWithString:urlStr];
[app openURL:url];
}
void OpenURL(std::string const&arg){
UIApplication *app = [UIApplication sharedApplication];
NSString *urlStr = [NSString stringWithUTF8String:arg.c_str()];
NSURL *url = [NSURL URLWithString:urlStr];
[app openURL:url];
}

View File

@ -0,0 +1,63 @@
ios 提审时遇到饮用UIWebView 无法过审的问题:
引用https://blog.csdn.net/aawoe/article/details/106219341
根据苹果应用商店的最新政策, UIWebView相关API已经Deprecated如果项目中有引用UIWebView则即将无法通过苹果审核提示信息如下
ITMS-90809: Deprecated API Usage - Apple will stop accepting submissions of apps that use UIWebView APIs . See https://developer.apple.com/documentation/uikit/uiwebview for more information.
对于Unity项目可以通过如下几个步骤排查
检查自己项目Plugins目录下的native代码或静态库是否有引用UIWebView源码文本文件可以比较容易检索出结果而对于已编译好的静态库二进制文件可以在Unity工程根目录下使用grep -r UIWebView .命令如果有输出Binary file xxxxx matches则对应的二进制文件也极可能引用了UIWebView(不排除部分文件中的非字符串数据也恰好能匹配上,但概率很低)。如果是业务代码引用则替换升级为WKWebView如果是三方库引用则更新到新版本即可。
检查自己项目使用的Unity版本Untiy官方提到在PlatformDependent/iPhonePlayer/URLUtility.mm中引用了UIWebView并在Unity 2017.4.32f12018.4.8f12019.2.4f12019.3.0b2和2020.1.0a2进行了修复所以对于大版本使用Unity2017及以上的项目可以将Unity升级为最新的LTS版本来去掉UIWebView的引用。如果升级引擎代价过大或者项目使用的Unity5.6及之前版本也可以重新编译URLUtility.mm并替换用于链接的Unity静态库中的目标文件URLUtility.o达到同样目的。
步骤2的具体操作如下(必须在MacOS构建机下)
进入Unity打包链接的静态库目录/Applications/Unity.app/Contents/PlaybackEngines/iOSSupport/Trampoline/Libraries(PlaybackEngines文件夹有时也在Unity.app平级目录下)libiPhone-lib-il2cpp.a 即iOS构建时链接的Unity静态库(构建xcode工程时会被拷贝到Libraries目录并重命名为libiPhone-lib.a)所以我们只要修改该文件就能一劳永逸而不需要每次构建xcode工程都重新修改但是建议在修改前将该文件备份。
使用命令otool -Vf libiPhone-lib-il2cpp.a查看该静态库支持armv7、armv7s(Unity5.6支持不完备)和arm64三种指令集架构然后使用lipo工具将三种指令集架构单独分离
lipo libiPhone-lib-il2cpp.a -thin armv7 -output libiPhone-lib-il2cpp-armv7.a
lipo libiPhone-lib-il2cpp.a -thin armv7s -output libiPhone-lib-il2cpp-armv7s.a
lipo libiPhone-lib-il2cpp.a -thin arm64 -output libiPhone-lib-il2cpp-arm64.a
新建一个不引用UIWebView的URLUtility.mm代码如下
#include <iostream>
#import <UIKit/UIKit.h>
using namespace std;
namespace core {
template <class type>
class StringStorageDefault {};
template <class type,class type2>
class basic_string {
public:
char *c_str(void);
};
}
void OpenURLInGame(core::basic_string< char,core::StringStorageDefault<char> > const&arg){}
void OpenURL(core::basic_string<char,core::StringStorageDefault<char> >const&arg){
const void *arg2= &arg;
UIApplication *app = [UIApplication sharedApplication];
NSString *urlStr = [NSString stringWithUTF8String:(char *)arg2];
NSURL *url = [NSURL URLWithString:urlStr];
[app openURL:url];
}
void OpenURL(std::string const&arg){
UIApplication *app = [UIApplication sharedApplication];
NSString *urlStr = [NSString stringWithUTF8String:arg.c_str()];
NSURL *url = [NSURL URLWithString:urlStr];
[app openURL:url];
}
分别针对armv7和arm64编译URLUtility.mm使用ar工具移除前面生成的对应指令集架构的静态库文件中的URLUtility.o然后使用ar工具将新编译的URLUtility.o重新打包进对应指令集架构的静态库文件。也可以只对arm64架构的进行替换因为目前市面几乎已经没有不支持arm64的iOS设备考虑到包体大小所以大部分项目Architectures都设置为仅支持arm64
clang++ -c URLUtility.mm -std=c++11 -stdlib=libc++ -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk
ar -d libiPhone-lib-il2cpp-armv7.a URLUtility.o
ar -q libiPhone-lib-il2cpp-armv7.a URLUtility.o
clang++ -c URLUtility.mm -std=c++11 -stdlib=libc++ -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk
ar -d libiPhone-lib-il2cpp-arm64.a URLUtility.o
ar -q libiPhone-lib-il2cpp-arm64.a URLUtility.o
使用lipo工具重新合并各指令集架构的.a文件然后删除临时文件此时新生成的libiPhone-lib-il2cpp_new.a已经去掉对UIWebView的引用最后将其重命名替换目录下的libiPhone-lib-il2cpp.a即可。
lipo -create -output libiPhone-lib-il2cpp_new.a libiPhone-lib-il2cpp-arm64.a libiPhone-lib-il2cpp-armv7s.a libiPhone-lib-il2cpp-armv7.a
rm libiPhone-lib-il2cpp-arm64.a libiPhone-lib-il2cpp-armv7s.a libiPhone-lib-il2cpp-armv7.a URLUtility.o
如果项目之前的版本有收到过苹果关于UIWebView的提示建议下个版本修复时先提交ipa到iOS预审平台检查一下是否完全去除了UIWebView然后再进行提审。

View File

@ -0,0 +1,26 @@
游戏内部部分配置和资源替换说明
包配置文件及资源替换路径为 包根目录/assets/Res
替换的资源文件也放置在此文件夹下,并在配置文件中配置好相应的文件名即可。
其中PackConfig.txt为json配置文件参数说明_Readme.md如下
包配置PackConfig.txt参数字段说明
PackID 用于标识子包的唯一ID
UpdatePanelBG 更新界面背景只支持png
LoginPanelBG 登录界面背景只支持png
LoginPanelLogo 登录界面Logo只支持png
LoginPanelVideoBG 登录界面视频背景只支持mp4
LoadingPanelBG 登录后游戏加载界面背景只支持png多个背景随机请用#号分割)
注:
1、 视频背景的参数目前是不生效的
2、PacklD的作用
1>定制用于切换子包提审状态的ID。配置后子包用于切换提审状态的ID将变为母包的渠道名MHT和PackID无分割符连接的字符串同时需要在GM后台GM管理->提审服管理对该ID进行配置并单独管理。如果渠道名为MHTPackID为1001则切换提审状态的ID为MHT1001
2>定制用于定制子包用户隐私协议的ID。配置后子包用户隐私协议的ID将变为母包的渠道名MHT和PackID无分割符连接的字符串同时需要在GM后台GM管理->游戏协议管理对该ID进行配置并单独管理。与切换子包提审状态的ID为相同的值
3>定制对来自相同母包的子包的公告内容。配置后子包的公告通道ID将变为母包的公告id和PackID无分割符连接的字符串同时需要对子包的公告通道ID在GM后台GM管理->频道管理对该ID进行配置并单独管理。与切换提审状态的ID类似

Binary file not shown.