ZeroNights 2017 Crackme#3でフクロウは何をしますか?















ZeroNights 2017 Crackme No. 3はかなり単純なタスクですが、それでもなお、興味深い点とフクロウがあります。







catの下-分解、逆コンパイル、IntelliJ IDEAでのプル要求であり、単一のデバッガー起動ではありません。







タスクファイルはhttps://events.kaspersky.com/crackme/files/crackme3.zipから入手できます

Androidアプリケーションapp-release.apk



は、アーカイブ内に単独で存在します。 APKは、現代の多くの場合と同様に、zipアーカイブです。 それを手に入れて解凍します。







内部では、 /res



標準Androidアプリケーションテンプレートの1つ、 /lib



ネイティブライブラリ、 /assets



奇妙な名前のファイル、そして最も重要なことに、 classes.dex



アプリケーションコードからclasses.dex



ます。 classes.dex



を使用して、 classes.dex



をjarファイルに変換します。







内部のコードは 、いくつかのパッケージに編成されています。









元のパッケージ名を保持することは、crackmeにとってはやや疑わしい習慣ですが、これにより簡単になります。 アプリケーションのメインロジックがパッケージcom.kaspersky.zeronights2017.nightwatcher



にあると想定するのは理にかなっています。 さらに、 MainActivity



クラスがそこにあります。







逆コンパイルして調査します。







MainActivity.java
 // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.kaspersky.zeronights2017.nightwatcher; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Build.VERSION; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.googlecode.tesseract.android.TessBaseAPI; import java.io.File; public class MainActivity extends Activity { public static EditText a; public static EditText b; public static String c; private String d; private final String e; public MainActivity() { this.d = \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.q; this.e = \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF(\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.d); } private void a() { Bitmap var1 = BitmapFactory.decodeResource(this.getResources(), 2131099746); TessBaseAPI var2; if (VERSION.SDK_INT > 19) { this.d = this.getFilesDir() + \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.e; var2 = new TessBaseAPI(); this.a(new File(this.d + this.e), \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.i); var2.a(this.d, \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.f); var2.a(var1); c = var2.a(); this.a(new File(this.d + this.e), \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.j); var2.a(this.d, \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.g); var2.a(var1); c = c + var2.a(); this.a(new File(this.d + this.e), \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.k); var2.a(this.d, \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.h); var2.a(var1); c = c + var2.a(); } else { this.d = this.getFilesDir() + \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.e; var2 = new TessBaseAPI(); this.a(new File(this.d + this.e), \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.i); var2.a(this.d, \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.f); var2.a(var1); c = var2.a().split("\n")[0]; this.a(new File(this.d + this.e), \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.j); var2.a(this.d, \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.g); var2.a(var1); c = c + var2.a().split("\n")[0]; this.a(new File(this.d + this.e), \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.k); var2.a(this.d, \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.h); var2.a(var1); c = c + var2.a().split("\n")[0]; } } private void a(File var1, String var2) { if (!var1.exists() && var1.mkdirs()) { this.a(var2); } if (var1.exists() && !(new File(this.d + this.e + var2)).exists()) { this.a(var2); } } private void a(String param1) { // $FF: Couldn't be decompiled } protected void onCreate(Bundle var1) { super.onCreate(var1); this.requestWindowFeature(1); this.getWindow().setFlags(1024, 1024); this.setContentView(2131296283); Button var2 = (Button)this.findViewById(2131165217); if ((new \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF(this)).\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF()) { Toast.makeText(this, 2131361827, 1).show(); this.finish(); } var2.setOnClickListener(new OnClickListener() { public void onClick(View var1) { MainActivity.a = (EditText)MainActivity.this.findViewById(2131165230); MainActivity.b = (EditText)MainActivity.this.findViewById(2131165280); MainActivity.this.a(); if (!MainActivity.a.getText().toString().matches(\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.q) && !MainActivity.b.getText().toString().toUpperCase().matches(\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.q)) { if (\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF()) { Toast.makeText(MainActivity.this, 2131361829, 1).show(); } else { Toast.makeText(MainActivity.this, 2131361828, 1).show(); } } else { Toast.makeText(MainActivity.this, 2131361828, 1).show(); } } }); } }
      
      





このリストおよび後続のリストを読みやすくするために、127を超えるコードを持つすべての文字は、 \uXXXX



形式のUnicodeエスケープシーケンスに置き換えられます。







クラス、フィールド、およびメソッドの名前の一部は難読化されており、一部のメソッドは逆コンパイルできませんでしたが、 onCreate()



メソッドは単純で単純です。 これから、少なくとも2つの入力フィールドと1つのボタンがあることがわかります。クリックすると、ユーザーは、読み取り不能な名前のメソッドによって返された結果に応じて、メッセージの1つを受け取ります。







クラス名とメソッド名の文字数(それぞれ34と62)に基づいて、このメソッドを見つけます。







入力されたキーをチェックするクラス
 // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.kaspersky.zeronights2017.nightwatcher; class \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF { public static boolean \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF() { boolean var0; if ( \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.t / \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.r * \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.f - \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.h == MainActivity.b.getText().toString().toUpperCase().length() && \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF .\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF( \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF .\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF( \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF .\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF( MainActivity.c.getBytes() ) + MainActivity.a.getText().toString() ) ).equals(MainActivity.b.getText().toString().toUpperCase()) ) { var0 = true; } else { var0 = false; } return var0; } }
      
      





これで終わりかもしれません。







2番目の入力フィールドの値の長さがチェックされます。 おそらく定数であるプレフィックスが最初の入力フィールドの値に追加され、結果の行からハッシュが計算されます。 後者の値は、2番目の入力フィールドの値と比較され、大文字に変換されます。 それだけです







比較の前に計算されたハッシュのログを追加して、apkファイルのコードをわずかに変更するだけで十分であり、crackmeは解決されます。 しかし、これはかなり退屈であり、記事を引っ張るわけではありません。







別の方法



代わりに、作業のロジックを分析し、キージェネレーターを作成します。







まず、識別子の難読化を取り除きます。 それらの一部は単なる1文字であり、一部は\uFEFF



は異なる長さのシーケンスです。 ほとんどの場合、この文字は、Unicodeエンコーディングのいずれかでテキストファイルの先頭にバイトオーダーマークとして使用されます。 ただし、もう1つの廃止された値があります。 ゼロ幅のノーブレークスペース(ZWNBSP)、またはロシア語の場合はゼロ幅のスペースです。 このプロパティにより、ファイルを開くダイアログには、いくつかの「名前なし」クラスファイルが表示されます。













ところで、興味深い事実:Java言語仕様の観点から、 \uFEFF



は決して目立たず、2番目の位置から始まる識別子の一部になります。 ただし、Oracle JDK / Open JDKのコンパイラの実装にはいくつかの問題に関する独自の見解があり、コンパイル中にこのような文字は識別子から静かに切り取られ、最終的なクラスファイルには入りません。 JLSにはこれに関する単語はありません。これに関する情報はjavacソースコードとバグトラッカーのJDK-7144981にのみあります。







IntelliJ IDEA含まれている逆コンパイラーであるFernflowerは、識別子の自動名前変更をサポートしています。 これを行うには、コマンドラインから逆-ren=1



呼び出すときに、 -ren=1



パラメーターを指定します。







しかし、逆コンパイルしようとすると失敗しますが、逆コンパイラはそのような識別子が間違っているとは考えません。 中を見て理由を見つけましょう。







識別子の名前を変更する必要があるかどうかを判断するためのメソッドは次のとおりです。







 @Override public boolean toBeRenamed(Type elementType, String className, String element, String descriptor) { String value = elementType == Type.ELEMENT_CLASS ? className : element; return value == null || value.length() <= 2 || Character.isDigit(value.charAt(0)) || KEYWORDS.contains(value) || elementType == Type.ELEMENT_CLASS && ( RESERVED_WINDOWS_NAMESPACE.contains(value.toLowerCase(Locale.US)) || value.length() > 255 - ".class".length()); }
      
      





識別子の名前を変更するには、数字で始まるか、Windowsでキーワードまたは予約されたファイル名と一致する長すぎます。







JLSによる識別子の検証と、その中にこれらの素晴らしい「無視できる文字」が存在しない場合、チェックを最初の位置の番号に置き換え、 プルリクエストを発行します







難読化は無効になりましたが、逆コンパイルに失敗したメソッドがあります。 それらに対処しましょう。







アセンブラーのビット



アセンブリと逆アセンブリには、OpenJDKのasmtoolsを使用します。







MainActivity



唯一の問題のあるメソッドから始めましょう。







MainActivity.jasm-void a(文字列)
 private Method a:"(Ljava/lang/String;)V" stack 4 locals 8 { aload_1; astore 4; try t0; new class java/lang/StringBuilder; astore 5; endtry t0; aload_1; astore 4; try t1; aload 5; invokespecial Method java/lang/StringBuilder."<init>":"()V"; endtry t1; aload_1; astore 4; try t2; aload 5; aload_0; getfield Field d:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_0; getfield Field e:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_1; invokestatic Method \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF."\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF":"(Ljava/lang/String;)Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; invokevirtual Method java/lang/StringBuilder.toString:"()Ljava/lang/String;"; astore 5; endtry t2; aload_1; astore 4; try t3; aload_0; invokevirtual Method getAssets:"()Landroid/content/res/AssetManager;"; astore 6; endtry t3; aload_1; astore 4; try t4; new class java/lang/StringBuilder; astore 7; endtry t4; aload_1; astore 4; try t5; aload 7; invokespecial Method java/lang/StringBuilder."<init>":"()V"; endtry t5; aload_1; astore 4; try t6; aload 6; aload 7; aload_0; getfield Field e:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_1; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; invokevirtual Method java/lang/StringBuilder.toString:"()Ljava/lang/String;"; invokevirtual Method android/content/res/AssetManager.open:"(Ljava/lang/String;)Ljava/io/InputStream;"; astore_1; endtry t6; aload_1; astore 4; try t7; new class java/io/FileOutputStream; astore 7; endtry t7; aload_1; astore 4; try t8; aload 7; aload 5; invokespecial Method java/io/FileOutputStream."<init>":"(Ljava/lang/String;)V"; endtry t8; aload_1; astore 4; try t9; getstatic Field \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.x:"I"; newarray byte; astore 6; endtry t9; L125: aload_1; astore 4; try t10; aload_1; aload 6; invokevirtual Method java/io/InputStream.read:"([B)I"; istore_3; endtry t10; aload_1; astore 4; try t11; iload_3; getstatic Field \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.b:"I"; if_icmpeq L202; endtry t11; aload_1; astore 4; try t12; getstatic Field \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.a:"I"; istore_2; endtry t12; L152: iload_2; iload_3; if_icmpge L179; aload_1; astore 4; try t13; aload 6; iload_2; aload 6; iload_2; baload; getstatic Field \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.l:"I"; ixor; i2b; bastore; endtry t13; iinc 2, 1; goto L152; L179: aload_1; astore 4; try t14; aload 7; aload 6; getstatic Field \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.a:"I"; iload_3; invokevirtual Method java/io/OutputStream.write:"([BII)V"; endtry t14; goto L125; catch t0 java/io/IOException; catch t1 java/io/IOException; catch t2 java/io/IOException; catch t3 java/io/IOException; catch t4 java/io/IOException; catch t5 java/io/IOException; catch t6 java/io/IOException; catch t7 java/io/IOException; catch t8 java/io/IOException; catch t9 java/io/IOException; catch t10 java/io/IOException; catch t11 java/io/IOException; catch t12 java/io/IOException; catch t13 java/io/IOException; catch t14 java/io/IOException; catch t15 java/io/IOException; catch t16 java/io/IOException; catch t17 java/io/IOException; catch t18 java/io/IOException; catch t19 java/io/IOException; catch t20 java/io/IOException; catch t21 java/io/IOException; catch t22 java/io/IOException; catch t23 java/io/IOException; astore_1; aload_1; invokevirtual Method java/io/IOException.printStackTrace:"()V"; L201: return; L202: aload_1; astore 4; try t15; aload 7; invokevirtual Method java/io/OutputStream.flush:"()V"; endtry t15; aload_1; astore 4; try t16; aload 7; invokevirtual Method java/io/OutputStream.close:"()V"; endtry t16; aload_1; astore 4; try t17; aload_1; invokevirtual Method java/io/InputStream.close:"()V"; endtry t17; aload_1; astore 4; try t18; new class java/io/File; astore_1; endtry t18; aload_1; astore 4; try t19; aload_1; aload 5; invokespecial Method java/io/File."<init>":"(Ljava/lang/String;)V"; endtry t19; aload_1; astore 4; try t20; aload_1; invokevirtual Method java/io/File.exists:"()Z"; ifne L201; endtry t20; aload_1; astore 4; try t21; new class java/io/FileNotFoundException; astore_1; endtry t21; aload_1; astore 4; try t22; aload_1; invokespecial Method java/io/FileNotFoundException."<init>":"()V"; endtry t22; aload_1; astore 4; try t23; aload_1; athrow; endtry t23; }
      
      





すぐに、単一のcatch



ブロックを通常のe.printStackTrace();



と共有する一連のtry



ブロックが表示されますe.printStackTrace();



中間のコードに隠されています。







これは、これまでのところ深刻な難読化の試みを示していないコードには複雑すぎるように見えます。 変換中にdex2jar



何かをdex2jar



ます







Javaバイトコードに変換する前に、 apktoolを使用して元のDalvikバイトコードを確認します。 同時に、リソースを取得します。







疑わしい点は確認されましたが、変換時にすべてがスムーズに進むとは限りませんでした。 catch



は確かに一般的ですが、 try



catch



は2つしかありません。







MainActivity.smali-void a(文字列)
 .method private a(Ljava/lang/String;)V .locals 8 .param p1, "arg0" # Ljava/lang/String; .prologue :try_start_0 new-instance v1, Ljava/lang/StringBuilder; invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V iget-object v2, p0, Lcom/kaspersky/zeronights2017/nightwatcher/MainActivity;->d:Ljava/lang/String; invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v1 iget-object v2, p0, Lcom/kaspersky/zeronights2017/nightwatcher/MainActivity;->e:Ljava/lang/String; invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v1 invoke-static {p1}, Lcom/kaspersky/zeronights2017/nightwatcher/\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF;->\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF(Ljava/lang/String;)Ljava/lang/String; move-result-object v2 invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v1 invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v2 invoke-virtual {p0}, Lcom/kaspersky/zeronights2017/nightwatcher/MainActivity;->getAssets()Landroid/content/res/AssetManager; move-result-object v1 new-instance v3, Ljava/lang/StringBuilder; invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V iget-object v4, p0, Lcom/kaspersky/zeronights2017/nightwatcher/MainActivity;->e:Ljava/lang/String; invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v3 invoke-virtual {v3, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v3 invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v3 invoke-virtual {v1, v3}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream; move-result-object p1 new-instance v3, Ljava/io/FileOutputStream; invoke-direct {v3, v2}, Ljava/io/FileOutputStream;-><init>(Ljava/lang/String;)V sget v1, Lcom/kaspersky/zeronights2017/nightwatcher/\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF;->x:I new-array v4, v1, [B :goto_0 invoke-virtual {p1, v4}, Ljava/io/InputStream;->read([B)I move-result v5 sget v1, Lcom/kaspersky/zeronights2017/nightwatcher/\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF;->b:I if-eq v5, v1, :cond_2 sget v1, Lcom/kaspersky/zeronights2017/nightwatcher/\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF;->a:I :goto_1 if-ge v1, v5, :cond_0 aget-byte v6, v4, v1 sget v7, Lcom/kaspersky/zeronights2017/nightwatcher/\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF;->l:I xor-int/2addr v6, v7 int-to-byte v6, v6 aput-byte v6, v4, v1 add-int/lit8 v1, v1, 0x1 goto :goto_1 :cond_0 sget v1, Lcom/kaspersky/zeronights2017/nightwatcher/\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF;->a:I invoke-virtual {v3, v4, v1, v5}, Ljava/io/OutputStream;->write([BII)V :try_end_0 .catch Ljava/io/IOException; {:try_start_0 .. :try_end_0} :catch_0 goto :goto_0 :catch_0 move-exception v1 move-object v0, p1 .end local p1 # "arg0":Ljava/lang/String; .local v0, "arg0":Ljava/lang/String; move-object p1, v1 .end local v0 # "arg0":Ljava/lang/String; .restart local p1 # "arg0":Ljava/lang/String; invoke-virtual {p1}, Ljava/io/IOException;->printStackTrace()V :cond_1 return-void :cond_2 :try_start_1 invoke-virtual {v3}, Ljava/io/OutputStream;->flush()V invoke-virtual {v3}, Ljava/io/OutputStream;->close()V invoke-virtual {p1}, Ljava/io/InputStream;->close()V new-instance p1, Ljava/io/File; invoke-direct {p1, v2}, Ljava/io/File;-><init>(Ljava/lang/String;)V invoke-virtual {p1}, Ljava/io/File;->exists()Z move-result v1 if-nez v1, :cond_1 new-instance p1, Ljava/io/FileNotFoundException; invoke-direct {p1}, Ljava/io/FileNotFoundException;-><init>()V throw p1 :try_end_1 .catch Ljava/io/IOException; {:try_start_1 .. :try_end_1} :catch_0 .end method
      
      





asmtools jdis MainActivity.class



を使用して取得したリストに戻り、わずかに変更します。 catch



ブロック本体をメソッド本体の最後に移動し、すべてのtry



ブロックを削除し、代わりに新しいブロックを追加します。新しいブロックは、最初のリストの開始位置から始まり、元のリストの最後のtry



ブロックの終了位置で終了します。







MainActivity.jasm-無効なボイドa(文字列)
 private Method a:"(Ljava/lang/String;)V" stack 4 locals 8 { aload_1; astore 4; try t0; new class java/lang/StringBuilder; astore 5; aload_1; astore 4; aload 5; invokespecial Method java/lang/StringBuilder."<init>":"()V"; aload_1; astore 4; aload 5; aload_0; getfield Field d:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_0; getfield Field e:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_1; invokestatic Method "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF"."\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF":"(Ljava/lang/String;)Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; invokevirtual Method java/lang/StringBuilder.toString:"()Ljava/lang/String;"; astore 5; aload_1; astore 4; aload_0; invokevirtual Method getAssets:"()Landroid/content/res/AssetManager;"; astore 6; aload_1; astore 4; new class java/lang/StringBuilder; astore 7; aload_1; astore 4; aload 7; invokespecial Method java/lang/StringBuilder."<init>":"()V"; aload_1; astore 4; aload 6; aload 7; aload_0; getfield Field e:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_1; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; invokevirtual Method java/lang/StringBuilder.toString:"()Ljava/lang/String;"; invokevirtual Method android/content/res/AssetManager."open":"(Ljava/lang/String;)Ljava/io/InputStream;"; astore_1; aload_1; astore 4; new class java/io/FileOutputStream; astore 7; aload_1; astore 4; aload 7; aload 5; invokespecial Method java/io/FileOutputStream."<init>":"(Ljava/lang/String;)V"; aload_1; astore 4; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".x:"I"; newarray byte; astore 6; L125: aload_1; astore 4; aload_1; aload 6; invokevirtual Method java/io/InputStream.read:"([B)I"; istore_3; aload_1; astore 4; iload_3; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".b:"I"; if_icmpeq L202; aload_1; astore 4; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".a:"I"; istore_2; L152: iload_2; iload_3; if_icmpge L179; aload_1; astore 4; aload 6; iload_2; aload 6; iload_2; baload; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".l:"I"; ixor; i2b; bastore; iinc 2, 1; goto L152; L179: aload_1; astore 4; aload 7; aload 6; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".a:"I"; iload_3; invokevirtual Method java/io/OutputStream.write:"([BII)V"; goto L125; L202: aload_1; astore 4; aload 7; invokevirtual Method java/io/OutputStream.flush:"()V"; aload_1; astore 4; aload 7; invokevirtual Method java/io/OutputStream.close:"()V"; aload_1; astore 4; aload_1; invokevirtual Method java/io/InputStream.close:"()V"; aload_1; astore 4; new class java/io/File; astore_1; aload_1; astore 4; aload_1; aload 5; invokespecial Method java/io/File."<init>":"(Ljava/lang/String;)V"; aload_1; astore 4; aload_1; invokevirtual Method java/io/File.exists:"()Z"; ifne L201; aload_1; astore 4; new class java/io/FileNotFoundException; astore_1; aload_1; astore 4; aload_1; invokespecial Method java/io/FileNotFoundException."<init>":"()V"; aload_1; astore 4; aload_1; athrow; endtry t0; catch t0 java/io/IOException; astore_1; aload_1; invokevirtual Method java/io/IOException.printStackTrace:"()V"; L201: return; }
      
      



uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF"。「\ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF \ uFEFF private Method a:"(Ljava/lang/String;)V" stack 4 locals 8 { aload_1; astore 4; try t0; new class java/lang/StringBuilder; astore 5; aload_1; astore 4; aload 5; invokespecial Method java/lang/StringBuilder."<init>":"()V"; aload_1; astore 4; aload 5; aload_0; getfield Field d:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_0; getfield Field e:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_1; invokestatic Method "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF"."\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF":"(Ljava/lang/String;)Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; invokevirtual Method java/lang/StringBuilder.toString:"()Ljava/lang/String;"; astore 5; aload_1; astore 4; aload_0; invokevirtual Method getAssets:"()Landroid/content/res/AssetManager;"; astore 6; aload_1; astore 4; new class java/lang/StringBuilder; astore 7; aload_1; astore 4; aload 7; invokespecial Method java/lang/StringBuilder."<init>":"()V"; aload_1; astore 4; aload 6; aload 7; aload_0; getfield Field e:"Ljava/lang/String;"; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; aload_1; invokevirtual Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;"; invokevirtual Method java/lang/StringBuilder.toString:"()Ljava/lang/String;"; invokevirtual Method android/content/res/AssetManager."open":"(Ljava/lang/String;)Ljava/io/InputStream;"; astore_1; aload_1; astore 4; new class java/io/FileOutputStream; astore 7; aload_1; astore 4; aload 7; aload 5; invokespecial Method java/io/FileOutputStream."<init>":"(Ljava/lang/String;)V"; aload_1; astore 4; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".x:"I"; newarray byte; astore 6; L125: aload_1; astore 4; aload_1; aload 6; invokevirtual Method java/io/InputStream.read:"([B)I"; istore_3; aload_1; astore 4; iload_3; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".b:"I"; if_icmpeq L202; aload_1; astore 4; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".a:"I"; istore_2; L152: iload_2; iload_3; if_icmpge L179; aload_1; astore 4; aload 6; iload_2; aload 6; iload_2; baload; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".l:"I"; ixor; i2b; bastore; iinc 2, 1; goto L152; L179: aload_1; astore 4; aload 7; aload 6; getstatic Field "\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF".a:"I"; iload_3; invokevirtual Method java/io/OutputStream.write:"([BII)V"; goto L125; L202: aload_1; astore 4; aload 7; invokevirtual Method java/io/OutputStream.flush:"()V"; aload_1; astore 4; aload 7; invokevirtual Method java/io/OutputStream.close:"()V"; aload_1; astore 4; aload_1; invokevirtual Method java/io/InputStream.close:"()V"; aload_1; astore 4; new class java/io/File; astore_1; aload_1; astore 4; aload_1; aload 5; invokespecial Method java/io/File."<init>":"(Ljava/lang/String;)V"; aload_1; astore 4; aload_1; invokevirtual Method java/io/File.exists:"()Z"; ifne L201; aload_1; astore 4; new class java/io/FileNotFoundException; astore_1; aload_1; astore 4; aload_1; invokespecial Method java/io/FileNotFoundException."<init>":"()V"; aload_1; astore 4; aload_1; athrow; endtry t0; catch t0 java/io/IOException; astore_1; aload_1; invokevirtual Method java/io/IOException.printStackTrace:"()V"; L201: return; }





class- asmtools jasm MainActivity.jasm



.







asmtools



: , unicode escape .







:







 --- a/src/org/openjdk/asmtools/jasm/Parser.java +++ b/src/org/openjdk/asmtools/jasm/Parser.java @@ -416,6 +416,12 @@ case STRINGVAL: v = scanner.stringValue; scanner.scan(); + if (uncond || (scanner.token == Token.FIELD)) { + if ((!v.contains("/")) // class identifier doesn't contain "/" + && (!v.contains("["))){ // class identifier doesn't contain "[" + v = pkgPrefix + v; // add package + } + } return pool.FindCellAsciz(v); // Some identifiers might coincide with token names. // these should be OK to use as identifier names.
      
      





:







MainActivity::a(String)
 private void a(String var1) { try { StringBuilder var5 = new StringBuilder(); String var12 = var5.append(this.d).append(this.e).append(\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF(var1)).toString(); AssetManager var6 = this.getAssets(); StringBuilder var7 = new StringBuilder(); InputStream var9 = var6.open(var7.append(this.e).append(var1).toString()); FileOutputStream var14 = new FileOutputStream(var12); byte[] var13 = new byte[\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.x]; while(true) { int var3 = var9.read(var13); if (var3 == \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.b) { var14.flush(); var14.close(); var9.close(); File var10 = new File(var12); if (!var10.exists()) { FileNotFoundException var11 = new FileNotFoundException(); throw var11; } break; } for(int var2 = \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.a; var2 < var3; ++var2) { var13[var2] = (byte)(var13[var2] ^ \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.l); } var14.write(var13, \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF.a, var3); } } catch (IOException var8) { var8.printStackTrace(); } }
      
      





. , XOR- , .







.

try



- catch



-, catch



- , , , , try {} catch {}



.







 .method public static \uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF\uFEFF(Ljava/lang/String;)Ljava/lang/String; .locals 7 .param p0, "\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff\ufeff" # Ljava/lang/String; .prologue :try_start_0 //      java.security.MessageDigest :cond_0 invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; :try_end_0 .catch Ljava/security/NoSuchAlgorithmException; {:try_start_0 .. :try_end_0} :catch_0 .catch Ljava/io/UnsupportedEncodingException; {:try_start_0 .. :try_end_0} :catch_1 move-result-object p0 :goto_1 return-object p0 :catch_0 move-exception p0 :goto_2 invoke-virtual {p0}, Ljava/lang/Exception;->printStackTrace()V const/4 p0, 0x0 goto :goto_1 :catch_1 move-exception p0 goto :goto_2 .end method
      
      





( android.*



, . .) , .









, , .







, class- -ren=1



. 32 . , , , .







GitHub







Android Studio.







MainActivity



, resource id . apktool res/values/public.xml , res/values/strings.xml res/values/ids.xml .







, id «email», — «serial», onCreate()



«Your Android device is rooted!», method_1297()



owl.png



:













, EditText



emailEditText



serialEditText



, :







 protected void onCreate(Bundle var1) { super.onCreate(var1); this.requestWindowFeature(1); this.getWindow().setFlags(1024, 1024); this.setContentView(0x7f09001b); Button var2 = (Button)this.findViewById(0x7f070021); if ((new class_108(this)).method_946()) { Toast.makeText(this, "Your Android device is rooted!", 1).show(); this.finish(); } var2.setOnClickListener(new OnClickListener() { public void onClick(View var1) { MainActivity.emailEditText = (EditText)MainActivity.this.findViewById(0x7f07002e); MainActivity.serialEditText = (EditText)MainActivity.this.findViewById(0x7f070060); MainActivity.this.method_1297(); if (!MainActivity.emailEditText.getText().toString().matches(class_170.field_1366) && !MainActivity.serialEditText.getText().toString().toUpperCase().matches(class_170.field_1366)) { if (class_46.method_502()) { Toast.makeText(MainActivity.this, "Congratulations! You did it!", 1).show(); } else { Toast.makeText(MainActivity.this, "Login Failed.", 1).show(); } } else { Toast.makeText(MainActivity.this, "Login Failed.", 1).show(); } } }); }
      
      





GitHub







Root check



. class_108



, method_350



class_33



com.scottyab.rootbeer



.







 class class_108 { // $FF: renamed from: a android.content.Context private final Context field_937; public class_108(Context var1) { this.field_937 = var1; } public boolean method_946() { return (new class_33(this.field_937)).method_350(); } }
      
      





GitHub , «su» «busybox». com.scottyab.rootbeer.RootBeer::isRooted()







, , if



, class_108



, com.scottyab.rootbeer



, .







GitHub









onCreate()



.

, class_170::field_1366



, class_46::method_502()



. -.







class_170



.







:







class_170
 // $FF: renamed from: q java.lang.String public static String field_1366 = method_1453(method_1452(method_1455(method_1457(method_1451(method_1456(method_1454(method_1458("")))))))); // $FF: renamed from: r java.lang.String public static String field_1367 = method_1453(method_1452(method_1455(method_1457(method_1451(method_1456(method_1454(method_1458("#81]A")))))))); // ... public static String method_1451(String var0) { char[] var2 = var0.toCharArray(); for(int var1 = 0; var1 < var2.length; ++var1) { var2[var1] = (char)(var2[var1] ^ 55); } return new String(var2); } public static String method_1452(String var0) { char[] var2 = var0.toCharArray(); for(int var1 = 0; var1 < var2.length; ++var1) { var2[var1] = (char)(var2[var1] ^ 22); } return new String(var2); } public static String method_1453(String var0) { char[] var2 = var0.toCharArray(); for(int var1 = 0; var1 < var2.length; ++var1) { var2[var1] = (char)(var2[var1] ^ 11); } return new String(var2); } public static String method_1454(String var0) { char[] var2 = var0.toCharArray(); for(int var1 = 0; var1 < var2.length; ++var1) { var2[var1] = (char)(var2[var1] ^ 77); } return new String(var2); } public static String method_1455(String var0) { char[] var2 = var0.toCharArray(); for(int var1 = 0; var1 < var2.length; ++var1) { var2[var1] = (char)(var2[var1] ^ 33); } return new String(var2); } public static String method_1456(String var0) { char[] var2 = var0.toCharArray(); for(int var1 = 0; var1 < var2.length; ++var1) { var2[var1] = (char)(var2[var1] ^ 66); } return new String(var2); } public static String method_1457(String var0) { char[] var2 = var0.toCharArray(); for(int var1 = 0; var1 < var2.length; ++var1) { var2[var1] = (char)(var2[var1] ^ 44); } return new String(var2); } public static String method_1458(String var0) { char[] var2 = var0.toCharArray(); for(int var1 = 0; var1 < var2.length; ++var1) { var2[var1] = (char)(var2[var1] ^ 88); } return new String(var2); }
      
      





, main()



:







class_170::main()
 public static void main(String... args) { System.out.print("package com.kaspersky.zeronights2017.nightwatcher;\n\n"); System.out.print("public class class_170 {\n\n"); System.out.printf(" public static final String field_1350 = \"%s\";%n", field_1350.replaceAll("\n", "\\\\n")); System.out.printf(" public static final String field_1351 = \"%s\";%n", field_1351); System.out.printf(" public static final String field_1352 = \"%s\";%n", field_1352); System.out.printf(" public static final String field_1353 = \"%s\";%n", field_1353); System.out.printf(" public static final String field_1354 = \"%s\";%n", field_1354); System.out.printf(" public static final String field_1355 = \"%s\";%n", field_1355); System.out.printf(" public static final String field_1356 = \"%s\";%n", field_1356); System.out.printf(" public static final String field_1357 = \"%s\";%n", field_1357); System.out.printf(" public static final String field_1358 = \"%s\";%n", field_1358); System.out.printf(" public static final String field_1359 = \"%s\";%n", field_1359); System.out.printf(" public static final String field_1360 = \"%s\";%n", field_1360); System.out.printf(" public static final String field_1361 = \"%s\";%n", field_1361); System.out.printf(" public static final String field_1362 = \"%s\";%n", field_1362); System.out.printf(" public static final String field_1363 = \"%s\";%n", field_1363); System.out.printf(" public static final String field_1364 = \"%s\";%n", field_1364); System.out.printf(" public static final String field_1365 = \"%s\";%n", field_1365); System.out.printf(" public static final String field_1366 = \"%s\";%n", field_1366); System.out.printf(" public static final String field_1367 = \"%s\";%n", field_1367); System.out.printf(" public static final String field_1368 = \"%s\";%n", field_1368); System.out.print("\n}\n\n"); }
      
      





GitHub







:







class_170
 package com.kaspersky.zeronights2017.nightwatcher; public class class_170 { public static final String field_1350 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam et maximus eros. Mauris laoreet molestie semper. Aliquam erat volutpat. Sed euismod neque ac ante viverra pellentesque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras efficitur ac augue a mattis. Nunc facilisis elementum lobortis. Ut vehicula malesuada pharetra. Pellentesque a interdum eros, nec pulvinar sem. Morbi dapibus in quam ut ullamcorper. Vivamus volutpat vehicula condimentum.\n\nNullam commodo vestibulum cursus. Aliquam semper ligula ac tortor rutrum molestie. Vivamus nec orci auctor quam vehicula tempor et id neque. Suspendisse fermentum velit ut ipsum pellentesque hendrerit. Fusce convallis aliquam ante non elementum. Donec at scelerisque lacus, eu eleifend nulla. Pellentesque congue nisi in dolor dignissim, non lobortis neque luctus. Mauris ac cursus turpis. Phasellus finibus facilisis justo, convallis mattis lorem lobortis et. Nam ac interdum est. Etiam ac molestie ligula. Maecenas vel purus a odio accumsan venenatis. Nunc ligula dui, pharetra id arcu laoreet, mollis semper leo. Phasellus id magna molestie, semper risus nec, vehicula sem.\n\nDonec eget nisl purus. Phasellus non nisi felis. Aliquam ut odio sit amet neque euismod vulputate non vel mauris. Suspendisse sit amet ligula sed leo condimentum vulputate convallis eu dui. Vestibulum tortor lacus, maximus quis tincidunt a, pretium sed lacus. Maecenas porta dui nisi, vel molestie tortor luctus at. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam odio ante, sollicitudin sed diam quis, ultricies pretium ex. Proin nisi arcu, tristique id leo et, lacinia semper nisi. Fusce posuere lacus at ex pretium venenatis. Sed porta nibh mauris, ut vestibulum nulla aliquam non. Nunc id tortor non nisi blandit volutpat. Phasellus malesuada hendrerit orci a semper. Nam a risus ac arcu dictum imperdiet.\n\nCras ut risus eget leo ultricies dictum vitae et enim. Aliquam erat volutpat. Fusce ut porttitor nisi. Praesent vel pulvinar orci. Aenean ac libero sed tortor sagittis tristique commodo in velit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam eu enim orci. Nullam consectetur lobortis tellus, ac facilisis ex dapibus sed.\n\nAliquam mollis eget turpis id vestibulum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque vitae lectus non metus convallis aliquam. Donec rutrum tincidunt quam, iaculis gravida nisl dictum id. Donec malesuada dapibus magna tristique convallis. Curabitur at turpis sed tellus accumsan condimentum. Nam accumsan nisi a ex hendrerit, in sagittis turpis feugiat. Morbi congue et est eu venenatis. Phasellus erat dui, rutrum sit amet fringilla sit amet, imperdiet in nulla. Quisque laoreet neque ac augue sodales, at mollis magna mollis. Mauris nec consectetur purus, quis aliquam leo. Sed lobortis magna efficitur vehicula finibus."; public static final String field_1351 = "ABCDEFGHIJKLONMPQRSTVUWXYZabcdefghijlkmnopqrstuvwxyz5193406782+/"; public static final String field_1352 = "0123456789ABCDEF"; public static final String field_1353 = "dGUzc9RhdGEv"; public static final String field_1354 = "/whoami/"; public static final String field_1355 = "who"; public static final String field_1356 = "am"; public static final String field_1357 = "i"; public static final String field_1358 = "d9hvLnRyYWkuZWRlYXRh"; public static final String field_1359 = "YW5udHJhaW0kZGRhdGE="; public static final String field_1360 = "aS05cmFpbmUlZGF5YQ=="; public static final String field_1361 = "[^"; public static final String field_1362 = "=]"; public static final String field_1363 = "="; public static final String field_1364 = "AA"; public static final String field_1365 = "A"; public static final String field_1366 = ""; public static final String field_1367 = "SHA-1"; public static final String field_1368 = "UTF-8"; }
      
      





GitHub







BASE64



- , «Inline all and remove the field».







class_87 : "AA"



, "A"



, "="



, 64- class_170::field_1351



, "dGUzc9RhdGEv"



, "d9hvLnRyYWkuZWRlYXRh"



, "YW5udHJhaW0kZGRhdGE="



"aS05cmFpbmUlZGF5YQ=="



, class_87::method_802()



. , class_87



BASE64 encoder/decoder . , class_170::field_1351



U



V



, .







, , . , IDEA/Android Studio . .







class_170



.







GitHub







BASE64-, , .







: field_1181



MainActivity



MainActivity::method_1300()



. , .







 private void method_1300(String resourceName) { try { StringBuilder var5 = new StringBuilder(); String var12 = var5.append(this.field_1180).append(this.field_1181).append(CustomBase64.decode(resourceName)).toString(); AssetManager var6 = this.getAssets(); StringBuilder var7 = new StringBuilder(); InputStream var9 = var6.open(var7.append(this.field_1181).append(resourceName).toString()); FileOutputStream var14 = new FileOutputStream(var12); // ...
      
      





:







 private void method_1299(File destDir, String resourceName, String outputFileName) { if (!destDir.exists() && destDir.mkdirs()) { this.method_1300(resourceName, outputFileName); } if (destDir.exists() && !(new File(this.field_1180 + this.field_1181 + resourceName)).exists()) { this.method_1300(resourceName, outputFileName); } } private void method_1300(String resourceName, String outputFileName) { try { String var12 = this.field_1180 + this.field_1181 + outputFileName; AssetManager assets = this.getAssets(); InputStream inputStream = assets.open(this.field_1181 + resourceName); FileOutputStream outputStream = new FileOutputStream(var12); // ...
      
      





, . , class_170



:







 public static void main(String... args) { System.out.printf("\"%s\"\t\"%s\"%n", "dGUzc9RhdGEv" , decode("dGUzc9RhdGEv" )); System.out.printf("\"%s\"\t\"%s\"%n", "d9hvLnRyYWkuZWRlYXRh", decode("d9hvLnRyYWkuZWRlYXRh")); System.out.printf("\"%s\"\t\"%s\"%n", "YW5udHJhaW0kZGRhdGE=", decode("YW5udHJhaW0kZGRhdGE=")); System.out.printf("\"%s\"\t\"%s\"%n", "aS05cmFpbmUlZGF5YQ==", decode("aS05cmFpbmUlZGF5YQ==")); }
      
      





:







dGUzc9RhdGEv tessdata/
d9hvLnRyYWkuZWRlYXRh who.traineddata
YW5udHJhaW0kZGRhdGE= am.traineddata
aS05cmFpbmUlZGF5YQ== i.traineddata


, , , .







GitHub









, class_44



, .







, class_170



, , . , method_465()



:







 public static int field_368 = ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( method_465(0, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0) + method_465(0, 0) ) * method_465(1, 0) * method_465(1, 0); // ... public static int method_465(int var0, int var1) { return var0 + var1; }
      
      





, — . «Inline all and remove the method» , :







 public static int field_368 = ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( 0 + 0 + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0) + 0 + 0 ) * (1 + 0) * (1 + 0);
      
      





, IntelliJ IDEA/Android Studio . Alt-Enter



, «Compute constant value of ...». — .







, . :







 public static int field_368 = 0;
      
      





class_44



, .







GitHub









class_46::method_502()



. , , , :







 class class_46 { public static boolean method_502() { boolean var0; if (2949 / 240 * 4 - 8 == MainActivity.serialEditText.getText().toString().toUpperCase().length() && class_135.method_1132( class_135.method_1133( CustomBase64.encode(MainActivity.field_1179.getBytes()) + MainActivity.emailEditText.getText().toString() ) ).equals(MainActivity.serialEditText.getText().toString().toUpperCase())) { var0 = true; } else { var0 = false; } return var0; } }
      
      





:







 class SerialValidator { public static boolean validateSerial() { String email = MainActivity.emailEditText.getText().toString(); String serial = MainActivity.serialEditText.getText().toString().toUpperCase(); String expectedSerial = class_135.method_1132( class_135.method_1133( CustomBase64.encode(MainActivity.field_1179.getBytes()) + email ) ); return (serial.length() == 40) && serial.equals(expectedSerial); } }
      
      





GitHub







40 , . . , crackme , .







, «email» , BASE64. class_135::method_1133()



, . , SHA-1 .







 public static String method_1132(String var0) { try { MessageDigest var2 = MessageDigest.getInstance("SHA-1"); StringBuilder var3 = new StringBuilder(var2.digest(var0.getBytes("UTF-8")).length); for(int var1 = 0; var1 < var2.digest(var0.getBytes("UTF-8")).length; ++var1) { var3 .append(HEX_DIGITS.charAt(var2.digest(var0.getBytes("UTF-8"))[var1] >> 4 & 15)) .append(HEX_DIGITS.charAt(var2.digest(var0.getBytes("UTF-8"))[var1] & 15)); } var0 = var3.toString(); return var0; } catch (UnsupportedEncodingException | NoSuchAlgorithmException var4) { var4.printStackTrace(); return null; } }
      
      





, MainActivity::field_1179



.









MainActivity::method_1297()



:







 private void method_1297() { // 0x7f060062: type="drawable" name="owl" Bitmap var1 = BitmapFactory.decodeResource(this.getResources(), 0x7f060062); TessBaseAPI var2; if (VERSION.SDK_INT > 19) { this.field_1180 = this.getFilesDir() + field_1354; var2 = new TessBaseAPI(); this.method_1299(new File(this.field_1180 + this.field_1181), "d9hvLnRyYWkuZWRlYXRh", "who.traineddata"); var2.method_997(this.field_1180, field_1355); var2.method_996(var1); field_1179 = var2.method_995(); this.method_1299(new File(this.field_1180 + this.field_1181), "YW5udHJhaW0kZGRhdGE=", "am.traineddata"); var2.method_997(this.field_1180, field_1356); var2.method_996(var1); field_1179 = field_1179 + var2.method_995(); this.method_1299(new File(this.field_1180 + this.field_1181), "aS05cmFpbmUlZGF5YQ==", "i.traineddata"); var2.method_997(this.field_1180, field_1357); var2.method_996(var1); field_1179 = field_1179 + var2.method_995(); } else { this.field_1180 = this.getFilesDir() + field_1354; var2 = new TessBaseAPI(); this.method_1299(new File(this.field_1180 + this.field_1181), "d9hvLnRyYWkuZWRlYXRh", "who.traineddata"); var2.method_997(this.field_1180, field_1355); var2.method_996(var1); field_1179 = var2.method_995().split("\n")[0]; this.method_1299(new File(this.field_1180 + this.field_1181), "YW5udHJhaW0kZGRhdGE=", "am.traineddata"); var2.method_997(this.field_1180, field_1356); var2.method_996(var1); field_1179 = field_1179 + var2.method_995().split("\n")[0]; this.method_1299(new File(this.field_1180 + this.field_1181), "aS05cmFpbmUlZGF5YQ==", "i.traineddata"); var2.method_997(this.field_1180, field_1357); var2.method_996(var1); field_1179 = field_1179 + var2.method_995().split("\n")[0]; } }
      
      





, - , field_1179



.







, (VERSION.SDK_INT <= 19)



, else



- .







. com.googlecode.tesseract.android.TessBaseAPI



. native- Android- OCR- Tesseract .







, tess-two . , API .







TessBaseAPI



, , native-, GitHub. . , . , . crackme , .







結果:







 private void computeSalt() { // 0x7f060062: type="drawable" name="owl" Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), 0x7f060062); TessBaseAPI tessBaseAPI; if (VERSION.SDK_INT > 19) { this.dataPath = this.getFilesDir() + DIRNAME_WHOAMI; tessBaseAPI = new TessBaseAPI(); this.method_1299(new File(this.dataPath + this.DIRNAME_TESSDATA), "d9hvLnRyYWkuZWRlYXRh", "who.traineddata"); tessBaseAPI.init(this.dataPath, LANGANAME_WHO); tessBaseAPI.setImage(bitmap); SALT = tessBaseAPI.getUTF8Text(); this.method_1299(new File(this.dataPath + this.DIRNAME_TESSDATA), "YW5udHJhaW0kZGRhdGE=", "am.traineddata"); tessBaseAPI.init(this.dataPath, LANGANAME_AM); tessBaseAPI.setImage(bitmap); SALT = SALT + tessBaseAPI.getUTF8Text(); this.method_1299(new File(this.dataPath + this.DIRNAME_TESSDATA), "aS05cmFpbmUlZGF5YQ==", "i.traineddata"); tessBaseAPI.init(this.dataPath, LANGANAME_I); tessBaseAPI.setImage(bitmap); SALT = SALT + tessBaseAPI.getUTF8Text(); } else { // ... } }
      
      





, . , "who"



, "am"



, "i"



, crackme MainActivity::method_1299()



.







GitHub







MainActivity::method_1299()



:







 private void method_1299(File destDir, String resourceName, String outputFileName) { if (!destDir.exists() && destDir.mkdirs()) { this.method_1300(resourceName, outputFileName); } if (destDir.exists() && !(new File(this.dataPath + this.DIRNAME_TESSDATA + resourceName)).exists()) { this.method_1300(resourceName, outputFileName); } }
      
      





, if



, - , , , , if



. , , — .







, , , Tesseract Android.







, :







 private void checkFile(File dir) { //directory does not exist, but we can successfully create it if (!dir.exists()&& dir.mkdirs()){ copyFiles(); } //The directory exists, but there is no data file in it if(dir.exists()) { String datafilepath = datapath+ "/tessdata/eng.traineddata"; File datafile = new File(datafilepath); if (!datafile.exists()) { copyFiles(); } } }
      
      





MainActivity::method_1300()



, xor 0x14



, try-catch .







, :













*.traineddata GitHub









, , , . Tesseract 4.xx, *.traineddata



.







:









, 0 DPI, . , «Raw line» , DPI .







 $ tesseract --tessdata-dir ./tessdata -psm 13 -l who owl.png stdout Warning. Invalid resolution 0 dpi. Using 70 instead. 7F6B45B $ tesseract --tessdata-dir ./tessdata -psm 13 -l am owl.png stdout Warning. Invalid resolution 0 dpi. Using 70 instead. 6E8AC25D6A9 $ tesseract --tessdata-dir ./tessdata -psm 13 -li owl.png stdout Warning. Invalid resolution 0 dpi. Using 70 instead. 9E7DB916E40FD0
      
      





*.traineddata



, — , « ».







"7F6B45B6E8AC25D6A99E7DB916E40FD0"



SALT



, com.googlecode.tesseract



, , .







GitHub







Keygen



.







K2017Crackme3Keygen



, E-Mail, crackme, SerialValidator::validateSerial()



:







 import com.kaspersky.zeronights2017.nightwatcher.CustomBase64; import com.kaspersky.zeronights2017.nightwatcher.MainActivity; import com.kaspersky.zeronights2017.nightwatcher.class_135; public class K2017Crackme3Keygen { public static void main(String... args) { System.out.print("E-Mail: "); String email = System.console().readLine(); String expectedSerial = class_135.method_1132( class_135.method_1133( CustomBase64.encode(MainActivity.SALT.getBytes()) + email ) ); System.out.printf("Serial: %s", expectedSerial); } }
      
      





CustomBase64.encode(MainActivity.SALT.getBytes())



TRUE_SALT



, , :







K2017Crackme3Keygen.java
 import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class K2017Crackme3Keygen { public static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam et maximus eros. Mauris laoreet molestie semper. Aliquam erat volutpat. Sed euismod neque ac ante viverra pellentesque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras efficitur ac augue a mattis. Nunc facilisis elementum lobortis. Ut vehicula malesuada pharetra. Pellentesque a interdum eros, nec pulvinar sem. Morbi dapibus in quam ut ullamcorper. Vivamus volutpat vehicula condimentum.\n\nNullam commodo vestibulum cursus. Aliquam semper ligula ac tortor rutrum molestie. Vivamus nec orci auctor quam vehicula tempor et id neque. Suspendisse fermentum velit ut ipsum pellentesque hendrerit. Fusce convallis aliquam ante non elementum. Donec at scelerisque lacus, eu eleifend nulla. Pellentesque congue nisi in dolor dignissim, non lobortis neque luctus. Mauris ac cursus turpis. Phasellus finibus facilisis justo, convallis mattis lorem lobortis et. Nam ac interdum est. Etiam ac molestie ligula. Maecenas vel purus a odio accumsan venenatis. Nunc ligula dui, pharetra id arcu laoreet, mollis semper leo. Phasellus id magna molestie, semper risus nec, vehicula sem.\n\nDonec eget nisl purus. Phasellus non nisi felis. Aliquam ut odio sit amet neque euismod vulputate non vel mauris. Suspendisse sit amet ligula sed leo condimentum vulputate convallis eu dui. Vestibulum tortor lacus, maximus quis tincidunt a, pretium sed lacus. Maecenas porta dui nisi, vel molestie tortor luctus at. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam odio ante, sollicitudin sed diam quis, ultricies pretium ex. Proin nisi arcu, tristique id leo et, lacinia semper nisi. Fusce posuere lacus at ex pretium venenatis. Sed porta nibh mauris, ut vestibulum nulla aliquam non. Nunc id tortor non nisi blandit volutpat. Phasellus malesuada hendrerit orci a semper. Nam a risus ac arcu dictum imperdiet.\n\nCras ut risus eget leo ultricies dictum vitae et enim. Aliquam erat volutpat. Fusce ut porttitor nisi. Praesent vel pulvinar orci. Aenean ac libero sed tortor sagittis tristique commodo in velit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam eu enim orci. Nullam consectetur lobortis tellus, ac facilisis ex dapibus sed.\n\nAliquam mollis eget turpis id vestibulum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque vitae lectus non metus convallis aliquam. Donec rutrum tincidunt quam, iaculis gravida nisl dictum id. Donec malesuada dapibus magna tristique convallis. Curabitur at turpis sed tellus accumsan condimentum. Nam accumsan nisi a ex hendrerit, in sagittis turpis feugiat. Morbi congue et est eu venenatis. Phasellus erat dui, rutrum sit amet fringilla sit amet, imperdiet in nulla. Quisque laoreet neque ac augue sodales, at mollis magna mollis. Mauris nec consectetur purus, quis aliquam leo. Sed lobortis magna efficitur vehicula finibus."; public static final String ALPHABET = "ABCDEFGHIJKLONMPQRSTVUWXYZabcdefghijlkmnopqrstuvwxyz5193406782+/"; public static final String HEX_DIGITS = "0123456789ABCDEF"; public static final String TRUE_SALT = "N5Y9QjQ1QjZFMEFDOjUENlE0MVV3REI0OTZFNDBGRDA="; public static void main(String... args) { System.out.print("E-Mail: "); String email = System.console().readLine(); String expectedSerial = calculateSha1Hex(method_1133(TRUE_SALT + email)); System.out.printf("Serial: %s", expectedSerial); } private static String method_1131(String s1, String s2) { StringBuilder stringBuilder = new StringBuilder(""); for(int i = 0; i < 256; i++) { stringBuilder.append(String.valueOf(s1.charAt(i) ^ s2.charAt(i % s2.length()))); } return encodeCustomBase64(stringBuilder.toString().getBytes()); } public static String method_1133(String s) { StringBuilder stringBuilder = new StringBuilder(""); for(int i = 0; i < 256; i++) { int var2 = ((i << 4 | i) << 240 * i) % 2000000 % 2949; stringBuilder.append(LOREM_IPSUM.substring(var2, 1 + var2)); } return method_1131(stringBuilder.toString(), s); } public static String calculateSha1Hex(String s) { try { byte[] bytes = s.getBytes(StandardCharsets.UTF_8); MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); StringBuilder stringBuilder = new StringBuilder(messageDigest.digest(bytes).length); for(int i = 0; i < messageDigest.digest(bytes).length; i++) { stringBuilder .append(HEX_DIGITS.charAt(messageDigest.digest(bytes)[i] >> 4 & 0xf)) .append(HEX_DIGITS.charAt(messageDigest.digest(bytes)[i] & 0xf)); } return stringBuilder.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } public static String encodeCustomBase64(byte[] bytes) { char[] alphabetChars = ALPHABET.toCharArray(); StringBuilder stringBuilder = new StringBuilder(); int var1 = 0; int var2; for(int i = 0; i < bytes.length; i += 3) { var2 = (bytes[i] & 0xff) << 16 & 0xffffff; if (1 + i < bytes.length) { var2 |= (bytes[1 + i] & 0xff) << 8; } else { var1++; } if (2 + i < bytes.length) { var2 |= bytes[2 + i] & 0xff; } else { var1++; } int var4 = var2; for(var2 = 0; var2 < 4 - var1; var2++) { stringBuilder.append(alphabetChars[(0xfc0000 & var4) >> 18]); var4 <<= 6; } } for(var2 = 0; var2 < var1; var2++) { stringBuilder.append("="); } return stringBuilder.toString(); } }
      
      





.







GitHub







確認する



チェックとして、文字列のキーを生成しますHabrahabr





crackmeのフィールドは「電子メール」と呼ばれますが、入力テキストの検証はありません。







 $ java K2017Crackme3Keygen E-Mail: Habrahabr Serial: 3C882D5EC917F92D6637F986BA6DAE02CD7E49E3
      
      





crackmeを実行する時が来ました:













キーは本当で、仕事は完了です。








All Articles