Android apkはどのように解読を防ぐか(逆コンパイルを防ぐ)を強化します


今主なツールはSDKに接触して、ゲームパッケージが解読されてコンパイルされることを防止して、および暗号化の列を発見するために、私は以下のいくつかの点を分かち合います:解読防止技術は主に4種類の実現方式があります:1.コード混同(ProGuard)技術2.署名比較技術3.NDK .soダイナミックライブラリ技術4.動的ロード技術5.サードパーティ製プラットフォームの暗号化および脆弱性の検出
これはAndroidセキュリティがapkパッケージをどのように逆コンパイルするかという文章でも関連する知識点に言及している.
  • 第1種:コード混同技術(ProGuard)この技術は主にコード混同を行い、コード逆コンパイル後の可読性を低減するが、この技術は加殻技術による加殻(吸費、広告、ウイルスなどのコードの加入)を防止することができず、また細心の注意を払う人であれば、コードに対して依然としてコードを逆方向に分析することができるため、この技術は根本的に問題を解決していない.解読の難しさを増しただけだ.
  • 第2種:署名比対技術この技術は主にシェル技術のシェル化を防止するが、コード逆分析リスクは依然として存在する.また,この技術は殻付けされた問題を根本的に解決することはできず,解読者が署名をコードに注釈してからコンパイルすれば,この技術は解読される.
  • 第3種:NDK.soダイナミックライブラリ技術は、重要なコアコードをすべてCファイルに格納、NDK技術を利用してコアコードをコンパイルすることを実現する.soダイナミックライブラリ、JNIで呼び出します.この技術はコアコードを保護することができるが、シェルされるリスクは依然として存在する.
  • 第4種:動的ロード技術、Javaでは比較的成熟した技術であり、Androidではまだ十分に利用されていない.
  • 第5種:サードパーティプラットフォームは主に第4種の方法を説明し、この技術は逆方向分析、解読、殻付けなどの問題を効果的に防止することができ、動的ロード技術は以下のステップに分けられる:
  • コアコードをdexファイルにコンパイルするJarパッケージ
  • jarパケットの暗号化処理
  • プログラムメインエントリでNDKによる復号
  • ClassLoaderを再利用してjarパッケージを動的にロードする
  • .
  • は、反射技術を用いてClassLoaderをシステムのClassLoaderに設定する.

  • 主な利点は、1.コアコードは暗号化されたjarにあるため、解読者はclassファイルを解凍することができず、暗号化鍵が解読者に渡されると、別のレベルのセキュリティ問題になります.      2.この技術はシェル技術を効果的に防止することができ、コードは動的にロードされ、解読者のシェルプログラムは暗号化されたjarパケットに加入することができず、直ちに解読者がシェルプログラムの入り口に注入する.シェルプログラムはClassLoaderのjarパケットに含まれていないため、解読者がClassLoaderのjarパケットを置き換え、NDK解読コードをオフにしない限り、実行することはできない.しかし、このような携帯電話へのインストールは、すでに私たちのアプリケーションではなく、ユーザーは必ずアンインストールします.
    だから総合的に比較して、第4種類のダイナミックロード技術は最も安全で、しかし効率の問題、本人は厳格なテストをしていないで、ざっと実験して、効率は明らかに下がっていません.
    //   1.Jar         //  
    public static boolean enOrDecryptFile(byte[] paramArrayOfByte,  
            String sourceFilePath, String destFilePath,int mode){  
        File sourceFile = new File(sourceFilePath);  
        File destFile = new File(destFilePath);  
        CipherOutputStream cout = null;  
        FileInputStream in  = null;  
        FileOutputStream out = null;  
        if (sourceFile.exists() && sourceFile.isFile()) {  
            if (!destFile.getParentFile().exists()) {  
                destFile.getParentFile().mkdirs();  
            }  
            try {  
                destFile.createNewFile();  
                in = new FileInputStream(sourceFile);  
                out = new FileOutputStream(destFile);  
                //     //  
                init();  
                SecretKeySpec secretKeySpec = new SecretKeySpec(defPassword, "AES");  
                Cipher cipher;  
                cipher = Cipher.getInstance("AES");  
                cipher.init(mode, secretKeySpec);  
                cout = new CipherOutputStream(out, cipher);  
                byte[] cache = new byte[CACHE_SIZE];  
                int nRead = 0;  
                while ((nRead = in.read(cache)) != -1) {  
                    cout.write(cache, 0, nRead);  
                    cout.flush();  
                }  
            }catch (IOException e) {  
                e.printStackTrace();  
                return false;  
            } catch (NoSuchAlgorithmException e) {  
                e.printStackTrace();  
                return false ;  
            } catch (NoSuchPaddingException e) {  
                e.printStackTrace();  
                return false ;  
            }catch (InvalidKeyException e) {  
                e.printStackTrace();  
                return false;  
            }finally{  
                    if(cout != null){  
                        try {  
                            cout.close();  
                        } catch (IOException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    if(out != null){  
                        try {  
                            out.close();  
                        } catch (IOException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    if(in != null){  
                        try {  
                            in.close();  
                        } catch (IOException e) {  
                            e.printStackTrace();  
                        }  
                    }  
            }  
            return true;  
        }  
        return false;  
    }  

    JArはSDKplatform-toolsの下のdxコマンドでdex形式変換
    dx   --dex    --output=          (    )          jar  (    )
                             :dx --dex --output=H:\classdex.jar     H:\dujinyang-KARL.jar

    そして暗号化ツールでjarファイルを生成して暗号化処理を行います
    最後に、コードを使用して動的にロードします.
    File file = new File("/data/data/" + base.getPackageName() + "/.cache/");  
            if (!file.exists()) {  
                file.mkdirs();  
            }  
            try {  
                Runtime.getRuntime().exec("chmod 755 " + file.getAbsolutePath()).waitFor();  
            } catch (InterruptedException e1) {  
                // TODO Auto-generated catch block  
                e1.printStackTrace();  
            } catch (IOException e1) {  
                // TODO Auto-generated catch block  
                e1.printStackTrace();  
            }  
            Util.copyJarFile(this);  
            Object currentActivityThread = RefInvoke.invokeStaticMethod(  
                    "android.app.ActivityThread", "currentActivityThread",  
                    new Class[] {}, new Object[] {});  
            String packageName = getPackageName();  
            HashMap mPackages = (HashMap) RefInvoke.getFieldOjbect(  
                    "android.app.ActivityThread", currentActivityThread,  
                    "mPackages");  
            WeakReference wr = (WeakReference) mPackages.get(packageName);  
            MyClassLoader dLoader = new MyClassLoader("/data/data/"  
                    + base.getPackageName() + "/.cache/classdex.jar", "/data/data/"  
                    + base.getPackageName() + "/.cache", "/data/data/"  
                    + base.getPackageName() + "/.cache/", base.getClassLoader());  
            try {  
                Class>  class1 = dLoader.loadClass("com.example.test.TestActivity");  
                Log.i("b364","----------->class1: "+class1);  
            } catch (ClassNotFoundException e){  
                Log.i("b364","----------->class not found Exception!");  
                e.printStackTrace();  
            }  
            Log.i("b364","------>PackageInfo: "+wr.get());  
            // DexClassLoader dLoader = new DexClassLoader(apkFileName, odexPath,  
            // libPath, (ClassLoader) RefInvoke.getFieldOjbect(  
            // "android.app.LoadedApk", wr.get(), "mClassLoader"));  
            RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader",  
                    wr.get(), dLoader);  

    処理が完了し、アプリケーションで特別な処理をすれば可能です.以前から暗号化が好きな暗号化方式を分析していたが、ここでは述べず、興味があれば一緒に議論することができる.
    次の記事では、apkのダイナミックライブラリを逆方向に使用する方法について説明します.