Java Card CAP文件分析

JAVA 智能的可执行文件(CAP 文件)是编译多个应用程序(Applet)的生成结果,包含了一个包中定义的所有类和接口,与包之间是一一对应的关系。实际发卡操作时,首先需要将该可执行文件下载至卡片中,并安装需要的应用实例;用户使用该安装的应用实例执行操作功能。

CAP文件包含12个组件:

Component Type

Value

COMPONENT_Header

1

COMPONENT_Directory

2

COMPONENT_Applet

3

COMPONENT_Import

4

COMPONENT_ConstantPool

5

COMPONENT_Class

6

COMPONENT_Method

7

COMPONENT_StaticField

8

COMPONENT_ReferenceLocation

9

COMPONENT_Export

10

COMPONENT_Descriptor

11

COMPONENT_Debug

12

注意:
一个完整的CAP文件,除Applet、Export 和Debug组件是可选外,其他均为必选。每个组件封装成一个CAP包,包含在Jar包中。最后在卡上只保留了5个组件:COMPONET_Method,COMPONET_Class,COMPONET_ConstantPool,COMPONET_StaticField和 COMPONET_Export。其余的组件只是安装时提取有用信息而不在卡中保存。

12个组件中,类class组件保存本应用声明的所有类和接口的信息; 方法method组件保存本应用声明的所有方法和接口,method中利用2字节索引index引用类、方法和域;常数池constant pool组件保存method组件引用的所有类、方法和域信息,分为类、实例域、虚方法、父方法、静态域和静态方法6类,每组信息为4个字节;相关地址reference location组件保存method组件中索引的偏移。

对于JavaCard而言,应用程序的下载过程是即CAP文件写入到EEPROM的过程,即是对CAP文件的下载过程。在CAP文件的下载过程中,需要将一部分组件进行解析,同时对reference location中指定的位置进行链接,能够链接到method组件中的一个索引号,并根据索引号查找constant pool中保存的、与该索引号对应的类、方法或域在 EEPROM中的实际地址,调用实际地址中存储的数据。也就是说,方法的调用其实是需要两个步骤来实现的:

  1. 根据reference location中指定的位置进行链接,获取method组件中的索引号;
  2. 根据索引号查找constant pool中保存的、与该索引号对应的类、方法或域在EEPROM中的实际地址,调用实际地址中存储的数据。

查看一个CAP文件的组件,可以通过两种方法实现:

  • 解压缩软件直接解压得到
  • 通过JCK中的capdump将其分解成各个组件

下面是加压cap的java源码:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import android.os.Environment;
import android.util.Log;

public class Cap {
	static final String TAG = "cap";
	static public final String CAP_DIRECTORY = "//mnt//sdcard//cap//";
	static final int READ_LENGTH = 1024;

	private List<String> mCapFileList;

	public void loadCapFile(String CapFileName) {
		try {
			if (!Environment.getExternalStorageState().equals(
					Environment.MEDIA_MOUNTED)) {
				Log.e(TAG, "SD card not available!");
				return;
			}
			File file = new File(CAP_DIRECTORY + CapFileName);
			if (!file.exists()) {
				Log.e(TAG, CAP_DIRECTORY + "safe.cap not available!");
				return;
			}
			mCapFileList = new ArrayList<String>();
			mCapFileList.clear();
			BufferedOutputStream dest = null;
			BufferedInputStream is = null;
			ZipEntry entry;
			ZipFile zipfile = new ZipFile(file);
			Enumeration<? extends ZipEntry> e = zipfile.entries();
			while (e.hasMoreElements()) {
				entry = (ZipEntry) e.nextElement();
				String fileName = entry.getName();
				if (fileName.endsWith(".MF"))
					continue;

				if (fileName.contains("/")) {
					int dir = fileName.lastIndexOf("/");
					String root = CAP_DIRECTORY + fileName.substring(0, dir);
					File path = new File(root);
					if (!path.exists()) {
						path.mkdirs();
					}
				}
				int count;
				byte data[] = new byte[READ_LENGTH];
				mCapFileList.add(CAP_DIRECTORY + entry.getName());

				FileOutputStream fos = new FileOutputStream(CAP_DIRECTORY
						+ entry.getName());
				dest = new BufferedOutputStream(fos, READ_LENGTH);

				is = new BufferedInputStream(zipfile.getInputStream(entry));
				while ((count = is.read(data, 0, READ_LENGTH)) != -1) {
					dest.write(data, 0, count);
				}
				dest.flush();
				dest.close();
				is.close();
				fos.close();
			}
		} catch (Exception e) {
			Log.e(TAG, "loadCap: " + e.getMessage());
		}
	}

	public List<String> getCapFileList() {
		return mCapFileList;
	}
}

使用方法

Cap cap = new Cap();
cap.loadCapFile("HelloWorld.cap");
就可以解压出各个组件,他们也是cap文件。

所有的组件均有通用结构格式,如下:

component {
    u1 tag      //u1表示无符号单字节类型的数据变量类型;tag为组件索引号,按照上面组件名称的顺序从1至12排列
 
    u2 size     //u2表示无符号双字节的数据变量类型;size为可变长度数组info[]的元素个数
 
    u1 info[]   //数组info[]中含了组件的所有信息,依据各组件属性不同而各不相同
}

比如Applet.cap的十六进制数据是: 
0300090105c0c1c2c3c40085

第一个03是tag,然后是0009是size,说明info为9个字符,01标示了这是包中的第一个applet,05为该Applet的AID的长度,后面的c0c1c2c3c4即为applet的AID,后面的0085是该Applet的install_method_offset,即当前Applet中的install()在Method组件info[]中的偏移。

推荐的CAP组件安装顺序:

  1. COMPONENT_Header
  2. COMPONENT_Directory
  3. COMPONENT_Import
  4. COMPONENT_Applet
  5. COMPONENT_Class
  6. COMPONENT_Method
  7. COMPONENT_StaticField
  8. COMPONENT_Export
  9. COMPONENT_ConstantPool
  10. COMPONENT_ReferenceLocation
  11. COMPONENT_Descriptor (optional)

COMPONENT_Debug组件不需要下载到卡内。

作者:fish

转载:http://www.dreamingfish123.info/?p=818

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值