/* OpenIDA - Outil d'analyse de fichiers binaires * pool.c - lecture du réservoir de constantes * * Copyright (C) 2008 Cyrille Bagard * * This file is part of OpenIDA. * * OpenIDA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * OpenIDA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "pool.h" #include #include #include #include "java-int.h" #include "../../common/endianness.h" /* Charge les propriétés d'une constante du réservoir. */ bool load_java_pool_entry(java_format *, constant_pool_entry *, off_t *); /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * pos = point de lecture à faire évoluer. [OUT] * * * * Description : Charge le réservoir de constantes d'un binaire Java. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool load_java_pool(java_format *format, off_t *pos) { bool result; /* Bilan à remonter */ uint16_t count; /* Nombre d'éléments présents */ uint16_t i; /* Boucle de parcours */ result = read_u16(&count, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); format->pool_len = count - 1; format->pool = (constant_pool_entry *)calloc(count - 1, sizeof(constant_pool_entry)); for (i = 1; i < count && result; i++) { result = load_java_pool_entry(format, &format->pool[i - 1], pos); if (format->pool[i - 1].tag == CONSTANT_LONG || format->pool[i - 1].tag == CONSTANT_DOUBLE) { i++; /* On n'est jamais trop prudent */ if (i < count) format->pool[i - 1].tag = CONSTANT_EMPTY; } } return result; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à vider. * * * * Description : Décharge le réservoir de constantes d'un binaire Java. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void unload_java_pool(java_format *format) { uint16_t i; /* Boucle de parcours */ for (i = 0; i < format->pool_len; i++) switch (format->pool[i].tag) { case CONSTANT_EMPTY: case CONSTANT_CLASS: case CONSTANT_FIELD_REF: case CONSTANT_METHOD_REF: case CONSTANT_INTERFACE_METHOD_REF: case CONSTANT_STRING: case CONSTANT_INTEGER: case CONSTANT_FLOAT: case CONSTANT_LONG: case CONSTANT_DOUBLE: case CONSTANT_NAME_AND_TYPE: break; case CONSTANT_UTF8: free(format->pool[i].info.utf8.bytes); break; } free(format->pool); } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * entry = élément à spécifier. [OUT] * * pos = point de lecture à faire évoluer. [OUT] * * * * Description : Charge les propriétés d'une constante du réservoir. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool load_java_pool_entry(java_format *format, constant_pool_entry *entry, off_t *pos) { bool result; /* Bilan à retourner */ uint8_t tag; /* Type de l'élément */ uint32_t low_bytes; /* Octets de poids faible */ uint32_t high_bytes; /* Octets de poids fort */ uint64_t bits; /* Nombre lu sur 64 bits */ int sign; /* Signe du nombre lu */ int exponent; /* Exposant du nombre lu */ uint64_t mantissa32; /* Mantisse du nombre lu 32b */ uint64_t mantissa64; /* Mantisse du nombre lu 64b */ uint16_t length; /* Taille d'une chaîne */ result = read_u8(&tag, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); entry->tag = tag; switch (entry->tag) { case CONSTANT_CLASS: result = read_u16(&entry->info.class.name_index, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); break; case CONSTANT_FIELD_REF: case CONSTANT_METHOD_REF: case CONSTANT_INTERFACE_METHOD_REF: result = read_u16(&entry->info.ref.class_index, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); result &= read_u16(&entry->info.ref.name_and_type_index, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); break; case CONSTANT_STRING: result = read_u16(&entry->info.string.string_index, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); break; case CONSTANT_INTEGER: result = read_u32(&entry->info.int_val.val, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); break; case CONSTANT_FLOAT: result = read_u32(&low_bytes, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); if (result) { if (low_bytes == 0x7f800000) entry->info.float_val.val = INFINITY; else if (low_bytes == 0xff800000) entry->info.float_val.val = /* -1* */INFINITY; else if ((low_bytes >= 0x7f800001 && low_bytes <= 0x7fffffff) || (low_bytes >= 0xff800001 && low_bytes <= 0xffffffff)) entry->info.float_val.val = NAN; else if (low_bytes == 0x00000000 || low_bytes == 0x80000000) entry->info.float_val.val = 0; else { sign = (low_bytes & 0x80000000) ? -1 : 1; exponent = (low_bytes >> 23) & 0xff; mantissa32 = (exponent == 0 ? (low_bytes & 0x7fffff) << 1 : (low_bytes & 0x7fffff) | 0x800000); entry->info.float_val.val = pow(2, (exponent - 150)); entry->info.float_val.val *= mantissa32; entry->info.float_val.val *= sign; } } break; case CONSTANT_LONG: result = read_u32(&high_bytes, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); result &= read_u32(&low_bytes, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); if (result) { entry->info.double_val.val = (uint64_t)high_bytes << 32; entry->info.double_val.val += low_bytes; } break; case CONSTANT_DOUBLE: result = read_u32(&high_bytes, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); result &= read_u32(&low_bytes, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); if (result) { bits = (uint64_t)high_bytes << 32 | (uint64_t)low_bytes; if (bits == 0x7ff0000000000000ll) entry->info.double_val.val = INFINITY; else if (bits == 0xfff0000000000000ll) entry->info.double_val.val = /* -1* */INFINITY; else if ((bits >= 0x7ff0000000000001ll && bits <= 0x7fffffffffffffffll) || (bits >= 0xfff0000000000001ll && bits <= 0xffffffffffffffffll)) entry->info.double_val.val = NAN; else if (bits == 0x0000000000000000ll || bits == 0x8000000000000000ll) entry->info.double_val.val = 0; else { sign = ((bits >> 63) == 0) ? 1 : -1; exponent = (bits >> 52) & 0x7ffl; mantissa64 = (exponent == 0 ? (bits & 0xfffffffffffffll) << 1 : (bits & 0xfffffffffffffll) | 0x10000000000000ll); entry->info.double_val.val = pow(2, (exponent - 1075)); entry->info.double_val.val *= mantissa64; entry->info.double_val.val *= sign; } } break; case CONSTANT_NAME_AND_TYPE: result = read_u16(&entry->info.name_type.name_index, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); result &= read_u16(&entry->info.name_type.descriptor_index, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); break; case CONSTANT_UTF8: result = read_u16(&length, EXE_FORMAT(format)->content, pos, EXE_FORMAT(format)->length, SRE_BIG); if (result) { entry->info.utf8.bytes = (char *)calloc(length + 1, sizeof(char)); memcpy(entry->info.utf8.bytes, &EXE_FORMAT(format)->content[*pos], length); *pos += length; } break; default: result = false; break; } return result; } /****************************************************************************** * * * Paramètres : format = description de l'exécutable à compléter. * * index = indice de l'élément dont la valeur est à recupérer. * * str = adresse où placer la chaîne de caractères trouvée. * * * * Description : Recherche une chaîne de caractères dans le réservoir. * * * * Retour : true si l'opération s'est bien déroulée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool get_java_pool_ut8_string(java_format *format, uint16_t index, const char **str) { bool result; /* Bilan à renvoyer */ constant_pool_entry *entry; /* Entrée du réservoir visée */ result = (index <= format->pool_len); if (result) { entry = &format->pool[index - 1]; result = (entry->tag == CONSTANT_UTF8); if (result) (*str) = entry->info.utf8.bytes; } return result; }