Dump & restore signature block at encode and decode #33

This commit is contained in:
REAndroid 2023-04-28 22:36:30 +02:00
parent 9fb87d972e
commit edf1d93d4a
6 changed files with 165 additions and 105 deletions

View File

@ -1,21 +1,22 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.reandroid.apk; package com.reandroid.apk;
import com.reandroid.archive.InputSource; import com.reandroid.archive.InputSource;
import com.reandroid.archive2.block.ApkSignatureBlock;
import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; import com.reandroid.arsc.chunk.xml.AndroidManifestBlock;
import com.reandroid.arsc.chunk.xml.ResXmlDocument; import com.reandroid.arsc.chunk.xml.ResXmlDocument;
@ -53,8 +54,18 @@ public class ApkJsonDecoder {
writeResources(dir); writeResources(dir);
writeRootFiles(dir); writeRootFiles(dir);
writePathMap(dir); writePathMap(dir);
dumpSignatures(dir);
return new File(dir, apkModule.getModuleName()); return new File(dir, apkModule.getModuleName());
} }
private void dumpSignatures(File outDir) throws IOException {
ApkSignatureBlock signatureBlock = apkModule.getApkSignatureBlock();
if(signatureBlock == null){
return;
}
apkModule.logMessage("Dumping signatures: " + ApkUtil.SIGNATURE_FILE_NAME);
File file = toSignatureFile(outDir);
signatureBlock.writeRaw(file);
}
private void writePathMap(File dir) throws IOException { private void writePathMap(File dir) throws IOException {
PathMap pathMap = new PathMap(); PathMap pathMap = new PathMap();
pathMap.add(apkModule.getApkArchive()); pathMap.add(apkModule.getApkArchive());
@ -189,6 +200,10 @@ public class ApkJsonDecoder {
String name = "public.xml"; String name = "public.xml";
return new File(file, name); return new File(file, name);
} }
private File toSignatureFile(File dir){
File file = new File(dir, apkModule.getModuleName());
return new File(file, ApkUtil.SIGNATURE_FILE_NAME);
}
private File toPathMapJsonFile(File dir){ private File toPathMapJsonFile(File dir){
File file = new File(dir, apkModule.getModuleName()); File file = new File(dir, apkModule.getModuleName());
return new File(file, PathMap.JSON_FILE); return new File(file, PathMap.JSON_FILE);

View File

@ -1,22 +1,23 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.reandroid.apk; package com.reandroid.apk;
import com.reandroid.archive.APKArchive; import com.reandroid.archive.APKArchive;
import com.reandroid.archive.FileInputSource; import com.reandroid.archive.FileInputSource;
import com.reandroid.archive2.block.ApkSignatureBlock;
import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; import com.reandroid.arsc.chunk.xml.AndroidManifestBlock;
import com.reandroid.json.JSONArray; import com.reandroid.json.JSONArray;
@ -40,12 +41,28 @@ public class ApkJsonEncoder {
scanResJsonDirs(moduleDir); scanResJsonDirs(moduleDir);
scanRootDirs(moduleDir); scanRootDirs(moduleDir);
ApkModule module=new ApkModule(moduleName, apkArchive); ApkModule module=new ApkModule(moduleName, apkArchive);
module.setLoadDefaultFramework(false);
module.setAPKLogger(apkLogger); module.setAPKLogger(apkLogger);
loadUncompressed(module, moduleDir); loadUncompressed(module, moduleDir);
applyResourceId(module, moduleDir); applyResourceId(module, moduleDir);
restorePathMap(moduleDir, module); restorePathMap(moduleDir, module);
restoreSignatures(moduleDir, module);
return module; return module;
} }
private void restoreSignatures(File dir, ApkModule apkModule){
File file = new File(dir, ApkUtil.SIGNATURE_FILE_NAME);
if(!file.isFile()){
return;
}
logMessage("Loading signature: " + file.getName());
ApkSignatureBlock signatureBlock = new ApkSignatureBlock();
try {
signatureBlock.read(file);
apkModule.setApkSignatureBlock(signatureBlock);
} catch (IOException exception){
logError("Failed to load signatures: ", exception);
}
}
private void restorePathMap(File dir, ApkModule apkModule){ private void restorePathMap(File dir, ApkModule apkModule){
File file = new File(dir, PathMap.JSON_FILE); File file = new File(dir, PathMap.JSON_FILE);
if(!file.isFile()){ if(!file.isFile()){

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -19,6 +19,7 @@ import com.reandroid.apk.xmldecoder.ResXmlDocumentSerializer;
import com.reandroid.archive.InputSource; import com.reandroid.archive.InputSource;
import com.reandroid.apk.xmldecoder.XMLBagDecoder; import com.reandroid.apk.xmldecoder.XMLBagDecoder;
import com.reandroid.apk.xmldecoder.XMLNamespaceValidator; import com.reandroid.apk.xmldecoder.XMLNamespaceValidator;
import com.reandroid.archive2.block.ApkSignatureBlock;
import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.TypeBlock; import com.reandroid.arsc.chunk.TypeBlock;
@ -92,6 +93,17 @@ import java.util.*;
extractRootFiles(outDir); extractRootFiles(outDir);
writePathMap(outDir); writePathMap(outDir);
dumpSignatures(outDir);
}
private void dumpSignatures(File outDir) throws IOException {
ApkSignatureBlock signatureBlock = apkModule.getApkSignatureBlock();
if(signatureBlock == null){
return;
}
logMessage("Dumping signatures: " + ApkUtil.SIGNATURE_FILE_NAME);
File file = new File(outDir, ApkUtil.SIGNATURE_FILE_NAME);
signatureBlock.writeRaw(file);
} }
private void writePathMap(File dir) throws IOException { private void writePathMap(File dir) throws IOException {
PathMap pathMap = new PathMap(); PathMap pathMap = new PathMap();

View File

@ -1,77 +1,90 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.reandroid.apk; package com.reandroid.apk;
import com.reandroid.archive.APKArchive; import com.reandroid.archive.APKArchive;
import com.reandroid.archive.FileInputSource; import com.reandroid.archive.FileInputSource;
import com.reandroid.apk.xmlencoder.RESEncoder; import com.reandroid.apk.xmlencoder.RESEncoder;
import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.archive2.block.ApkSignatureBlock;
import com.reandroid.json.JSONArray; import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.xml.XMLException; import com.reandroid.json.JSONArray;
import com.reandroid.xml.XMLException;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
public class ApkModuleXmlEncoder { public class ApkModuleXmlEncoder {
private final RESEncoder resEncoder; private final RESEncoder resEncoder;
public ApkModuleXmlEncoder(){ public ApkModuleXmlEncoder(){
this.resEncoder = new RESEncoder(); this.resEncoder = new RESEncoder();
} }
public ApkModuleXmlEncoder(ApkModule module, TableBlock tableBlock){ public ApkModuleXmlEncoder(ApkModule module, TableBlock tableBlock){
this.resEncoder = new RESEncoder(module, tableBlock); this.resEncoder = new RESEncoder(module, tableBlock);
} }
public void scanDirectory(File mainDirectory) throws IOException, XMLException { public void scanDirectory(File mainDirectory) throws IOException, XMLException {
loadUncompressedFiles(mainDirectory); loadUncompressedFiles(mainDirectory);
resEncoder.scanDirectory(mainDirectory); resEncoder.scanDirectory(mainDirectory);
File rootDir=new File(mainDirectory, "root"); File rootDir=new File(mainDirectory, "root");
scanRootDir(rootDir); scanRootDir(rootDir);
restorePathMap(mainDirectory); restorePathMap(mainDirectory);
} restoreSignatures(mainDirectory);
private void restorePathMap(File dir) throws IOException{ }
File file = new File(dir, PathMap.JSON_FILE); private void restoreSignatures(File dir) throws IOException {
if(!file.isFile()){ File file = new File(dir, ApkUtil.SIGNATURE_FILE_NAME);
return; if(!file.isFile()){
} return;
PathMap pathMap = new PathMap(); }
FileInputStream inputStream = new FileInputStream(file); ApkModule apkModule = getApkModule();
JSONArray jsonArray = new JSONArray(inputStream); apkModule.logMessage("Loading signature: " + file.getName());
pathMap.fromJson(jsonArray); ApkSignatureBlock signatureBlock = new ApkSignatureBlock();
pathMap.restore(getApkModule()); signatureBlock.read(file);
} apkModule.setApkSignatureBlock(signatureBlock);
public ApkModule getApkModule(){ }
return resEncoder.getApkModule(); private void restorePathMap(File dir) throws IOException{
} File file = new File(dir, PathMap.JSON_FILE);
if(!file.isFile()){
return;
}
PathMap pathMap = new PathMap();
FileInputStream inputStream = new FileInputStream(file);
JSONArray jsonArray = new JSONArray(inputStream);
pathMap.fromJson(jsonArray);
pathMap.restore(getApkModule());
}
public ApkModule getApkModule(){
return resEncoder.getApkModule();
}
private void scanRootDir(File rootDir){ private void scanRootDir(File rootDir){
APKArchive archive=getApkModule().getApkArchive(); APKArchive archive=getApkModule().getApkArchive();
List<File> rootFileList=ApkUtil.recursiveFiles(rootDir); List<File> rootFileList=ApkUtil.recursiveFiles(rootDir);
for(File file:rootFileList){ for(File file:rootFileList){
String path=ApkUtil.toArchivePath(rootDir, file); String path=ApkUtil.toArchivePath(rootDir, file);
FileInputSource inputSource=new FileInputSource(file, path); FileInputSource inputSource=new FileInputSource(file, path);
archive.add(inputSource); archive.add(inputSource);
} }
} }
private void loadUncompressedFiles(File mainDirectory) throws IOException, XMLException { private void loadUncompressedFiles(File mainDirectory) throws IOException, XMLException {
File file=new File(mainDirectory, UncompressedFiles.JSON_FILE); File file=new File(mainDirectory, UncompressedFiles.JSON_FILE);
UncompressedFiles uncompressedFiles = getApkModule().getUncompressedFiles(); UncompressedFiles uncompressedFiles = getApkModule().getUncompressedFiles();
uncompressedFiles.fromJson(file); uncompressedFiles.fromJson(file);
} }
public void setApkLogger(APKLogger apkLogger) { public void setApkLogger(APKLogger apkLogger) {
this.resEncoder.setAPKLogger(apkLogger); this.resEncoder.setAPKLogger(apkLogger);
} }
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -16,6 +16,7 @@
package com.reandroid.apk; package com.reandroid.apk;
import com.reandroid.archive.InputSource; import com.reandroid.archive.InputSource;
import com.reandroid.archive2.block.ApkSignatureBlock;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
@ -192,5 +193,7 @@ public class ApkUtil {
public static final String TAG_STRING_ARRAY = "string-array"; public static final String TAG_STRING_ARRAY = "string-array";
public static final String TAG_INTEGER_ARRAY = "integer-array"; public static final String TAG_INTEGER_ARRAY = "integer-array";
public static final String SIGNATURE_FILE_NAME = "signatures" + ApkSignatureBlock.FILE_EXT;
private static final int MAX_FILE_NAME_LENGTH = 50; private static final int MAX_FILE_NAME_LENGTH = 50;
} }

View File

@ -157,5 +157,5 @@ public class ApkSignatureBlock extends LengthPrefixedList<SignatureInfo>
return 0; return 0;
} }
public static final String FILE_EXT = ".signature.block.bin"; public static final String FILE_EXT = ".sig";
} }