我的unity il2cpp5里,怎么没有IL2CPP选项

今天看啥 热点:
(二)Unity5.0新特性------unity内部:内存 和 性能(以及Unity5的升级优化),unity5
&&&&& 我们的脚本代码里经常会需要访问gameObject引用或者某个组件的引用,最好的方式当然是在脚本Awake的时候就把这些可能访问的东西都缓存下来;如果需要访问临时gameObject实例的某属性或者临时某组件的gameObject实例,在能够确保组件一定存在(可以使用[RequireComponent(&typeof(AudioSource&))] 如果没有自动添加移除不了!)的情况下,可以用属性访问,毕竟属性访问比GetComponent要快上一倍,但是如果不能确定组件是否存在,甚至是需要对组件的存在性做判断时,一定不要用对属性访问结果判空的方式,而要用GetComponent,这里面节省的开销不是一点半点。 &&&&& 而在unity5中你是没得选择了,因为没有了属性访问器。 看看下图的 GameObject类的对比。(4.6和5.0版本)&&&&& unity内部:内存&和&性能Topicso Memory Overviewo Garbage Collectiono Mesh Internalso Scriptingo Job System一、 Memory OverviewMemory Domains内存域o Native (internal)本地 (内部)o Asset Data: Textures, AudioClips, Mesheso Game Objects & Components: Transform, etc..o Engine Internals: Managers, Rendering, Physics, etc..o Managed - Monoo Script objects (Managed dlls)o Wrappers (包装类)for Unity objects: Game objects, assets,componentso Native Dllso User’s dlls and external dlls (for example: DirectX)Native Memory: Internal Allocators本机内存: 内部分配器o Defaulto GameObjecto Gfx 图形和渲染相关o Profiler事件探查器& & & & & & & &5.x: 在 Dll 中使用本机的分配器公开的 APIManaged Memory托管的内存o Value types值类型&(bool, int, float, struct, ...)& & & & & o 在堆栈内存中存在。当从堆栈中移除时取消分配。没有GC。o Reference types (classes)&引用类型 (类)o 在堆上存在,当长时间不再被引用时都由mono/.net GC删除。o 包装为&Unity Objects :o GameObjecto Assets : Texture2D, AudioClip, Mesh, …o Components : MeshRenderer, Transform, MonoBehaviourMono Memory Internalso Allocates system heap blocks for internal allocator(为内部分配器分配系统堆块)o Will allocate new heap blocks when needed(&在需要时将分配新的堆块)o Heap blocks are kept in Mono for later use(&堆块保持在Mono中以后使用)o Memory can be given back to the system after a while(&当过一段时间内存可以被交还给系统)o......但是它取决于平台è?&,别指望它o Garbage collector cleans up(垃圾回收器清理)o Fragmentation can cause new heap blocks even though memory is not exhausted(碎片可以导致新的堆块,即使内存不耗尽)二、Garbage CollectionUnity Object wrapper(封装)o Some Objects used in scripts have large native backing memory in unity(在unity中在脚本中被使用的一些对象有大批的本机支持内存)o&直到运行Finalizers终结器内存才会释放Mono Garbage Collectiono
GC.Collecto Runs on the main thread when(运行在主线程上当:o Mono exhausts the heap space(&Mono耗尽堆空间)o Or user calls System.GC.Collect()(或用户调用 System.GC.Collect())o
Finalizers终结器& & &o Run on a separate thread(运行在一个单独的线程上当:o Controlled by mono(由mono控制o Can have several seconds delay(可以有几秒钟的延迟o
Unity native memory(unity本机内存o Dispose() cleans up internal memory(Dispose () 清理内部内存o Eventually called from finalizer(&最终从finalizer终结器调用o Manually call Dispose() to cleanup(手动调用&Dispose() 清理Garbage Collectiono Roots are not collected in a GC.Collect(在GC.Collect上Roots不会被收集)o Thread stacks(线程堆栈)o CPU Registers(CPU 寄存器)o GC Handles (used by Unity to hold onto managed objects)&GC 句柄 (使用Unity来守住托管对象)o 静态变量 !!o&Collection的时间尺度与托管的堆的大小o 您分配的越多,gets变得越慢GC: Best Practices&最佳做法o Reuse objects . Use object pools(重用对象,使用对象池)o 更喜欢基于堆栈的分配。使用结构而不是类o System.GC.Collect 可以用于触发collectiono 手动调用&Dispose立即清理Avoid temp allocations避免临时分配o Don’t use FindObjects or LINQo Use StringBuilder for string concatenationo Reuse large temporary work buffers(重用大量临时工作缓冲区)o ToString()o .tag 改用 CompareTag() 方法Unity API Temporary Allocations(临时分配)一些例子:o GetComponents&T&o Vector3[] Mesh.verticeso Camera[] Camera.allCameraso foreacho
does not allocate by definition(定义不会分配)o
However, there can be a small allocation, depending on the implementation of .GetEnumerator()o 然而,根据具体的.GetEnumerator()实现可能会有&small有小的分配5.x: 正在研究新的非分配non-allocating版本Memory fragmentation内存碎片o Memory fragmentation is hard to account for(内存碎片很难解释)o Fully unload dynamically allocated content(完全卸载动态分配内容)o 切换到一个空白场景,在next level之前o This scene could have a hook where you may pause the game long enough to sample if there is anything significant in memoryo Ensure you clear out variables so GC.Collect will remove as much as possibleo 确保你clear变量,GC.Collect将删除尽可能多地o 尽可能避免分配o 重用对象尽可能在scene play下o Clear them out for map load to clean the memory(把它们清理干净memory的地图加载)Unloading Unused Assets卸载未使用的资产o Resources.UnloadUnusedAssets 将触发资产垃圾回收o他是搜索所有unreferenced assets 和卸载他们o他是一个async operation异步操作的&o 它loading 一个 level后在内部被调用o Resources.UnloadAsset 是最好的o 您需要知道到底您需要Unload卸载什么oUnity而不必全部扫描o&Unity 5.0: 多线程的asset垃圾回收三、Mesh InternalsMesh Read/Write Optiono 它允许您在运行时修改mesho 如果启用enabled, Mesh的系统副本会保留在内存中o enabled是默认o 在某些情况下,禁用此选项不会减少内存使用量o Skinned meshes皮肤网格o iOSUnity 5.0: disable by default默认情况下是禁用&– under considerationNon-Uniform scaled Meshes非均匀缩放网格我们需要正确转换的顶点法线o Unity 4.x:o 在 CPU 上变换transform网格mesho 创建数据的额外副本o Unity 5.0o 在 GPU 上缩放Scaledo 不再需要额外的内存Static Batching这是什么?o 它是优化,减少了draw calls&和状态改变的数量他如何使用?o 在player settings&+&Tag对象为static。如下:它内部如何工作?o Build-time&生成时间: Vertices are transformed to world- space顶点转换为世界空间o Run-time运行时间: Index buffer is created with indices of visible objects索引缓冲区创建与指数的可见对象Unity 5.0:o Re-implemented static batching without copying of index buffers重新实施静态配料而不复制索引缓冲区Dynamic Batching这是什么?o 类似于静态配料,在运行时对象是non-static他如何使用?o 在player settingso no need to tag. it auto-magically works…无需标记。它自动神奇地工作......它内部如何工作?o objects are transformed to world space on the对象转换到世界空间上CPUo 创建临时的 VB & IBo 在一个draw call&中呈现Rendered&Unity 5.x:&&我们正在考虑使每个平台参数Mesh Skinning根据平台的不同实现:o x86: SSEo iOS/Android/WP8: Neon optimizationso D3D11/XBoxOne/GLES3.0: GPUo XBox360, WiiU: GPU (memexport)o PS3: SPUo WiiU: GPU w/ stream outUnity 5.0: Skinned meshes&通过共享实例之间的索引缓冲区使用较少的内存四、Scripting(重要!)Unity 5.0: Monoo No upgrade不能升级o Mainly bug fixes主要 bug 修复o New tech in WebGL: IL2CPP新科技在 WebGL: IL2CPPo //on-the-future-of-web-publishing-in-unity/o 敬请: 会有关于它的博客文章GetComponent&T& & & &&它要求游戏物体,得到一个指定类型的组件:o The GO contains a list of Componentso&GO包含Components组件的列表o 每个组件类型被比作 To 第一个组件的类型 T (或从 T 派生),将返回给调用方o 不太多的开销,但它仍然需要调入本机代码Unity 5.0: Property Accessors属性的访问器o&大多数accessors将在Unity 5.0中被移除o 目的是减少依赖,因此提高模块化o&Transform将仍然被保留o 现有的脚本将被转换。示例:in 5.0:Transform Componento this.transform 是和 GetComponent&Transform&() 一样o
transform.position/rotation&需要:o find Transform componento Traverse hierarchy to calculate absolute position遍历层次结构来计算绝对位置o Apply translation/rotationo
transform internally stores the position relative to the parent变换在内部存储的位置是相对于父级o transform.localPosition = new Vector(…) → &简单的赋值o transform.position = new Vector(…)→ &costs the same if no father, otherwise it will need to traverse the hierarchy up to transform the abs position into localo transform.position = 新的 Vector(...)→ &如果没有父亲代价是一样的,否则它将需要本地遍历hierarchy得到transform的位置绝对值o 最后,将通过messages通知其他组件 (对撞机、 刚体、 轻型、 相机、)。InstantiateAPI:o Object Instantiate(Object, Vector3, Quaternion);o Object Instantiate(Object);Implementation执行:o 克隆GameObject Hierarchy and Componentso Copy Properties复制属性o Awakeo Apply new Transform (if provided)适用新的变换 (如果提供)Instantiate cont..edo Awake&可以是昂贵的o AwakeFromLoad (主线程)o clear states清理状态o internal state caching内部状态缓存o pre-compute预先计算Unity 5.0:o Allocations have been reduced分配已被减少o 一些内部的循环,用于复制的数据进行了优化JIT Compilation(JIT 编译)这是什么?o 在进程中从 CIL 代码生成机器代码,在应用程序运行期间Pros:优点:o&为当前平台,它生成优化的代码Cons:缺点:o
Each time a method is called for the first time, the application will suffer a certain performance penalty because of the compilationo 每次方法被第一次调用时,应用程序因为汇编将受到某些性能处罚&JIT compilation spikespre-JITting怎么样?o RuntimeHelpers.PrepareMethod 是行不通的:....MethodHandle.GetFunctionPointer() 比较好五、Job SystemUnity 5.0: Job System (internal)job system的目标:o&基于多线程的代码&可以很容易地写得很高效率的工作o The jobs should be able to run safely in parallel to script codeo&jobs工作应该能够安全地平行的运行脚本代码Job System:&它是什么&?o&它是一个Framework框架,我们打算在现有的和新的子系统中使用的o&我们想要Animation, NavMesh, Occlusion, Rendering,等等尽可能多的并行运行o 这最终将导致更好的性能
相关搜索:
相关阅读:
相关频道:
Android教程最近更新1723人阅读
Unity Blog Bak(3)
转载地址:/339671.html
Unity 官方博客译文(看完这篇博文非常的兴奋,第一时间想到的是翻译后介绍给大家,文章是以IL2CPP内部开发人员的角度来讲述。
  大约在一年以前,我们写了一篇博客讨论Unity中脚本将来会是个什么样子,在那篇博客中我们提到了崭新的IL2CPP后端,并许诺其会为Unity带来更高效和更适合于各个平台的虚拟机。在2015年的一月份,我们正式发布了第一个使用IL2CPP的平台:iOS 64-bit。而随着Unity 5的发布,又带给大家另一个使用IL2CPP的平台:WebGL。感谢我们社区中用户的大量宝贵的反馈,我们在接下来的时间里根据这些反馈得以更新IL2CPP,发布补丁版本,从而持续的改进IL2CPP的编译器和运行时库。
  我们没有停止改进IL2CPP的打算,但是在目前这个时间点上,我们觉得可以回过头来抽出点时间告诉大家一些IL2CPP的内部工作机制。在接下来的几个月的时间里,我们打算对以下话题(或者还有其他未列出的话题)进行讨论,来做一个IL2CPP深入讲解系列。目前准备讨论的话题有:
  1.基础 - 工具链和命令行参数
  2.IL2CPP生成代码介绍
  3.IL2CPP生成代码调试小窍门
  4.方法调用介绍(一般方法调用和虚方法调用等)
  5. 通用代码共享的实现
  6.P/invoke(Platform Invocation Service)对于类型(types)和方法(methods)的封装
  7.垃圾回收器的集成
  8.测试框架(Testing frameworks)及其使用
  为了能让这个系列的讨论成为可能,我们会涉及到一些将来肯定会进行改动的IL2CPP的实现细节。但这也没有关系,通过这些讨论,我们希望能给大家提供一些有用和有趣的信息。
  什么是IL2CPP?
  从技术层面上来说,我们说的IL2CPP包含了两部分:
  一个进行 预先编译(译注:ahead-of-time,又叫AOT,以下一律使用AOT缩写)的编译器
  一个支持虚拟机的运行时库
  AOT编译器将由.NET 输出的中间语言(IL)代码生成为C++代码。运行时库则提供诸如垃圾回收,与平台无关的线程,IO以及内部调用(C++原生代码直接访问托管代码结构)这样的服务和抽象层。
  AOT编译器
  IL2CPP AOT编译器实际的执行文件是il2cpp.exe。在Windows平台你可以在Unity安装路径的Editor\Data\il2cpp目录下找到。对于OSX平台,它位于Unity安装路径的Contents/Frameworks/il2cpp/build目录内。 il2cpp.exe这个工具是一个托管代码可执行文件,其完全由C#写成。在开发IL2CPP的过程中,我们同时使用.NET和Mono编译器对其进行编译。
  il2cpp 接受来自Unity自带的或者由Mono编译器产生的托管程序集,将这些程序集转换成C++代码。这些转换出的C++代码最终由部署目标平台上的C++编译器进行编译。
  你可以参照下图理解IL2CPP工具链的作用:
  运行时库
  IL2CPP的另外一个部分就是对虚拟机提供支持的运行时库。我们基本上是用C++代码来实现整个运行时库的(好吧,其实里面还是有一些和平台相关的代码使用了程序集,这个只要你知我知便好,不要告诉别人 )。我们把运行时库称之为libli2cpp,它是作为一个静态库被连接到最终的游戏可执行文件中。这么做的一个主要的好处是可以使得整个IL2CPP技术是简单并且是可移植的。
  你能通过查看随Unity一起发布的libil2cpp头文件来窥探其代码组织方式(Windows平台,头文件在Editor\Data\PlaybackEngines\webglsupport\BuildTools\Libraries\libil2cpp\include目录中。OSX平台,头文件在Contents/Frameworks/il2cpp/libil2cpp目录中)。举个例子,由il2cpp产生的C++代码和libil2cpp之间的接口API,存在于codegen/il2cpp-codegen.h这个文件中。
  运行时的另外一个重要的部分,就是垃圾收集器。在Unity 5中,我们使用libgc垃圾收集器。它是一个典型的贝姆垃圾收集器(Boehm-Demers-Weiser garbage collector)。(译注:相对使用保守垃圾回收策略)。然而我们的libil2cpp被设计成可以方便使用其他垃圾回收器。因此我们现在也在研究集成微软开源的垃圾回收器(Microsoft
GC)。对于垃圾回收器这一点,我们会在后续的一篇中专门的讨论,这里就不多说了。
  il2cpp是如何执行的?
  让我们从一个简单的例子入手。这里使用Unity的版本是5.0.1,在Windows环境并且建立一个全新的空项目。然后创建一个带MonoBehaviour的脚本文件,将其作为组件加入到Main Camera上。代码也是非常的简单,输出Hello World:
using UnityE
public class HelloWorld : MonoBehaviour {
&&void Start () {
& & Debug.Log(&Hello, IL2CPP!&);
  当我切换到WebGL平台进行项目生成的时候,我们可以用Process Explorer来对il2cpp的命令行进行观察,得到以下内容:
  &C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe& &C:\Program    Files\Unity\Editor\Data\il2cpp/il2cpp.exe& --copy-level=None --enable-generic-sharing
--enable-unity-event-support --output-format=Compact --extra-types.file=&C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt& &C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\Assembly-CSharp.dll& &C:\Users\Josh
Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\UnityEngine.UI.dll& &C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\il2cppOutput&
  嗯,这个真是老太太的裹脚布 - 又臭又长......,所以让我们把命令分拆一下,Unity运行的是这个可执行文件:
&C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe&
  下一个参数是il2cpp.exe工具本身:
&C:\Program Files\Unity\Editor\Data\il2cpp/il2cpp.exe&
  请注意剩下的参数其实都是传递给il2cpp.exe的而不是mono.exe。上面的例子里传递了5个参数给il2cpp.exe:
  o–copy-level=None
    o指明il2cpp.exe不对生成的C++文件进行copy操作
  o–enable-generic-sharing
    o告诉IL2CPP如果可以,对通用方法进行共享。这个可以减少代码并降低最后二进制文件的尺寸
  o–enable-unity-event-support
    o确保和Unity events相关的,通过反射机制来运作的代码,能够正确生成。
  o–output-format=Compact
     o在生成C++代码时为里面的类型和方法使用更短的名字。这会使得C++代码难以阅读,因为原来在IL中的名字被更短的取代了。但好处是可以让C++编译器运行的更快。
  o–extra-types.file=”C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt”
    o使用默认的(也是空的)额外类型文件。il2cpp.exe会将在这个文件中出现的基本类型或者数组类型看作是在运行时生成的而不是一开始出现在IL代码中来对待。
  需要注意的是这些参数可能会在以后的Unity版本中有所变化。我们现在还没有稳定到把il2cpp.exe的命令行参数整理固定下来的阶段。
  最后,我们有由两个文件组成的一个列表和一个目录在这个长长的命令行中:
  o“C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\Assembly-CSharp.dll”
  o“C:\Users\Josh Peterson\Documents\IL2CPP Blog   Example\Temp\StagingArea\Data\Managed\UnityEngine.UI.dll”
  o“C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\il2cppOutput”
  il2cpp.exe工具可以接收一个由IL程序集组成的列表。在上面这个例子中,程序集包含了项目中的简单脚本程序集:Assembly-CSharp.dll,和GUI程序集:UnityEngine.UI.dll。大家可能会注意到这里面明显少了什么:UnityEngine.dll到哪去了?系统底层的mscorlib.dll也不见了踪影。实际上,il2cpp.exe会在内部自动引用这些程序集。你当然也可以把这些放入列表中,但他们不是必须的。你只需要提及那些根程序集(那些没有被其他任何程序集引用到的程序集),剩下的il2cpp.exe会根据引用关系自动加入。
  裹脚布的最后一块是一个目录,il2cpp.exe会将最终的C++代码生成到这里。如果你还保持着一颗好奇的心,可以看看这个目录中产生的文件。这些文件是我们下一个讨论的主题。在你审视这些代码前,可以考虑将WebGL构建设置中的“Development Player”选项勾上。这么做会移除–output-format=Compact命令行参数从而让C++代码中的类型和方法的名字更加可读。
  尝试在WebGL或者iOS构建设置中进行些改变。这样你会发现传递给il2cpp.exe的参数也会相应的发生变化。例如,将“Enable Exceptions” 设置成“Full” 会将–emit-null-checks,–enable-stacktrace,和 –enable-array-bounds-check这三个参数加入il2cpp.exe命令行。
  IL2CPP没做的事情
  我想指出IL2CPP有一向挑战我们没有接受,而且我们也高兴我们忽略了它。我们没有尝试重写整个C#标准库。当你使用IL2CPP后端构建Unity项目的时候,所有在mscorlib.dll,System.dll等中的C#标准库和原来使用Mono编译时候的一模一样。
  我们可以依赖健壮的且久经考验的C#标准库,所以当处理有关IL2CPP的bug的时候,我们可以很肯定的说问题出在AOT编译器或者运行时库这两个地方而不是在其他地方。
  我们如何开发,测试,发布IL2CPP
  自从我们在一月份的4.6.1 p5版本中首次引入IL2CPP以来,我们已经连续发布了6个Unity版本和7个补丁(Unity版本号跨越4.6和5.0)。在这些发布中我们修正了超过100个bug。
  为了确保持续的改进得以实施,我们内部只保留一份最新的开发代码在主干分之(trunk branch)上,在发布各个版本之前,我们会将IL2CPP的改动挂到一个特定的分之下,然后进行测试,确保所有的bug已经正确的修正了。我们的QA和维护工作组为此付出了惊人的努力才得以保证发布版本的快速迭代。(译注:感觉是版本管理的标准的开发流程,另外由文中提到的trunk
branch来看,他们貌似还在使用SVN)
  提供高质量Bug的用户社区被证明是一个无价之宝。我们非常感谢用户的反馈来帮助我们改进IL2CPP,并且希望这类反馈越多越好。
  我们的IL2CPP研发组有很强烈的“测试优先”意识。我们时常使用“Test Driven Design”方法,在没有进行足够全面的测试的情况下,几乎不会进行代码的合并工作。这个策略用在IL2CPP项目上非常的棒。我们现在所面对的大部分bug并不是意想不到的行为产生的,而是由意想不到的特殊情况产生的。(例如在一个32位的索引数组中使用了64位的指针从而导致C++编译器失败,具体讨论在这里)面对这种类型的bug我们可以快速的并且很自信的进行修正。
  有了社区的帮助,我们非常努力的让IL2CPP既快又稳定。顺便说一句,如果你对我刚才说的这些有兴趣,我们正在招人(嗯.....我只是这么一说)
  好戏连台
  关于IL2CPP我们还有很多可以说的。下一次我们会深入到il2cpp.exe代码生成的细节中。看看对于C++编译器来说,由il2cpp.exe生成的代码会是个什么样子。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:43720次
排名:千里之外
原创:41篇
转载:25篇
(1)(5)(1)(2)(4)(2)(3)(2)(3)(2)(22)(14)(2)(2)(1)(3)程序写累了,就来玩玩酷跑小游戏吧,嘿嘿。
雨松MOMO送你一首歌曲,嘿嘿。
Unity3D研究院之Android二次加密.so二次加密DLL(八十二)
Unity3D研究院之Android二次加密.so二次加密DLL(八十二)
围观19745次
编辑日期: 字体:
上文中说了怎么给DLL加密来防止别人反编译你的C#代码。
文章的最后我们发现IDA PRO神器可以解开libmono从而查到你的解密算法,这样你的C#代码又会被别人轻易的拿到。
这两天我就一直在寻找怎样才能更好的保护代码。终于找到了加密so的办法,此法我觉得防小白觉对够用。大神恐怕还是能解开,但是我觉得这就够了。我已经在项目中测试通过,也欢迎大家也能加入一起来测试的队伍。
在啰嗦一句在不远的将来可能我们也不用这么做了, 因为很快unity就全线l2cpp了。但是我觉得等真正稳定恐怕还有很多路要走,所以估计大部分正在开发的项目不会冒这个险升级。
阅读下面之前请大家先看一下这篇大神的文章。 文章写的很清晰。但是坦白说看了半天我没怎么看懂,逆向工程真是一门深奥的学问。。主要还是技术关注领域不在这里。文章的最后有作者给出的源码,大家记得下载下来。然后我就开始说我是怎么把这个加在unity3d上的。还有我遇到了那些坑。
它的例子工程下载解压后,开始对shellAdder1.c进行编译,编译的方法是
gcc -o encry shellAdder1.c
我开始编译的时候老通不过,提示缺少 elf.h 文件,我看了一下,其实就是少了一些结构体和类型的声明,把下面代码拷贝到shellAdder1.c里面即可。Main函数上面添加如下代码。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
#include &stdio.h&#include &fcntl.h&#include &stdlib.h&#include &string.h&&&/* 32-bit ELF base types. */typedef unsigned int Elf32_Addr;typedef unsigned short Elf32_Half;typedef unsigned int Elf32_Off;typedef signed int Elf32_Sword;typedef unsigned int Elf32_Word;&&&&#define EI_NIDENT 16&/* * ELF header. */&typedef struct {&&unsigned char&&e_ident[EI_NIDENT];&&/* File identification. */&&Elf32_Half&&e_type;&&&&/* File type. */&&Elf32_Half&&e_machine;&&/* Machine architecture. */&&Elf32_Word&&e_version;&&/* ELF format version. */&&Elf32_Addr&&e_entry;&&/* Entry point. */&&Elf32_Off&&e_phoff;&&/* Program header file offset. */&&Elf32_Off&&e_shoff;&&/* Section header file offset. */&&Elf32_Word&&e_flags;&&/* Architecture-specific flags. */&&Elf32_Half&&e_ehsize;&&/* Size of ELF header in bytes. */&&Elf32_Half&&e_phentsize;&&/* Size of program header entry. */&&Elf32_Half&&e_phnum;&&/* Number of program header entries. */&&Elf32_Half&&e_shentsize;&&/* Size of section header entry. */&&Elf32_Half&&e_shnum;&&/* Number of section header entries. */&&Elf32_Half&&e_shstrndx;&&/* Section name strings section. */} Elf32_Ehdr;&/* * Section header. */&typedef struct {&&Elf32_Word&&sh_name;&&/* Section name (index into the&&&&&&&&&&&& section header string table). */&&Elf32_Word&&sh_type;&&/* Section type. */&&Elf32_Word&&sh_flags; /* Section flags. */&&Elf32_Addr&&sh_addr;&&/* Address in memory image. */&&Elf32_Off sh_offset;&&/* Offset in file. */&&Elf32_Word&&sh_size;&&/* Size in bytes. */&&Elf32_Word&&sh_link;&&/* Index of a related section. */&&Elf32_Word&&sh_info;&&/* Depends on section type. */&&Elf32_Word&&sh_addralign; /* Alignment in bytes. */&&Elf32_Word&&sh_entsize; /* Size of each entry in section. */} Elf32_Shdr;
最终shellAdder1将编译成一个名叫encry的可执行文件, 用来给libmono进行加密。那么加密算法必然是要写在shellAdder1.c里面,作者给出的是取反你也可以改成自己需要的算法。至于c代码是什么意思,我相信 这篇文章已经写的是非常的全面了
然后执行 encry libmono.so 就会把libmono.so里 名叫 mytext 的断 进行加密,你要觉得这个名子不好也可以换一个断名,加密后的libmono.so文件会替换原有的。
接着到mono/metadata/image.c里来编写解密.so断的代码。把下面这段代码拷贝到image.c的最上面,关键的两个地方我已添加注释了。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
//SO---------------加密----------------------&#include &sys/types.h&#include &elf.h&#include &sys/mman.h&&//注意上面说解密算法里面的断.mytext就是这里,//这里把getKey进行了加密,这样对方拿不到你的密钥都没法破解你的dll了int getKey() __attribute__((section (".mytext")));int getKey(){ return 2048;};//这里就是.so初始化的时候,这里进行mytext断的解密工作void init_getKey() __attribute__((constructor));unsigned long getLibAddr();&void init_getKey(){&&char name[15];&&unsigned int nblock;&&unsigned int nsize;&&unsigned long base;&&unsigned long text_addr;&&unsigned int i;&&Elf32_Ehdr *ehdr;&&Elf32_Shdr *shdr;&&&&base = getLibAddr();&&&&ehdr = (Elf32_Ehdr *)base;&&text_addr = ehdr-&e_shoff + base;&&&&nblock = ehdr-&e_entry && 16;&&nsize = ehdr-&e_entry & 0xffff;&&&&g_message("momo: nblock = %d\n", nblock);&&&&&if(mprotect((void *) base, 4096 * nsize, PROT_READ | PROT_EXEC | PROT_WRITE) != 0){&&&&g_message("momo: mem privilege change failed");&&&}&&//注意这里就是解密算法, 要和加密算法完全逆向才行不然就解不开了。&&for(i=0;i& nblock; i++){&&&&&&char *addr = (char*)(text_addr + i);&&&&*addr = ~(*addr);&&}&&&&if(mprotect((void *) base, 4096 * nsize, PROT_READ | PROT_EXEC) != 0){&&&&g_message("momo: mem privilege change failed");&&}&&g_message("momo: Decrypt success");}&unsigned long getLibAddr(){&&unsigned long ret = 0;&&char name[] = "libmono.so";&&char buf[4096], *temp;&&int pid;&&FILE *fp;&&pid = getpid();&&sprintf(buf, "/proc/%d/maps", pid);&&fp = fopen(buf, "r");&&if(fp == NULL)&&{&&&&g_message("momo: open failed");&&&&goto _error;&&}&&while(fgets(buf, sizeof(buf), fp)){&&&&if(strstr(buf, name)){&&&&&&temp = strtok(buf, "-");&&&&&&ret = strtoul(temp, NULL, 16);&&&&&&break;&&&&}&&}_error:&&fclose(fp);&&return ret;}&//SO---------------加密----------------------
然后在mono_image_open_from_data_with_name方法里
if(strstr(name,"Assembly-CSharp.dll")){&&&&&&&&&&&&&&&&//这里就能取到密钥,那么这个函数被加密了。&&&&&&&&&&&&&&&&//IDA就看不到它了
g_message("momo: key = %d\n", getKey()); }
密钥被保护了,代码修改完就是开始编译mono吧。编译完用刚刚我们说过的方法来执行 encry libmono.so
然后把libmono拷贝到项目里打包android就行了。
可以测试一下加密的效果。用Ida 打开。这里的函数已经打不开了
这段密钥进行了保护那么就可以随意的做加密算法了。
我相信这个方法还是存在漏洞,肯定也有大神能破解。也希望各位大神不吝赐教,谢谢啦。使用上有问题欢迎在下面留言大家可以一起讨论。
shellAdder1.c 很多人都问我要我还是都放出来吧。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
#include &stdio.h&#include &fcntl.h&#include &stdlib.h&#include &string.h&&&/* 32-bit ELF base types. */typedef unsigned int Elf32_Addr;typedef unsigned short Elf32_Half;typedef unsigned int Elf32_Off;typedef signed int Elf32_Sword;typedef unsigned int Elf32_Word;&&&&#define EI_NIDENT 16&/* * ELF header. */&typedef struct {&&unsigned char&&e_ident[EI_NIDENT];&&/* File identification. */&&Elf32_Half&&e_type;&&&&/* File type. */&&Elf32_Half&&e_machine;&&/* Machine architecture. */&&Elf32_Word&&e_version;&&/* ELF format version. */&&Elf32_Addr&&e_entry;&&/* Entry point. */&&Elf32_Off&&e_phoff;&&/* Program header file offset. */&&Elf32_Off&&e_shoff;&&/* Section header file offset. */&&Elf32_Word&&e_flags;&&/* Architecture-specific flags. */&&Elf32_Half&&e_ehsize;&&/* Size of ELF header in bytes. */&&Elf32_Half&&e_phentsize;&&/* Size of program header entry. */&&Elf32_Half&&e_phnum;&&/* Number of program header entries. */&&Elf32_Half&&e_shentsize;&&/* Size of section header entry. */&&Elf32_Half&&e_shnum;&&/* Number of section header entries. */&&Elf32_Half&&e_shstrndx;&&/* Section name strings section. */} Elf32_Ehdr;&/* * Section header. */&typedef struct {&&Elf32_Word&&sh_name;&&/* Section name (index into the&&&&&&&&&&&& section header string table). */&&Elf32_Word&&sh_type;&&/* Section type. */&&Elf32_Word&&sh_flags; /* Section flags. */&&Elf32_Addr&&sh_addr;&&/* Address in memory image. */&&Elf32_Off sh_offset;&&/* Offset in file. */&&Elf32_Word&&sh_size;&&/* Size in bytes. */&&Elf32_Word&&sh_link;&&/* Index of a related section. */&&Elf32_Word&&sh_info;&&/* Depends on section type. */&&Elf32_Word&&sh_addralign; /* Alignment in bytes. */&&Elf32_Word&&sh_entsize; /* Size of each entry in section. */} Elf32_Shdr;&&int main(int argc, char** argv){&&char target_section[] = ".mytext";&&char *shstr = NULL;&&char *content = NULL;&&Elf32_Ehdr ehdr;&&Elf32_Shdr shdr;&&int i;&&unsigned int base, length;&&unsigned short nblock;&&unsigned short nsize;&&unsigned char block_size = 16;&&&&int fd;&&&&if(argc & 2){&&&&puts("Input .so file");&&&&return -1;&&}&&&&fd = open(argv[1], O_RDWR);&&if(fd & 0){&&&&printf("open %s failed\n", argv[1]);&&&&goto _error;&&}&&&&if(read(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){&&&&puts("Read ELF header error");&&&&goto _error;&&}&&&&lseek(fd, ehdr.e_shoff + sizeof(Elf32_Shdr) * ehdr.e_shstrndx, SEEK_SET);&&&&if(read(fd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)){&&&&puts("Read ELF section string table error");&&&&goto _error;&&}&&&&if((shstr = (char *) malloc(shdr.sh_size)) == NULL){&&&&puts("Malloc space for section string table failed");&&&&goto _error;&&}&&&&lseek(fd, shdr.sh_offset, SEEK_SET);&&if(read(fd, shstr, shdr.sh_size) != shdr.sh_size){&&&&puts("Read string table failed");&&&&goto _error;&&}&&&&lseek(fd, ehdr.e_shoff, SEEK_SET);&&for(i = 0; i & ehdr.e_shnum; i++){&&&&if(read(fd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)){&&&&&&puts("Find section .text procedure failed");&&&&&&goto _error;&&&&}&&&&if(strcmp(shstr + shdr.sh_name, target_section) == 0){&&&&&&base = shdr.sh_offset;&&&&&&length = shdr.sh_size;&&&&&&printf("Find section %s\n", target_section);&&&&&&break;&&&&}&&}&&&&lseek(fd, base, SEEK_SET);&&content = (char*) malloc(length);&&if(content == NULL){&&&&puts("Malloc space for content failed");&&&&goto _error;&&}&&if(read(fd, content, length) != length){&&&&puts("Read section .text failed");&&&&goto _error;&&}&&&&nblock = length / block_size;&&nsize = base / 4096 + (base % 4096 == 0 ? 0 : 1);&&printf("base = %d, length = %d\n", base, length);&&printf("nblock = %d, nsize = %d\n", nblock, nsize);&&&&ehdr.e_entry = (length && 16) + nsize;&&ehdr.e_shoff = base;&&&&&&&&for(i=0;i&length;i++){&&&&content[i] = ~content[i];&&}&&&&&&&&lseek(fd, 0, SEEK_SET);&&if(write(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){&&&&puts("Write ELFhead to .so failed");&&&&goto _error;&&}&&&&&&lseek(fd, base, SEEK_SET);&&if(write(fd, content, length) != length){&&&&puts("Write modified content to .so failed");&&&&goto _error;&&}&&&&&&puts("Completed");_error:&&free(content);&&free(shstr);&&close(fd);&&return 0;}
最近有朋友说在Android7.0上遇到这个错误,今天我抽空尝试的解决了一下。
Unable to load library:xxx/arm/libunity.so [dlopen failed: “xxx/arm/libmono.so” .dynamic section header was not found]
测试环境unity4.7.2
并且在github上取下mono 对应的unity4.6(我看前几天刚更新了一些代码)的最新代码编译方法和文中介绍的一样。唯一有一点需要注意,就是NDK编译的时候要用android-ndk-r10e 或者更高版本。 (我测试通过用的就是r10e)
另外,如果你的项目是unity5.x我建议升级到5.4 android使用il2cpp这样就不需要这个方法加密了。如果是unity4.x的项目我建议用r10e在尝试编译一下,测试的过程中有问题欢迎在下面给我留言。
本文固定链接:
转载请注明:
雨松MOMO提醒您:亲,如果您觉得本文不错,快快将这篇文章分享出去吧 。另外请点击网站顶部彩色广告或者捐赠支持本站发展,谢谢!
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
如果您愿意花10块钱请我喝一杯咖啡的话,请用手机扫描二维码即可通过支付宝直接向我捐款哦。
您可能还会对这些文章感兴趣!

我要回帖

更多关于 unity il2cpp 反编译 的文章

 

随机推荐