对于Mono脚本后端,代码被编译进DLL,如果没有安全措施,利用dnSpy就可以很轻松的修改其中的字符串。
对于il2cpp脚本后端,代码中的字符都在global-metadata.dat文件中。用il2cppdumper,通过libil2cpp.so和global-metadata.dat导出很多信息,其中stringliteral.json文件中就有代码中的字符串,但是这个工具是用来dump信息的,不是用来修改的,所以我参考他的源码,做了一个简单的工具来对代码进行修改,下面是操作过程。
一、Demo制作
Demo很简单,页面上添加一个UI/Text,绑定一个脚本,然后导出apk之前,记得先在Player Settings里面设置好使用il2cpp脚本后端。
脚本代码如下:
1 public class MyScript : MonoBehaviour {
2 void Start () {
3 var text = gameObject.GetComponent<Text>();
4 text.text = "Test String";
5 }
6 }
运行效果(没有截全屏)如下:
二、修改
Demo是Unity直接导出的,没有安全措施,直接用WinRAR打开,在\assets\bin\Data\Managed\Metadata下找到global-metadata.dat文件,用我自己做的一个小工具(https://github.com/JeremieCHN/MetaDataStringEditor)打开他,效果如下:
上面的输入框是搜索用的,搜索要改的字符串,回车或者点击下一个找到它,然后右键该字符串,编辑(可以中文,但要考虑字体支不支持),保存,效果如下
我没有做成写回源文件的方式,要另存为,手动覆盖一下,然后装回去。最终效果(没有截全屏)如下:
三、基本原理
global-metadata.dat里面的信息很多,在il2cppdumper里面可以看到,字符串的区域有两个,代码中的字符串在其中一个,这个区域的特点是这样,首先在文件头部有一个列表,里面放了每一个字符串的长度和在数据区的偏移量,同时在数据区,字符串是紧凑放置的,也就是说字符串和字符串之间没有分割符号,用010 Editor打开文件的话,可以找到字符串的区域,
而另一个区域则是每一个字符串的结尾都会有一个\0,两个区域的功能应该是不同的,我的猜测是,我改的这个区域是代码中的字符串,而另一个区域则是类名、方法名等。
具体修改过程也比较简单,对于头部的列表,因为修改前后字符串的数量是不变的,所以这个列表所占据的空间也是不变的,数据区的话大概率是会变的,我的做法是,在修改之后先计算数据区的长度,如果可以放入原来数据区所在的空间,就直接放,否则在文件尾另外开辟一块空间来放,这样我就不需要去重排后面的其他数据了。关于字符串的编码,还是Unity常用的UTF-8编码。