/* 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;
}