您的位置:首页 > 移动开发 > Unity3D

Unity3D研究院之Android二次加密.so二次加密DLL(八十二)

2015-10-14 17:34 429 查看


Unity3D研究院之Android二次加密.so二次加密DLL(八十二)

雨松MOMO 【Unity3D研究院之游戏开发】 围观3916次 42条评论 编辑日期:2015-07-17 字体:大 中 小

<iframe id="cproIframe_u1121907_1" width="300" height="250" src="http://pos.baidu.com/acom?adn=4&at=134&aurl=&cad=1&ccd=24&cec=UTF-8&cfv=11&ch=0&col=zh-CN&conOP=0&cpa=1&dai=1&dis=0&layout_filter=rank%2Ctabcloud&ltr=http%3A%2F%2Fwww.xuanyusong.com%2Farchives%2F3553&ltu=http%3A%2F%2Fwww.xuanyusong.com%2Farchives%2F3571&lunum=6&n=92004029_cpr&pcs=1920x954&pis=10000x10000&ps=369x1329&psr=1920x1080&pss=1920x409&qn=e076dd127958a991&rad=&rsi0=300&rsi1=250&rsi5=4&rss0=%23FFFFFF&rss1=%23FFFFFF&rss2=%230000FF&rss3=%23444444&rss4=%23008000&rss5=&rss6=%23e10900&rss7=&scale=&skin=&td_id=1121907&tn=text_default_300_250&tpr=1444814692268&ts=1&version=2.0&xuanting=0&dtm=BAIDU_DUP2_SETJSONADSLOT&dc=2&di=u1121907&ti=Unity3D%E7%A0%94%E7%A9%B6%E9%99%A2%E4%B9%8BAndroid%E4%BA%8C%E6%AC%A1%E5%8A%A0%E5%AF%86.so%E4%BA%8C%E6%AC%A1%E5%8A%A0%E5%AF%86DLL%EF%BC%88%E5%85%AB%E5%8D%81%E4%BA%8C%EF%BC%89%20%7C%20%E9%9B%A8%E6%9D%BEMOMO%E7%A8%8B%E5%BA%8F%E7%A0%94%E7%A9%B6%E9%99%A2&tt=1444814692266.3.74.75" align="center,center" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" allowtransparency="true" style="margin: 0px; padding: 0px; font-family: inherit;"></iframe>

上文中说了怎么给DLL加密来防止别人反编译你的C#代码。 Unity3D研究院之Android加密DLL与破解DLL .SO(八十一) 文章的最后我们发现IDA PRO神器可以解开libmono从而查到你的解密算法,这样你的C#代码又会被别人轻易的拿到。

这两天我就一直在寻找怎样才能更好的保护代码。终于找到了加密so的办法,此法我觉得防小白觉对够用。大神恐怕还是能解开,但是我觉得这就够了。我已经在项目中测试通过,也欢迎大家也能加入一起来测试的队伍。

在啰嗦一句在不远的将来可能我们也不用这么做了, 因为很快unity就全线l2cpp了。但是我觉得等真正稳定恐怕还有很多路要走,所以估计大部分正在开发的项目不会冒这个险升级。

阅读下面之前请大家先看一下这篇大神的文章。http://bbs.pediy.com/showthread.php?t=191649 文章写的很清晰。但是坦白说看了半天我没怎么看懂,逆向工程真是一门深奥的学问。。主要还是技术关注领域不在这里。文章的最后有作者给出的源码,大家记得下载下来。然后我就开始说我是怎么把这个加在unity3d上的。还有我遇到了那些坑。

它的例子工程下载解压后,开始对shellAdder1.c进行编译,编译的方法是

1

gcc
-o
encry
shellAdder1.c

我开始编译的时候老通不过,提示缺少 elf.h 文件,我看了一下,其实就是少了一些结构体和类型的声明,把下面代码拷贝到shellAdder1.c里面即可。Main函数上面添加如下代码。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

#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代码是什么意思,我相信 这篇文章已经写的是非常的全面了 http://0nly3nd.sinaapp.com/?p=695

然后执行 encry libmono.so 就会把libmono.so里 名叫 mytext 的断 进行加密,你要觉得这个名子不好也可以换一个断名,加密后的libmono.so文件会替换原有的。

接着到mono/metadata/image.c里来编写解密.so断的代码。把下面这段代码拷贝到image.c的最上面,关键的两个地方我已添加注释了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

//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方法里

1

2

3

4

5

if(strstr(name,"Assembly-CSharp.dll")){

//这里就能取到密钥,那么这个函数被加密了。

//IDA就看不到它了

g_message("momo:
key = %d\n",
getKey());

}

密钥被保护了,代码修改完就是开始编译mono吧。编译完用刚刚我们说过的方法来执行 encry libmono.so 然后把libmono拷贝到项目里打包android就行了。

可以测试一下加密的效果。用Ida 打开。这里的函数已经打不开了





这段密钥进行了保护那么就可以随意的做加密算法了。





我相信这个方法还是存在漏洞,肯定也有大神能破解。也希望各位大神不吝赐教,谢谢啦。使用上有问题欢迎在下面留言大家可以一起讨论。

本文固定链接: http://www.xuanyusong.com/archives/3571

转载请注明: 雨松MOMO 2015年07月17日 于 雨松MOMO程序研究院 发表
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: