每次github上有人提issue时都要重新看代码来回顾整个过程,遂写下这篇文章减少复习的时间。
什么是exe文件
这里的exe文件专门指由Matlab使用mcc命令编译出来的exe文件,可以在Windows环境中运行。
mcc命令的部分说明如下:
您可以使用 将 MATLAB 程序打包和部署为独立应用程序、Excel 加载项、Spark™ 应用程序或 Hadoop 作业。
如果你有一个 MATLAB 编译器SDK™许可证,可用于创建C/C++共享库, .NET 汇编、Java 包、Python 包、MATLAB 生产服务器™可部署存档,或用于 MATLAB 的 Excel 加载项 生产服务器。
mcc -m [选项] mfilename
将函数编译为独立的应用程序。可执行文件类型由 您的操作系统。
从描述上看,Windows的exe文件只是mcc命令众多功能的一个子集,但是本文的视角仅聚焦在Windows下的exe文件。
既然是exe文件,文件结构当然是一个标准的PE结构。
上述信息展示了overlay是一个ZIP文件,可以用任何压缩软件解压。
overlay的压缩包
overlay的压缩包主要包含了两类文件,一种是包含各种信息的xml文件,另一种是Matlab的加密脚本文件(有固定的开头),还有一些数据、界面、依赖等不是特别重要的信息本文将忽略。
manifest.xml
xml中最为重要的是.META目录下的manifest.xml,该文件包含了用于解密加密脚本的密钥,其本身也受到哈希保护。
manifest.xml的signature字段用于校验自身,当signature为128字节时采用SHA512保护(v2),当signature为40字节时采用SHA1保护(v1)。
manifest.xml包含两个重要的密钥,解决方案密钥(solution-key)和编译密钥(compiler-key),分别由session-key字段和public-key字段提供。
密钥
由于在解密过程出现很多的密钥,下面先对这些密钥进行归纳
名称 |
来源 |
用途 |
session-key |
manifest.xml |
作为solution-key |
public-key |
manifest.xml |
作为compiler-key |
solution-key |
manifest.xml |
用于导出symmetric-key,导出时需要私钥matlab-key,动态的候选密钥 |
compiler-key |
manifest.xml |
用于验证加密脚本的完整性 |
matlab-key |
mclmcr.dll |
用于解密solution-key导出symmetric-key |
toolbox-key |
ctfrtcrypto.dll |
用于导出symmetric-key,导出时需要私钥matlab-key,静态的候选密钥 |
symmetric-key |
solution-key或toolbox-key |
用于计算aes-key(symmetric-key的SHA256) |
aes-key |
symmetric-key |
用于解密加密脚本,验证加密脚本完整性 |
加密脚本
加密脚本目前收录了两个版本,分别以V1MCC4000MEC1000MCR1000
和V2MCC8000MEC2000MCR2000
开头。这两个版本在结构和算法上有较大的区别,下文会按两种版本分别阐述。
序号 |
开头特征 |
适用版本 |
1 |
V1MCC4000MEC1000MCR1000 |
R2018B之前版本(含) |
2 |
V2MCC8000MEC2000MCR2000 |
R2019A之后版本(含) |
V1版本
以下展示加密脚本的部分截图:
从上图可以看到,V1版本的文件结构主要分为两个部分,记为body1和body2。body1有一个Int型指示大小,剩下的就是body2。
body1
body1使用AES128-CFB进行加密,解密则需要aes-key和aes-iv。
根据上述密钥章节,solution-key和toolbox-key都可以导出aes-key,所以存在两份aes-key,至于使用哪一份aes-key,需要通过HMAC来确认。分别对两份aes-key进行HMAC\<SHA1\>算法,其中一份aes-key的结果将与HMAC相匹配。
aes-iv由8字节的AES-IV-DATA派生。首先取AES-IV-DATA的SHA256,得到32字节结果,再将32字节对折异或,得到16字节的aes-iv。简单的过程如下所示:
1 2 3 4 5 6 7 8 9 | ArrayByte sha256_result;
SHA256 sha256;
StringSource(iv_data, true, new HashFilter(sha256, new StringSink(sha256_result)));
int i;
for (i = 0 ; i < 16 ; i + + )
{
sha256_result[i] ^ = sha256_result[i + 16 ];
}
|
在得到aes-key和aes-iv后,就可以解密,以下是解密后的数据:
解密后的数据先分成3部分,第一部分是开头7个字节,含义不明;第二部分是signature,用于检验下面的message;第三部分是message,存放一些matlab的配置信息。
message使用了非对称算法进行签名,密钥固定为complier-key,具体算法为RSASS<PKCS1v15, SHA1>
,关于签名的编码规则、哈希算法、签名算法等有太多细节,请自行查阅相关资料,本文不再赘述。
message
如上图所示,message包含了多个部分的内容。
- 选中的20字节为solution-key的SHA1结果,如果修改了manifest.xml中的session-key,则此处将要同步修改。
- 下滑红线的数据是一个日期时间字符串,通常为25字符串,并以0x0A结尾。该日期是本文件构建的时间。
- 紧跟日期时间字符串未作任何标记的部分目前含义不明。
- 红框包围的部分是一段用户字符串,最大128字节,最后必须以0结尾。
- 橙框包围的一个字节是demo标志,当该值为1时,程序为演示模式,只能自本文件构建的时间起30天内运行。
body2
body2结构与body1相近,HMAC和AES-IV-DATA的用法与body1相同。
解密后,得到以下结构:
从图中可以得知,结构主要分为3部分:
- 紫框包围的数据,含义不明,第一个字节的低4位(+3)指示了这部分数据的长度。例:0xAB低4位为0xB,+3后为0xE,故数据长度为14字节。
- 选中的128字节为signature,用于校验红框数据(解压后)。
- 剩余被红框包围数据是使用了zlib压缩的数据,使用zlib库即可解压。
uncompressed-data
红框数据解压后即可得到原始的脚本文件,见下图:
和原始的脚本文件比较,发现所有注释都被删除了,其他部分不变。以下是一部分的比较图:
V2版本
以下展示加密脚本的部分截图:
从上图可见,V2版本和V1版本在文件结构上稍有差别。
- V2版本中HMAC校验是对整个文件进行的,V1版本是body1和body2分别进行的
- V2版本用了8个字节来记录body2解压后的大小
- V2版本body1和body2共用一份AES密钥,V1版本则需要分开独立计算。
- V2版本直接提供aes-iv,V1版本提供的AES-IV-DATA需要转换一下才能得到aes-iv
body1
与V1版本类似,可以通过HMAC确定aes-key,不同的是,aes-iv是直接给出,无需计算。得到aes-key和aes-iv后,则可以使用AES128-CFB来进行解密。
解密后的结构同样分为signature和message部分,signature部分用于检验message部分的完整性,使用的算法为 RSASS<PSS, SHA512>
,密钥同样为complier-key。
message
- 位于最初的64字节是SHA512的16进制字符串,用于验证manifest.xml中的session-key的完整性。
- 下滑绿线的数据是一个日期时间字符串,通常为25字符串,并以0x0A结尾。该日期是本文件构建的时间。
- 后面跟着一推字符串,有UTF8编码的,也有UTF16编码的,目前这些字符串用途不明。
- 最后一个字节同样是demo_flag,用于与V1一致。
body2
body2同样需要解密,解密过程与body1一致(使用相同的aes-key和aes-iv)。
解密后还需要进行zlib解压。
uncompressed-data
解压后的数据结构很简单,一个signature部分和一个message部分。其中signature部分256字节,用于校验message部分的完整性,使用方法和body1一致。
message部分是明文脚本,与V1不同的是,V2版本中脚本的注释被保留下来了。
其他
- 每个maltab运行库都有一个很好的参考例子(mps_check.ctf)。
- mcc本质是个打包指令,根据内容的不同,打包的结构可能会有所不同。
普通的脚本文件打包结构正如本文所描述;而一些应用程序可能存在如下图情况:
其中的mlapp并不是一个加密脚本,而是一个压缩包。真正的加密脚本被已经被打包到mlapp中,为了应对这种情况,在解析代码增加嵌套解压的过程(或许应该根据后缀名做不同的处理)。
- matlab-key位于mclmcr.dll中,但无法直接在mclmcr.dll中搜索到该值,因为matlab-key使用比较简单的编码(加扰),如下图所示:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!