Dans cette entrée, je laisserai une note de ce que j'ai essayé:
--Comment vérifier le contenu lorsqu'un fichier JAR Java est passé en binaire uniquement
Ce que j'ai écrit est GitHub [https://github.com/hrkt/gohatto-j/releases/tag/0.0.1-qiita](https://github.com/hrkt/gohatto-j/releases/tag/ Je l'ai mis dans 0.0.1-qiita).
―― Le lecteur est en charge de l'enseignement de la programmation en Java, et le stagiaire doit soumettre un fichier JAR de l'exercice et vérifier le fonctionnement.
Il existe une classe appelée JarFile, donc j'utiliserai ce pouvoir.
L'énumération
try (JarFile jarFile = new JarFile(jarFilePath)) {
val e = jarFile.entries();
val urls = new URL[]{new URL("jar:file:" + jarFilePath + "!/")};
val ucl = URLClassLoader.newInstance(urls);
val repository = new ClassLoaderRepository(ucl);
return Collections.list(e).stream()
.filter(je -> !je.isDirectory())
.filter(je -> je.getName().endsWith(".class"))
.flatMap(je -> check(repository, je).stream())
BCEL
La fonction Java standard Reflection nécessite ce temps. Vous ne pouvez pas obtenir d'informations telles que la classe à laquelle le code dans le fichier de classe (après avoir été compilé en code d'octet) fait référence.
Par conséquent, nous utiliserons Apache Commons BCEL, une bibliothèque pour gérer le code d'octet Java.
Utilisez la classe Commons JavaClass pour charger la classe obtenue à partir du chargeur de classe Java ci-dessus et regardez le bytecode qu'il contient. Plus précisément, BCEL's "ConstantPool" (= fichier de classe analysé Examinez la chaîne contenue dans la liste des constantes contenues dans).
J'ai écrit le code suivant, créé un fichier jar et l'ai essayé.
package io.hrkt;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("message", "Hello");
System.out.println(map.get("message"));
}
}
À ce stade, si vous excluez le pool de constantes dans BCEL, vous pouvez obtenir la liste suivante.
CONSTANT_Methodref[10](class_index=12,name_and_type_index=30)
CONSTANT_Class[7](name_index=31)
CONSTANT_Methodref[10](class_index=2,name_and_type_index=30)
CONSTANT_String[8](string_index=32)
CONSTANT_String[8](string_index=33)
CONSTANT_InterfaceMethodref[11](class_index=34,name_and_type_index=35)
CONSTANT_Fieldref[9](class_index=36,name_and_type_index=37)
CONSTANT_InterfaceMethodref[11](class_index=34,name_and_type_index=38)
CONSTANT_Class[7](name_index=39)
CONSTANT_Methodref[10](class_index=40,name_and_type_index=41)
CONSTANT_Class[7](name_index=42)
CONSTANT_Class[7](name_index=43)
CONSTANT_Utf8[1]("<init>")
CONSTANT_Utf8[1]("()V")
CONSTANT_Utf8[1]("Code")
CONSTANT_Utf8[1]("LineNumberTable")
CONSTANT_Utf8[1]("LocalVariableTable")
CONSTANT_Utf8[1]("this")
CONSTANT_Utf8[1]("Lio/hrkt/Main;")
CONSTANT_Utf8[1]("main")
CONSTANT_Utf8[1]("([Ljava/lang/String;)V")
CONSTANT_Utf8[1]("args")
CONSTANT_Utf8[1]("[Ljava/lang/String;")
CONSTANT_Utf8[1]("map")
CONSTANT_Utf8[1]("Ljava/util/Map;")
CONSTANT_Utf8[1]("LocalVariableTypeTable")
CONSTANT_Utf8[1]("Ljava/util/Map<Ljava/lang/String;Ljava/lang/String;>;")
CONSTANT_Utf8[1]("SourceFile")
CONSTANT_Utf8[1]("Main.java")
CONSTANT_NameAndType[12](name_index=13,signature_index=14)
CONSTANT_Utf8[1]("java/util/HashMap")
CONSTANT_Utf8[1]("message")
CONSTANT_Utf8[1]("Hello")
CONSTANT_Class[7](name_index=44)
CONSTANT_NameAndType[12](name_index=45,signature_index=46)
CONSTANT_Class[7](name_index=47)
CONSTANT_NameAndType[12](name_index=48,signature_index=49)
CONSTANT_NameAndType[12](name_index=50,signature_index=51)
CONSTANT_Utf8[1]("java/lang/String")
CONSTANT_Class[7](name_index=52)
CONSTANT_NameAndType[12](name_index=53,signature_index=54)
CONSTANT_Utf8[1]("io/hrkt/Main")
CONSTANT_Utf8[1]("java/lang/Object")
CONSTANT_Utf8[1]("java/util/Map")
CONSTANT_Utf8[1]("put")
CONSTANT_Utf8[1]("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")
CONSTANT_Utf8[1]("java/lang/System")
CONSTANT_Utf8[1]("out")
CONSTANT_Utf8[1]("Ljava/io/PrintStream;")
CONSTANT_Utf8[1]("get")
CONSTANT_Utf8[1]("(Ljava/lang/Object;)Ljava/lang/Object;")
CONSTANT_Utf8[1]("java/io/PrintStream")
CONSTANT_Utf8[1]("println")
CONSTANT_Utf8[1]("(Ljava/lang/String;)V")
Parmi les chaînes de caractères incluses dans ConstantPool, celles dont la balise indique un fichier de classe sont extraites.
JavaClass clazz = null;
try {
clazz = repository.loadClass(fqcn);
val cp = clazz.getConstantPool();
int cpLength = cp.getLength();
val referencedClasses = new ArrayList<ConstantUtf8>();
IntStream.range(0, cpLength).forEach(i -> {
val constant = cp.getConstant(i);
if (null == constant || !(constant instanceof ConstantClass)) {
// do nothing
} else {
val constantClass = (ConstantClass) constant;
val referencedConstant = cp.getConstant(constantClass.getNameIndex());
referencedClasses.add((ConstantUtf8) referencedConstant);
}
});
val tc = referencedClasses.stream()
.map(c -> c.getBytes())
.map(s -> s.replace("/", "."))
.collect(Collectors.toList());
return tc;
} catch (ClassNotFoundException e) {
throw new GohattoApplicationException(e);
}
Cette fois, il est déterminé en le faisant correspondre avec le nom du package inclus dans le fichier de paramètres de format de texte.
Comme vous pouvez le voir en regardant le code, il s'agit simplement d'une comparaison utilisant des expressions régulières.
Si vous préparez un fichier comme celui-ci, il sera détecté comme une erreur lorsque "java.util ou com.sun est utilisé".
java.util
com.sun
Si vous préparez un fichier comme celui-ci, il sera détecté comme une erreur "lorsque vous utilisez autre chose que java.lang ou java.io".
^(?!java.lang|java.io)
Voici un exemple d'utilisation de la source dans le référentiel.
Lorsqu'il est exécuté en tant que commande, s'il y a du code qui n'autorise pas la référence au package Java, un journal d'erreurs comme celui illustré ci-dessous sera généré sur la sortie standard.
$ java -jar build/libs/gohatto-j-0.0.1-SNAPSHOT-all.jar --jar src/test/resources/testproject.jar --forbiddenPackageList src/test/resources/rule_forbid_jav-util_and_com-sun.txt
[main] INFO io.hrkt.gohatto.Gohatto - ERROR DoNotUseForbiddenPackage java.util.HashMap violates rule
[main] INFO io.hrkt.gohatto.Gohatto - ERROR DoNotUseForbiddenPackage java.util.Map violates rule
[main] INFO io.hrkt.gohatto.Gohatto - rules applied to: 2
Dans la classe "Gohatto" dans le référentiel mentionné ci-dessus, qui est l'entrée de la fonction de vérification,
String resDir = "src/test/resources/";
Gohatto gohatto = new Gohatto();
gohatto.init(resDir + "testproject.jar", resDir + "rule_forbid_jav-util_and_com-sun.txt");
List<Result> ret = gohatto.executeRules();
Assert.assertTrue(ret.size() == 0);
Je vous ai montré comment lire le fichier JAR et vérifier le package de la classe précédente référencée par la classe qu'il contient.
Le code de travail est stocké dans le référentiel. Veuillez vous y référer le cas échéant.
Recommended Posts