【Unity3D】apk加密(global-metadata.dat加密)

涉及:apk、aab、global-metadata.dat、jks密钥文件、APKTool、zipalign

使用7z打开apk文件观察发现有如下3个针对加密的文件。

xxx.apk\assets\bin\Data\Managed\Metadata\global-metadata.dat
xxx.apk\lib\armeabi-v7a\libil2cpp.so
xxx.apk\lib\arm64-v8a\libil2cpp.so

xxx.aab\base\assets\bin\Data\Managed\Metadata\global-metadata.dat
xxx.aab\base\lib\armeabi-v7a\libil2cpp.so
xxx.aab\base\lib\arm64-v8a\libil2cpp.so

如上打包配置:Player Settings - Other Settings - Scripting Backend 选IL2CPP
若选Mono,libil2cpp.so会变成libmono.so,针对.so文件的加密较为复杂可参考libmono.so打包
【Unity3D】unity-mono编译libmono.so成功-CSDN博客

本文章仅针对global-metadata.dat文件加密,global-metadata.dat是一种元数据文件,包含了编译后的IL代码所需要的所有信息,包括类型信息、方法信息、字段信息等等。

它由两部分组成:文件头和元数据。
文件头包含了两个重要的信息:魔数和版本号。
魔数是一个4字节的标志,用于确定这个文件是Unity的元数据文件,它的值是0xFAB11BAF。
版本号是一个4字节的无符号整数,用于表示Unity引擎的版本号,它的值为24(0x18)

HxD Hex Editor工具查看

using UnityEngine;
using UnityEditor;
using System.IO;

public static class EncryptEditor
{
    [MenuItem("Tools/加密global-metadata.dat")]
    public static void Encrypt()
    {
        string path = Application.dataPath + "/global-metadata.dat";
        string key_char = "abcd ";
        byte[] bytes = File.ReadAllBytes(path);
        for (int i = 0; i < bytes.Length; i++)
        {
            int keyCharIndex = i % key_char.Length;
            if (keyCharIndex == 4)
            {
                continue;
            }
            bytes[i] = (byte)(bytes[i] ^ key_char[i % key_char.Length]);
        }
        File.WriteAllBytes(path, bytes);
    }
}

加密后 

找到Unity工程安装目录

\Editor\Data\il2cpp\libil2cpp\vm\MetadataLoader.cpp (选择IL2CPP打包方式)
\Editor\Data\il2cpp\libmono\vm\MetadataLoader.cpp (选择Mono打包方式)

#include "il2cpp-config.h"
#include "MetadataLoader.h"
#include "os/File.h"
#include "os/Mutex.h"
#include "utils/MemoryMappedFile.h"
#include "utils/PathUtils.h"
#include "utils/Runtime.h"
#include "utils/Logging.h"

void* il2cpp::vm::MetadataLoader::LoadMetadataFile(const char* fileName)
{
    std::string resourcesDirectory = utils::PathUtils::Combine(utils::Runtime::GetDataDir(), utils::StringView<char>("Metadata"));

    std::string resourceFilePath = utils::PathUtils::Combine(resourcesDirectory, utils::StringView<char>(fileName, strlen(fileName)));

    int error = 0;
    os::FileHandle* handle = os::File::Open(resourceFilePath, kFileModeOpen, kFileAccessRead, kFileShareRead, kFileOptionsNone, &error);
    if (error != 0)
    {
        utils::Logging::Write("ERROR: Could not open %s", resourceFilePath.c_str());
        return NULL;
    }
	//解密相关改动 读取数据长度
	int64_t length = 0;
	int error2 = 0;
	length = os::File::GetLength(handle, &error2);
	//解密相关改动
    void* fileBuffer = utils::MemoryMappedFile::Map(handle);

    os::File::Close(handle, &error);
    if (error != 0)
    {
        utils::MemoryMappedFile::Unmap(fileBuffer);
        fileBuffer = NULL;
        return NULL;
    }
	
	//解密相关改动 拷贝数据至data,解密data
	char *data = (char*)malloc(length);
	memcpy(data, fileBuffer, length);
	void* result = utils::MemoryMappedFile::DecryptFile(data, length);
	return result;
	//解密相关改动

	//注释源代码
    //return fileBuffer;
}

\Editor\Data\il2cpp\libil2cpp\utils\MemoryMappedFile.cpp

	void* MemoryMappedFile::DecryptFile(char* data, int64_t length)
	{
		char *result;
		result = (char*)malloc(length);
		char a[5] = "abcd";
		for (int i = 0; i < length; i++)
		{
			result[i] = data[i] ^ a[i%5];
		}
		return static_cast<void*>(result);
	}

\Editor\Data\il2cpp\libil2cpp\utils\MemoryMappedFile.h

#pragma once

#include <map>
#include "os/File.h"
#include "os/Mutex.h"
#include "os/MemoryMappedFile.h"

namespace il2cpp
{
namespace utils
{
    class MemoryMappedFile
    {
    public:
        static void* Map(os::FileHandle* file);
        static void* Map(os::FileHandle* file, int64_t length, int64_t offset);
        static void* Map(os::FileHandle* file, int64_t length, int64_t offset, int32_t access);
		static void* DecryptFile(char* data, int64_t length);
        static bool Unmap(void* address);
        static bool Unmap(void* address, int64_t length);
    };
}
}

修改完毕后,进行打包工程apk,得到test.apk,然后按如下流程进行反编译,加密,重签名打包。

使用APKTool库反编译test.apk得到test文件夹
apktool d test.apk -o test

进入test文件夹,将\test\assets\bin\Data\Managed\Metadata\global-metadata.dat挪到项目里加密,然后再覆盖test文件夹内的,接着进行重打包apk得到ex_test.apk
apktool b test -o ex_test.apk

使用Android Studio(3.5.1)创建keystore_test.jks,alias别名:key3  密码:123456
jarsigner -verbose -keystore keystore_test.jks -signedjar xxx_signed.apk ex_test.apk key3

使用zipalign对签名后的文件进行对齐
zipalign -p -f -v 4 xxx_signed.apk xxx_zipalign.apk

文件对齐后还需要使用apksigner,进行签名
apksigner sign --ks keystore_test.jks --ks-key-alias key3 --ks-pass pass:123456 --v2-signing-enabled true -v --out final.apk xxx_zipalign.apk

注意事项: 

针对global-metadata.dat文件的加密和解密写法看着有点奇怪,是不是?
因为C++的char[]数组会末尾自动添加'\0'结束符

char a[5] = "abcd";
for (int i = 0; i < length; i++)
{
    result[i] = data[i] ^ a[i%5];
}

上面这个操作,当i%5=4时,取到a[4]是'\0',data[i] ^ '\0' = data[i] 不会发生变化的,因此C#侧加密代码需要如下写法,当i%5=4时,我直接continue跳过,不对bytes[i]做处理。

string key_char = "abcd ";
for (int i = 0; i < bytes.Length; i++)
{
    int keyCharIndex = i % key_char.Length;
    if (keyCharIndex == 4)
    {
        continue;
    }
    bytes[i] = (byte)(bytes[i] ^ key_char[i % key_char.Length]);
}

1、如果apk无法安装,说明没有正常签名以及对齐文件再签名。
2、如果apk可以安装,但运行会闪退说明加密或解密操作出问题,或者真的是项目apk有问题,需确保apk没有解密操作情况下也能正常跑。 (也就是不要修改MetadataLoader.cpp文件 全部还原先)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/951535.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[免费]微信小程序(高校就业)招聘系统(Springboot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序(高校就业)招聘系统(Springboot后端Vue管理端)&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序(高校就业)招聘系统(Springboot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项目介绍…

RNN心脏病预测-Pytorch版本

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 导入数据 import numpy as np import pandas as pd import torch from torch import nn import torch.nn.functional as F import seaborn as sns from sklearn.preprocessing import Standard…

科普CMOS传感器的工作原理及特点

在当今数字化成像的时代&#xff0c;图像传感器无疑是幕后的关键 “功臣”&#xff0c;它宛如一位神奇的 “光影魔法师”&#xff0c;通过光电效应这一奇妙的物理现象&#xff0c;将光子巧妙地转换成电荷&#xff0c;为图像的诞生奠定基础。而在众多类型的图像传感器中&#xf…

Ubuntu 18.04 解决screen无法滚屏的问题

Ubuntu 18.04 解决screen无法滚屏的问题_ubuntu screen 无法上滑-CSDN博客文章浏览阅读2.7k次&#xff0c;点赞2次&#xff0c;收藏3次。在etc/screenrc中加入termcapinfo xterm* ti:te重新进入screen的sessionscreen -d -r XXX_ubuntu screen 无法上滑https://blog.csdn.net/w…

2025年01月09日Github流行趋势

1. 项目名称&#xff1a;khoj 项目地址url&#xff1a;https://github.com/khoj-ai/khoj项目语言&#xff1a;Python历史star数&#xff1a;22750今日star数&#xff1a;1272项目维护者&#xff1a;debanjum, sabaimran, MythicalCow, aam-at, eltociear项目简介&#xff1a;你…

Spring boot接入xxl-job

Spring boot接入xxl-job 导入maven包加入配置增加配置类创建执行器类&#xff08;写job的业务逻辑&#xff09;去控制台中配置job 导入maven包 <dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactId><version>…

Cglib动态代理中method.invoke与methodProxy.invokeSuper区别浅尝

前段时间看了黑马Spring教程中&#xff0c;有期视频讲解Cglib动态代理。 代码如下图&#xff1a; 可以看到调用目标对象的方法代码为&#xff1a; method.invoke(target,objects);在其他地方看到的此处代码是&#xff1a; methodProxy.invokeSuper(o,objects);注意&#xff…

【Linux 之一 】Linux常用命令汇总

Linux常用命令 ./catcd 命令chmodclearcphistoryhtoplnmkdirmvpwdrmtailunamewcwhoami 我从2021年4月份开始才开始真正意义上接触Linux&#xff0c;最初学习时是一脸蒙圈&#xff0c;啥也不会&#xff0c;啥也不懂&#xff0c;做了很多乱七八糟&#xff0c;没有条理的笔记。不知…

NO.3 《机器学习期末复习篇》以题(问答题)促习(人学习),满满干huo,大胆学大胆补!

目录 &#x1f50d; 1. 对于非齐次线性模型 &#xff0c;试将其表示为齐次线性模型形式。 ​编辑 &#x1f50d; 2. 某汽车公司一年内各月份的广告投入与月销量数据如表3-28所示&#xff0c;试根据表中数据构造线性回归模型&#xff0c;并使用该模型预测月广告投入为20万元时…

Javascript算法——贪心算法(一)

贪心算法详解&#xff08;JavaScript&#xff09;&#xff08;局部最优->全局最优&#xff09; 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在每一步选择中都采取当前状态下的最优选择&#xff08;局部最优&#xff09;的算法设计方法。通过局部最优解的累积&…

【Vue】分享一个快速入门的前端框架以及如何搭建

先上效果图: 登录 菜单: 下载地址: 链接&#xff1a;https://pan.baidu.com/s/1m-ZlBARWU6_2n8jZil_RAQ 提取码&#xff1a;ui20 … 主要是可以自定义设置token,更改后端请求地址较为方便。 应用设置: 登录与token设置: 在这里设置不用登录,可以请求的接口: request.js i…

jdk8升级JDK21(Springboot2.7.18升级Springboot3.4.0)

目录 背景&#xff1a; 一、maven升级 二、代码改造 2.1 javax替换为jakarta 2.2 swagger2升级swagger3相关更新 2.2.1 新增SpringDocConfig配置类 2.2.2 全局代码更新 2.2.3 全局代码替换&#xff08;普通正则替换&#xff09; 2.3 Mybatis Plus升级 2.4 logback.xm…

数据库(3)--针对列的CRUD操作

1.Create 新增 语法&#xff1a; insert into 表名 &#xff08;列名&#xff09;values &#xff08;列&#xff09;... 创建一个学生表用于演示&#xff1a; create table if not exists student( id bigint comment 编号, name varchar(20) comment 姓名 ); 1.1直接增加…

加速科技荣获“浙江省企业研究院”认定

近日&#xff0c;浙江省经济和信息化厅公布“2024年认定&#xff08;备案&#xff09;省级企业研发机构名单”。经过多轮严格评审和公示&#xff0c;加速科技荣获“省企业研究院”认定。这是加速科技继获国家级专精特新“小巨人”企业认定荣誉后的又一里程碑。 “浙江省企业研究…

leetcode:1784. 检查二进制字符串字段(python3解法)

难度&#xff1a;简单 给你一个二进制字符串 s &#xff0c;该字符串 不含前导零 。 如果 s 包含 零个或一个由连续的 1 组成的字段 &#xff0c;返回 true​​​ 。否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;s "1001" 输出&#xff1a;fa…

双向列表的实现(C++)

一.实现思路 主要是一个空间存储一个数值&#xff0c;然后为了索引后面的数据单元和前面的数据单元&#xff0c;所以在每个空间里面还要存储前面和后面数据单元的指针&#xff0c;就形成了每个数据单元 后面就是要管理的是双向列表的头结点和尾节点&#xff0c;方便实现后面的头…

【前端开发常用网站汇总-01】

1、仿mac界面代码截图 https://codeimg.io/?utm_sourceappinn.com 2、可视化大屏汇总(在线Demo) https://www.xiongze.net/viewdata/index.html 3、在线Photoshop(实现简单P图) https://ps.gaoding.com/#/ 4、在线生成ico图标(png转icon文件) https://www.bitbug.net/in…

腾讯云AI代码助手编程挑战赛-百事一点通

作品简介 百事通问答是一款功能强大的智能问答工具。它依托海量知识储备&#xff0c;无论你是想了解生活窍门、学习难点&#xff0c;还是工作中的专业疑惑&#xff0c;只需输入问题&#xff0c;就能瞬间获得精准解答&#xff0c;以简洁易懂的方式呈现&#xff0c;随时随地为你…

网络安全 信息收集入门

1.信息收集定义 信息收集是指收集有关目标应用程序和系统的相关信息。这些信息可以帮助攻击者了解目标系统的架构、技术实现细节、运行环境、网络拓扑结构、安全措施等方面的信息&#xff0c;以便我们在后续的渗透过程更好的进行。 2.收集方式-主动和被动收集 ①收集方式不同…

Qt QDockWidget详解以及例程

Qt QDockWidget详解以及例程 引言一、基本用法二、深入了解2.1 窗口功能相关2.2 停靠区域限制2.3 在主窗体布局 引言 QDockWidget类提供了一个可以停靠在QMainWindow内的小窗口 (理论上可以在QMainWindow中任意排列)&#xff0c;也可以作为QMainWindow上的顶级窗口浮动 (类似一…