如何破解已签名JAR包

本文版权归赣州兆鑫软件所有,原创未经许可禁止转载!
本文仅作学习交流目的,提倡软件正版,反对盗版!


工欲善其事必先利其器

做事要先掌握大局

  1. 将已签名包转化为未签名包;
  2. 定位关键代码位置;
  3. 修改class文件字节码;
  4. 替换class文件重新打包;

不行动总也不能成功

1.将已签名包转化为未签名包

如果你用到的Jar文件使用了签名,它会保证里面的每个class文件不能被修改,所以即使你成功修改了class文件中的字节码,得到的Jar也是无法运行的。这些经过签名的Jar包的META-INF文件夹中一般包含了*.SF和相应的*.RSA文件。这些文件记录Jar包中每个文件的签名信息,以保证代码不被篡改。

使用下面的方法可以重新生成一个未签名Jar包。参考自stackoverflow作者Houtman的回答

// 使用JDK编译代码
javac JarUnsigner.java

// 执行JarUnsigner,如果是同一个文件夹
java -cp . JarUnsigner <inJar> <outJar>

附上源代码,免得回答被删

// JarUnsigner.java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class JarUnsigner {

  private static final String MANIFEST = "META-INF/MANIFEST.MF";

  public static void main(String[] args){

    if (args.length!=2){
      System.out.println("Arguments: <infile.jar> <outfile.jar>");
      System.exit(1);
    }
    String infile = args[0];
    String outfile = args[1];
    if ((new File(outfile)).exists()){
      System.out.println("Output file already exists:" + outfile);
      System.exit(1);
    }
    try{
      ZipFile zipFile = new ZipFile(infile);
      final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outfile));
      for (Enumeration e = zipFile.entries(); e.hasMoreElements();) {
        ZipEntry entryIn = (ZipEntry) e.nextElement();

        if (! exclude_file( entryIn.getName() ) ) {

          /* copy the entry as-is */
          zos.putNextEntry( new ZipEntry( entryIn.getName() ));
          InputStream is = zipFile.getInputStream(entryIn);
          byte[] buf = new byte[1024];
          int len;
          while ((len = (is.read(buf))) > 0) {
            zos.write(buf, 0, len);
          }
          zos.closeEntry();

        } else {

          if (MANIFEST.equals(entryIn.getName())){
            /* if MANIFEST, adjust the entry */
            zos.putNextEntry(new ZipEntry(MANIFEST));

            // manifest entries until first empty line. i.e. the 'MainAttributes' section
            // (this method is used so to keep the formatting exactly the same)
            InputStream mIS = zipFile.getInputStream(entryIn);
            BufferedReader in = new BufferedReader(new InputStreamReader(mIS));
            String line = in.readLine();
            byte[] mNL = "\n".getBytes("UTF-8");
            while( line != null && !line.trim().isEmpty() ) {
              zos.write( line.getBytes("UTF-8"));
              zos.write( mNL );
              line = in.readLine();
            }
            zos.write( mNL );
            zos.closeEntry();

          }else{
            /* else: Leave out the Signature files */
          }

        }

      }
      zos.close();
      System.out.println("Successfully unsigned " + outfile);

    }catch(IOException ex){
      System.err.println("Error for file: " + infile);
      ex.printStackTrace();
      System.exit(1);
    }
  }

  /**
   * Exclude .SF signature file
   * Exclude .RSA and DSA (signed version of .SF file) 
   * Exclude SIG-  files  (unknown sign types for signed .SF file)
   * Exclude Manifest file
   * @param filename
   * @return 
   */
  public static boolean exclude_file(String filename){
    return filename.equals("META-INF/MANIFEST.MF") ||
           filename.startsWith("META-INF/SIG-") || 
           filename.startsWith("META-INF/") && ( filename.endsWith(".SF") || filename.endsWith(".RSA") || filename.endsWith(".DSA") );
  }

}


2. 定位代码关键位置

举一个需要输入序列号才能试用的库文件的例子,但是为了保护Jar包作者权益,对包名进行打码了。通过Jar包的说明书,可以知道如何使用它,就知道是什么地方输入序列号啦,要不然是个正常人也没法用对吧。例如

// 文档说这样子可以验证序列号
authentication.User("333");
authentication.Serial("94306-56191-128286-2967422");

rock & roll

  1. 使用JD反编译Jar包,然后Save All Sources,具体步骤这里省略;
  2. 从IDEA新建一个工程,把反编译的源代码放到源目录,Jar包可能是经过混淆过的,不过这个关系不大,我们字节码都能改,还怕看不懂混淆?继续往下走
  3. 右击authentication这个类文件,选择Find Usages,快捷键一般是Ctrl+G,看到有个叫做p.java的文件用到,做了一些判断操作Blabla,看屏幕截图1:
    屏幕截图1
  4. 点开这个p.java类搜索到的地方,可以看到,它在比较一个返回结果,然后给出不同的错误提示,这个结果是由一个t.a(三个参数)的方法计算得到,并且看得出来当计算结果的a属性值为0时就是Licence OK!,看屏幕截图2:
    屏幕截图2
  5. 好,我们再来看t.java这个文件的a方法又有什么东东(按住Ctrl键,鼠标点击那个t.a),我们只要保证他得到的结果的a属性等于0就好了,可以看到只有一种情况下a属性才会等于0,其他时候都是等于-1的,到这一步IDEA的使命就完成了,看屏幕截图3:
    屏幕截图3

结果

通过上面5步(取决于不同的包,不一定都是5步),我们知道了需要改动t类里面的a方法,让它里面操作属性a时,值为-1的都改为0就能成功。

3. 修改class文件字节码

接下来就要使用dirtyJOE软件来定位并修改字节码了,作者也试过Class Editor, Java Bytecode Editor都因年久失修,没改成功。通过查阅JVM文档我们知道给整数赋值有几种指令,这里就说两种:

  • iconst_<i> i可以为 m1,0,1,2,3,4,5,分别设置的值为-1,0,1,2,3,4,5,指令16进制字节码分别是02设置-1,03设置0,04设置1,以此类推
  • bipush <i> i范围可以是0-255,指令16进制字节码是10,比如代码里面有的21就是bipush 21,16字节码表示为10 15

let's go

  1. 使用dirtyJOE打开t.class文件,切换到 Methods 页上,如下图所示:

    image.png

  2. 双击我们需要修改的方法(同名时通过比对方法签名来区分),进入编辑界面,图中的两个指令的组合就是将值-1赋值给t$a.a属性,双击图中的iconst_ml,字节码是02,改为03,然后回车即可,可以使用Ctrl+F查找多处进行修改:

    image.png

  3. 关闭编辑窗口,保存修改。

warning

要保证字节码的数量不增多,也不减少,因为类和类之间代码调用跟字节位置关系密切。不然会导致修改的class文件无法使用。原来一行是1个字节的,继续用1个字节,2个的就继续两个,3个的继续保持三个。

4. 替换class文件重新打包

这是最简单的一步,将修改好的class文件,使用zip压缩工具替换掉即可。如果是你Windows用户不推荐使用WinRaR,可以将jar文件(第一步生成的未签名包)重命名为zip文件,然后选择用Windows资源管理器打开,将修改的class文件复制粘贴进去。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,627评论 6 517
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 95,180评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 169,346评论 0 362
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,097评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,100评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,696评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,165评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,108评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,646评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,709评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,861评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,527评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,196评论 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,698评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,804评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,287评论 3 379
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,860评论 2 361

推荐阅读更多精彩内容

  • 俗话说:"有钱没钱,回家过年。"钢筋水泥浇筑的城市里冷漠的没有温馨过新年浓郁的味道,小桥流水又炊烟四起的故土才是我...
    嘉雁38677阅读 339评论 3 2
  • 养孩方知,养孩不易,养孩️死好几回: 孩儿天真可爱、聪明伶俐,美死; 孩儿不慎吞异物、吃东西卡了一下,吓死; 孩儿...
    紫柠檬2016阅读 259评论 0 0
  • 文|璇子 希望你多点坚强 方能做自己的铠甲 不因困难而停步不前 希望你多点谦虚 不忘开始的初心 路方能持续走得更远...
    花非物欲阅读 173评论 0 6