Java中如何修改Jar中的内容[转载]

1.这篇文章讲了一种曲折的方式来修改jar中的字节码. 比较有趣,可以用来参考.原文链接:http://blog.csdn.net/jiangwei0910410003/article/details/45600385

如果原文链接可达推荐跳往原文链接阅读,有更好的界面布局.

2. 对于直接修改字节码,可以看我之前发表的文章: http://ieroot.com/2014/02/11/1435.html

############### Java中如何修改Jar中的内容 [转载]############

一、摘要

好长时间没写blog了,之前换了一家公司。表示工作更有战斗力了,可惜就是没时间写文章了。在这段时间其实是遇到很多问题的,只是都是记录下来,并没有花时间去研究解决。但是这周遇到这个问题没办法让我继续前进了。必须记录一下。以被后人使用。不多说了,进入主题。

二、前提

1、对于GA的了解(自行google)

2、对CampaignTrackingReceiver类的了解,他是当从GP上下载并且安装完成一个app的时候,发送一个广播,会在Intent中携带一些数据,一般是Refer值,这里可以区分从哪里下载的,具体简单的例子:A应用是我需要发布到GP上的应用,但是我们可能会在各个渠道上推广A,所以我们可能需要加上渠道号进行统计,所以这时候需要在A应用添加CampaignTrackingReceiver广播接收器,然后处理接收到的广播中的Intent的内容,解析出具体的渠道号,进行上报即可。所以说GP发送这个广播还是很奇特的,他发送了这个广播,然后等我们安装A并且运行了之后就可以接收到这个广播,等于这个广播发出去了,他会等待有一个接收器接受他。

3、本文中需要用到的工具下载地址:http://download.csdn.net/detail/jiangwei0910410003/8679153,下载完之后,首先要看一下txt文档中的说明。

三、问题描述

工程中接入了GA统计(Google提供的一种app统计功能的SDK),但是我们自己可能需要统计app从GP上下载的统计(这里一般是注册一个CampaignTrackingReceiver的广播),但是有问题就是GA的SDK中已经包含了CampaignTrackingReceiver类了,当时在弄的时候进入到了一个误区:就是认为如果app中想接收到这个广播的话。广播接收器的包名必须是:com.google.analytics.tracking.android,类名:CampaignTrackingReceiver,类似于下面的注册代码:

[html] view plaincopy

  1. <receiver  
  2.     android:name=“com.google.analytics.tracking.android.CampaignTrackingReceiver”  
  3.     android:exported=“true”>  
  4.     <intent-filter>  
  5.         <action android:name=“com.android.vending.INSTALL_REFERRER” />  
  6.     </intent-filter>  
  7. </receiver>  

但是之后发现不需要这样的,只要包名一样即可,其实从Android中发送广播的机制就可以知道。类名没有关系的,但是当时这个东西没办法测试的(需要发布一个测试app到GP上,时间上也是不允许的,只能听前辈的)。最后也是自己发布了一个测试app测试了才知道,不需要类名一样的,这个也算是一种收获,那么既然类名不一样的话,这里就没有问题了。就不会和GA中的类重复了。但是我在没有解释这个误区前用了另外的一种方法解决了这个问题。既然GA中有这个广播接收类,我们不能定义的话,可以在它的SDK中的这个广播类中插入一段代码:发送一个广播,把Intent中的数据带出来即可。思路有了,下面来看一下具体操作:

四、技术介绍

下面讲述的内容是基于上面的误区没有被解释的情况下说的,而且侧重点也不是解释误区。而是如何修改Jar中内容

首先说一下这个过程中的三个角色:jar,dex,smali

四个工具:dx.bat,dex2jar.bat,baksmali.jar,smali.jar

关系图如下:

我们这里需要修改jar中的代码,

首先说明一下,关于修改jar中的代码其实有很多方法的:

1、直接用压缩包工具打开jar中的class文件进行修改(除非你对指令集很熟悉,反正我是不愿意尝试)

2、使用jd-gui工具直接打开jar,进行修改(这个虽然能看懂代码,但是有一个问题就是如果代码被混淆了,那个难度还不如第一种方法了,所以也没有尝试)

好吧,那么第三种方法就是修改smali文件,这个文件的好处在于:指令简单,而且如果混淆了,也是没有关系的。关于smail的指令说明,可以自行google一下。很简单这里就不做解释了。

那么问题来了,如何将jar变成smali呢?这里没有发现他们两之间的直接转化工具,所以就曲线救国的方式做了。

首先将jar==>dex==>smali

然后修改smail中的内容

修改完之后会变成jar

smail==>dex==>jar

相当于dex是中转站了。

五、项目演示

技术实现说明完之后,下面来看一下Demo:

ReceiverLib工程

1、BtnReceiver.java

[java] view plaincopy

  1. package com.example.receiverdemo;  
  2.   
  3. import android.content.BroadcastReceiver;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.util.Log;  
  7.   
  8. public class BtnReceiver extends BroadcastReceiver{  
  9.   
  10.     private String action = “demo.action.myreceiver”;  
  11.       
  12.     @Override  
  13.     public void onReceive(Context context, Intent intent) {  
  14.         Log.i(“demo”“action:”+intent.getAction());  
  15.     }  
  16.   
  17. }  

接收到广播然后打印log一下

2、MyReceiver.java

[java] view plaincopy

  1. package com.example.receiverdemo;  
  2.   
  3. import android.content.BroadcastReceiver;  
  4. import android.content.Context;  
  5. import android.content.Intent;  
  6. import android.util.Log;  
  7.   
  8. public class MyReceiver extends BroadcastReceiver{  
  9.   
  10.     private String action = “demo.action.myreceiver”;  
  11.       
  12.     @Override  
  13.     public void onReceive(Context context, Intent intent) {  
  14.         Log.i(“demo”“action:”+intent.getAction());  
  15.     }  
  16.   
  17. }  

3、Utils.java

[java] view plaincopy

  1. package com.example.receiverdemo;  
  2.   
  3. import android.content.Context;  
  4. import android.content.Intent;  
  5.   
  6. public class Utils {  
  7.       
  8.     public static void sendBroadcast(Context context,String action){  
  9.         Intent intent = new Intent();  
  10.         intent.setAction(action);  
  11.         context.sendBroadcast(intent);  
  12.     }  
  13.   
  14. }  

说明:BtnReceiver是点击Button之后发送的一个模拟广播,相当于上面需要改的CampaignTrackingReceiver类,MyReceiver是我们需要自己添加的广播接收器。

项目下载:http://download.csdn.net/detail/jiangwei0910410003/8679113

ReceiverDemo工程(需要导入ReceiverLib导出的jar)

[java] view plaincopy

  1. package com.example.receiverdemo;  
  2.   
  3. import android.os.Bundle;  
  4. import android.support.v7.app.ActionBarActivity;  
  5. import android.view.View;  
  6. import android.view.View.OnClickListener;  
  7.   
  8. public class MainActivity extends ActionBarActivity {  
  9.       
  10.     private String action = “demo.action.btnreceiver”;  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.         findViewById(R.id.btn).setOnClickListener(new OnClickListener(){  
  17.             @Override  
  18.             public void onClick(View v) {  
  19.                 Utils.sendBroadcast(MainActivity.this, action);  
  20.             }});  
  21.     }  
  22. }  

模拟发送一个广播

项目下载:http://download.csdn.net/detail/jiangwei0910410003/8679123

效果:

点击Button之后,发送了广播,BtnReceiver也接收到了。

那么下面就开始在BtnReceiver.java中插入代码,发送一个MyReceiver

首先使用dx命令,将我们上面ReceiverLib导出的jar变成dex文件:

dx命令的使用方式:dx –dex –output C:\receiver.dex receiver.jar

然后在将receiver.dex转化成smali:

baksmali.jar的使用方式:java -jar baksmali-2.0.5.jar -o c:\classout/ c:\receiver.dex 

我们可以查看smali文件,我们重点看BtnReceiver.smali文件,因为我们要在这里插入代码:

[java] view plaincopy

  1. .class public Lcom/example/receiverdemo/BtnReceiver;  
  2. .super Landroid/content/BroadcastReceiver;  
  3. .source “BtnReceiver.java”  
  4.   
  5.   
  6. # direct methods  
  7. .method public constructor <init>()V  
  8.     .registers 1  
  9.   
  10.     .prologue  
  11.     .line 8  
  12.     invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V  
  13.   
  14.     returnvoid  
  15. .end method  
  16.   
  17.   
  18. # virtual methods  
  19. .method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V  
  20.     .registers 7  
  21.     .param p1, “context”    # Landroid/content/Context;  
  22.     .param p2, “intent”    # Landroid/content/Intent;  
  23.   
  24.     .prologue  
  25.     .line 12  
  26.     invoke-virtual {p2}, Landroid/content/Intent;->getAction()Ljava/lang/String;  
  27.   
  28.     move-result-object v0  
  29.   
  30.     .line 13  
  31.     .local v0, “action”:Ljava/lang/String;  
  32.     const-string v1, “demo”  
  33.   
  34.     new-instance v2, Ljava/lang/StringBuilder;  
  35.   
  36.     const-string v3, “action:”  
  37.   
  38.     invoke-direct {v2, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V  
  39.   
  40.     invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;  
  41.   
  42.     move-result-object v2  
  43.   
  44.     invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;  
  45.   
  46.     move-result-object v2  
  47.   
  48.     invoke-static {v1, v2}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I  
  49.   
  50.     const-string v4, “demo.action.myreceiver”  
  51.   
  52.     invoke-static {p1, v4}, Lcom/example/receiverdemo/Utils;->sendBroadcast(Landroid/content/Context;Ljava/lang/String;)V  
  53.   
  54.     const-string v5, “sendbroadcast”  
  55.   
  56.     invoke-static {v1, v5}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I  
  57.   
  58.     .line 14  
  59.     returnvoid  
  60. .end method  

关于smali指令网上自行搜索,很简单的,我们需要插入一行代码就是:

Utils.sendBroadcast方法:

这个过程中没有难度的,就不做解释了

下面我们就需要还原成jar了:

使用smali.jar工具将samli变成dex

用法:java -jar smali-2.0.5.jar c:\classout/ -o c:\receiver.dex

然后使用dex2jar命令将dex变成jar

用法:dex2jar receiver.dex

这时候我们就产生了修改之后的jar,我们将这个jar替换ReceiverDemo中的jar,然后运行结果:

成功显示了。我们的MyReceiver接收到了BtnReceiver中发送出来的广播了。

问题:

在这个过程中可能使用一些命令的时候会出现问题:

这个是class版本号不对,需要修改一下Eclipse中的Java编译器版本在编译导出jar就可以了。

其他的问题我这里没有遇到了。如果在开发的过程中遇到问题,记得回复留言,我尽量解答一下~~

六、总结

1、关于上面说到的问题,就是GA包中的类重复的问题,再次在说明一下,那个是个误区,我们自定一个Receiver也是可以的,不需要类名必须是:CampaignTrackingReceiver,所以有同学如果用到这个类的话,一定要记得,不要在入这个误区了。

2、关于修改jar中的内容,其实用途还是很多的,但是不是正规的解决方法,这个有点偏向于破解的方向了,这个是不符合开发原则的,这里说明一下就是为了多一条解决问题的办法,而且对逆向领域的一种知识补充,这个内容对逆向领域用处还是很大的。

3、关于这种方式使用与所有Java编写的程序,这里可能偏向于Android移动端了,但是如果JavaWeb中遇到这样的问题,也是可以使用这种方式解决的,不仅仅局限于Android方向。

Compile java projects using javac command

I downloaded a java project from github today, which seems an eclipse project. But do not want to import into eclipse to compile and pack it because it will let my workspace mass. So I struggled to compile it with java and javac commands on terminal.

The file tree looked as this :

$ tree
.
├── README.md
├── jars
│   ├── commons-codec-1.6.jar
│   ├── commons-logging-1.1.3.jar
│   ├── fluent-hc-4.3.3.jar
│   ├── httpclient-4.3.3.jar
│   ├── httpclient-cache-4.3.3.jar
│   ├── httpcore-4.3.2.jar
│   ├── httpmime-4.3.3.jar
│   ├── jsoup-1.7.2.jar
│   └── mysql-connector-java-5.1.22-bin.jar
├── pic
│   ├── pic.jpg
│   ├── pic2.fla
│   ├── pic2.jpg
│   ├── pic3.jpg
│   └── pic4.jpg
└── src
└── com
└── td1madao
├── bean
│   ├── JsoupBean.java
│   ├── KeyWord.java
│   └── UrlScoreBean.java
├── db
│   └── DBOperator.java
├── filters
│   ├── FiltTag.java
│   ├── URLTool.java
│   └── fetchUrlUtil.java
├── global
│   ├── GlobalVar.java
│   └── TaskQueue.java
├── gui
│   ├── MyFrame.java
│   └── NoGui.java
├── htmlGet
│   └── GetHttp.java
├── math
│   ├── ListProcess.java
│   └── WordDensity.java
├── stringUtil
│   └── MyStringUtil.java
├── threads
│   ├── DaemonThread.java
│   ├── MEngine.java
│   ├── MSpider.java
│   └── SpiderUtil.java
└── useEngine
├── CopyOfFetchSouSou.java
├── Fetch360.java
├── FetchBaidu.java
├── FetchGoogle.java
└── FetchSouSou.java
15 directories, 39 files

To compile this project , I used the command as shown below:

 

javac `find . -type f -name "[!^Copy]*.java"` -encoding GBK -cp .:jars/* -d classes/
`find . -type f -name "[!^Copy]*.java"`

list all the java files in the sub-directories from the current.

-encoding GBK

switch specifics source code encoding.

-cp .:jars/*

specifics the classpath, : is used to append paths together.

-d classes/

specifics which directory to generate the target class files.

After the command, the file tree was like this:

$ tree
.
├── README.md
├── classes
│   └── com
│       └── td1madao
│           ├── bean
│           │   ├── JsoupBean.class
│           │   ├── KeyWord.class
│           │   └── UrlScoreBean.class
│           ├── db
│           │   └── DBOperator.class
│           ├── filters
│           │   ├── FiltTag.class
│           │   ├── URLTool.class
│           │   └── fetchUrlUtil.class
│           ├── global
│           │   ├── GlobalVar.class
│           │   └── TaskQueue.class
│           ├── gui
│           │   ├── MyFrame$1.class
│           │   ├── MyFrame$2.class
│           │   ├── MyFrame$3.class
│           │   ├── MyFrame$4.class
│           │   ├── MyFrame$5.class
│           │   ├── MyFrame$6.class
│           │   ├── MyFrame.class
│           │   └── NoGui.class
│           ├── htmlGet
│           │   └── GetHttp.class
│           ├── math
│           │   ├── ListProcess.class
│           │   └── WordDensity.class
│           ├── stringUtil
│           │   └── MyStringUtil.class
│           ├── threads
│           │   ├── DaemonThread.class
│           │   ├── MEngine.class
│           │   ├── MSpider.class
│           │   └── SpiderUtil.class
│           └── useEngine
│               ├── Fetch360.class
│               ├── FetchBaidu.class
│               ├── FetchGoogle.class
│               └── FetchSouSou.class
├── jars
│   ├── commons-codec-1.6.jar
│   ├── commons-logging-1.1.3.jar
│   ├── fluent-hc-4.3.3.jar
│   ├── httpclient-4.3.3.jar
│   ├── httpclient-cache-4.3.3.jar
│   ├── httpcore-4.3.2.jar
│   ├── httpmime-4.3.3.jar
│   ├── jsoup-1.7.2.jar
│   └── mysql-connector-java-5.1.22-bin.jar
├── pic
│   ├── pic.jpg
│   ├── pic2.fla
│   ├── pic2.jpg
│   ├── pic3.jpg
│   └── pic4.jpg
└── src
    └── com
        └── td1madao
            ├── bean
            │   ├── JsoupBean.java
            │   ├── KeyWord.java
            │   └── UrlScoreBean.java
            ├── db
            │   └── DBOperator.java
            ├── filters
            │   ├── FiltTag.java
            │   ├── URLTool.java
            │   └── fetchUrlUtil.java
            ├── global
            │   ├── GlobalVar.java
            │   └── TaskQueue.java
            ├── gui
            │   ├── MyFrame.java
            │   └── NoGui.java
            ├── htmlGet
            │   └── GetHttp.java
            ├── math
            │   ├── ListProcess.java
            │   └── WordDensity.java
            ├── stringUtil
            │   └── MyStringUtil.java
            ├── threads
            │   ├── DaemonThread.java
            │   ├── MEngine.java
            │   ├── MSpider.java
            │   └── SpiderUtil.java
            └── useEngine
                ├── CopyOfFetchSouSou.java
                ├── Fetch360.java
                ├── FetchBaidu.java
                ├── FetchGoogle.java
                └── FetchSouSou.java

28 directories, 68 files


Now, we can execute the compiled project already, with this command:


java -cp classes com.td1madao.gui.MyFrame

Now I want to pack these class files together to be a jar file, so that, it will look good and easy to move.

with these commands:


cd classes;
jar cvf mspider *

To run with this command:


java -cp mspider.jar com.td1madao.gui.MyFrame

This all.

Java与数字签名

本文中介绍了Java

 

数字签名的基本知识, 发布与验证过程, 数字证书的构成,各个部分的含义.

使用keytool工具生成,导入,导出数字证书的命令, 制作keystore的过程等.

使用jarsigner对jar文件进行签名的命令,过程.

使用信任签名的证书签名后的applet可以访问读写本地文件.

 

原文链接: http://www.blogjava.net/sylilzy/articles/javaadndigtalsign.html

 

sylilzy@163.com
版权所有,转载请注明出处

关键字:Java 数字签名 PKI Keystore 数字证书 keytool jarsigner

摘要:本文介绍了数字签名的相关基础知识,并介绍了如何用java实现数字签名。

字签名作为一种电子身份的认证的手段,被普遍用于网上银行,安全网络通信等领域.数字签名是电子签名的一种特定形式.本文不对数字签名的原理作介绍,只对相关概念作一些简单的介绍,详细讲解了在java中如何对jar文件进行数字签名.

数字签名的相关概念

实际上数字签名又称作基于PKI的电子签名, PKI的核心机构是电子认证服务提供者,即通称的认证机构CA,PKI签名的核心元素是由CA签发的数字证书,数字证书就如同日常生活中的身份证一样,用来标识网上实体的身份,CA就是对网上实体进行认证的第三方机构.数字证书就是CA机构对网上实体进行认证而产生的电子证书,它是数据签名的基础技术保障.CA机构对电子证书的有效性,有效期等提供查询服务.数字证书所包含公钥用来对使用对应的私钥加密的数据信息进行验证.

数字签名实现的具体原理是:
1、 将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证,只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。(详见参考资料的”公钥密码技术原理”章节)
2、 将该报文摘要值用发送者的私人密钥加密,然后连同原报文和数字证书(包含公钥)一起发送给接收者而产生的报文即称数字签名。
3、接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较,如相等则说明报文确实来自所称的发送者。
4、同时通过证书颁发机构CA确认证书的有效性即可确认发送的真实身份。

数字证书的技术实现:
数字证书是公钥的载体,是PKI的核心元素.数字证书符合X.509标准,现行的PIK机制一般为又证书,即一个实体一般有两个证书,两个密码对,一个用于电子签名,一个用于加密通信.按照X.509标准,一个标准和数字证书的格式为:

CA《A》=CA{V,SN,AI,CA,UCA,A,UA,Ap,Ta}

它将包含证书颁发机构和标识及用户的标识,证书ID,有效期等信息(详见参考资料),另外还包含CA对此证书内容的进行了数字签名,以验证此证书的有效性.在验证一个数字证书的过程中,对数字证书的数字签名的验证将递归进行,只到找到双方共同可信任的CA根证书为止.

如何获取数字证书

数字证书可向专门的CA机构申请,有免费的数字证书和付费的数字证书.比如:中国数字认证网(http://www.ca365.com)、广东省电子商务认证中心(http://www.cnca.net/)就可申请到有效期为一年的免费数字证书.注意申请的证书是以该CA的证书作为申请的个人证书的根证书,所以如果想要申请的证书有效,需要下载并安装相应CA的根证书.另外,其它一些工具也可生成个人使用的数字证书,如微软的makecert(下载地址http://www.microsoft.com/downloads/details.aspx?familyid=2b742795-d0f0-4a66-b27f-22a95fcd3425&displaylang=en)),JDK中包含的keytool工具(以下会详细介绍如何使用)都可生成没有经过认证的数字证书.

Java如何实现数字签名

JDK有部分工具和API提供了对数字签名的支持:keytool,jarsigner,policytool等.

KeyTool工具可生成,导入,导出数字证书,支持的证书的格式为当前流行的

生成证书:keytool -genkey -alias mykey -keystore mystore

导入证书:keytool -import -alias abc -file ABCCA.cer -keystore mystore

导出证书: keytool -export -alias mykey -file MJ.cer -keystore mystore

对jar文件进行签名使用的工具是jarsigner:

格式如下:jarsigner -keystore keystoreFile jarfile alias

例如:jarsigner -keystore sylilzyKeystore.dat test.jar sylilzy

验证一个jar文件如下:

jarsigner -verify jarfile

以下步骤演示了一个完整的由获取数字证书到签名jar文件,然后访问该jar文件时显示签名信息的全过程:

上面提到,数字证书可由以下方式生成,第一,去http://www.ca365.com申请一个免费的数字证书,下载后为test.der

也可用keytool -genkey -alias mykey -keystore mystore生成,运行此命令后,提示相关信息,并填写完毕,如下:

E:\temp>keytool -genkey -alias mykey -keystore mystore
输入keystore密码: 111111
您的名字与姓氏是什么?
[Unknown]: shi
您的组织单位名称是什么?
[Unknown]: eshore
您的组织名称是什么?
[Unknown]: de
您所在的城市或区域名称是什么?
[Unknown]: gz
您所在的州或省份名称是什么?
[Unknown]: gd
该单位的两字母国家代码是什么
[Unknown]: cn
CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn 正确吗?
[否]: y
输入<mykey>的主密码
(如果和 keystore 密码相同,按回车):

到此,我们则生成了一个名为mystore的keystore文件,该文件中保存有别名为mykey的数字证书.输入以下命令即可查看此数字证书:

E:\temp>keytool -list -alias mykey -keystore mystore
输入keystore密码: 111111
mykey, 2006-7-5, keyEntry,
认证指纹 (MD5): A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17

或者带上-v参数显示详细信息

E:\temp>keytool -list -alias mykey -keystore mystore -v
输入keystore密码: 111111
别名名称: mykey
创建日期: 2006-7-5
输入类型:KeyEntry
认证链长度: 1
认证 [1]:
Owner: CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn
发照者: CN=shi, OU=eshore, O=de, L=gz, ST=gd, C=cn
序号: 44ab3fb8
有效期间: Wed Jul 05 12:27:36 CST 2006 至: Tue Oct 03 12:27:36 CST 2006
认证指纹:
MD5: A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17
SHA1: AC:8D:AA:9D:A7:62:48:70:ED:F4:28:4C:DC:DE:56:CE:41:FE:52:C9

以上为创建的一个证书,我们可以将它从keystore文件中导出:

E:\temp>keytool -export -keystore mystore -alias mykey -file my.cer
输入keystore密码: 111111
保存在文件中的认证 <my.cer>

我们也可将前面从网上申请的电子证书导入keystore文件:

E:\temp>keytool -import -alias sily -file test.der -keystore mystore
输入keystore密码: 111111
Owner: CN=施祖阳, OU=develop, O=eshore, L=广州, ST=广东, C=CN
发照者: CN=CA365 Free Root Certificate, O=CA365, L=Beijing, ST=Beijing, C=CN
序号: 653e1a63bb003fb3
有效期间: Tue Jul 04 12:02:25 CST 2006 至: Wed Jul 04 12:02:25 CST 2007
认证指纹:
MD5: 4A:AA:63:2A:8A:E2:8D:76:4B:2B:73:E9:F3:03:CD:6F
SHA1: 02:B3:9E:D0:7E:BB:9E:C4:B3:B0:79:19:FA:89:B6:93:DB:0F:4A:88
信任这个认证? [否]: y
认证已添加至keystore中

现在查看mystore中已经存了两个证书:

E:\temp>keytool -list -keystore mystore
输入keystore密码: 111111
Keystore 类型: jks
Keystore 提供者: SUN
您的 keystore 包含 2 输入
sily, 2006-7-5, trustedCertEntry,
认证指纹 (MD5): 4A:AA:63:2A:8A:E2:8D:76:4B:2B:73:E9:F3:03:CD:6F
mykey, 2006-7-5, keyEntry,
认证指纹 (MD5): A1:A9:A7:C6:D8:E5:E5:20:EA:80:59:AF:C2:65:B4:17

现在,我们开始利用前面生成的数字证书给jar文件签名.由于applet在浏览器中运行时的权限是受限的,不能对本地文件进行读写,但是如果applet所在的jar文件如果是经过数字签名,并且用户信任该签名,那此applet则可对本地文件进行读写,下面给出一个写本地文件的applet:

 

 * Created on 2004-7-16
package   com.applet;

import   java.applet.Applet;

public   class   TestSecurity   extends   Applet   {
/**
*
*/
private   static   final   long   serialVersionUID   =   1L;

public   TestSecurity()   {
System. out .println( “this is good! ” );
}

public   void   init()   {
JButton   button   =   new   JButton( “Create a file” );
button.addActionListener( new   ActionListener()   {
public   void   actionPerformed(ActionEvent   evt)   {
File   file   =   new   File( “c:\\a.txt” );
try   {
file.createNewFile();
JOptionPane. showMessageDialog ( null ,   ” 成功创建文件c:\\a.txt” ,   “消息” ,
JOptionPane. INFORMATION_MESSAGE );
}   catch   (Exception   ex)   {
JOptionPane. showMessageDialog ( null ,  ex.getMessage(),   “错误” ,   JOptionPane. ERROR_MESSAGE );
}
}
});
add(button);
}
}

 

将此文件编译后生成在com\applet生成两个class文件,用jar打包:

E:\sylilzy\documents\project\tjava\classes>jar -cvf test.jar com
标明清单(manifest)
增加:com/(读入= 0) (写出= 0)(存储了 0%)

会发现在当前目录下会生成一个”test.jar”文件,将此文件copy到与mystore同一个目录,准备对该文件进行电子签名.

E:\temp>jarsigner -keystore mystore test.jar mykey
输入密钥库的口令短语: 111111
警告: 签名者证书将在六个月内过期。

则test.jar已经被签名,编码一个简单的html文件对其进行访问,html如下:

						
Created with Colorer-take5 Library. Type 'html'

<html><head><metahttp-equiv="Content-Type"content="text/html; charset=GB2312"><title>
			HTML Test Page
		</title></head><body>
		test.Applet1 will appear below in a Java enabled browser.<br><appletcodebase="."code="com.applet.TestSecurity"name="TestApplet"width="400"height="300"hspace="0"vspace="0"align="middle"archive="test.jar"></applet></body></html>

 

将以上html文件与test.jar文件放在同一目录,用IE打开,则可看到IE弹出安全警告: The application’s digital signature is invalid.Do you want to run the application?

用户可查看test.jar的签名信息,如果选择取消息,然后点击create a file 按钮,则提示:access denied(java.io.FilePermission c:\a.txt write)

如果在IE弹出安全警告选择”始终信任此发行者的内容”,然后点击运行,再点击create a file 按钮,则提示:成功创建文件c:\a.txt

上面给test.jar签名的数字证书是未经验证的,现在我们使用从网上申请的经过验证的数字证书给test.jar签名,看会出现什么结果:

E:\temp>jarsigner -keystore mystore test.jar sily
输入密钥库的口令短语: 111111
jarsigner: 找不到 sily 的证书链。sily 必须引用包含专用密钥和相应的公共密钥证书链的有效密钥库密钥条目。

这是因为sily的证书链不存在导致的,我们需要导入sily的证书链才可形成完整的sily的证书链,可以通过keytool -certreq生成证书链的PKCS#10格式的请求,然后再导入请求的PKCS#7格式的回复即可,由于名为sily的key是从cer文件导入的,它在keystore中是以trusted certificate entries类型存储的,没有私钥,所以不能生成证书链的请求.我们可以将前面名为mykey的key导出证书请求,或者导出mykey的证书,然后将此证书安装至”受信任的根证书颁发机构”,然后访问用此证书签名过的文件,则IE将不再弹出安全警告窗口.


 

公告

参考资料:
http://www.qqread.com/net-saft/z532114081.html 电子签名的技术实现
http://www.qqread.com/java/w292768600.html JAVA对数字证书的常用操作
http://java.sun.com/j2se/1.5.0/docs/index.html JDK 5.0 Documentation

 

 

作者简介

施祖阳,网名sylilzy,1979年生。
2002年起从事软件开发工作,主要研究JAVA、Linux及相关技术。
你可通过sylilzy@163.com与作者联系。

JAVA对数字证书的常用操作

原文链接:http://www.qqread.com/java/w292768600.html
本文中介绍了使用Java对数字证书的各种操作.
包括读取证书的各项详细,对新的证书签名,验证证书是否过期,签名是否正确等信息.

一需要包含的包

import java.security.*;

import java.io.*;

import java.util.*;

import java.security.*;

import java.security.cert.*;

import sun.security.x509.*

import java.security.cert.Certificate;

import java.security.cert.CertificateFactory;

二 从文件中读取证书

用keytool将.keystore中的证书写入文件中,然后从该文件中读取证书信息

CertificateFactory cf=CertificateFactory.getInstance(“X.509”);

FileInputStream in=new FileInputStream(“out.csr”);

Certificate c=cf.generateCertificate(in); String s=c.toString();

三 从密钥库中直接读取证书

String pass=”123456″;

FileInputStream in=new FileInputStream(“.keystore”);

KeyStore ks=KeyStore.getInstance(“JKS”);

ks.load(in,pass.toCharArray());

java.security.cert.Certificate c=ks.getCertificate(alias);//alias为条目的别名

四 JAVA程序中显示证书指定信息

System.out.println(“输出证书信息:\n”+c.toString());

System.out.println(“版本号:”+t.getVersion());

System.out.println(“序列号:”+t.getSerialNumber().toString(16));

System.out.println(“主体名:”+t.getSubjectDN());

System.out.println(“签发者:”+t.getIssuerDN());

System.out.println(“有效期:”+t.getNotBefore());

System.out.println(“签名算法:”+t.getSigAlgName());

byte [] sig=t.getSignature();//签名值

PublicKey pk=t.getPublicKey();

byte [] pkenc=pk.getEncoded();

System.out.println(“公钥”);

for(int i=0;i<pkenc.length;i++)System.out.print(pkenc[i]+”,”);

五 JAVA程序列出密钥库所有条目

String pass=”123456″;

FileInputStream in=new FileInputStream(“.keystore”);

KeyStore ks=KeyStore.getInstance(“JKS”);

ks.load(in,pass.toCharArray());

Enumeration e=ks.aliases();

while(e.hasMoreElements())

java.security.cert.Certificate c=ks.getCertificate((String)e.nextElement());

六 JAVA程序修改密钥库口令

String oldpass=”123456″;

String newpass=”654321″;

FileInputStream in=new FileInputStream(“.keystore”);

KeyStore ks=KeyStore.getInstance(“JKS”);

ks.load(in,oldpass.toCharArray());

in.close();

FileOutputStream output=new FileOutputStream(“.keystore”);

ks.store(output,newpass.toCharArray());

output.close();

七 JAVA程序修改密钥库条目的口令及添加条目

FileInputStream in=new FileInputStream(“.keystore”);

KeyStore ks=KeyStore.getInstance(“JKS”);

ks.load(in,storepass.toCharArray());

Certificate [] cchain=ks.getCertificate(alias);获取别名对应条目的证书链

PrivateKey pk=(PrivateKey)ks.getKey(alias,oldkeypass.toCharArray());获取别名对应条目的私钥

ks.setKeyEntry(alias,pk,newkeypass.toCharArray(),cchain);向密钥库中添加条目

第一个参数指定所添加条目的别名,假如使用已存在别名将覆盖已存在条目,使用新别名将增加一个新条目,第二个参数为条目的私钥,第三个为设置的新口令,第四个为该私钥的公钥的证书链

FileOutputStream output=new FileOutputStream(“another”);

ks.store(output,storepass.toCharArray())将keystore对象内容写入新文件

八 JAVA程序检验别名和删除条目

FileInputStream in=new FileInputStream(“.keystore”);

KeyStore ks=KeyStore.getInstance(“JKS”);

ks.load(in,storepass.toCharArray());

ks.containsAlias(“sage”);检验条目是否在密钥库中,存在返回true

ks.deleteEntry(“sage”);删除别名对应的条目

FileOutputStream output=new FileOutputStream(“.keystore”);

ks.store(output,storepass.toCharArray())将keystore对象内容写入文件,条目删除成功

九 JAVA程序签发数字证书

(1)从密钥库中读取CA的证书

FileInputStream in=new FileInputStream(“.keystore”);

KeyStore ks=KeyStore.getInstance(“JKS”);

ks.load(in,storepass.toCharArray());

java.security.cert.Certificate c1=ks.getCertificate(“caroot”);

(2)从密钥库中读取CA的私钥

PrivateKey caprk=(PrivateKey)ks.getKey(alias,cakeypass.toCharArray());

(3)从CA的证书中提取签发者的信息

byte[] encod1=c1.getEncoded(); 提取CA证书的编码

X509CertImpl cimp1=new X509CertImpl(encod1); 用该编码创建X509CertImpl类型对象

X509CertInfo cinfo1=(X509CertInfo)cimp1.get(X509CertImpl.NAME+”.”+X509CertImpl.INFO); 获取X509CertInfo对象

X500Name issuer=(X500Name)cinfo1.get(X509CertInfo.SUBJECT+”.”+CertificateIssuerName.DN_NAME); 获取X509Name类型的签发者信息

(4)获取待签发的证书

CertificateFactory cf=CertificateFactory.getInstance(“X.509”);

FileInputStream in2=new FileInputStream(“user.csr”);

java.security.cert.Certificate c2=cf.generateCertificate(in);

(5)从待签发的证书中提取证书信息

byte [] encod2=c2.getEncoded();

X509CertImpl cimp2=new X509CertImpl(encod2); 用该编码创建X509CertImpl类型对象

X509CertInfo cinfo2=(X509CertInfo)cimp2.get(X509CertImpl.NAME+”.”+X509CertImpl.INFO); 获取X509CertInfo对象

(6)设置新证书有效期

Date begindate=new Date(); 获取当前时间

Date enddate=new Date(begindate.getTime()+3000*24*60*60*1000L); 有效期为3000天

CertificateValidity cv=new CertificateValidity(begindate,enddate); 创建对象

cinfo2.set(X509CertInfo.VALIDITY,cv); 设置有效期

(7)设置新证书序列号

int sn=(int)(begindate.getTime()/1000); 以当前时间为序列号

CertificateSerialNumber csn=new CertificateSerialNumber(sn);

cinfo2.set(X509CertInfo.SERIAL_NUMBER,csn);

(8)设置新证书签发者

cinfo2.set(X509CertInfo.ISSUER+”.”+CertificateIssuerName.DN_NAME,issuer);应用第三步的结果

(9)设置新证书签名算法信息

AlgorithmId algorithm=new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);

cinfo2.set(CertificateAlgorithmId.NAME+”.”+CertificateAlgorithmId.ALGORITHM,algorithm);

(10)创建证书并使用CA的私钥对其签名

X509CertImpl newcert=new X509CertImpl(cinfo2);

newcert.sign(caprk,”MD5WithRSA”); 使用CA私钥对其签名

(11)将新证书写入密钥库

ks.setCertificateEntry(“lf_signed”,newcert);

FileOutputStream out=new FileOutputStream(“newstore”);

ks.store(out,”newpass”.toCharArray()); 这里是写入了新的密钥库,也可以使用第七条来增加条目

十 数字证书的检验

(1)验证证书的有效期

(a)获取X509Certificate类型对象

CertificateFactory cf=CertificateFactory.getInstance(“X.509”);

FileInputStream in1=new FileInputStream(“aa.crt”);

java.security.cert.Certificate c1=cf.generateCertificate(in1);

X509Certificate t=(X509Certificate)c1;

in2.close();

(b)获取日期

Date TimeNow=new Date();

(c)检验有效性

try{

t.checkValidity(TimeNow);

System.out.println(“OK”);

}catch(CertificateExpiredException e){ //过期

System.out.println(“Expired”);

System.out.println(e.getMessage());

}catch((CertificateNotYetValidException e){ //尚未生效

System.out.println(“Too early”);

System.out.println(e.getMessage());}

(2)验证证书签名的有效性

(a)获取CA证书

CertificateFactory cf=CertificateFactory.getInstance(“X.509”);

FileInputStream in2=new FileInputStream(“caroot.crt”);

java.security.cert.Certificate cac=cf.generateCertificate(in2);

in2.close();

(c)获取CA的公钥

PublicKey pbk=cac.getPublicKey();

(b)获取待检验的证书(上步已经获取了,就是C1)

(c)检验证书

boolean pass=false;

try{

c1.verify(pbk);

pass=true;

}catch(Exception e){

pass=false;

System.out.println(e);

}

ACM在线系统编译命令

C

/usr/bin/gcc -DEVAL -static -O2 -o HelloWorld HelloWorld.c -lm

C++

/usr/bin/g++ -DEVAL -static -O2 -o HelloWorld HelloWorld.cpp

Java

/bin/mv HelloWorld.java Task.java
/usr/bin/gcj –main=Task -O3 -o HelloWorld Task.java

嗯其实我想记录的是把一个(几个)java文件编译成一个linux上可执行的ELF文件方法

gcj –main=Task(main函数所在的java文件为Task.java,所以..) -O3 -o HelloWorld(编译之后产生ELF的名字) Task.java A.java(Java源文件依次列在这里)

Java的反射机制


1.反射不受到public,private,protected等的限制,
可以随意创建,修改,读取private(等)类的private(等)函数或者成员变量
2.
Class clz = Class.forName("类名")

Method mtd = clz.getMethod("函数名",new Class[]{参数类型列表})
这种方法只能获取到clz类中public的函数,private的函数无法获取到

Method mtd = clz.getDeclaredMethod("函数名",new Class[]{参数类型列表})
这种方法能够获取到clz类的所有声明的函数,无论是public的,private的还是protected的

Field,同样有clz.getField和clz.getDeclaredField之分(与Method同理)

mtd.invoke(obj,new Object[]{参数列表})
如果是一个实例函数的调用(非static的函数), 则obj应该是该类的实例
如果调用的是static函数,obj = null即可

常用的写法:

                Class DexFileClz = Class.forName("dalvik.system.DexFile");
		
		Class[] paratype = new Class[1];
		paratype[0] = byte[].class;   //注意 数组的类型 如何表示
				
		Object[] paraobj = new Object[1];
		paraobj[0] = dexContent;//dexContent是byte[]
		
		Method openDexFilemtd = DexFileClz.getDeclaredMethod("openDexFile", paratype);
		openDexFilemtd.setAccessible(true);    //不管是否private,protected,在该程序中都设为可见.
		int retv = (Integer) openDexFilemtd.invoke(null, paraobj);

3.如果反射返回的object是一个数组类型,

例如:
		Object dexElements = RefInvoke.getFieldOjbect("dalvik.system.DexPathList", pthList, "dexElements");

其中dexElements是一个final的protected类, 对当前的程序员来说是不可见的, 所以无法进行强制类型转换. 那么如果想要操作其中的每个
元素就需要使用Array类型:

		int length = Array.getLength(dexElements); //获取数组的长度

		Object ele = Array.get(dexElements, i); //获取数组的第i个元素,i从0开始 (i即数组index)

以上都能明白, Java的反射再无困难

==== === === =天使般的分割线 = = = == = = == = = = = =

以下为反射常用函数集合,若用到反射,下类基本够用!



import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class RefInvoke {
	
	public static  Object invokeStaticMethod(String class_name, String method_name, Class[] pareTyple, Object[] pareVaules){
		
		try {
			Class obj_class = Class.forName(class_name);
			Method method = obj_class.getMethod(method_name,pareTyple);
			return method.invoke(null, pareVaules);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		}  catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static  Object invokeMethod(String class_name, String method_name, Object obj ,Class[] pareTyple, Object[] pareVaules){
		
		try {
			Class obj_class = Class.forName(class_name);
			Method method = obj_class.getMethod(method_name,pareTyple);
			return method.invoke(obj, pareVaules);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		}  catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static Object getFieldOjbect(String class_name,Object obj, String filedName){
		try {
			Class obj_class = Class.forName(class_name);
			Field field = obj_class.getDeclaredField(filedName);
			field.setAccessible(true);
			return field.get(obj);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static Object getStaticFieldOjbect(String class_name, String filedName){
		
		try {
			Class obj_class = Class.forName(class_name);
			Field field = obj_class.getDeclaredField(filedName);
			field.setAccessible(true);
			return field.get(null);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static void setFieldOjbect(String classname, String filedName, Object obj, Object filedVaule){
		try {
			Class obj_class = Class.forName(classname);
			Field field = obj_class.getDeclaredField(filedName);
			field.setAccessible(true);
			field.set(obj, filedVaule);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}	
	}
	
	public static void setStaticOjbect(String class_name, String filedName, Object filedVaule){
		try {
			Class obj_class = Class.forName(class_name);
			Field field = obj_class.getDeclaredField(filedName);
			field.setAccessible(true);
			field.set(null, filedVaule);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}		
	}


}

ubuntu 13.04 安装 JDK

  具体步骤参详了如下链接:

http://blog.csdn.net/yang_hui1986527/article/details/6677450

  1、到 Sun 的官网下载

http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
  选择 accept license ,然后选择适合自己机型的JDK下载。

  2、解压文件,修改文件名

$ sudo mkdir /usr/lib/jvm
$ sudo tar zxvf jdk-7u21-linux-i586.tar.gz -C /usr/lib/jvm
$ cd /usr/lib/jvm
$ sudo mv jdk1.7.0_21 java
  3、添加环境变量

$ sudo vim ~/.bashrc
  加入如下内容

export JAVA_HOME=/usr/lib/jvm/java
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
  4、配置默认JDK版本

sudo update-alternatives –install /usr/bin/java java /usr/lib/jvm/java/bin/java 300
sudo update-alternatives –install /usr/bin/javac javac /usr/lib/jvm/java/bin/javac 300
sudo update-alternatives –install /usr/bin/jar jar /usr/lib/jvm/java/bin/jar 300
sudo update-alternatives –install /usr/bin/javah javah /usr/lib/jvm/java/bin/javah 300
sudo update-alternatives –install /usr/bin/javap javap /usr/lib/jvm/java/bin/javap 300
  然后执行

sudo update-alternatives –config java
  若是初次安装 JDK, 将提示

There is only one alternative in link group java (providing /usr/bin/java): /usr/lib/jvm/java/bin/java
无需配置。
  若是非初次安装,将有不同版本的 JDK 选项。

  5、测试

$ java -version
java version “1.7.0_21”
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) Server VM (build 23.21-b01, mixed mode)

jdb调试运行本地jar包

运行命令:

1一个shell中,使用该命令启动jar

java -agentlib:jdwp=transport=dt_socket,server=y,address=8000 -jar jeb.jar

另一个shell中,使用jdb连接该调试线程:

jdb -attach localhost:8000

 

须在启动之前下好断点,以便单步调试.故此需要对jar内的类以及函数有所了解.

可以使用jd-gui或者jad反编译原始jar包,阅读java代码对原始jar稍作了解.

 

———————————————–

要进行调试,你必须将调试JDWP代理加载到应用程序的JVM中。从Java 5.0开始,你可以用-agentlib:jdwp选项来完成加载。5.0以前版本则使用-Xdebug和-Xrunjdwp选项(5.0也支持-Xdebug和-Xrunjdwp选项,不过新的-agentlib:jdwp选项更加好用。因为5.0中的JDWP代理使用JVMTI接口连接VM,而非旧的JVMDI接口)。你应该向-agentlib:jdwp(Java 5.0中)或-Xrunjdwp(Java 5.0以前版本) 参数提供子选项;两组可能的子选项相同。

以下列方式指定子选项:

-agentlib:jdwp=<name1>[=<value1>],<name2>[=<value2>]…

-Xrunjdwp:<name1>[=<value1>],<name2>[=<value2>]…

你可以使用这些选项:

help:打印如何应用它的简单信息,并退出VM。
server:(是”y”或否”n”):如“server=y”,收到一个要依附的调试应用程序;如“server=n”,依附到指定地址的调试应用程序。
address:连接传送地址。如果server=n,尝试依附到这个地址的调试应用程序;如server=y,收到这个地址的连接。
timeout:如果server=y,它以毫秒为单位指定等待调试器依附的时间;如server=n,它以毫秒为单位指定依附到调试器所用的时间。
suspend:如“是”,JVM延缓执行,直到调试器与被调试JVM建立连接。
以下是命令行实例:

-agentlib:jdwp=transport=dt_socket,server=y,address=8000

在端口8000收听一个套接字连接。在主类加载前延缓这个VM(默认suspend=y)。一旦连接上调试应用程序,它发送一个JDWP命令恢复VM。

-agentlib:jdwp=transport=dt_shmem,server=y,suspend=n

选择一个有效的共享内存传输地址并将它打印出来。在那个地址收听一个共享内存连接。在调试应用程序依附之前,允许VM开始执行。

-agentlib:jdwp=transport=dt_socket,address=myhost:8000

通过myhost主机端口8000的套接字依附到一个运行的调试应用程序。在主类加载前延缓这个VM。

————————————————

—————————————————–

由于直接使用JDB调试时,浏览源代码时很不方便,如果机器上安装了emacs,可以直接在emacs里启动JDB,获取跟eclipse相近的源代码级别的调试体验。

 

在emacs里运行JDB的方法:

1.在emacs里按下ALT+X键,在提示符后面输入JDB,敲击回车。
2.接着再输入JDB的启动参数。
3.按下CTRL + X,2键,将emacs分屏。
4.再按CTRL + X, B键,将其中一个屏幕显示源代码。
5.按CTRL + X, O键,再两个屏幕间切换。
6.在JDB的那个窗口里输入正常的调试命令。
———————————————————————-

 

参考:

http://tech.it168.com/j/2006-12-22/200612221226341_1.shtml

http://wenku.baidu.com/link?url=vWrcQVtSL97AlqPzkTGVdUoVJaPR_WOiu9Ok_5dibE72lygVMTe9iI2aNLy5gSs8oEe_qd0lBmGzHSIrqB5IQPqHzdPr8iTEAWog17Owa1q

JAVA不定参数探秘

JAVA中可以使用不定参数,

例如 public void test(String …args){…} 这里test方法可以传入参数的情况是:

1.不使用参数,如test()

2.使用一个或多个参数,如test(“1”); test(“1″,”2”);

3.使用数组 test(new String[]{“1″,”2”});

在test方法内部,我们可以像使用数组的访问方式一样来访问参数args.如:args[i] 这样就有一个好处,在参数输入不定的情况下,使用这个方法非常简单。非常易于使用。

有几点需要注意的就是  

  我们见到的是不定参数,其实编译器编译之后它会将这个test(String …args){…} 编译成为数组调用的方式test(String[] args){} ,这个过程是编译中就完成了的,我们程序编写过程中看不到这个实际的转换过程。  而我们调用这个test方法时,编译器同样会把参数转换成new String[]{“”}的形式调用,所以,本质上来讲,就是一个以数组为参数的调用方法,我们看不到而已,具体详细情况可以反编译class类就可以明了。

如果同时同一个类中还有一个test方法,例如test(),或者test(String args) ,我们采用 test(“1”)的方式调用,我们就可以知道了,因为有这个方法存在,所以编译器就会优先使用这个 test(String args)    方法,而不会使用不定参数的方法,这个原因很明确,因为不定参数本质上是一个数组为参数的方式。所以,如果你定义了一个不定参数的test方法,如果你再定义一个test(String[] args)的以数组为参数的方法,编译器就会提示你方法定义重复。道理就在这里。

  希望以上的解释能够帮助到大家。

原链接: http://www.cnblogs.com/lovingprince/archive/2008/05/20/2166386.html