Files
yara/libyara/modules/dex/dex.c
T

1345 lines
38 KiB
C

/*
Copyright (c) 2018. The YARA Authors. All Rights Reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <yara/dex.h>
#include <yara/endian.h>
#include <yara/mem.h>
#include <yara/modules.h>
#define MODULE_NAME dex
// DEX File layout information:
// https://source.android.com/devices/tech/dalvik/dex-format
begin_declarations
declare_string("DEX_FILE_MAGIC_035");
declare_string("DEX_FILE_MAGIC_036");
declare_string("DEX_FILE_MAGIC_037");
declare_string("DEX_FILE_MAGIC_038");
declare_string("DEX_FILE_MAGIC_039");
declare_integer("ENDIAN_CONSTANT");
declare_integer("REVERSE_ENDIAN_CONSTANT");
declare_integer("NO_INDEX");
declare_integer("ACC_PUBLIC");
declare_integer("ACC_PRIVATE");
declare_integer("ACC_PROTECTED");
declare_integer("ACC_STATIC");
declare_integer("ACC_FINAL");
declare_integer("ACC_SYNCHRONIZED");
declare_integer("ACC_VOLATILE");
declare_integer("ACC_BRIDGE");
declare_integer("ACC_TRANSIENT");
declare_integer("ACC_VARARGS");
declare_integer("ACC_NATIVE");
declare_integer("ACC_INTERFACE");
declare_integer("ACC_ABSTRACT");
declare_integer("ACC_STRICT");
declare_integer("ACC_SYNTHETIC");
declare_integer("ACC_ANNOTATION");
declare_integer("ACC_ENUM");
declare_integer("ACC_CONSTRUCTOR");
declare_integer("ACC_DECLARED_SYNCHRONIZED");
declare_integer("TYPE_HEADER_ITEM");
declare_integer("TYPE_STRING_ID_ITEM");
declare_integer("TYPE_TYPE_ID_ITEM");
declare_integer("TYPE_PROTO_ID_ITEM");
declare_integer("TYPE_FIELD_ID_ITEM");
declare_integer("TYPE_METHOD_ID_ITEM");
declare_integer("TYPE_CLASS_DEF_ITEM");
declare_integer("TYPE_CALL_SITE_ID_ITEM");
declare_integer("TYPE_METHOD_HANDLE_ITEM");
declare_integer("TYPE_MAP_LIST");
declare_integer("TYPE_TYPE_LIST");
declare_integer("TYPE_ANNOTATION_SET_REF_LIST");
declare_integer("TYPE_ANNOTATION_SET_ITEM");
declare_integer("TYPE_CLASS_DATA_ITEM");
declare_integer("TYPE_CODE_ITEM");
declare_integer("TYPE_STRING_DATA_ITEM");
declare_integer("TYPE_DEBUG_INFO_ITEM");
declare_integer("TYPE_ANNOTATION_ITEM");
declare_integer("TYPE_ENCODED_ARRAY_ITEM");
declare_integer("TYPE_ANNOTATIONS_DIRECTORY_ITEM");
begin_struct("header")
declare_string("magic");
declare_integer("checksum");
declare_string("signature");
declare_integer("file_size");
declare_integer("header_size");
declare_integer("endian_tag");
declare_integer("link_size");
declare_integer("link_offset");
declare_integer("map_offset");
declare_integer("string_ids_size");
declare_integer("string_ids_offset");
declare_integer("type_ids_size");
declare_integer("type_ids_offset");
declare_integer("proto_ids_size");
declare_integer("proto_ids_offset");
declare_integer("field_ids_size");
declare_integer("field_ids_offset");
declare_integer("method_ids_size");
declare_integer("method_ids_offset");
declare_integer("class_defs_size");
declare_integer("class_defs_offset");
declare_integer("data_size");
declare_integer("data_offset");
end_struct("header")
begin_struct_array("string_ids")
declare_integer("offset");
declare_integer("size");
declare_string("value");
end_struct_array("string_ids")
begin_struct_array("type_ids")
declare_integer("descriptor_idx");
end_struct_array("type_ids")
begin_struct_array("proto_ids")
declare_integer("shorty_idx");
declare_integer("return_type_idx");
declare_integer("parameters_offset");
end_struct_array("proto_ids")
begin_struct_array("field_ids")
declare_integer("class_idx");
declare_integer("type_idx");
declare_integer("name_idx");
end_struct_array("field_ids")
begin_struct_array("method_ids")
declare_integer("class_idx");
declare_integer("proto_idx");
declare_integer("name_idx");
end_struct_array("method_ids")
begin_struct_array("class_defs")
declare_integer("class_idx");
declare_integer("access_flags");
declare_integer("super_class_idx");
declare_integer("interfaces_offset");
declare_integer("source_file_idx");
declare_integer("annotations_offset");
declare_integer("class_data_offset");
declare_integer("static_values_offset");
end_struct_array("class_defs")
begin_struct_array("class_data_item")
declare_integer("static_fields_size");
declare_integer("instance_fields_size");
declare_integer("direct_methods_size");
declare_integer("virtual_methods_size");
end_struct_array("class_data_item")
begin_struct("map_list")
declare_integer("size");
begin_struct_array("map_item")
declare_integer("type");
declare_integer("unused");
declare_integer("size");
declare_integer("offset");
end_struct_array("map_item");
end_struct("map_list")
declare_integer("number_of_fields");
begin_struct_array("field")
declare_string("class_name");
declare_string("name");
declare_string("proto");
declare_integer("field_idx_diff");
declare_integer("access_flags");
end_struct_array("field")
declare_integer("number_of_methods");
begin_struct_array("method")
declare_string("class_name");
declare_string("name");
declare_string("proto");
declare_integer("direct");
declare_integer("virtual");
declare_integer("method_idx_diff");
declare_integer("access_flags");
declare_integer("code_off");
begin_struct("code_item")
declare_integer("registers_size");
declare_integer("ins_size");
declare_integer("outs_size");
declare_integer("tries_size");
declare_integer("debug_info_off");
declare_integer("insns_size");
declare_string("insns");
declare_integer("padding");
begin_struct("tries")
end_struct("tries");
begin_struct_array("handlers")
end_struct_array("handlers");
end_struct("code_item")
end_struct_array("method")
end_declarations
// https://android.googlesource.com/platform/dalvik/+/android-4.4.2_r2/libdex/Leb128.cpp
static int32_t read_uleb128(const uint8_t* pStream, uint32_t* size)
{
const uint8_t* ptr = pStream;
int32_t result = *(ptr++);
*size = *size + 1;
if (result > 0x7f)
{
int cur = *(ptr++);
*size = *size + 1;
result = (result & 0x7f) | ((cur & 0x7f) << 7);
if (cur > 0x7f)
{
cur = *(ptr++);
*size = *size + 1;
result |= (cur & 0x7f) << 14;
if (cur > 0x7f)
{
cur = *(ptr++);
*size = *size + 1;
result |= (cur & 0x7f) << 21;
if (cur > 0x7f)
{
/*
* Note: We don't check to see if cur is out of
* range here, meaning we tolerate garbage in the
* high four-order bits.
*/
cur = *(ptr++);
*size = *size + 1;
result |= cur << 28;
}
}
}
}
return result;
}
static int64_t dex_get_integer(
YR_OBJECT* object,
const char* pattern,
int64_t index)
{
if (index == YR_UNDEFINED)
return YR_UNDEFINED;
// Impose a reasonably large limit to table indexes.
if (index > 0x80000)
return YR_UNDEFINED;
return get_integer(object, pattern, (int) index);
}
static SIZED_STRING* dex_get_string(
YR_OBJECT* object,
const char* pattern,
int64_t index)
{
if (index == YR_UNDEFINED)
return NULL;
// Impose a reasonably large limit to table indexes.
if (index > 0x80000)
return NULL;
return get_string(object, pattern, (int) index);
}
dex_header_t* dex_get_header(const uint8_t* data, size_t data_size)
{
dex_header_t* dex_header;
if (data_size < sizeof(dex_header_t))
return NULL;
// Check if we have a valid DEX file
dex_header = (dex_header_t*) data;
if (memcmp(dex_header->magic, DEX_FILE_MAGIC_035, 8) != 0 &&
memcmp(dex_header->magic, DEX_FILE_MAGIC_036, 8) != 0 &&
memcmp(dex_header->magic, DEX_FILE_MAGIC_037, 8) != 0 &&
memcmp(dex_header->magic, DEX_FILE_MAGIC_038, 8) != 0 &&
memcmp(dex_header->magic, DEX_FILE_MAGIC_039, 8) != 0)
{
return NULL;
}
return dex_header;
}
void dex_parse_header(dex_header_t* dex_header, YR_OBJECT* module_object)
{
set_sized_string(
(char*) dex_header->magic,
strnlen((char*) dex_header->magic, 8 * sizeof(char)),
module_object,
"header.magic");
set_integer(
yr_le32toh(dex_header->checksum), module_object, "header.checksum");
set_sized_string(
(char*) dex_header->signature,
strnlen((char*) dex_header->signature, 20 * sizeof(char)),
module_object,
"header.signature");
set_integer(
yr_le32toh(dex_header->file_size), module_object, "header.file_size");
set_integer(
yr_le32toh(dex_header->header_size), module_object, "header.header_size");
set_integer(
yr_le32toh(dex_header->endian_tag), module_object, "header.endian_tag");
set_integer(
yr_le32toh(dex_header->link_size), module_object, "header.link_size");
set_integer(
yr_le32toh(dex_header->link_offset), module_object, "header.link_offset");
set_integer(
yr_le32toh(dex_header->map_offset), module_object, "header.map_offset");
set_integer(
yr_le32toh(dex_header->string_ids_size),
module_object,
"header.string_ids_size");
set_integer(
yr_le32toh(dex_header->string_ids_offset),
module_object,
"header.string_ids_offset");
set_integer(
yr_le32toh(dex_header->type_ids_size),
module_object,
"header.type_ids_size");
set_integer(
yr_le32toh(dex_header->type_ids_offset),
module_object,
"header.type_ids_offset");
set_integer(
yr_le32toh(dex_header->proto_ids_size),
module_object,
"header.proto_ids_size");
set_integer(
yr_le32toh(dex_header->proto_ids_offset),
module_object,
"header.proto_ids_offset");
set_integer(
yr_le32toh(dex_header->field_ids_size),
module_object,
"header.field_ids_size");
set_integer(
yr_le32toh(dex_header->field_ids_offset),
module_object,
"header.field_ids_offset");
set_integer(
yr_le32toh(dex_header->method_ids_size),
module_object,
"header.method_ids_size");
set_integer(
yr_le32toh(dex_header->method_ids_offset),
module_object,
"header.method_ids_offset");
set_integer(
yr_le32toh(dex_header->class_defs_size),
module_object,
"header.class_defs_size");
set_integer(
yr_le32toh(dex_header->class_defs_offset),
module_object,
"header.class_defs_offset");
set_integer(
yr_le32toh(dex_header->data_size), module_object, "header.data_size");
set_integer(
yr_le32toh(dex_header->data_offset), module_object, "header.data_offset");
}
uint32_t load_encoded_field(
DEX* dex,
size_t start_offset,
uint32_t* previous_field_idx,
int index_encoded_field,
int static_field,
int instance_field)
{
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse encoded field start_offset:0x%zx\n", start_offset);
#endif
if (!fits_in_dex(dex, dex->data + start_offset, sizeof(uint32_t) * 2))
return 0;
uint32_t current_size = 0;
encoded_field_t encoded_field;
encoded_field.field_idx_diff = (uint32_t) read_uleb128(
(dex->data + start_offset + current_size), &current_size);
encoded_field.access_flags = (uint32_t) read_uleb128(
(dex->data + start_offset + current_size), &current_size);
set_integer(
encoded_field.field_idx_diff,
dex->object,
"field[%i].field_idx_diff",
index_encoded_field);
set_integer(
encoded_field.access_flags,
dex->object,
"field[%i].access_flags",
index_encoded_field);
set_integer(
static_field, dex->object, "field[%i].static", index_encoded_field);
set_integer(
instance_field, dex->object, "field[%i].instance", index_encoded_field);
*previous_field_idx = encoded_field.field_idx_diff + *previous_field_idx;
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX]\tEncoded field field_idx:0x%x field_idx_diff:0x%x "
"access_flags:0x%x\n",
*previous_field_idx,
encoded_field.field_idx_diff,
encoded_field.access_flags);
#endif
int64_t name_idx = dex_get_integer(
dex->object, "field_ids[%i].name_idx", *previous_field_idx);
if (name_idx == YR_UNDEFINED)
return 0;
SIZED_STRING* field_name = dex_get_string(
dex->object, "string_ids[%i].value", name_idx);
if (field_name != NULL)
{
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX]\tFIELD_NAME %s NAME_IDX 0x%x\n", field_name->c_string, name_idx);
#endif
set_sized_string(
field_name->c_string,
field_name->length,
dex->object,
"field[%i].name",
index_encoded_field);
}
int64_t class_idx = dex_get_integer(
dex->object, "field_ids[%i].class_idx", *previous_field_idx);
int64_t descriptor_idx = dex_get_integer(
dex->object, "type_ids[%i].descriptor_idx", class_idx);
SIZED_STRING* class_name = dex_get_string(
dex->object, "string_ids[%i].value", descriptor_idx);
if (class_name != NULL)
{
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX]\tCLASS_NAME %s CLASS_IDX 0x%x DESCRIPTOR_IDX 0x%x\n",
class_name->c_string,
class_idx,
descriptor_idx);
#endif
set_sized_string(
class_name->c_string,
class_name->length,
dex->object,
"field[%i].class_name",
index_encoded_field);
}
int type_idx = dex_get_integer(
dex->object, "field_ids[%i].type_idx", *previous_field_idx);
int shorty_idx = dex_get_integer(
dex->object, "type_ids[%i].descriptor_idx", type_idx);
SIZED_STRING* proto_name = dex_get_string(
dex->object, "string_ids[%i].value", shorty_idx);
if (proto_name != NULL)
{
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX]\tPROTO_NAME %s TYPE_IDX 0x%x SHORTY_IDX 0x%x\n",
proto_name->c_string,
type_idx,
shorty_idx);
#endif
set_sized_string(
proto_name->c_string,
proto_name->length,
dex->object,
"field[%i].proto",
index_encoded_field);
}
return current_size;
}
uint32_t load_encoded_method(
DEX* dex,
size_t start_offset,
uint32_t* previous_method_idx,
int index_encoded_method,
int direct_method,
int virtual_method)
{
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse encoded method start_offset:0x%zx\n", start_offset);
#endif
if (!fits_in_dex(dex, dex->data + start_offset, sizeof(uint32_t) * 3))
return 0;
uint32_t current_size = 0;
encoded_method_t encoded_method;
encoded_method.method_idx_diff = (uint32_t) read_uleb128(
(dex->data + start_offset + current_size), &current_size);
encoded_method.access_flags = (uint32_t) read_uleb128(
(dex->data + start_offset + current_size), &current_size);
encoded_method.code_off = (uint32_t) read_uleb128(
(dex->data + start_offset + current_size), &current_size);
set_integer(
encoded_method.method_idx_diff,
dex->object,
"method[%i].method_idx_diff",
index_encoded_method);
set_integer(
encoded_method.access_flags,
dex->object,
"method[%i].access_flags",
index_encoded_method);
set_integer(
encoded_method.code_off,
dex->object,
"method[%i].code_off",
index_encoded_method);
set_integer(
direct_method, dex->object, "method[%i].direct", index_encoded_method);
set_integer(
virtual_method, dex->object, "method[%i].virtual", index_encoded_method);
*previous_method_idx = encoded_method.method_idx_diff + *previous_method_idx;
int64_t name_idx = dex_get_integer(
dex->object, "method_ids[%i].name_idx", *previous_method_idx);
if (name_idx == YR_UNDEFINED)
return 0;
#ifdef DEBUG_DEX_MODULE
printf("[DEX]\tNAME_IDX 0x%x\n", name_idx);
#endif
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX]\tEncoded method method_idx:0x%x method_idx_diff:0x%x "
"access_flags:0x%x code_off:0x%x\n",
*previous_method_idx,
encoded_method.method_idx_diff,
encoded_method.access_flags,
encoded_method.code_off);
#endif
SIZED_STRING* method_name = dex_get_string(
dex->object, "string_ids[%i].value", name_idx);
if (method_name != NULL)
{
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX]\tMETHOD_NAME %s NAME_IDX 0x%x\n",
method_name->c_string,
name_idx);
#endif
set_sized_string(
method_name->c_string,
method_name->length,
dex->object,
"method[%i].name",
index_encoded_method);
}
int64_t class_idx = dex_get_integer(
dex->object, "method_ids[%i].class_idx", *previous_method_idx);
int64_t descriptor_idx = dex_get_integer(
dex->object, "type_ids[%i].descriptor_idx", class_idx);
SIZED_STRING* class_name = dex_get_string(
dex->object, "string_ids[%i].value", descriptor_idx);
if (class_name != NULL)
{
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX]\tCLASS_NAME %s CLASS_IDX 0x%x DESCRIPTOR_IDX:0x%x\n",
class_name->c_string,
class_idx,
descriptor_idx);
#endif
set_sized_string(
class_name->c_string,
class_name->length,
dex->object,
"method[%i].class_name",
index_encoded_method);
}
int64_t proto_idx = dex_get_integer(
dex->object, "method_ids[%i].proto_idx", *previous_method_idx);
int64_t shorty_idx = dex_get_integer(
dex->object, "proto_ids[%i].shorty_idx", proto_idx);
SIZED_STRING* proto_name = dex_get_string(
dex->object, "string_ids[%i].value", shorty_idx);
if (proto_name != NULL)
{
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX]\tPROTO_NAME %s CLASS_IDX 0x%x DESCRIPTOR_IDX:0x%x\n",
proto_name->c_string,
class_idx,
descriptor_idx);
#endif
set_sized_string(
proto_name->c_string,
proto_name->length,
dex->object,
"method[%i].proto",
index_encoded_method);
}
if (encoded_method.code_off != 0)
{
#ifdef DEBUG_DEX_MODULE
printf("[DEX]\t\tParse CODE item\n");
#endif
if (struct_fits_in_dex(
dex, dex->data + encoded_method.code_off, sizeof(code_item_t)))
{
code_item_t* code_item =
(code_item_t*) (dex->data + encoded_method.code_off);
set_integer(
code_item->registers_size,
dex->object,
"method[%i].code_item.registers_size",
index_encoded_method);
set_integer(
code_item->ins_size,
dex->object,
"method[%i].code_item.ins_size",
index_encoded_method);
set_integer(
code_item->outs_size,
dex->object,
"method[%i].code_item.outs_size",
index_encoded_method);
set_integer(
code_item->tries_size,
dex->object,
"method[%i].code_item.tries_size",
index_encoded_method);
set_integer(
code_item->debug_info_off,
dex->object,
"method[%i].code_item.debug_info_off",
index_encoded_method);
set_integer(
code_item->insns_size,
dex->object,
"method[%i].code_item.insns_size",
index_encoded_method);
if (fits_in_dex(
dex,
dex->data + encoded_method.code_off + sizeof(code_item_t),
code_item->insns_size * 2))
{
set_sized_string(
(const char*) (dex->data + encoded_method.code_off + sizeof(code_item_t)),
code_item->insns_size * 2,
dex->object,
"method[%i].code_item.insns",
index_encoded_method);
}
}
}
return current_size;
}
void dex_parse(DEX* dex, uint64_t base_address)
{
dex_header_t* dex_header;
int i, j;
uint32_t uleb128_size = 0;
uint32_t new_size = 0;
uint32_t index_class_data_item = 0;
uint32_t index_encoded_method = 0;
uint32_t index_encoded_field = 0;
if (!struct_fits_in_dex(dex, dex->data, dex_header_t))
return;
dex_parse_header(dex->header, dex->object);
dex_header = dex->header;
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(dex_header->string_ids_offset),
yr_le32toh(dex_header->string_ids_size) * sizeof(string_id_item_t)))
return;
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse STRING ID section\n");
#endif
// Get information about the String ID section
for (i = 0; i < yr_le32toh(dex_header->string_ids_size); i++)
{
string_id_item_t* string_id_item =
(string_id_item_t*) (dex->data + yr_le32toh(dex_header->string_ids_offset) + i * sizeof(string_id_item_t));
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX] STRING ID item data_offset:0x%x\n",
yr_le32toh(string_id_item->string_data_offset));
#endif
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(string_id_item->string_data_offset),
sizeof(uint32_t)))
continue;
uint32_t value = (uint32_t) read_uleb128(
(dex->data + yr_le32toh(string_id_item->string_data_offset)),
&uleb128_size);
#ifdef DEBUG_DEX_MODULE
printf("[DEX] STRING ID item size:0x%x\n", value);
#endif
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(string_id_item->string_data_offset),
value))
continue;
set_integer(
yr_le32toh(string_id_item->string_data_offset),
dex->object,
"string_ids[%i].offset",
i);
set_integer(value, dex->object, "string_ids[%i].size", i);
set_sized_string(
(const char*) ((
dex->data + yr_le32toh(string_id_item->string_data_offset) + 1)),
value,
dex->object,
"string_ids[%i].value",
i);
}
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(dex_header->type_ids_offset),
yr_le32toh(dex_header->type_ids_size) * sizeof(type_id_item_t)))
return;
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse TYPE ID section\n");
#endif
// Get information about the Type ID section
for (i = 0; i < yr_le32toh(dex_header->type_ids_size); i++)
{
type_id_item_t* type_id_item =
(type_id_item_t*) (dex->data + yr_le32toh(dex_header->type_ids_offset) + i * sizeof(type_id_item_t));
set_integer(
yr_le32toh(type_id_item->descriptor_idx),
dex->object,
"type_ids[%i].descriptor_idx",
i);
}
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(dex_header->proto_ids_offset),
yr_le32toh(dex_header->proto_ids_size) * sizeof(proto_id_item_t)))
return;
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse PROTO ID section\n");
#endif
// Get information about the Proto ID section
for (i = 0; i < yr_le32toh(dex_header->proto_ids_size); i++)
{
proto_id_item_t* proto_id_item =
(proto_id_item_t*) (dex->data + yr_le32toh(dex_header->proto_ids_offset) + i * sizeof(proto_id_item_t));
set_integer(
yr_le32toh(proto_id_item->shorty_idx),
dex->object,
"proto_ids[%i].shorty_idx",
i);
set_integer(
yr_le32toh(proto_id_item->return_type_idx),
dex->object,
"proto_ids[%i].return_type_idx",
i);
set_integer(
yr_le32toh(proto_id_item->parameters_offset),
dex->object,
"proto_ids[%i].parameters_offset",
i);
}
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(dex_header->field_ids_offset),
yr_le32toh(dex_header->field_ids_size) * sizeof(field_id_item_t)))
return;
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse FIELD ID section\n");
#endif
// Get information about the Field ID section
for (i = 0; i < yr_le32toh(dex_header->field_ids_size); i++)
{
field_id_item_t* field_id_item =
(field_id_item_t*) (dex->data + yr_le32toh(dex_header->field_ids_offset) + i * sizeof(field_id_item_t));
set_integer(
yr_le16toh(field_id_item->class_idx),
dex->object,
"field_ids[%i].class_idx",
i);
set_integer(
yr_le16toh(field_id_item->type_idx),
dex->object,
"field_ids[%i].type_idx",
i);
set_integer(
yr_le32toh(field_id_item->name_idx),
dex->object,
"field_ids[%i].name_idx",
i);
}
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(dex_header->method_ids_offset),
yr_le32toh(dex_header->method_ids_size) * sizeof(method_id_item_t)))
return;
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse METHOD ID section\n");
#endif
// Get information about the Method ID section
for (i = 0; i < yr_le32toh(dex_header->method_ids_size); i++)
{
method_id_item_t* method_id_item =
(method_id_item_t*) (dex->data + yr_le32toh(dex_header->method_ids_offset) + i * sizeof(method_id_item_t));
set_integer(
yr_le16toh(method_id_item->class_idx),
dex->object,
"method_ids[%i].class_idx",
i);
set_integer(
yr_le16toh(method_id_item->proto_idx),
dex->object,
"method_ids[%i].proto_idx",
i);
set_integer(
yr_le32toh(method_id_item->name_idx),
dex->object,
"method_ids[%i].name_idx",
i);
}
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse MAP List ID section\n");
#endif
// Get information about the Map List ID section
if (yr_le32toh(dex_header->map_offset) != 0 &&
fits_in_dex(
dex,
dex->data + yr_le32toh(dex_header->map_offset),
sizeof(uint32_t)))
{
uint32_t* map_list_size =
(uint32_t*) (dex->data + yr_le32toh(dex_header->map_offset));
set_integer(yr_le32toh(*map_list_size), dex->object, "map_list.size");
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(dex_header->map_offset),
sizeof(uint32_t) + yr_le32toh(*map_list_size) * sizeof(map_item_t)))
return;
for (i = 0; i < yr_le32toh(*map_list_size); i++)
{
map_item_t* map_item =
(map_item_t*) (dex->data + yr_le32toh(dex_header->map_offset) + sizeof(uint32_t) + i * sizeof(map_item_t));
set_integer(
yr_le16toh(map_item->type),
dex->object,
"map_list.map_item[%i].type",
i);
set_integer(
yr_le16toh(map_item->unused),
dex->object,
"map_list.map_item[%i].unused",
i);
set_integer(
yr_le32toh(map_item->size),
dex->object,
"map_list.map_item[%i].size",
i);
set_integer(
yr_le32toh(map_item->offset),
dex->object,
"map_list.map_item[%i].offset",
i);
}
}
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(dex_header->class_defs_offset),
yr_le32toh(dex_header->class_defs_size) * sizeof(class_id_item_t)))
return;
#ifdef DEBUG_DEX_MODULE
printf("[DEX] Parse CLASS ID section\n");
#endif
// Get information about the Class ID section
for (i = 0; i < yr_le32toh(dex_header->class_defs_size); i++)
{
class_id_item_t* class_id_item =
(class_id_item_t*) (dex->data + yr_le32toh(dex_header->class_defs_offset) + i * sizeof(class_id_item_t));
#ifdef DEBUG_DEX_MODULE
printf(
"[DEX] CLASS ID item class_idx:0x%x access_flags:0x%x "
"super_class_idx:0x%x interfaces_offset:0x%x source_file_idx:0x%x "
"annotations_offset:0x%x class_data_offset:0x%x "
"static_values_offset:0x%x\n",
yr_le32toh(class_id_item->class_idx),
yr_le32toh(class_id_item->access_flags),
yr_le32toh(class_id_item->super_class_idx),
yr_le32toh(class_id_item->interfaces_offset),
yr_le32toh(class_id_item->source_file_idx),
yr_le32toh(class_id_item->annotations_offset),
yr_le32toh(class_id_item->class_data_offset),
yr_le32toh(class_id_item->static_values_offset));
#endif
set_integer(
yr_le32toh(class_id_item->class_idx),
dex->object,
"class_defs[%i].class_idx",
i);
set_integer(
yr_le32toh(class_id_item->access_flags),
dex->object,
"class_defs[%i].access_flags",
i);
set_integer(
yr_le32toh(class_id_item->super_class_idx),
dex->object,
"class_defs[%i].super_class_idx",
i);
set_integer(
yr_le32toh(class_id_item->interfaces_offset),
dex->object,
"class_defs[%i].interfaces_offset",
i);
set_integer(
yr_le32toh(class_id_item->source_file_idx),
dex->object,
"class_defs[%i].source_file_idx",
i);
set_integer(
yr_le32toh(class_id_item->annotations_offset),
dex->object,
"class_defs[%i].annotations_offset",
i);
set_integer(
yr_le32toh(class_id_item->class_data_offset),
dex->object,
"class_defs[%i].class_data_offset",
i);
set_integer(
yr_le32toh(class_id_item->static_values_offset),
dex->object,
"class_defs[%i].static_values_offset",
i);
if (yr_le32toh(class_id_item->class_data_offset) != 0)
{
class_data_item_t class_data_item;
if (!fits_in_dex(
dex,
dex->data + yr_le32toh(class_id_item->class_data_offset),
4 * sizeof(uint32_t)))
return;
uleb128_size = 0;
class_data_item.static_fields_size = (uint32_t) read_uleb128(
(dex->data + yr_le32toh(class_id_item->class_data_offset)),
&uleb128_size);
class_data_item.instance_fields_size = (uint32_t) read_uleb128(
(dex->data + yr_le32toh(class_id_item->class_data_offset) +
uleb128_size),
&uleb128_size);
class_data_item.direct_methods_size = (uint32_t) read_uleb128(
(dex->data + yr_le32toh(class_id_item->class_data_offset) +
uleb128_size),
&uleb128_size);
class_data_item.virtual_methods_size = (uint32_t) read_uleb128(
(dex->data + yr_le32toh(class_id_item->class_data_offset) +
uleb128_size),
&uleb128_size);
set_integer(
class_data_item.static_fields_size,
dex->object,
"class_data_item[%i].static_fields_size",
index_class_data_item);
set_integer(
class_data_item.instance_fields_size,
dex->object,
"class_data_item[%i].instance_fields_size",
index_class_data_item);
set_integer(
class_data_item.direct_methods_size,
dex->object,
"class_data_item[%i].direct_methods_size",
index_class_data_item);
set_integer(
class_data_item.virtual_methods_size,
dex->object,
"class_data_item[%i].virtual_methods_size",
index_class_data_item);
#ifdef DEBUG_DEX_MODULE
printf("[DEX] CLASS DATA item static fields\n");
#endif
uint32_t previous_field_idx = 0;
for (j = 0; j < class_data_item.static_fields_size; j++)
{
new_size = load_encoded_field(
dex,
yr_le32toh(class_id_item->class_data_offset) + uleb128_size,
&previous_field_idx,
index_encoded_field,
1,
0);
// If the current field isn't parsed the other fields aren't likely to
// parse.
if (new_size == 0)
break;
uleb128_size += new_size;
index_encoded_field += 1;
}
#ifdef DEBUG_DEX_MODULE
printf("[DEX] CLASS DATA item instance fields\n");
#endif
previous_field_idx = 0;
for (j = 0; j < class_data_item.instance_fields_size; j++)
{
new_size = load_encoded_field(
dex,
yr_le32toh(class_id_item->class_data_offset) + uleb128_size,
&previous_field_idx,
index_encoded_field,
0,
1);
// If the current field isn't parsed the other fields aren't likely to
// parse.
if (new_size == 0)
break;
uleb128_size += new_size;
index_encoded_field += 1;
}
#ifdef DEBUG_DEX_MODULE
printf("[DEX] CLASS DATA item direct methods\n");
#endif
uint32_t previous_method_idx = 0;
for (j = 0; j < class_data_item.direct_methods_size; j++)
{
new_size = load_encoded_method(
dex,
yr_le32toh(class_id_item->class_data_offset) + uleb128_size,
&previous_method_idx,
index_encoded_method,
1,
0);
// If the current field isn't parsed the other fields aren't likely to
// parse.
if (new_size == 0)
break;
uleb128_size += new_size;
index_encoded_method += 1;
}
#ifdef DEBUG_DEX_MODULE
printf("[DEX] CLASS DATA item virtual methods\n");
#endif
previous_method_idx = 0;
for (j = 0; j < class_data_item.virtual_methods_size; j++)
{
new_size = load_encoded_method(
dex,
yr_le32toh(class_id_item->class_data_offset) + uleb128_size,
&previous_method_idx,
index_encoded_method,
0,
1);
// If the current field isn't parsed the other fields aren't likely to
// parse.
if (new_size == 0)
break;
uleb128_size += new_size;
index_encoded_method += 1;
}
index_class_data_item++;
}
}
set_integer(index_encoded_method, dex->object, "number_of_methods");
set_integer(index_encoded_field, dex->object, "number_of_fields");
}
int module_initialize(YR_MODULE* module)
{
return ERROR_SUCCESS;
}
int module_finalize(YR_MODULE* module)
{
return ERROR_SUCCESS;
}
int module_load(
YR_SCAN_CONTEXT* context,
YR_OBJECT* module_object,
void* module_data,
size_t module_data_size)
{
YR_MEMORY_BLOCK* block;
YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator;
dex_header_t* dex_header;
set_string(DEX_FILE_MAGIC_035, module_object, "DEX_FILE_MAGIC_035");
set_string(DEX_FILE_MAGIC_036, module_object, "DEX_FILE_MAGIC_036");
set_string(DEX_FILE_MAGIC_037, module_object, "DEX_FILE_MAGIC_037");
set_string(DEX_FILE_MAGIC_038, module_object, "DEX_FILE_MAGIC_038");
set_string(DEX_FILE_MAGIC_039, module_object, "DEX_FILE_MAGIC_039");
set_integer(0x12345678, module_object, "ENDIAN_CONSTANT");
set_integer(0x78563412, module_object, "REVERSE_ENDIAN_CONSTANT");
set_integer(0xffffffff, module_object, "NO_INDEX");
set_integer(0x1, module_object, "ACC_PUBLIC");
set_integer(0x2, module_object, "ACC_PRIVATE");
set_integer(0x4, module_object, "ACC_PROTECTED");
set_integer(0x8, module_object, "ACC_STATIC");
set_integer(0x10, module_object, "ACC_FINAL");
set_integer(0x20, module_object, "ACC_SYNCHRONIZED");
set_integer(0x40, module_object, "ACC_VOLATILE");
set_integer(0x40, module_object, "ACC_BRIDGE");
set_integer(0x80, module_object, "ACC_TRANSIENT");
set_integer(0x80, module_object, "ACC_VARARGS");
set_integer(0x100, module_object, "ACC_NATIVE");
set_integer(0x200, module_object, "ACC_INTERFACE");
set_integer(0x400, module_object, "ACC_ABSTRACT");
set_integer(0x800, module_object, "ACC_STRICT");
set_integer(0x1000, module_object, "ACC_SYNTHETIC");
set_integer(0x2000, module_object, "ACC_ANNOTATION");
set_integer(0x4000, module_object, "ACC_ENUM");
set_integer(0x10000, module_object, "ACC_CONSTRUCTOR");
set_integer(0x20000, module_object, "ACC_DECLARED_SYNCHRONIZED");
set_integer(0x0000, module_object, "TYPE_HEADER_ITEM");
set_integer(0x0001, module_object, "TYPE_STRING_ID_ITEM");
set_integer(0x0002, module_object, "TYPE_TYPE_ID_ITEM");
set_integer(0x0003, module_object, "TYPE_PROTO_ID_ITEM");
set_integer(0x0004, module_object, "TYPE_FIELD_ID_ITEM");
set_integer(0x0005, module_object, "TYPE_METHOD_ID_ITEM");
set_integer(0x0006, module_object, "TYPE_CLASS_DEF_ITEM");
set_integer(0x0007, module_object, "TYPE_CALL_SITE_ID_ITEM");
set_integer(0x0008, module_object, "TYPE_METHOD_HANDLE_ITEM");
set_integer(0x1000, module_object, "TYPE_MAP_LIST");
set_integer(0x1001, module_object, "TYPE_TYPE_LIST");
set_integer(0x1002, module_object, "TYPE_ANNOTATION_SET_REF_LIST");
set_integer(0x1003, module_object, "TYPE_ANNOTATION_SET_ITEM");
set_integer(0x2000, module_object, "TYPE_CLASS_DATA_ITEM");
set_integer(0x2001, module_object, "TYPE_CODE_ITEM");
set_integer(0x2002, module_object, "TYPE_STRING_DATA_ITEM");
set_integer(0x2003, module_object, "TYPE_DEBUG_INFO_ITEM");
set_integer(0x2004, module_object, "TYPE_ANNOTATION_ITEM");
set_integer(0x2005, module_object, "TYPE_ENCODED_ARRAY_ITEM");
set_integer(0x2006, module_object, "TYPE_ANNOTATIONS_DIRECTORY_ITEM");
foreach_memory_block(iterator, block)
{
const uint8_t* block_data = block->fetch_data(block);
if (block_data == NULL)
continue;
dex_header = dex_get_header(block_data, block->size);
if (dex_header != NULL)
{
DEX* dex = (DEX*) yr_malloc(sizeof(DEX));
if (dex == NULL)
return ERROR_INSUFFICIENT_MEMORY;
dex->data = block_data;
dex->data_size = block->size;
dex->object = module_object;
dex->header = dex_header;
module_object->data = dex;
dex_parse(dex, block->base);
break;
}
}
return ERROR_SUCCESS;
}
int module_unload(YR_OBJECT* module_object)
{
DEX* dex = (DEX*) module_object->data;
if (dex == NULL)
return ERROR_SUCCESS;
yr_free(dex);
return ERROR_SUCCESS;
}
#undef MODULE_NAME