Unity3D研究院之Android二次加密.so二次加密DLL(八十二)
雨松MOMO 【Unity3D研究院之游戏开发】 围观3916次 42条评论 编辑日期:2015-07-17 字体:大 中 小上文中说了怎么给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程序研究院 发表