Skip to content

Commit

Permalink
fix: include input files timestamp into code hash
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed May 17, 2022
1 parent 3788555 commit fee77c5
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 22 deletions.
15 changes: 6 additions & 9 deletions jadx-core/src/main/java/jadx/api/JadxArgs.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package jadx.api;

import java.io.File;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
Expand All @@ -18,6 +16,7 @@
import jadx.api.data.ICodeData;
import jadx.api.impl.AnnotatedCodeWriter;
import jadx.api.impl.InMemoryCodeCache;
import jadx.core.utils.files.FileUtils;

public class JadxArgs {

Expand Down Expand Up @@ -524,16 +523,12 @@ public String makeCodeArgsHash() {
String argStr = "args:" + decompilationMode + useImports + showInconsistentCode
+ inlineAnonymousClasses + inlineMethods
+ deobfuscationOn + deobfuscationMinLength + deobfuscationMaxLength
+ parseKotlinMetadata + useKotlinMethodsForVarNames
+ insertDebugLines + extractFinally
+ debugInfo + useSourceNameAsClassAlias + escapeUnicode + replaceConsts
+ respectBytecodeAccModifiers + fsCaseSensitive + renameFlags
+ commentsLevel + useDxInput + pluginOptions;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(argStr.getBytes(StandardCharsets.US_ASCII));
return new BigInteger(1, md.digest()).toString(16);
} catch (Exception e) {
throw new RuntimeException(e);
}
return FileUtils.md5Sum(argStr.getBytes(StandardCharsets.US_ASCII));
}

@Override
Expand All @@ -555,6 +550,8 @@ public String toString() {
+ ", useSourceNameAsClassAlias=" + useSourceNameAsClassAlias
+ ", parseKotlinMetadata=" + parseKotlinMetadata
+ ", useKotlinMethodsForVarNames=" + useKotlinMethodsForVarNames
+ ", insertDebugLines=" + insertDebugLines
+ ", extractFinally=" + extractFinally
+ ", deobfuscationMinLength=" + deobfuscationMinLength
+ ", deobfuscationMaxLength=" + deobfuscationMaxLength
+ ", escapeUnicode=" + escapeUnicode
Expand Down
29 changes: 21 additions & 8 deletions jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
Expand Down Expand Up @@ -237,18 +239,19 @@ private static File cutFileName(File file) {
return new File(file.getParentFile(), name);
}

private static String bytesToHex(byte[] bytes) {
char[] hexArray = "0123456789abcdef".toCharArray();
if (bytes == null || bytes.length <= 0) {
return null;
private static final byte[] HEX_ARRAY = "0123456789abcdef".getBytes(StandardCharsets.US_ASCII);

public static String bytesToHex(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return "";
}
char[] hexChars = new char[bytes.length * 2];
byte[] hexChars = new byte[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
return new String(hexChars, StandardCharsets.UTF_8);
}

public static boolean isZipFile(File file) {
Expand Down Expand Up @@ -298,4 +301,14 @@ public static List<Path> fileNamesToPaths(List<String> fileNames) {
public static List<File> toFiles(List<Path> paths) {
return paths.stream().map(Path::toFile).collect(Collectors.toList());
}

public static String md5Sum(byte[] data) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(data);
return bytesToHex(md.digest());
} catch (Exception e) {
throw new JadxRuntimeException("Failed to build hash", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package jadx.gui.utils.codecache.disk;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand All @@ -9,8 +11,10 @@
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -26,13 +30,14 @@
import jadx.api.ICodeInfo;
import jadx.api.JadxArgs;
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException;
import jadx.core.utils.files.FileUtils;

public class DiskCodeCache implements ICodeCache {
private static final Logger LOG = LoggerFactory.getLogger(DiskCodeCache.class);

private static final int DATA_FORMAT_VERSION = 6;
private static final int DATA_FORMAT_VERSION = 7;

private final Path srcDir;
private final Path metaDir;
Expand All @@ -58,10 +63,6 @@ public DiskCodeCache(RootNode root, Path baseDir) {
}
}

private String buildCodeVersion(JadxArgs args) {
return String.format("%d:%s", DATA_FORMAT_VERSION, args.makeCodeArgsHash());
}

private boolean checkCodeVersion() {
try {
if (!Files.exists(codeVersionFile)) {
Expand Down Expand Up @@ -209,6 +210,33 @@ private void writeFile(Path file, String data) {
}
}

private String buildCodeVersion(JadxArgs args) {
return DATA_FORMAT_VERSION
+ ":" + args.makeCodeArgsHash()
+ ":" + buildInputsHash(args.getInputFiles());
}

/**
* Hash timestamps of all input files
*/
private String buildInputsHash(List<File> inputs) {
try (ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream data = new DataOutputStream(bout)) {
List<Path> inputPaths = Utils.collectionMap(inputs, File::toPath);
List<Path> inputFiles = FileUtils.expandDirs(inputPaths);
Collections.sort(inputFiles);
data.write(inputs.size());
data.write(inputFiles.size());
for (Path inputFile : inputFiles) {
FileTime modifiedTime = Files.getLastModifiedTime(inputFile);
data.writeLong(modifiedTime.toMillis());
}
return FileUtils.md5Sum(bout.toByteArray());
} catch (Exception e) {
throw new JadxRuntimeException("Failed to build hash for inputs", e);
}
}

private Path getJavaFile(String clsFullName) {
return srcDir.resolve(clsFullName.replace('.', File.separatorChar) + ".java");
}
Expand Down

0 comments on commit fee77c5

Please sign in to comment.