引言
该博客是写给需要保护自己知识产权的游戏开发者,本文加密方式相对简单易懂,但起到的效果足以让大多数小白窃取者望而却步
Windows加密篇
基于Unity2017
一.准备
1.Mono源码(根据自己的Unity版本下载相应源码): https://github.com/Unity-Technologies/mono
2.Visual Studio 2010(2017的Mono版本需要用此VS版本进行编译)
3.加密的算法(随意,基于C编码)
二.正文
1.修改载入源码(前几部分比较简单,不再一一赘述,直接进入主题)
- 原理:C#是可以动态加载DLL(Assembly.LoadFile), 我们主要是在这里做文章
- 通过阅读mono源码后我们可以知道
- 对DLL解析代码为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)
{
MonoCLIImageInfo *iinfo;
MonoImage *image;
char *datac;
if (!data || !data_len) {
if (status)
*status = MONO_IMAGE_IMAGE_INVALID;
return NULL;
}
// 这里的data为读取DLL后的数据
// 我们可以在这里通过对名字的筛选来对我们已加密的DLL进行解密
datac = data;
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);
}
image = g_new0 (MonoImage, 1);
image->raw_data = datac;
image->raw_data_len = data_len;
image->raw_data_allocated = need_copy;
image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
iinfo = g_new0 (MonoCLIImageInfo, 1);
image->image_info = iinfo;
image->ref_only = refonly;
image->ref_count = 1;
image = do_mono_image_load (image, status, TRUE, TRUE);
if (image == NULL)
return NULL;
return register_image (image);
}
- 读取DLL代码为assembly.c的mono_assembly_open_full
MonoAssembly *
mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
{
MonoImage *image;
MonoAssembly *ass;
MonoImageOpenStatus def_status;
gchar *fname;
gchar *new_fname;
g_return_val_if_fail (filename != NULL, NULL);
if (!status)
status = &def_status;
*status = MONO_IMAGE_OK;
if (strncmp (filename, "file://", 7) == 0) {
GError *error = NULL;
gchar *uri = (gchar *) filename;
gchar *tmpuri;
/*
* MS allows file://c:/... and fails on file://localhost/c:/...
* They also throw an IndexOutOfRangeException if "file://"
*/
if (uri [7] != '/')
uri = g_strdup_printf ("file:///%s", uri + 7);
tmpuri = uri;
uri = mono_escape_uri_string (tmpuri);
fname = g_filename_from_uri (uri, NULL, &error);
g_free (uri);
if (tmpuri != filename)
g_free (tmpuri);
if (error != NULL) {
g_warning ("%s\n", error->message);
g_error_free (error);
fname = g_strdup (filename);
}
} else {
fname = g_strdup (filename);
}
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
"Assembly Loader probing location: '%s'.", fname);
new_fname = NULL;
if (!mono_assembly_is_in_gac (fname))
new_fname = mono_make_shadow_copy (fname);
if (new_fname && new_fname != fname) {
g_free (fname);
fname = new_fname;
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
"Assembly Loader shadow-copied assembly to: '%s'.", fname);
}
image = NULL;
// 这里会对读取进来的数据进行分析
// 当bundles加密后,原来的DLL数据格式被改变
// 所以我们需要在这里做处理,让读进来的DLL数据不被过滤
FILE * pFile;
long lSize;
char * buffer;
size_t result;
char*name;
name = g_path_get_basename(filename); // 获取DLL名称
if (strstr(name, "MyXXX.dll" != NULL) // 判断是否符合需要解密条件(这里是用DLL的名称)
{
pFile = fopen(filename, "rb");
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
rewind(pFile);
buffer = (char*) malloc (sizeof(char)*lSize);
result=fread(buffer, 1, lSize, pFile);
fclose(pFile);
image = mono_image_open_from_data_with_name(buffer, lSize, FALSE, status, refonly, name);
free(buffer);
}
else if (bundles != NULL)
image = mono_assembly_open_from_bundle (fname, status, refonly);
if (!image)
image = mono_image_open_full (fname, status, refonly);
if (!image){
if (*status == MONO_IMAGE_OK)
*status = MONO_IMAGE_ERROR_ERRNO;
g_free (fname);
return NULL;
}
if (image->assembly) {
/* Already loaded by another appdomain */
mono_assembly_invoke_load_hook (image->assembly);
mono_image_close (image);
g_free (fname);
return image->assembly;
}
ass = mono_assembly_load_from_full (image, fname, status, refonly);
if (ass) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
"Assembly Loader loaded assembly from location: '%s'.", filename);
if (!refonly)
mono_config_for_assembly (ass->image);
}
/* Clear the reference added by mono_image_open */
mono_image_close (image);
g_free (fname);
return ass;
}
之后使用VS2010进行编译替换即可生效
2018后,方法有所不同,后面我再找个时间更新下,原理基本还是一样的
来源:https://blog.csdn.net/supermanbr/article/details/99291984