【Unity】代码加密(二)dll加密so加密

来源:互联网 发布:python 单元测试 编辑:程序博客网 时间:2024/05/16 15:31

写在前面

libmono的编译方法请参见我的前一篇文章【Unity】代码加密(一)编译libmono
如需转载,请注明出自喵喵丸的博客 (http://blog.csdn.net/u011643833/article/details/49102423)

加密Dll

【这一部分操作我在Windows VS中完成(用的C)】
这个其实可以用任何你熟悉的语言来实现,只要和你的解密方法相对应即可。我所做的流程是这样的:

  • 读取从Unity导出Android工程中Assembly-CSharp.dll
  • 读取的字节流,进行加密(这里说道的读取以及下面所述输出,指的是文件读写)
  • 输出加密后的字节流,生成新的dll,名字依旧是Assembly-CSharp.dll,覆盖原文件。

(加密后,查看文件内容可发现与未加密之前明显的不同)

解密Dll

【这一部分操作我在Ubuntu中完成】

  • 从源码根目录文件夹下,找到/mono/metadata/image.c这个文件
  • 找到函数mono_image_open_from_data_with_name,这个函数的参数形式是这样的MonoImage* mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name) 说一下要注意的几个参数。
  • data 需要加密的字节流
  • data_len data字节流长度
  • need_copy 是否需要深拷贝

  • 代码形式参考下面(自己添加的部分参照两段 Add-Addend注释 之间的代码)

MonoImage* mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name){    //..    //*********************************Add*********************************//    char *refKey;    //取得自己解密所需的秘钥(下方so加密中再进行叙述)    refKey = getKey();    //..    //*******************************Addend*******************************//    //...    if (!data || !data_len){        if(status)            *status = MONO_IMAGE_IMAGE_INVALID;        return NULL;    }    //*********************************Add*********************************//    ifstrstr(name, "Assembly-CSharp.dll")){        char* decodeResult = (char *) malloc (data_len * sizeof(char));        //..        //Assembly-CShap.dll字节流(即data)解密(与加密算法对应)         //refKey为秘钥 将解密结果注入decodeResult中 (这部分就请大家自己填充)        //..        memcpy(data, decodeResult, data_len);        free(decodeResult);        decodeResult = NULL;        datac = data;    }else{        datac = data;    }    //*******************************Addend*******************************//    //自己修改的代码一定要放到原文中下面代码的前面、否则自己解密后的内容会得不到正常的拷贝    if (need_copy){        datac = g_try_malloc (data_len);        if (!datac){            if (status)                *status = MONO_IMAGE_ERROR_ERRNO;            return NULL;            }        memcpy (datac, data, data_len);    }    //..    //其余代码}
  • 第一段Add-Addend 说明:这部分作用是取到你即将在下面so加密中藏起来的加密秘钥,在测试时,可以先写成明文的秘钥填充refKey,完成so加密后,使用getKey()函数取代。
  • 第二段Add-Addend说明:这部分将参数中传入的data做解密。调试时,先把这部分代码正确性做以验证(反正是C嘛。。在VS里面写个命令行。。把加密过的Assembly-CSharp.dll解密后,与未加密前的Assembly-CSharp.dll文件进行文件对比,即可验证代码正确性),再放入上面代码段之中。

加密so

【这一部分操作我在Ubuntu中完成】

为了解决我们在libmono.so中藏不起来秘钥的这个问题,在雨松Momo大大的博客指导下,已经可以解决啦~
其实解决这个问题的过程雨松Momo阐述的已经很明白了,重点的部分在于编译出encry可执行文件。编译过程我就不赘述了,只是说一下自己遇到的几个不太一样的点

  • 我下载了shelldemo后直接编译并没有遇到Momo所遇到的缺少elf.h文件的报错。正确编译了(可能和Mono下载到的版本有些出入,但是后续工作完成后发现功能上是没有问题的)
  • shellAdder1.c中, 存在变量target_section[] = "xxxxxx";,这里的target_section需要与你写入image.c中int getKey() __attribute__((section (".xxxxxx")));section字段对应。这篇文章对section的说明比较明确,也是Momo推荐的,我在看的时候其实对0x1、0x2、0x3疑惑了好久,结果发现是标题。。。
  • image.c中解密section的方法写在哪Momo已经明确的标注了,那么shellAdder1.c中加密section的方法在哪呢?—–打开shellAdder1.c文件,搜索符号取反’~’(我下载的版本在90行的左右)这里就是加密方法所在的地方。既然找到了加密解密section的位置,大家自行填充想要的算法即可。
  • 如何快速的验证加密成功了呢~其一,可以观察libmono.so文件内容(其实根本不直观);其二,IDA搜索getKey,没有加密成功你就可以看到这个函数内容;其三,第一次执行encry libmono.so时,正常执行,第二次执行encry同一文件,报错为找不到section字段。证明已经加密过了~

调试以及Tips

这里是自己觉得有一些助益的小经验吧

  • 作业的顺序,基本和这两篇博客大标题的顺序一致,最好一项一项在工程中验证,循序渐进。
  • 调试工程,需要有至少一处的交互,或者活动的GameObject,以便观察。比如说:点击反馈的事件(不能正常解密的dll 或者so,会显示第一个静态的镜头,如果没有一些反馈,比较难验证你的解密是否真的做成功了)
  • 不要选择windows来编译libmono,这个在前一篇有说过,windows用cygwin来做难度和Linux(我没用Mac实验)来比,是指数级的。后来Linux成功完成所有工作之后,我又尝试在windows上面做了一次,还是失败了。
  • 关于如何将加密的源码文件加入libmono编译过程中,这方面其实我很抓瞎的,虽然解决了,但是方法很野蛮。在 mono-unity-x.x/mono/metadata 目录下有三个makefile文件, 在这三个文件中搜索image关键字,在搜索到的位置前面,添加你需要编译的.h .c文件。这样就可以在image.c中引用你新添加的文件了。

其实,当时遇到好多想说明的问题,可是如今却是回忆不起来。暂时只写到这边。

如果大家在加密时候遇到了问题,欢迎留言。我会努力解答。

(:з」∠)事实证明,为了举一反三 勤快的笔头子是重要的

0 0
原创粉丝点击