Locked History Actions

proguard/Options

オプション

proguardは、難読化だけではなく、黙っていると最高度の最適化をしてしまい、意図しないコードを生成し、結果動作しなくなってしまう。 しかも、どのように変更されるのか調査するのが面倒なため、オプションを調整しながら、どのように最適化・難読化されたのかを確認しづらい。 以下では、「難読化」という目的を果たしつつ、「動かない」というトラブルに巻き込まれないための最低限のオプション(あるいは事前のコード変更)について述べる。

以下はbuild.gradleに記述する例。proguardとfatjarも参照のこと。

入出力の指定

入出力指定、警告等の以下のオプションはここでは省略。

  injars
  outjars 
  libraryjars  
  dontwarn
  dontnote

シュリンクと最適化の拒否

これは必須。苦労したくなければ指定した方がよい。少なくとも最初の段階では絶対に指定しておくべき。

dontshrink
dontoptimize

Javaエントリポイント

Javaのエントリポイントを保護する。これが無いと当然実行できなくなるのだが、指定しないとproguardはお構い無しに名前変更してしまう。

  keep 'public class sample.AppMain { \
    public static void main(java.lang.String[]); \
  }'

直列化フィールドの保護

Javaのシリアライゼーションを使う場合には、パッケージ名、クラス名、フィールド名のどれも変更されてはならないので以下では不十分。 ここでは、他の仕組み、例えばJSON等を使うことを想定している。

  keepclassmembers '@sample.Serialized class * {\
    <fields>;\
  }'

以下のようなコードでJSONを使ってシリアライズすることを想定した。この場合、パッケージ名・クラス名は変更されてもよい。 フィールド名が変更されなければよい。

package sample;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)  
public @interface Serialized {
  public long key();
}

@Serialized(key=-4069057649147625984L)
public class InputFile {
  private String path;

※本当はstatic, transientは名前変更されても良いのだが対応は省略。

リソース取得コードの変更

これはproguardオプションではなく、コードの方を変更する。proguardはリソースに対しては何もしない。パッケージ名もそのまま、ファイル名もそのままなのだが、それを取得しようとするコードの方はパッケージの変更もしてしまう。例えば、

sample.resources
  Resources.java
  stylesheet.css
  icon.png

などというパッケージがあり、

@Singleton
public class Resources {
  private Image iconImage = new Image(Resources.class.getResourceAsStream("icon.png"));
  ....
}

などとやってると動作しない。Resourceクラスのパッケージが移動しないように保護するか、あるいはリソースの取得方法を変更する。

@Singleton
public class Resources {
  private static final String PATH = "/sample/resources/";  
  private Image iconImage = new Image(Resources.class.getResourceAsStream(PATH + "icon.png"));
  ....

マップの取得

難読化後のプログラムがうまく動作せず例外が出る場合、あるいはリリースした後で例外が出る場合、そのスタックトレースも難読化後のパッケージ名、クラス名、メソッド名になっているので、そのまま見てもチンプンカンプンということになる。これを元に戻すためのマップの出力も必須。例えば以下のようにする。

  printmapping 'mapping.txt' // 何でもよい
  renamesourcefileattribute 'SourceFile'
  keepattributes 'SourceFile,LineNumberTable'

例外のスタックトレースをstacktrace.txtに取得したとすると以下のように元のスタックトレースを表示することができる。

C:\proguard5.3.2\bin\retrace.bat mapping.txt stacktrace.txt 

他のkeepattributes

'SourceFile,LineNumberTable'の他にも以下があり、正直どのような働きをするのかわからないが、指定しないと意図しないコードになるようだ。 おいおい調査する予定。

 keepattributes 'Exceptions,InnerClasses,Signature,Deprecated,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod'