Skip to content

本プラットフォームが提供するゲームセキュリティ保護ソリューションにおいて、CLI版ハードニングツールの利用者は、apkまたはaabファイルがSO単独モードハードニング機能を使用した後、必ずハードニング後のゲームが正常に動作することを検証してください。

元ドキュメント: Single File Guide

使用前の注意事項

  1. SO単独ハードニングモードは特定のSOファイルのみ暗号化をサポートしており、ホットアップデート等のシナリオに適しています。
  2. SO単独ハードニングモードの実行時、apk/aabパッケージ単位で行われます。入力・出力ともに完全なapk/aabパッケージですが、ハードニングプロセスでは選択されたSOファイルのみ保護し、他のファイルは変更しません。ゲーム側はハードニング後のapk/aabパッケージからハードニングされた対象ファイルを抽出し、対象ファイルに対してホットアップデートやその他の後続処理を行う必要があります。

ツール説明

CLI版ハードニングツールを使用すると、ハードニングと署名プロセスをCIフローに統合できます。わずか1行のコードでハードニングと署名の自動化を実現できます。

特記事項:

  1. 本ツールが対応しているゲームバージョン:Androidゲーム

  2. 本ツールが対応しているOS:Windows、macOS、Linux(WindowsおよびLinuxシステムについて、それぞれx86版とx64版のツールを提供していますので、お使いのPCのOS構成を確認してから対応するツールバージョンを選択してください)

  3. 本ツール実行時、まずゲームの認証を行います。本プラットフォームは各ゲームにcert形式の証明書を発行します。ダウンロードしたツールパッケージに対応ゲームの証明書がない場合は、カスタマーサービスにお問い合わせください

  4. 本ツールは2種類のハードニングを提供します:APKハードニング、App Bundleハードニング

  5. MacおよびLinuxシステムでツールを呼び出す前に、まずツールに権限を付与してください:ツール所在ディレクトリで以下を実行します

    xml
    cd where_your_mtpclientconsole_dir
    chmod -R 777 ./*

APKハードニング

呼び出し方法:

cmd
cd where_your_mtpclientconsole_dir
MTPClientConsole.exe -d <gameId> <apkpath> <outDir> <certPath> -c <configPath>

パラメータ説明:

パラメータ説明
-d標準版(デフォルトオプション、変更不可)
gameIdゲームID(コンソール登録)
apkPathハードニング対象apkファイルの完全パス(パスに非ASCII文字を含めないでください)
outDirハードニング後apkファイルの出力先完全パス(パスに非ASCII文字を含めないでください)
certPathゲームIDに対応する証明書パス(証明書名はGame_ID.cert、パスに非ASCII文字を含めないでください)
-c設定ファイル呼び出し(デフォルトオプション、変更不可)
configPathtpshell-config.xml設定ファイルのパス(パスに非ASCII文字を含めないでください)。設定ファイル内のタグペアは同一行に配置し、ファイル名は.xmlで終わる必要があります

App Bundleハードニング

App Bundleハードニングモード。Android App BundleはGoogleが最新リリースしたAPKダイナミックパッケージング・ダイナミックコンポーネント化技術で、最終的に.aabで終わるbundleファイルが生成されます。

呼び出し方法:

cmd
cd where_your_mtpclientconsole_dir
MTPClientConsole.exe -a <gameId> <aabPath> <outDir> <certPath> -c <configPath>

パラメータ説明:

パラメータ説明
-aAppBundle版(デフォルトオプション、変更不可)
gameIdゲームID(コンソール登録)
aabPathハードニング対象aabファイルの完全パス(パスに非ASCII文字を含めないでください)
outDirハードニング後apkファイルの出力先完全パス(パスに非ASCII文字を含めないでください)
certPathゲームIDに対応する証明書パス(証明書名はGame_ID.cert、パスに非ASCII文字を含めないでください)
-c設定ファイル呼び出し(デフォルトオプション、変更不可)
configPathtpshell-config.xml設定ファイルのパス(パスに非ASCII文字を含めないでください)。設定ファイル内のタグペアは同一行に配置し、ファイル名は.xmlで終わる必要があります

tpshell-config.xml設定ファイルの記述例:

xml
<?xml version="1.0" encoding="utf-8"?>
<!-- This configuration only configures basic properties -->
<Config>
	<!--Server Tools Version, please use default value and modify it after contacting with customer service-->
	<TPVersion>default</TPVersion>
    <!--ToolPath: tools location,default ClientConsole/tools or cut this atrribute-->
    <ToolPath>your_tool_absolute_path</ToolPath>
    <!--TPSvrHost: provite server host if you deploy a private svr. Use official host when not set. -->
    <!--TPSvrHost>your_private_svr_host</TPSvrHost-->
    <!-- Sign: information of keystore when using local sign-->
    <Sign>
        <sign-argument name = "keystorePath" value="your_keystore_absolute_path"/>
        <sign-argument name = "keypass" value="123456"/>
        <sign-argument name = "storepass" value="123456"/>
        <sign-argument name = "alianame" value="test"/>
        <!-- This config is obsolete -->
        <!-- <sign-argument name = "v1SigningEnabled" value="true"/>
        <sign-argument name = "v2SigningEnabled" value="false"/>
        <sign-argument name = "v3SigningEnabled" value="false"/> -->
    </Sign>    

    <!-- EncSo: so fileName that you want to encrypt, less than 5 files for performance-->
    <EncSo>libmono.so</EncSo>
    <!-- Encrypt global-metadata requires configuring libil2cpp.so and enable_globalmetadata_enc to true-->
    <EncSo>libil2cpp.so</EncSo>
    <EncSo>libGameCore.so</EncSo>
    <!-- if you want so independent enc,just add: "enc_independent": true to extparams -->
    <extparams>{
        "enable_globalmetadata_enc" : false,
        "enc_independent": true
    }
    </extparams>
</Config>

tpshell-config設定ファイル説明:

設定項目説明
TPVersion必須項目、ハードニングバージョン番号を指定
ToolPathCLI版ハードニングツールの実行にはツールパッケージ内のtoolsディレクトリ情報に依存しますので、そのtoolsディレクトリの完全な絶対パスを記入してください(引用符不要)
Sign任意項目、署名証明書情報。ゲーム開発者が提供します
keystorePathキーストアファイルのパス、文字列型(絶対パスを記入してください)
keyPassキーパスワード、文字列型
storePassストアパスワード、文字列型
aliaNameエイリアス、文字列型
EncSo暗号化対象.soファイル名リスト。メインのゲームロジック.soのみ選択することをお勧めします。暗号化.so数が多すぎるとゲームパフォーマンスに影響します(引用符不要)
enable_globalmetadata_encglobal-metadata.dat暗号化機能の有無。il2cpp.soファイル暗号化と同時でのみ有効。"true"または"false"のみ
enc_independentSO単独ハードニング機能の有無。"true"または"false"のみ

特記事項:

*TPVersionについて: コマンドラインツール付属のデフォルトバージョンの使用をお勧めします。バージョンの変更が必要な場合は当社までご連絡ください。

*署名について: ローカル署名を使用する場合、証明書および証明書情報のアップロードは不要で、keystorePath、storePass、keyPass、aliaNameの署名情報を記入するだけでOKです。 APKハードニング、App Bundleハードニングともに、署名方式はハードニング前後で同一バージョンを維持し、v1、v2、v3の設定は不要です。署名情報未記入・誤記入、またはハードニング対象パッケージが未署名の場合、デフォルトで署名せず、ハードニング後のゲームは手動署名が必要になります。一般的にaabパッケージはv1署名のみ使用します。

*暗号化ファイルリストについて: EncSoが空リストまたは未記入の場合、デフォルトでlibmono.soファイル、libil2cpp.soファイルなどを暗号化します。

*SO単独ハードニングモードについて: enc_independentフィールドはファイルSO単独ハードニングモードを有効にするための設定で、ハードニングバージョン3.0以上でのみサポートされています。

*global-metadata.dat暗号化について: enable_globalmetadata_encフィールドはglobal-metadata.dat暗号化を有効にするための設定で、同時にil2cpp.soファイルを暗号化する必要があります。デフォルトは無効です。ハードニングバージョン2.6でのみカスタム設定をサポートしています。

*高速アップロードについて: 本バージョンのCLI版ハードニングツールには高速アップロード機能が統合されており、ネットワーク転送内容を精簡し転送速度を向上させています。また、完全パッケージのアップロードは不要です。

一般的な返却結果

パラメータ説明
The shelling task was finishedハードニングタスク完了
Shell failed for time outハードニングタイムアウト失敗
Configuration error設定解析エラー
Command line parameter errorコマンドラインパラメータエラー
Shelling errorシェルエラー
Local client errorローカルクライアントエラー
Server errorサーバーエラー

バッチ処理疑似コード

注意

シェリング処理には多くのIO操作が含まれます。マシンのCPUやネットワーク帯域を考慮し、同時実行プロセス数は10個以下(マシンパフォーマンスに応じて調整)にすることをお勧めします。スレッドプールを使用して大量のインストールパッケージをバッチ処理します。

ディレクトリ構造:

py
#/usr/local/bin/python3
import os
import sys
import time
import shutil
from contextlib import contextmanager
from multiprocessing import Pool
import subprocess

g_temp_out = os.path.realpath("./multi_out")
g_is_aab_shell = False
@contextmanager
def _cwd(path):
    #change workspace into multichannel
    saved_dir = os.getcwd()
    if path is not None:
        os.chdir(path)
    try:
        yield
    finally:
        os.chdir(saved_dir)

def get_timestamp():
    now = int(round(time.time()*1000))
    now = time.strftime('%Y%m%d%H%M%S',time.localtime(now/1000))
    return now

def shell_sub_main(apk_absolute_path):
    channal_name = get_timestamp() + "_" + os.path.basename(apk_absolute_path).replace(".apk", "")
    workspace = os.path.join(g_temp_out, channal_name)
    if os.path.isdir(workspace):
        shutil.rmtree(workspace)
    os.makedirs(workspace)
    result = {apk_absolute_path:"None"}
    with _cwd(workspace):
        '''
        here run console command
        note:
        use Absolute Path in config!!!
        '''
        #customize your config begin
        mtpclient_absolute_path = "MTPClientConsole" # Absolute MTPClientConsole path
        shell_type = "-a" if g_is_aab_shell else "-d"
        gameid = "12345" #your gameid
        output_dir = "./"
        cert = "12345.cert" #your cert
        config_xml = "tpshell-config.xml" #your tpshell config
        #customize your config end
        
        cmd = "%s %s %s %s %s %s -c %s" %(mtpclient_absolute_path,shell_type,gameid,apk_absolute_path,output_dir,cert,config_xml)
        pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
        print("workace:",workspace)
        while True:
            line = pipe.stdout.readline()
            if not line:
                break
            line = line.decode("utf-8", "ignore").replace("\r","").replace("\n","")
            print(line)
            if "The shelling task was finished" in line:
                if "apkPath" in line:
                    output = line.split("apkPath:")[1][:-1]
                else:
                    output = line.split("aabPath:")[1][:-1]
                result[apk_absolute_path] = output

    return result

def process_result(results):
    # You can customize the processing result
    for result in results:
        print(result)
        for k,v in result.items():
            if v == "None":
                print("input:%s shell FAILED!!!"%(k))
            else:
                print("input:%s shell ok,output:%s"%(k,v))
    return

def shell_main():
    inDir = os.path.realpath("./in")
    files = os.listdir(inDir)
    tasks = []
    for fi in files:
        path = "%s/%s"%(inDir, fi)
        if fi.endswith(".apk"):
            tasks.append(path)
    pool = Pool(maxtasksperchild=1)
    ret = pool.map_async(shell_sub_main, tasks, callback=process_result)
    pool.close()
    pool.join()
    if ret.successful():
        print("all over,result:",ret.get())
    else:
        print("something wrong,please check")

if __name__ == '__main__':
    shell_main()

Tencent Cloud プロダクトドキュメント