【Android签名文件META-INF】

文章详细介绍了AndroidAPK安装包中的META-INF文件夹作用,包括MANIFEST.MF文件中记录的文件SHA1值,.SF文件对MANIFEST.MF的整体及条目SHA1签名,以及.RSA文件中包含的私钥签名和公钥证书信息,这些都关乎APK的验证和安全性。
摘要由CSDN通过智能技术生成

android安装包apk中,有一个META-INF文件夹,该文件夹下面必须有以下几个扩展名的文件:.SF,.RSA,*.MF。一般为MANIFEST.MF,包名.SF,包名.RSA(也有可能是EC或者DSA)。

其中:
MANIFEST.MF:除去META-INF文件夹外,所有文件的base64(sha1)值。
在这里插入图片描述
以文件activity_search_result.xml为例,从MANIFEST.MF中可以看到,该文件的base64(sha1)值为 4L3KEBI/a+som57XQEDsO+uWBrk=,base64解码该值得到如下值:

在这里插入图片描述

base代码如下:



#include <windows.h>
#include "Base64.h"

// base64.h

// 参考文章:http://www.cstc.net.cn/docs/docs.php?id=202

//************************************************************************/
//    base64编码表
// 
//  0 A 17 R 34 i 51 z 
//  1 B 18 S 35 j 52 0 
//  2 C 19 T 36 k 53 1 
//  3 D 20 U 37 l 54 2 
//  4 E 21 V 38 m 55 3 
//  5 F 22 W 39 n 56 4 
//  6 G 23 X 40 o 57 5 
//  7 H 24 Y 41 p 58 6 
//  8 I 25 Z 42 q 59 7 
//  9 J 26 a 43 r 60 8 
//  10 K 27 b 44 s 61 9 
//  11 L 28 c 45 t 62 + 
//  12 M 29 d 46 u 63 / 
//  13 N 30 e 47 v (pad) = 
//  14 O 31 f 48 w 
//  15 P 32 g 49 x 
//  16 Q 33 h 50 y 
//
// base64编码步骤:
// 
//  原文:
//
//  你好
//  C4 E3 BA C3
//  11000100 11100011 10111010 11000011
//  00110001 00001110 00001110 00111010
//  49       14       (十进制)
//  x        O        O        6  字符
//  01111000 01001111 01001111 00110110
//  78         (十六进制)
//  xOO6
//
//  解码:
//  xOO6
//  78 4f 4f 36
//  01111000 01001111 01001111 00110110
//  49       14 
//  00110001 00001110 00001110 00111010   31 0e 0e 3a
//
//  11000100 11100011 10111010
//  C4       E3       BA
//

#ifndef _BASE64_INCLUDE__H__
#define _BASE64_INCLUDE__H__

// 存储编码结果需要的长度,包含\0的长度
#define BASE64_ENCODE_LEN(A) ((A+2)/3 * 4 + 1)
// 存储解码结果需要的长度,包含\0的长度
#define BASE64_DECODE_LEN(A) (A / 4 * 3 + 2)

// 编码后的长度一般比原文多占1/3的存储空间,请保证base64code有足够的空间


__inline char GetB64Char(int index)
{
	const char szBase64Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	if (index >= 0 && index < 64)
		return szBase64Table[index];

	return '=';
}

// 从双字中取单字节
#define B0(a) (a & 0xFF)
#define B1(a) (a >> 8 & 0xFF)
#define B2(a) (a >> 16 & 0xFF)
#define B3(a) (a >> 24 & 0xFF)

// 编码后的长度一般比原文多占1/3的存储空间,请保证base64code有足够的空间
int Base64::Base64Encode(char * base64code, const unsigned char * src, int src_len)
{
	if (src_len == 0)
		src_len = strlen((char*)src);

	int len = 0;
	unsigned char* psrc = (unsigned char*)src;
	char * p64 = base64code;
	int i = 0;
	for (i = 0; i < src_len - 3; i += 3)
	{
		unsigned long ulTmp = *(unsigned long*)psrc;
		register int b0 = GetB64Char((B0(ulTmp) >> 2) & 0x3F);
		register int b1 = GetB64Char((B0(ulTmp) << 6 >> 2 | B1(ulTmp) >> 4) & 0x3F);
		register int b2 = GetB64Char((B1(ulTmp) << 4 >> 2 | B2(ulTmp) >> 6) & 0x3F);
		register int b3 = GetB64Char((B2(ulTmp) << 2 >> 2) & 0x3F);
		*((unsigned long*)p64) = b0 | b1 << 8 | b2 << 16 | b3 << 24;
		len += 4;
		p64 += 4;
		psrc += 3;
	}

	// 处理最后余下的不足3字节的饿数据
	if (i < src_len)
	{
		int rest = src_len - i;
		unsigned long ulTmp = 0;
		for (int j = 0; j < rest; ++j)
		{
			*(((unsigned char*)&ulTmp) + j) = *psrc++;
		}

		p64[0] = GetB64Char((B0(ulTmp) >> 2) & 0x3F);
		p64[1] = GetB64Char((B0(ulTmp) << 6 >> 2 | B1(ulTmp) >> 4) & 0x3F);
		p64[2] = rest > 1 ? GetB64Char((B1(ulTmp) << 4 >> 2 | B2(ulTmp) >> 6) & 0x3F) : '=';
		p64[3] = rest > 2 ? GetB64Char((B2(ulTmp) << 2 >> 2) & 0x3F) : '=';
		p64 += 4;
		len += 4;
	}

	*p64 = '\0';

	return len;
}


__inline int GetB64Index(char ch)
{
	int index = -1;
	if (ch >= 'A' && ch <= 'Z')
	{
		index = ch - 'A';
	}
	else if (ch >= 'a' && ch <= 'z')
	{
		index = ch - 'a' + 26;
	}
	else if (ch >= '0' && ch <= '9')
	{
		index = ch - '0' + 52;
	}
	else if (ch == '+')
	{
		index = 62;
	}
	else if (ch == '/')
	{
		index = 63;
	}

	return index;
}

// 解码后的长度一般比原文少用占1/4的存储空间,请保证buf有足够的空间
int Base64::Base64Decode(char * buf, const char * base64code, int src_len)
{
	if (src_len == 0)
		src_len = strlen(base64code);

	int len = 0;
	unsigned char* psrc = (unsigned char*)base64code;
	char * pbuf = buf;
	int i = 0;
	for (i = 0; i < src_len - 4; i += 4)
	{
		unsigned long ulTmp = *(unsigned long*)psrc;

		register int b0 = (GetB64Index((char)B0(ulTmp)) << 2 | GetB64Index((char)B1(ulTmp)) << 2 >> 6) & 0xFF;
		register int b1 = (GetB64Index((char)B1(ulTmp)) << 4 | GetB64Index((char)B2(ulTmp)) << 2 >> 4) & 0xFF;
		register int b2 = (GetB64Index((char)B2(ulTmp)) << 6 | GetB64Index((char)B3(ulTmp)) << 2 >> 2) & 0xFF;

		*((unsigned long*)pbuf) = b0 | b1 << 8 | b2 << 16;
		psrc += 4;
		pbuf += 3;
		len += 3;
	}

	// 处理最后余下的不足4字节的饿数据
	if (i < src_len)
	{
		int rest = src_len - i;
		unsigned long ulTmp = 0;
		for (int j = 0; j < rest; ++j)
		{
			*(((unsigned char*)&ulTmp) + j) = *psrc++;
		}

		register int b0 = (GetB64Index((char)B0(ulTmp)) << 2 | GetB64Index((char)B1(ulTmp)) << 2 >> 6) & 0xFF;
		*pbuf++ = b0;
		len++;

		if ('=' != B1(ulTmp) && '=' != B2(ulTmp))
		{
			register int b1 = (GetB64Index((char)B1(ulTmp)) << 4 | GetB64Index((char)B2(ulTmp)) << 2 >> 4) & 0xFF;
			*pbuf++ = b1;
			len++;
		}

		if ('=' != B2(ulTmp) && '=' != B3(ulTmp))
		{
			register int b2 = (GetB64Index((char)B2(ulTmp)) << 6 | GetB64Index((char)B3(ulTmp)) << 2 >> 2) & 0xFF;
			*pbuf++ = b2;
			len++;
		}

	}

	*pbuf = '\0';

	return len;
}

#endif // #ifndef _BASE64_INCLUDE__H__ 

(注意:有些网站比如网址https://c.runoob.com/front-end/693/,只能解码可打印字符,无法显示不可打印的二进制编码值。) 把该文件复制到d:\盘下,cmd中使用certutil命令中获取该文件的sha1值。
在这里插入图片描述
可以看到两者相等。

*.SF:对MANIFEST.MF文件整体的sha1值,以及其中各个条目的sha1值。每一条对应MANIFEST.MF中的一个条目,是对各个条目的再次计算sha1值。
在这里插入图片描述
例如,图中的SHA1-Digest-Manifest-Main-Attributes字段是对MANIFEST.MF中“Manifest-Version: 1.0\r\n
Created-By: 1.8.0_152-release (JetBrains s.r.o)\r\n\r\n"的base64(sha1)。注意,每个条目后要多加一个"\r\n"。
在这里插入图片描述
base64解码图中的值得到如下结果:
在这里插入图片描述
cmd中使用certutil命令获取文件的sha1值得到如下结果:

在这里插入图片描述
可以看到两者的值是一致的。

而*.sf中的SHA1-Digest-Manifest字段,下面的文字是certutil计算的MANIFEST.MF文件的sha1值,图中显示的是“ko/mCIuDu02v/nxJ/ycSj2GY12E=” 的base64解码后的值。可见两者也是一致的。

92 8f e6 08 8b 83 bb 4d af fe 7c 49 ff 27 12 8f 61 98 d7 61
在这里插入图片描述

*.RSA:包含用私钥对 .SF的签名以及包含公钥信息的数字证书。可以使用证书中的公钥解密该签名文件以便验证该文件的发布者。该文件是对android安装包验证的核心文件,其原理是,计算.sf文件的hash值,然后使用rsa私钥对其加密,得出如下图中的签名。未验证。
该文件也是一个数字证书文件,但是跟windows平台的cert文件格式不同,有兴趣的朋友可以用下图中的公钥解密图中所示的签名信息查看是否匹配。
可以通过以下命令查看该文件的内容:
openssl pkcs7 -inform der -in *.rsa -noout -print_certs -text
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值