苹果重复应用问题

苹果提审中,被4.3重复应用打回来很常见(诸如上马甲包等),而首先一步是面对机审,苹果检测二进制文件,而游戏主要要处理的也就代码和资源文件,以及icon和splash。

一、处理资源文件

  我的做法是将所有资源压缩成一个文件,再对压缩资源进行简单的异或加密,游戏时,在解压前再用相同的key对资源进行异或运算还原资源,最后直接解压到persistentDataPath目录。以下是异或加密算法。 

 1     //异或加密
 2     public static void XOREncryption(string resPath, string key)
 3     {
 4         //读取资源文件
 5         FileStream fileStream = File.OpenRead(resPath);
 6         byte[] data = new byte[fileStream.Length];
 7         fileStream.Read(data, 0, data.Length);
 8         fileStream.Close();
 9 
10         //异或加密
11         for (int i = 0; i < data.Length; i++)
12         {
13             int index = i % key.Length;
14             data[i] = (byte)(data[i] ^ key[index]);
15         }
16 
17         //替换加密后文件
18         File.Delete(resPath);
19         File.WriteAllBytes(resPath, data);
20     }
View Code

二、处理代码

  处理方法是通过工具生成一些垃圾代码来改变代码二进制文件,以下是整个工具实现:

  1 using LuaFramework;
  2 using UnityEditor;
  3 using System;
  4 using System.Text;
  5 using System.IO;
  6 using System.Security.Cryptography;
  7 
  8 //文件定义:垃圾代码生成器
  9 //一、设计要点:
 10 //1、用当前时间+生成代码序号生成md5字符,用md5字符命名类名、函数名、变量名等
 11 //2、随机一种函数模版,用1生成的函数名、参数名生成函数体
 12 //3、生成GarbageCodeManager类调用所有生成的代码
 13 //二、范式生成要点:
 14 //1、用正常c#写代码
 15 //2、用ChangeClassFile2CodeCreateTool.py工具将正常代码转成生成该代码的代码(类名、函数名等已替换为参数)
 16 //三、游戏调用
 17 //1、在main.cs中通过UNITY_IPHONE && SDK宏控制调用GarbageCodeManager.CallAllGarbageCode()调用生成的代码
 18 //作者:青树
 19 //时间:2017/10/20
 20 
 21 //垃圾代码参数
 22 public class GarbageCodeParam {
 23     public string className;         //类名
 24     public string mainFuncName;      //入口函数名
 25     public string mainFuncParam1;    //入口函数参数1
 26     public string mainFuncParam2;    //入口函数参数2
 27     public string mainFuncParam3;    //入口函数参数3
 28 }
 29 
 30 //垃圾代码生成器
 31 public class GarbageCodeTool
 32 {
 33     //生成垃圾代码函数模版个数
 34     private const int funcTplCount = 1;
 35     //函数模版委托:入口函数名,入口函数参数1,入口函数参数2,入口函数参数3 ;返回生成该函数的字符串
 36     private delegate string FuncTplHandle(string methonName, string param1, string param2, string param3);
 37     //函数模版数组
 38     private static FuncTplHandle[] arrFuncTplHandle;
 39     //管理所有垃圾代码的文件名
 40     private const string garbageCodeManagerName = "CallAllCodeManager";
 41     private static bool isGenerateXcode = false;    
 42 
 43     //c#垃圾代码变量
 44     private const  string namespaceName = "LuaFramework";                         //生成代码的命名空间    
 45     private static string mstCreateCodeFilePath =                                 //生成代码路径
 46         UnityEngine.Application.dataPath + "/LuaFramework/Scripts/GarbageCode";  
 47     private const  int    maxFileCount = 1000;                                     //垃圾代码个数
 48 
 49     //Xcode垃圾代码变量
 50     private static string mstCreateXCodeFilePath =                                //生成XCode代码路径
 51         UnityEngine.Application.dataPath + "/LuaFramework/Scripts/GarbageXCode";
 52     private const int maxXCodeFileCount = 50;                                     //XCode垃圾代码个数
 53 
 54     //生成C#垃圾代码
 55     [MenuItem("Tools/GenerateGarbageCode")]
 56     static void GenerateGarbageCode() {
 57         isGenerateXcode = false;
 58 
 59         //删除旧目录代码
 60         if (Directory.Exists(mstCreateCodeFilePath))
 61         {
 62             Directory.Delete(mstCreateCodeFilePath, true);
 63         }
 64         AssetDatabase.Refresh();
 65         AssetDatabase.SaveAssets();
 66 
 67 #if !UNITY_IPHONE
 68         //只有苹果才生成垃圾代码
 69         return;
 70 #endif
 71        
 72         //重新创建目录
 73         Directory.CreateDirectory(mstCreateCodeFilePath);
 74         Directory.CreateDirectory(mstCreateCodeFilePath + "/Code");
 75 
 76         //获取本地时间作为生成md5条件之一
 77         string timeNow = DateTime.Now.ToString();
 78         string[] arrClassName  = new string[maxFileCount];
 79         string[] arrMethonName = new string[maxFileCount];
 80 
 81 #region 生成所有垃圾代码
 82         StringBuilder stringBuilder = null;
 83         for (int i = 0; i < maxFileCount; i++) {
 84             //获取垃圾代码参数
 85             GarbageCodeParam funcTplParam = GetFuncTplParam(timeNow,i);
 86 
 87             //生成文件名
 88             string fileName = Path.Combine(mstCreateCodeFilePath + "/Code", funcTplParam.className + ".cs");
 89             if (string.IsNullOrEmpty(fileName))
 90             {
 91                 continue;
 92             }
 93 
 94             //构造生成文本对象
 95             stringBuilder = new StringBuilder();
 96 
 97             //添加命名空间
 98             if (!string.IsNullOrEmpty(namespaceName))
 99             {
100                 stringBuilder.AppendFormat(string.Format("namespace {0}\n", namespaceName));
101                 stringBuilder.AppendLine("{");
102             }
103             stringBuilder.AppendLine("");
104 
105             //生成类名
106             stringBuilder.AppendFormat("public class {0} \n", funcTplParam.className);
107             stringBuilder.AppendLine("{");
108 
109             //随机选择一种函数模版作为类函数
110             string funcContent = GetFuncContent(funcTplParam.mainFuncName, 
111                 funcTplParam.mainFuncParam1, funcTplParam.mainFuncParam2, funcTplParam.mainFuncParam3);
112             stringBuilder.Append(funcContent);
113 
114             //添加最后的括号,保存文件
115             stringBuilder.AppendLine("}");
116             if (!string.IsNullOrEmpty(namespaceName))
117             {
118                 stringBuilder.AppendLine("}");
119             }
120             File.WriteAllText(fileName, stringBuilder.ToString());
121 
122             arrClassName[i]  = funcTplParam.className;
123             arrMethonName[i] = funcTplParam.mainFuncName;
124         }
125 #endregion 生成所有垃圾代码
126 
127 #region 生成调用所有垃圾代码的代码
128         string managerFilePath = Path.Combine(mstCreateCodeFilePath, garbageCodeManagerName + ".cs");
129         if (string.IsNullOrEmpty(managerFilePath))
130         {
131             return;
132         }
133         stringBuilder = new StringBuilder();
134         if (!string.IsNullOrEmpty(namespaceName))
135         {
136             stringBuilder.AppendFormat(string.Format("namespace {0}\n", namespaceName));
137             stringBuilder.AppendLine("{");
138         }
139         stringBuilder.AppendLine("using UnityEngine;");
140         stringBuilder.AppendLine("using System.Collections;");
141         stringBuilder.AppendLine("");
142         stringBuilder.AppendLine("namespace LuaFramework {");
143         stringBuilder.AppendLine("    //垃圾代码管理器");
144         stringBuilder.AppendFormat("public class {0}\n", garbageCodeManagerName);
145         stringBuilder.AppendLine("    {");
146         stringBuilder.AppendLine("        //调用所有垃圾代码");
147         stringBuilder.AppendLine("        public static void CallAllGarbageCode() {");
148 
149 
150         //调用所有垃圾代码
151         Random rd = new Random();
152         for (int i = 0; i < arrClassName.Length; i++)
153         {
154             string className = arrClassName[i];
155             string methonName = arrMethonName[i];
156             if (className == "" || methonName == "")
157             {
158                 continue;
159             }
160             int randa = rd.Next(0, 1000);
161             int randb = rd.Next(0, 1000);
162             int randc = rd.Next(0, 1000);
163             stringBuilder.AppendFormat("            {0} _{1} = new {2}();\n", className, className, className);
164             if (randc > 500)
165             {
166                 stringBuilder.AppendFormat("            _{0}.{1}({2},{3});\n", className, methonName, randa, randb);
167             }
168             else
169             {
170                 stringBuilder.AppendFormat("            _{0}.{1}({2},{3},{4});\n", className, methonName, randa, randb, randc);
171             }
172             stringBuilder.AppendLine("");
173         }
174 
175 
176         stringBuilder.AppendLine("        }");
177         stringBuilder.AppendLine("    }");
178         stringBuilder.AppendLine("}");
179         stringBuilder.AppendLine("");
180         if (!string.IsNullOrEmpty(namespaceName))
181         {
182             stringBuilder.AppendLine("}");
183         }
184         File.WriteAllText(managerFilePath, stringBuilder.ToString());
185 #endregion 生成调用所有垃圾代码的代码
186 
187         AssetDatabase.Refresh();
188         AssetDatabase.SaveAssets();
189 
190         EditorUtility.DisplayDialog("GenerateGarbageCode","生成完毕!", "确定");
191     }
192 
193     //生成Xcode垃圾代码
194     [MenuItem("Tools/GenerateXCodeGarbageCode")]
195     static void GenerateXCodeGarbageCode()
196     {
197         isGenerateXcode = true;
198 
199         //删除旧目录代码
200         if (Directory.Exists(mstCreateXCodeFilePath))
201         {
202             Directory.Delete(mstCreateXCodeFilePath, true);
203         }
204         AssetDatabase.Refresh();
205         AssetDatabase.SaveAssets();
206 
207 #if !UNITY_IPHONE
208         //只有苹果才生成垃圾代码
209         return;
210 #endif
211 
212         //重新创建目录
213         Directory.CreateDirectory(mstCreateXCodeFilePath);
214         Directory.CreateDirectory(mstCreateXCodeFilePath + "/Code");
215 
216         //获取本地时间作为生成md5条件之一
217         string timeNow = DateTime.Now.ToString();
218         string[] arrClassName = new string[maxXCodeFileCount];
219         string[] arrMethonName = new string[maxXCodeFileCount];
220 
221 #region 生成所有xcode垃圾代码     
222         StringBuilder stringBuilder = null;
223         for (int i = 0; i < maxXCodeFileCount; i++)
224         {
225             //获取垃圾代码参数
226             GarbageCodeParam funcTplParam = GetFuncTplParam(timeNow, i);
227 
228             //生成文件名
229             string fileName = Path.Combine(mstCreateXCodeFilePath + "/Code", funcTplParam.className + ".mm");
230             if (string.IsNullOrEmpty(fileName))
231             {
232                 continue;
233             }
234 
235             //构造生成文本对象
236             stringBuilder = new StringBuilder();
237 
238             stringBuilder.AppendLine("");
239 
240             //随机选择一种函数模版作为类函数
241             string funcContent = GetFuncContent(funcTplParam.mainFuncName,
242                 funcTplParam.mainFuncParam1, funcTplParam.mainFuncParam2, funcTplParam.mainFuncParam3);
243             stringBuilder.Append(funcContent);
244 
245             //保存文件
246             File.WriteAllText(fileName, stringBuilder.ToString());
247 
248             arrClassName[i] = funcTplParam.className;
249             arrMethonName[i] = funcTplParam.mainFuncName;
250         }
251 #endregion 生成所有xcode垃圾代码
252 
253 #region 生成调用所有垃圾代码的代码
254         string managerFilePath = Path.Combine(mstCreateXCodeFilePath, garbageCodeManagerName + ".mm");
255         if (string.IsNullOrEmpty(managerFilePath))
256         {
257             return;
258         }
259         stringBuilder = new StringBuilder();
260         stringBuilder.AppendLine("        //调用所有代码");
261         stringBuilder.AppendFormat("         void {0}()\n", garbageCodeManagerName);
262         stringBuilder.AppendLine("{");
263 
264         //调用所有垃圾代码
265         Random rd = new Random();
266         for (int i = 0; i < arrMethonName.Length; i++)
267         {
268             string methonName = arrMethonName[i];
269             if (methonName == "")
270             {
271                 continue;
272             }
273             int randa = rd.Next(0, 1000);
274             int randb = rd.Next(0, 1000);
275             int randc = rd.Next(0, 1000);
276 
277             stringBuilder.AppendFormat("            extern int {0}(int a,int b,int c = 0);\n", methonName);
278             if (randc > 500)
279             {
280                 stringBuilder.AppendFormat("            {0}({1},{2});\n", methonName, randa, randb);
281             }
282             else
283             {
284                 stringBuilder.AppendFormat("            {0}({1},{2},{3});\n", methonName, randa, randb, randc);
285             }
286             stringBuilder.AppendLine("");
287         }
288         stringBuilder.AppendLine("}");
289         stringBuilder.AppendLine("");
290         File.WriteAllText(managerFilePath, stringBuilder.ToString());
291 #endregion 生成调用所有垃圾代码的代码
292 
293         AssetDatabase.Refresh();
294         AssetDatabase.SaveAssets();
295 
296         EditorUtility.DisplayDialog("GenerateGarbageXCodeCode", "生成完毕!", "确定");
297     }
298 
299     //根据时间字符加序号产生垃圾代码参数
300     public static GarbageCodeParam GetFuncTplParam(string timeNow,int index) {      
301         //根据当前时间+序号 生成md5值
302         string md5 = CalcMd5(timeNow + index.ToString());
303         md5 = "_" + md5;
304 
305         //用md5值生成类名、入口函数名、参数名
306         GarbageCodeParam garbageCodeParam  = new GarbageCodeParam();
307         garbageCodeParam.className      = md5;
308         garbageCodeParam.mainFuncName   = md5 + "m";
309         garbageCodeParam.mainFuncParam1 = md5 + "a";
310         garbageCodeParam.mainFuncParam2 = md5 + UnityEngine.Random.Range(0, 100);
311         garbageCodeParam.mainFuncParam3 = md5 + "c";
312         return garbageCodeParam;
313     }
314 
315     //获取函数体(根据已有模版随机生成)
316     public static string GetFuncContent(string methonName, string param1, string param2, string param3) {
317 #if !UNITY_IPHONE
318         //只有苹果才生成垃圾代码
319         return "";
320 #endif 
321         //如果没有初始化则初始化函数模版
322         if (null == arrFuncTplHandle || arrFuncTplHandle.Length < funcTplCount) {
323             arrFuncTplHandle = new FuncTplHandle[funcTplCount];
324             arrFuncTplHandle[0] = FuncTpl1;
325         }
326 
327         //随机一种模版生成函数体
328         int randNum = UnityEngine.Random.Range(0, funcTplCount);
329         if (arrFuncTplHandle[randNum] == null)
330         {
331             Util.LogError("不存在范式,索引:" + randNum.ToString());
332             return "";
333         }
334         return arrFuncTplHandle[randNum](methonName, param1, param2, param3);
335     }
336 
337     /// <summary>
338     /// 计算字符串的MD5值
339     /// </summary>
340     static string CalcMd5(string source)
341     {
342         MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
343         byte[] data = System.Text.Encoding.UTF8.GetBytes(source);
344         byte[] md5Data = md5.ComputeHash(data, 0, data.Length);
345         md5.Clear();
346 
347         string destString = "";
348         for (int i = 0; i < md5Data.Length; i++)
349         {
350             destString += System.Convert.ToString(md5Data[i], 16).PadLeft(2, '0');
351         }
352         destString = destString.PadLeft(32, '0');
353         return destString;
354     }
355 
356 
357     //函数模版1
358     static string FuncTpl1(string methonName, string param1, string param2, string param3)
359     {
360         StringBuilder stringBuilder = new StringBuilder();
361         stringBuilder.AppendFormat("    int {0}2(int {1})\n", methonName, param1);
362         stringBuilder.AppendLine("    {");
363         stringBuilder.AppendFormat("        return (int)(3.1415926535897932384626433832795028841 * {0} * {0});\n", param1);
364         stringBuilder.AppendLine("    }");
365         stringBuilder.AppendLine("");
366         if (isGenerateXcode)
367         {
368             //入口函数xcode没有public
369             stringBuilder.AppendFormat("    int {0}(int {1},int {2},int {3} = 0) \n", methonName, param1, param2, param3);
370         }
371         else
372         {
373             stringBuilder.AppendFormat("    public int {0}(int {1},int {2},int {3} = 0) \n", methonName, param1, param2, param3);
374         }    
375         stringBuilder.AppendLine("    {");
376         stringBuilder.AppendFormat("        int t{0}p = {0} * {1};\n", param1, param2);
377         stringBuilder.AppendFormat("        if ({1} != 0 && t{0}p > {1})\n", param1,param3);
378         stringBuilder.AppendLine("        {");
379         stringBuilder.AppendFormat("            t{1}p = t{1}p / {0};\n", param3, param1);
380         stringBuilder.AppendLine("        }");
381         stringBuilder.AppendLine("        else");
382         stringBuilder.AppendLine("        {");
383         stringBuilder.AppendFormat("            t{1}p -= {0};\n", param3, param1);
384         stringBuilder.AppendLine("        }");
385         stringBuilder.AppendLine("");
386         stringBuilder.AppendFormat("        return {0}2(t{1}p);\n", methonName, param1);
387         stringBuilder.AppendLine("    }");            
388         return stringBuilder.ToString();
389     }
390 }
View Code

 三、人工审核

  暂时没有一套好的方案,我们的方案是只保留了充值和最简单的功能,资源也用简单几套替换,提包的时候用vpn隐藏真实ip。

posted @ 2017-10-29 17:29  青树  阅读(1212)  评论(0编辑  收藏  举报