最近、独自の暗号化ロジックの一部を APK ファイルに挿入する必要があったため、golang を使用して APK ファイルを変更しようとし、無事に目的を達成しました。
まず、APK ファイルを解析する方法を学ぶ必要があります。 APK ファイルは zip 形式のファイルで、AndroidManifest.xml、classes.dex、リソース ファイルなどの複数の部分で構成されます。解析する前に、まず dex ファイルの構造を理解する必要があります。
dex ファイルは複数の部分で構成されており、各部分のサイズと形式は固定されています。次の golang 構造を使用して dex ファイルを解析できます。
type DexFileHeader struct { magic [8]byte checksum uint32 signature [20]byte fileSize uint32 headerSize uint32 endianTag uint32 ... }
その中で、magic、checksum、signature、fileSize、headerSize フィールドは dex ファイルのメタ情報を表し、endianTag は dex ファイルのバイト順序を表します。 dexファイル。より具体的な dex ファイルの構造については、dex ファイルの仕様を参照してください。
次に、golang の archive/zip パッケージを使用して APK ファイルを解凍し、dex2jar ツールを使用してclasses.dex ファイルを jar ファイルに変換する必要があります。最後に、golang の jar パッケージを使用して、jar ファイルを逆コンパイルし、ソース コードを変更します。変更が完了したら、dx ツールを使用して変更されたソース コードを dex ファイルに再コンパイルし、それを元の APK ファイルに戻す必要があります。
APK ファイルを変更する具体的なプロセスは次のとおりです。
apkFile, err := zip.OpenReader(apkPath) if err != nil { panic(err) } defer apkFile.Close() var dexFile *zip.File for _, f := range apkFile.File { if f.Name == "classes.dex" { dexFile = f break } } if dexFile == nil { panic("no classes.dex found") } dexReader, err := dexFile.Open() if err != nil { panic(err) } defer dexReader.Close() tmpDexPath := filepath.Join(tmpDir, "classes.dex") tmpJarPath := filepath.Join(tmpDir, "classes.jar") tmpDexFile, err := os.Create(tmpDexPath) if err != nil { panic(err) } defer tmpDexFile.Close() io.Copy(tmpDexFile, dexReader) cmd := exec.Command("d2j-dex2jar", tmpDexPath, "-f", "-o", tmpJarPath) if err := cmd.Run(); err != nil { panic(err) }
jarFile, err := jar.Open(tmpJarPath) if err != nil { panic(err) } defer jarFile.Close() for _, classFile := range jarFile.Files() { if !strings.HasSuffix(classFile.Name, ".class") { continue } className := strings.TrimSuffix(classFile.Name, ".class") className = strings.ReplaceAll(className, "/", ".") classReader, err := classFile.Open() if err != nil { panic(err) } defer classReader.Close() classBytes, err := ioutil.ReadAll(classReader) if err != nil { panic(err) } // 修改源代码 modifiedClassBytes := modifyClassBytes(classBytes) tmpClassPath := filepath.Join(tmpDir, className+".class") tmpClassFile, err := os.Create(tmpClassPath) if err != nil { panic(err) } defer tmpClassFile.Close() _, err = tmpClassFile.Write(modifiedClassBytes) if err != nil { panic(err) } }
ソース コードを変更する場合、golang の go/javaparser パッケージを使用して Java コードを解析し、AST (抽象構文ツリー) を変更できます。
unit, err := parser.ParseFile(token.NewFileSet(), "", modifiedSource, parser.ParseComments) if err != nil { panic(err) } // 修改AST var buf bytes.Buffer printer.Fprint(&buf, token.NewFileSet(), unit) return buf.Bytes()
cmd = exec.Command("d2j-jar2dex", tmpJarPath, "-o", tmpDexPath) if err := cmd.Run(); err != nil { panic(err) } outDex, err := os.Open(tmpDexPath) if err != nil { panic(err) } defer outDex.Close() outDexInfo, err := os.Stat(tmpDexPath) if err != nil { panic(err) } outDexHeader := &zip.FileHeader{ Name: "classes.dex", Method: zip.Store, } outDexHeader.SetModTime(outDexInfo.ModTime()) outDexWriter, err := apkWriter.CreateHeader(outDexHeader) if err != nil { panic(err) } if _, err := io.Copy(outDexWriter, outDex); err != nil { panic(err) }
最後に、変更された APK ファイルを取得し、独自の暗号化ロジックをそのファイルに正常に挿入できます。全体の処理はgolangで実装されており、コードは簡潔で分かりやすく、保守性・拡張性も高いです。
以上がGolangでAPKを変更する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。