zoukankan      html  css  js  c++  java
  • 如何获取JavaCard栈信息

    继综合评估JavaCard虚拟机文章发布后,跟网友也在讨论获取栈的问题,今天也就此问题提出自己的分析方法,欢迎拍砖。

    JavaCard虚拟机的栈的实现结构,每个厂商的可能并不一致,有些可能是是将局部变量与栈帧(frame)分开,有两个不同的栈顶;有些可能是一个大的RAM区,局部变量与frame从两端开始向中间增加,直到两端数据在中间相会,则栈满。

    如下图所示:

    那我们如何得知每个帧的大小,以及每个局部变量存储几个字节呢?在图中我们分别以x、y来表示栈中Frame的尺寸与short类型局部变量的尺寸。为此我们可以设计一个函数来获取这些信息,我们设计几个函数,分别为只有0、1、2、3个参数的函数,进行递归调用,使用全局变量记录调用次数,得出每个函数调用调用深度,然后再解一个方程就可以获得以上信息了。为了方便后面的表述,我们假定手里拿到的卡的栈RAM的可使用RAM大小为tSize.

    具体的实现方式如下:

    没有参数的函数递归调用

        /**
         * 没有参数的递归调用,获取调用深度
         */
        public static void sgetJavaCardStack() {
            sCount1++;
            sgetJavaCardStack();
        }

    对应的字节码:

    P:0   7d 0 7         getstatic_s     sCount1 (S)
    P:3   4               sconst_1        
    P:4   41               sadd            
    P:5   81 0 7         putstatic_s     sCount1 (S)
    P:8   8d 0 8         invokestatic    sgetJavaCardStack; ()V
    P:b   7a               return  

    从字节码中可以看到该函数的确没有局部变量(参数与局部变量在JCA中都叫local变量)

    执行结果:

    cm>  /send 8000000000
     => 80 00 00 00 00                                     .....
     (335762 usec)
     <= 00 2B 90 00                                        .+..
    Status: No Error

    那我们可以得出一个方程式1:

    0x2B*x = tSize

    有一个参数的函数递归调用:

        /**
         * 有一个参数的递归调用,获取调用深度
         */
        public static void sgetJavaCardStack(short s0) {
           sCount1++;
           sgetJavaCardStack(s0);
        }

    对应字节码:

    P:0   7d 0 7         getstatic_s     sCount1 (S)
    P:3   4               sconst_1        
    P:4   41               sadd            
    P:5   81 0 7         putstatic_s     sCount1 (S)
    P:8   1c               sload_0          s0 (S)
    P:9   8d 0 b         invokestatic    sgetJavaCardStack; (S)V
    P:c   7a               return     

    执行结果:

    cm>  /send 8001000000
     => 80 01 00 00 00                                     .....
     (279340 usec)
     <= 00 23 90 00                                        .#..
    Status: No Error

    得出方程式2:

    0x23*x + 0x23*(y*1) = tSize – n; (n<x+y) 

    有两个参数的递归调用   

     /**
         * 有二个参数的递归调用,获取调用深度
         */
        public static void sgetJavaCardStack(short s0, short s1) {
           sCount1++;
           sgetJavaCardStack(s0, s1);
        }

    对应的字节码

    P:0   7d 0 7         getstatic_s     sCount1 (S)
    P:3   4               sconst_1        
    P:4   41               sadd            
    P:5   81 0 7         putstatic_s     sCount1 (S)
    P:8   1c               sload_0          s0 (S)
    P:9   1d               sload_1          s1 (S)
    P:a   8d 0 c         invokestatic    sgetJavaCardStack; (SS)V
    P:d   7a               return      

     执行结果

    cm>  /send 8002000000
     => 80 02 00 00 00                                     .....
     (230688 usec)
     <= 00 1D 90 00                                        ....
    Status: No Error

    得出方程式3:

    0x1D*x +0x1D*(y*2) = tSize – n; (n<x+2y)  

    有三个参数的递归调用   

     /**
         * 有三个参数的递归调用,获取调用深度
         */
        public static void sgetJavaCardStack(short s0, short s1, short s2) {
           sCount1++;
           sgetJavaCardStack(s0, s1, s2);
        }

    对应的字节码

    P:0   7d 0 7         getstatic_s     sCount1 (S)
    P:3   4               sconst_1        
    P:4   41               sadd            
    P:5   81 0 7         putstatic_s     sCount1 (S)
    P:8   1c               sload_0          s0 (S)
    P:9   1d               sload_1          s1 (S)
    P:a   1e               sload_2          s2 (S)
    P:b   8d 0 d         invokestatic    sgetJavaCardStack; (SSS)V
    P:e   7a               return   

     执行结果

    cm>  /send 8003000000
     => 80 03 00 00 00                                     .....
     (197498 usec)
     <= 00 18 90 00                                        ....
    Status: No Error

    得出方程式4:

    0x18*x +0x18*(y*3) = tSize – n; (n<x+3y) 

    在解方式的时候,可以把n忽略,通过以上几个方式式解出的结果可能是个小数,但不影响,因为这本身就是一个不严谨的分析方式。 

    通过计算得到的结果为:

    X = 8;

    Y = 2;

    tSize = 344;

    即每一帧使用8字节,每个局部变量存储为2字节。

    这里的tSize就是你调用函数时的可用栈空间,但不是虚拟机的全部栈空间,因为API以及JCRE的实现还会占用一部分。

     

    如果感兴趣的话,还可以分析一下其它数据类型的栈使用使用情况,如引用类型,通过实例函数实现等。事实上除了int类型外,其它类型在栈上都使用两个字节存储。关于栈的结构,本博客在深入JavaCard虚拟机系列中还会进一步探讨。

    以下是本文分析使用的完整源代码:

      1 package GetJavaCardStackInfoPkg;
      2 
      3 import javacard.framework.APDU;
      4 import javacard.framework.ISO7816;
      5 import javacard.framework.Applet;
      6 import javacard.framework.ISOException;
      7 import javacard.framework.Util;
      8 
      9 /**
     10  * @author SCPlatform@outlook.com
     11  */
     12 public class GetJavaCardStackInfoApp extends Applet {
     13     static short sCount1 = 0;
     14     public static void install(byte[] bArray, short bOffset, byte bLength) {
     15         new GetJavaCardStackInfoApp().register(bArray, (short) (bOffset + 1),
     16                 bArray[bOffset]);
     17     }
     18 
     19     public void process(APDU apdu) {
     20         if (selectingApplet()) {
     21             return;
     22         }
     23         byte[] buffer = apdu.getBuffer();
     24         sCount1 = 0;
     25         switch (buffer[ISO7816.OFFSET_INS]) {
     26         case (byte) 0x00:
     27             sCount1 = (short) 0;
     28             try {
     29                 sgetJavaCardStack();
     30             } catch (Exception e) {
     31             } finally {
     32                 apdu.setOutgoingAndSend((short) 0, Util.setShort(buffer, (short) 0, sCount1));
     33             }
     34             break;
     35 
     36         case (byte) 0x01:
     37             sCount1 = (short) 0;
     38             try {
     39                 sgetJavaCardStack((short) 0);
     40             } catch (Exception e) {
     41             } finally {
     42                 apdu.setOutgoingAndSend((short) 0, Util.setShort(buffer, (short) 0, sCount1));
     43             }
     44             break;
     45 
     46         case (byte) 0x02:
     47             sCount1 = (short) 0;
     48             try {
     49                 sgetJavaCardStack((short) 0, (short) 0);
     50             } catch (Exception e) {
     51             } finally {
     52                 apdu.setOutgoingAndSend((short) 0, Util.setShort(buffer, (short) 0, sCount1));
     53             }
     54             break;
     55         case (byte) 0x03:
     56             sCount1 = (short) 0;
     57             try {
     58                 sgetJavaCardStack((short) 0, (short) 0, (short) 0);
     59             } catch (Exception e) {
     60             } finally {
     61                 apdu.setOutgoingAndSend((short) 0, Util.setShort(buffer, (short) 0, sCount1));
     62             }
     63             break;
     64         case (byte) 0x04:
     65             sCount1 = (short) 0;
     66             try {
     67                 sgetJavaCardStack((short) 0, (short) 0, (short) 0, (short) 0);
     68             } catch (Exception e) {
     69             } finally {
     70                 apdu.setOutgoingAndSend((short) 0, Util.setShort(buffer, (short) 0, sCount1));
     71             }
     72             break;
     73         default:
     74             ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
     75         }
     76     }
     77 
     78     /**
     79      * 没有参数的递归调用,获取调用深度
     80      */
     81     public static void sgetJavaCardStack() {
     82         sCount1++;
     83         sgetJavaCardStack();
     84     }
     85 
     86     /**
     87      * 有一个参数的递归调用,获取调用深度
     88      */
     89     public static void sgetJavaCardStack(short s0) {
     90         sCount1++;
     91         sgetJavaCardStack(s0);
     92     }
     93 
     94     /**
     95      * 有二个参数的递归调用,获取调用深度
     96      */
     97     public static void sgetJavaCardStack(short s0, short s1) {
     98         sCount1++;
     99         sgetJavaCardStack(s0, s1);
    100     }
    101 
    102     /**
    103      * 有三个参数的递归调用,获取调用深度
    104      */
    105     public static void sgetJavaCardStack(short s0, short s1, short s2) {
    106         sCount1++;
    107         sgetJavaCardStack(s0, s1, s2);
    108     }
    109 
    110     /**
    111      * 有四个参数的递归调用,获取调用深度
    112      */
    113     public static void sgetJavaCardStack(short s0, short s1, short s2, short s3) {
    114         sCount1++;
    115         sgetJavaCardStack(s0, s1, s2, s3);
    116     } 
    118 }

    作者:SCPlatform
    Email:SCPlatform@outlook.com
    本文旨在学习、交流使用,任何对文章内容的出版、印刷,对文章中提到的技术的商业使用时,请注意可能存在的法律风险。

  • 相关阅读:
    Binary Tree Inorder Traversal
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Majority Element
    Excel Sheet Column Number
    Reverse Bits
    Happy Number
    House Robber
    Remove Linked List Elements
    Contains Duplicate
  • 原文地址:https://www.cnblogs.com/SCPlatform/p/5088496.html
Copyright © 2011-2022 走看看