Blame wrestool/restable.c

Packit 6e6f77
/* restable.c - Decoding PE and NE resource tables
Packit 6e6f77
 *
Packit 6e6f77
 * Copyright (C) 1998 Oskar Liljeblad
Packit 6e6f77
 *
Packit 6e6f77
 * This program is free software: you can redistribute it and/or modify
Packit 6e6f77
 * it under the terms of the GNU General Public License as published by
Packit 6e6f77
 * the Free Software Foundation, either version 3 of the License, or
Packit 6e6f77
 * (at your option) any later version.
Packit 6e6f77
 *
Packit 6e6f77
 * This program is distributed in the hope that it will be useful,
Packit 6e6f77
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6e6f77
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6e6f77
 * GNU General Public License for more details.
Packit 6e6f77
 *
Packit 6e6f77
 * You should have received a copy of the GNU General Public License
Packit 6e6f77
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 6e6f77
 */
Packit 6e6f77
Packit 6e6f77
#include <config.h>
Packit 6e6f77
#include <inttypes.h>		/* ? */
Packit 6e6f77
#include "gettext.h"		/* Gnulib */
Packit 6e6f77
#define _(s) gettext(s)
Packit 6e6f77
#define N_(s) gettext_noop(s)
Packit 6e6f77
#include "common/intutil.h"
Packit 6e6f77
#include "xalloc.h"		/* Gnulib */
Packit 2bb993
#include "xvasprintf.h"	/* Gnulib */
Packit 6e6f77
#include "minmax.h"		/* Gnulib */
Packit 6e6f77
#include "common/error.h"
Packit 6e6f77
#include "wrestool.h"
Packit 6e6f77
#include "win32.h"
Packit 6e6f77
#include "fileread.h"
Packit 6e6f77
Packit 6e6f77
static bool decode_pe_resource_id (WinLibrary *, WinResource *, uint32_t);
Packit 6e6f77
static bool decode_ne_resource_id (WinLibrary *, WinResource *, uint16_t);
Packit 6e6f77
static WinResource *list_ne_type_resources (WinLibrary *, int *);
Packit 6e6f77
static WinResource *list_ne_name_resources (WinLibrary *, WinResource *, int *);
Packit 6e6f77
static WinResource *list_pe_resources (WinLibrary *, Win32ImageResourceDirectory *, int, int *);
Packit 6e6f77
static int calc_vma_size (WinLibrary *);
Packit 6e6f77
static void do_resources_recurs (WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, const char *, const char *, const char *, DoResourceCallback);
Packit 6e6f77
static char *get_resource_id_quoted (WinResource *);
Packit 6e6f77
static WinResource *find_with_resource_array(WinLibrary *, WinResource *, const char *);
Packit 6e6f77
static WinResource *list_resources (WinLibrary *fi, WinResource *res, int *count);
Packit 6e6f77
static bool compare_resource_id (WinResource *wr, const char *id);
Packit 6e6f77
Packit 6e6f77
/* Check whether access to a PE_SECTIONS is allowed */
Packit 6e6f77
#define RETURN_IF_BAD_PE_SECTIONS(ret, module)                                              \
Packit 6e6f77
    do {                                                                                    \
Packit 6e6f77
        void* pe_sec_;                                                                      \
Packit 6e6f77
        RETURN_IF_BAD_POINTER(ret, PE_HEADER(module)->optional_header);                     \
Packit 6e6f77
        RETURN_IF_BAD_POINTER(ret, PE_HEADER(module)->file_header.number_of_sections);      \
Packit 6e6f77
        pe_sec_ = PE_SECTIONS(module);                                                      \
Packit 6e6f77
        RETURN_IF_BAD_OFFSET(ret, pe_sec_, sizeof(Win32ImageSectionHeader)                  \
Packit 6e6f77
            * PE_HEADER(module)->file_header.number_of_sections);                           \
Packit 6e6f77
    } while(0)
Packit 6e6f77
Packit 6e6f77
/* do_resources:
Packit 6e6f77
 *   Do something for each resource matching type, name and lang.
Packit 6e6f77
 */
Packit 6e6f77
Packit 6e6f77
void
Packit 6e6f77
do_resources (WinLibrary *fi, const char *type, const char *name, const char *lang, DoResourceCallback cb)
Packit 6e6f77
{
Packit 6e6f77
    WinResource *type_wr;
Packit 6e6f77
    WinResource *name_wr;
Packit 6e6f77
    WinResource *lang_wr;
Packit 6e6f77
Packit 6e6f77
    type_wr = malloc(sizeof(WinResource)*3);
Packit 6e6f77
    name_wr = type_wr + 1;
Packit 6e6f77
    lang_wr = type_wr + 2;
Packit 6e6f77
    memset(type_wr, 0, sizeof(WinResource)*3);
Packit 6e6f77
Packit 6e6f77
    do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, cb);
Packit 6e6f77
Packit 6e6f77
    free(type_wr);
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
/* what is each entry in this directory level for? type, name or language? */
Packit 6e6f77
#define WINRESOURCE_BY_LEVEL(x) ((x)==0 ? type_wr : ((x)==1 ? name_wr : lang_wr))
Packit 6e6f77
Packit 6e6f77
/* does the id of this entry match the specified id? */
Packit 6e6f77
#define LEVEL_MATCHES(x) (x == NULL || x ## _wr->id[0] == '\0' || compare_resource_id(x ## _wr, x))
Packit 6e6f77
Packit 6e6f77
static void
Packit 6e6f77
do_resources_recurs (WinLibrary *fi, WinResource *base, WinResource *type_wr,
Packit 6e6f77
                     WinResource *name_wr, WinResource *lang_wr,
Packit 6e6f77
                     const char *type, const char *name, const char *lang, DoResourceCallback cb)
Packit 6e6f77
{
Packit 6e6f77
    int c, rescnt;
Packit 6e6f77
    WinResource *wr;
Packit 6e6f77
Packit 6e6f77
    /* get a list of all resources at this level */
Packit 6e6f77
    wr = list_resources (fi, base, &rescnt);
Packit 6e6f77
    if (wr == NULL)
Packit 6e6f77
        return;
Packit 6e6f77
Packit 6e6f77
    /* process each resource listed */
Packit 6e6f77
    for (c = 0 ; c < rescnt ; c++) {
Packit 6e6f77
        /* (over)write the corresponding WinResource holder with the current */
Packit 6e6f77
        memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource));
Packit 6e6f77
        if ((base && (wr[c].level <= base->level))
Packit 6e6f77
            || (wr[c].level >= 3))
Packit 6e6f77
        {
Packit 6e6f77
            warn(_("%s: resource structure malformed"), fi->name);
Packit 6e6f77
            return;
Packit 6e6f77
        }
Packit 6e6f77
Packit 6e6f77
        /* go deeper unless there is something that does NOT match */
Packit 6e6f77
        if (LEVEL_MATCHES(type) && LEVEL_MATCHES(name) && LEVEL_MATCHES(lang)) {
Packit 6e6f77
            if (wr->is_directory)
Packit 6e6f77
                do_resources_recurs (fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, cb);
Packit 6e6f77
            else
Packit 6e6f77
                cb(fi, wr+c, type_wr, name_wr, lang_wr);
Packit 6e6f77
        }
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    /* since we're moving back one level after this, unset the
Packit 6e6f77
     * WinResource holder used on this level */
Packit 6e6f77
    memset(WINRESOURCE_BY_LEVEL(wr[0].level), 0, sizeof(WinResource));
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
void
Packit 6e6f77
print_resources_callback (WinLibrary *fi, WinResource *wr,
Packit 6e6f77
                          WinResource *type_wr, WinResource *name_wr,
Packit 6e6f77
                          WinResource *lang_wr)
Packit 6e6f77
{
Packit 6e6f77
    const char *type, *offset;
Packit 6e6f77
    int32_t id;
Packit 6e6f77
    size_t size;
Packit 2bb993
    char *type_quoted, *name_quoted, *lang_quoted;
Packit 6e6f77
Packit 6e6f77
    /* get named resource type if possible */
Packit 6e6f77
    type = NULL;
Packit 6e6f77
    if (parse_int32(type_wr->id, &id))
Packit 6e6f77
        type = res_type_id_to_string(id);
Packit 6e6f77
Packit 6e6f77
    /* get offset and size info on resource */
Packit 6e6f77
    offset = get_resource_entry(fi, wr, &size);
Packit 6e6f77
    if (offset == NULL)
Packit 6e6f77
        return;
Packit 6e6f77
Packit 2bb993
    type_quoted = get_resource_id_quoted(type_wr);
Packit 2bb993
    name_quoted = get_resource_id_quoted(name_wr);
Packit 2bb993
    lang_quoted = get_resource_id_quoted(lang_wr);
Packit 6e6f77
    printf(_("--type=%s --name=%s%s%s [%s%s%soffset=0x%x size=%zu]\n"),
Packit 2bb993
      type_quoted,
Packit 2bb993
      name_quoted,
Packit 6e6f77
      (lang_wr->id[0] != '\0' ? _(" --language=") : ""),
Packit 2bb993
      lang_quoted,
Packit 6e6f77
      (type != NULL ? "type=" : ""),
Packit 6e6f77
      (type != NULL ? type : ""),
Packit 6e6f77
      (type != NULL ? " " : ""),
Packit 6e6f77
      (uint32_t) (offset - fi->memory), size);
Packit 2bb993
    free(type_quoted);
Packit 2bb993
    free(name_quoted);
Packit 2bb993
    free(lang_quoted);
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
/* return the resource id quoted if it's a string, otherwise just return it */
Packit 6e6f77
static char *
Packit 6e6f77
get_resource_id_quoted (WinResource *wr)
Packit 6e6f77
{
Packit 6e6f77
    if (wr->numeric_id || wr->id[0] == '\0')
Packit 2bb993
        return xstrdup(wr->id);
Packit 6e6f77
Packit 2bb993
    return xasprintf("'%s'", wr->id);
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
static bool
Packit 6e6f77
compare_resource_id (WinResource *wr, const char *id)
Packit 6e6f77
{
Packit 6e6f77
    if (wr->numeric_id) {
Packit 6e6f77
        int32_t cmp1, cmp2;
Packit 6e6f77
        if (id[0] == '+')
Packit 6e6f77
            return false;
Packit 6e6f77
        if (id[0] == '-')
Packit 6e6f77
            id++;
Packit 6e6f77
        if (!parse_int32(wr->id, &cmp1) || !parse_int32(id, &cmp2) || cmp1 != cmp2)
Packit 6e6f77
            return false;
Packit 6e6f77
    } else {
Packit 6e6f77
        if (id[0] == '-')
Packit 6e6f77
            return false;
Packit 6e6f77
        if (id[0] == '+')
Packit 6e6f77
            id++;
Packit 6e6f77
        if (strcmp(wr->id, id))
Packit 6e6f77
            return false;
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    return true;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
static bool
Packit 6e6f77
decode_pe_resource_id (WinLibrary *fi, WinResource *wr, uint32_t value)
Packit 6e6f77
{
Packit 6e6f77
    if (value & IMAGE_RESOURCE_NAME_IS_STRING) {	/* numeric id */
Packit 6e6f77
        int c, len;
Packit 6e6f77
        uint16_t *mem = (uint16_t *)
Packit 6e6f77
          (fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING));
Packit 6e6f77
Packit 6e6f77
        /* copy each char of the string, and terminate it */
Packit 6e6f77
        RETURN_IF_BAD_POINTER(false, *mem);
Packit 6e6f77
        len = mem[0];
Packit 6e6f77
        RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(uint16_t) * len);
Packit 6e6f77
Packit 6e6f77
        len = MIN(mem[0], WINRES_ID_MAXLEN);
Packit 6e6f77
        for (c = 0 ; c < len ; c++)
Packit 6e6f77
            wr->id[c] = mem[c+1] & 0x00FF;
Packit 6e6f77
        wr->id[len] = '\0';
Packit 6e6f77
    } else {					/* Unicode string id */
Packit 6e6f77
        /* translate id into a string */
Packit 6e6f77
        snprintf(wr->id, WINRES_ID_MAXLEN, "%" PRIu32, value);
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    wr->numeric_id = (value & IMAGE_RESOURCE_NAME_IS_STRING ? false:true);
Packit 6e6f77
    return true;
Packit 6e6f77
}
Packit 6e6f77
 
Packit 6e6f77
void *
Packit 6e6f77
get_resource_entry (WinLibrary *fi, WinResource *wr, size_t *size)
Packit 6e6f77
{
Packit 6e6f77
    if (fi->is_PE_binary) {
Packit 6e6f77
        Win32ImageResourceDataEntry *dataent;
Packit 6e6f77
Packit 6e6f77
        dataent = (Win32ImageResourceDataEntry *) wr->children;
Packit 6e6f77
        RETURN_IF_BAD_POINTER(NULL, *dataent);
Packit 6e6f77
        *size = dataent->size;
Packit 6e6f77
        RETURN_IF_BAD_OFFSET(NULL, fi->memory + dataent->offset_to_data, *size);
Packit 6e6f77
Packit 6e6f77
        return fi->memory + dataent->offset_to_data;
Packit 6e6f77
    } else {
Packit 6e6f77
        Win16NENameInfo *nameinfo;
Packit 6e6f77
        int sizeshift;
Packit 6e6f77
Packit 6e6f77
        nameinfo = (Win16NENameInfo *) wr->children;
Packit 6e6f77
        sizeshift = *((uint16_t *) fi->first_resource - 1);
Packit 6e6f77
        *size = nameinfo->length << sizeshift;
Packit 6e6f77
        RETURN_IF_BAD_OFFSET(NULL, fi->memory + (nameinfo->offset << sizeshift), *size);
Packit 6e6f77
Packit 6e6f77
        return fi->memory + (nameinfo->offset << sizeshift);
Packit 6e6f77
    }
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
static bool
Packit 6e6f77
decode_ne_resource_id (WinLibrary *fi, WinResource *wr, uint16_t value)
Packit 6e6f77
{
Packit 6e6f77
    if (value & NE_RESOURCE_NAME_IS_NUMERIC) {		/* numeric id */
Packit 6e6f77
        /* translate id into a string */
Packit 6e6f77
        snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value & ~NE_RESOURCE_NAME_IS_NUMERIC);
Packit 6e6f77
    } else {					/* ASCII string id */
Packit 6e6f77
        unsigned char len;
Packit 6e6f77
        char *mem = (char *) NE_HEADER(fi->memory)
Packit 6e6f77
                             + NE_HEADER(fi->memory)->rsrctab
Packit 6e6f77
                             + value;
Packit 6e6f77
Packit 6e6f77
        /* copy each char of the string, and terminate it */
Packit 6e6f77
        RETURN_IF_BAD_POINTER(false, *mem);
Packit 6e6f77
        len = mem[0];
Packit 6e6f77
        RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(char) * len);
Packit 6e6f77
        memcpy(wr->id, &mem[1], len);
Packit 6e6f77
        wr->id[len] = '\0';
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    wr->numeric_id = (value & NE_RESOURCE_NAME_IS_NUMERIC ? true:false);
Packit 6e6f77
    return true;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
static WinResource *
Packit 6e6f77
list_pe_resources (WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count)
Packit 6e6f77
{
Packit 6e6f77
    WinResource *wr;
Packit 6e6f77
    unsigned int out_c;
Packit 6e6f77
    int dirent_c, rescnt;
Packit 6e6f77
    Win32ImageResourceDirectoryEntry *dirent
Packit 6e6f77
      = (Win32ImageResourceDirectoryEntry *) (pe_res + 1);
Packit 6e6f77
Packit 6e6f77
    /* count number of `type' resources */
Packit 6e6f77
    RETURN_IF_BAD_POINTER(NULL, *dirent);
Packit 6e6f77
    rescnt = pe_res->number_of_named_entries + pe_res->number_of_id_entries;
Packit 6e6f77
    *count = 0;
Packit 6e6f77
    if (rescnt == 0) return NULL;
Packit 6e6f77
Packit 6e6f77
    /* allocate WinResource's */
Packit 6e6f77
    wr = xmalloc(sizeof(WinResource) * rescnt);
Packit 6e6f77
Packit 6e6f77
    /* fill in the WinResource's */
Packit 6e6f77
    out_c = 0;
Packit 6e6f77
    for (dirent_c = 0 ; dirent_c < rescnt ; dirent_c++) {
Packit 6e6f77
        RETURN_IF_BAD_POINTER(NULL, dirent[dirent_c]);
Packit 6e6f77
        wr[out_c].this = pe_res;
Packit 6e6f77
        wr[out_c].level = level;
Packit 6e6f77
        wr[out_c].is_directory = (dirent[dirent_c].u2.s.data_is_directory);
Packit 6e6f77
        /* Require data to point somewhere after the directory */
Packit 6e6f77
        if (dirent[dirent_c].u2.s.offset_to_directory < sizeof(Win32ImageResourceDirectory))
Packit 6e6f77
            continue;
Packit 6e6f77
        wr[out_c].children = fi->first_resource + dirent[dirent_c].u2.s.offset_to_directory;
Packit 6e6f77
Packit 6e6f77
        /* fill in wr->id, wr->numeric_id */
Packit 6e6f77
        if (!decode_pe_resource_id (fi, wr + out_c, dirent[dirent_c].u1.name))
Packit 6e6f77
            continue;
Packit 6e6f77
Packit 6e6f77
        ++out_c;
Packit 6e6f77
        ++(*count);
Packit 6e6f77
    }
Packit 6e6f77
    if (out_c == 0) {
Packit 6e6f77
        free(wr);
Packit 6e6f77
        return NULL;
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    return wr;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
static WinResource *
Packit 6e6f77
list_ne_name_resources (WinLibrary *fi, WinResource *typeres, int *count)
Packit 6e6f77
{
Packit 6e6f77
    int c, rescnt;
Packit 6e6f77
    WinResource *wr;
Packit 6e6f77
    Win16NETypeInfo *typeinfo = (Win16NETypeInfo *) typeres->this;
Packit 6e6f77
    Win16NENameInfo *nameinfo = (Win16NENameInfo *) typeres->children;
Packit 6e6f77
Packit 6e6f77
    /* count number of `type' resources */
Packit 6e6f77
    RETURN_IF_BAD_POINTER(NULL, typeinfo->count);
Packit 6e6f77
    *count = rescnt = typeinfo->count;
Packit 6e6f77
    if (rescnt == 0) return NULL;
Packit 6e6f77
Packit 6e6f77
    /* allocate WinResource's */
Packit 6e6f77
    wr = xmalloc(sizeof(WinResource) * rescnt);
Packit 6e6f77
Packit 6e6f77
    /* fill in the WinResource's */
Packit 6e6f77
    for (c = 0 ; c < rescnt ; c++) {
Packit 6e6f77
        RETURN_IF_BAD_POINTER(NULL, nameinfo[c]);
Packit 6e6f77
        wr[c].this = nameinfo+c;
Packit 6e6f77
        wr[c].is_directory = false;
Packit 6e6f77
        wr[c].children = nameinfo+c;
Packit 6e6f77
        wr[c].level = 1;
Packit 6e6f77
Packit 6e6f77
        /* fill in wr->id, wr->numeric_id */
Packit 6e6f77
        if (!decode_ne_resource_id (fi, wr + c, (nameinfo+c)->id)) {
Packit 6e6f77
            free(wr);
Packit 6e6f77
            return NULL;
Packit 6e6f77
        }
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    return wr;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
static WinResource *
Packit 6e6f77
list_ne_type_resources (WinLibrary *fi, int *count)
Packit 6e6f77
{
Packit 6e6f77
    size_t c, rescnt;
Packit 6e6f77
    WinResource *wr;
Packit 6e6f77
    Win16NETypeInfo *typeinfo;
Packit 6e6f77
Packit 6e6f77
    /* count number of `type' resources */
Packit 6e6f77
    typeinfo = (Win16NETypeInfo *) fi->first_resource;
Packit 6e6f77
    RETURN_IF_BAD_POINTER(NULL, *typeinfo);
Packit 6e6f77
    for (rescnt = 0 ; typeinfo->type_id != 0 ; rescnt++) {
Packit 6e6f77
        if (((char *) NE_TYPEINFO_NEXT(typeinfo))+sizeof(uint16_t) > fi->memory + fi->total_size) {
Packit 6e6f77
            warn(_("%s: resource table invalid, ignoring remaining entries"), fi->name);
Packit 6e6f77
            break;
Packit 6e6f77
        }
Packit 6e6f77
        typeinfo = NE_TYPEINFO_NEXT(typeinfo);
Packit 6e6f77
        RETURN_IF_BAD_POINTER(NULL, *typeinfo);
Packit 6e6f77
    }
Packit 6e6f77
    *count = rescnt;
Packit 6e6f77
    if (rescnt == 0) return NULL;
Packit 6e6f77
Packit 6e6f77
    /* allocate WinResource's */
Packit 6e6f77
    wr = xmalloc(sizeof(WinResource) * rescnt);
Packit 6e6f77
Packit 6e6f77
    /* fill in the WinResource's */
Packit 6e6f77
    typeinfo = (Win16NETypeInfo *) fi->first_resource;
Packit 6e6f77
    for (c = 0 ; c < rescnt ; c++) {
Packit 6e6f77
        wr[c].this = typeinfo;
Packit 6e6f77
        wr[c].is_directory = (typeinfo->count != 0);
Packit 6e6f77
        wr[c].children = typeinfo+1;
Packit 6e6f77
        wr[c].level = 0;
Packit 6e6f77
Packit 6e6f77
        /* fill in wr->id, wr->numeric_id */
Packit 6e6f77
        if (!decode_ne_resource_id (fi, wr + c, typeinfo->type_id)) {
Packit 6e6f77
            free(wr);
Packit 6e6f77
            return NULL;
Packit 6e6f77
        }
Packit 6e6f77
Packit 6e6f77
        typeinfo = NE_TYPEINFO_NEXT(typeinfo);
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    return wr;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
/* list_resources:
Packit 6e6f77
 *   Return an array of WinResource's in the current
Packit 6e6f77
 *   resource level specified by res.
Packit 6e6f77
 */
Packit 6e6f77
static WinResource *
Packit 6e6f77
list_resources (WinLibrary *fi, WinResource *res, int *count)
Packit 6e6f77
{
Packit 6e6f77
    if (res != NULL && !res->is_directory)
Packit 6e6f77
        return NULL;
Packit 6e6f77
Packit 6e6f77
    if (fi->is_PE_binary) {
Packit 6e6f77
        return list_pe_resources(fi, (Win32ImageResourceDirectory *)
Packit 6e6f77
                 (res == NULL ? fi->first_resource : res->children),
Packit 6e6f77
                 (res == NULL ? 0 : res->level+1),
Packit 6e6f77
                 count);
Packit 6e6f77
    } else {
Packit 6e6f77
        return (res == NULL
Packit 6e6f77
                ? list_ne_type_resources(fi, count)
Packit 6e6f77
                : list_ne_name_resources(fi, res, count));
Packit 6e6f77
    }
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
static Win32ImageDataDirectory *
Packit 6e6f77
get_data_directory_entry (WinLibrary *fi, unsigned int entry)
Packit 6e6f77
{
Packit 6e6f77
    Win32ImageNTHeaders *pe_header;
Packit 6e6f77
    pe_header = PE_HEADER(fi->memory);
Packit 6e6f77
    RETURN_IF_BAD_POINTER(NULL, pe_header->optional_header.magic);
Packit 6e6f77
Packit 6e6f77
    if (pe_header->optional_header.magic == OPTIONAL_MAGIC_PE32) {
Packit 6e6f77
        Win32ImageOptionalHeader *optional_header = &(pe_header->optional_header);
Packit 6e6f77
        RETURN_IF_BAD_POINTER(false, optional_header->data_directory[entry]);
Packit 6e6f77
        return optional_header->data_directory + entry;
Packit 6e6f77
    } else if (pe_header->optional_header.magic == OPTIONAL_MAGIC_PE32_64) {
Packit 6e6f77
        Win32ImageOptionalHeader64 *optional_header =
Packit 6e6f77
            (Win32ImageOptionalHeader64*)&(pe_header->optional_header);
Packit 6e6f77
        RETURN_IF_BAD_POINTER(false, optional_header->data_directory[entry]);
Packit 6e6f77
        return optional_header->data_directory + entry;
Packit 6e6f77
    } else {
Packit 6e6f77
        return NULL;
Packit 6e6f77
    }
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
/* read_library:
Packit 6e6f77
 *
Packit 6e6f77
 * Read header and get resource directory offset in a Windows library
Packit 6e6f77
 * (AKA module).
Packit 6e6f77
 */
Packit 6e6f77
bool
Packit 6e6f77
read_library (WinLibrary *fi)
Packit 6e6f77
{
Packit 6e6f77
    /* check for DOS header signature `MZ' */
Packit 6e6f77
    RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic);
Packit 6e6f77
    if (MZ_HEADER(fi->memory)->magic == IMAGE_DOS_SIGNATURE) {
Packit 6e6f77
        DOSImageHeader *mz_header = MZ_HEADER(fi->memory);
Packit 6e6f77
Packit 6e6f77
        RETURN_IF_BAD_POINTER(false, mz_header->lfanew);
Packit 6e6f77
        if (mz_header->lfanew < sizeof (DOSImageHeader)) {
Packit 6e6f77
            warn(_("%s: not a PE or NE library"), fi->name);
Packit 6e6f77
            return false;
Packit 6e6f77
        }
Packit 6e6f77
Packit 6e6f77
        /* falls through */
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    RETURN_IF_BAD_OFFSET(false, MZ_HEADER(fi->memory), sizeof(Win32ImageNTHeaders));
Packit 6e6f77
    /* check for OS2 (Win16) header signature `NE' */
Packit 6e6f77
    RETURN_IF_BAD_POINTER(false, NE_HEADER(fi->memory)->magic);
Packit 6e6f77
    if (NE_HEADER(fi->memory)->magic == IMAGE_OS2_SIGNATURE) {
Packit 6e6f77
        OS2ImageHeader *header = NE_HEADER(fi->memory);
Packit 6e6f77
        uint16_t *alignshift;
Packit 6e6f77
Packit 6e6f77
        RETURN_IF_BAD_POINTER(false, header->rsrctab);
Packit 6e6f77
        RETURN_IF_BAD_POINTER(false, header->restab);
Packit 6e6f77
        if (header->rsrctab >= header->restab) {
Packit 6e6f77
            warn(_("%s: no resource directory found"), fi->name);
Packit 6e6f77
            return false;
Packit 6e6f77
        }
Packit 6e6f77
Packit 6e6f77
        fi->is_PE_binary = false;
Packit 6e6f77
        alignshift = (uint16_t *) ((uint8_t *) NE_HEADER(fi->memory) + header->rsrctab);
Packit 6e6f77
        fi->first_resource = ((uint8_t *) alignshift) + sizeof(uint16_t);
Packit 6e6f77
        RETURN_IF_BAD_POINTER(false, *(Win16NETypeInfo *) fi->first_resource);
Packit 6e6f77
Packit 6e6f77
        return true;
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    /* check for NT header signature `PE' */
Packit 6e6f77
    RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature);
Packit 6e6f77
    if (PE_HEADER(fi->memory)->signature == IMAGE_NT_SIGNATURE) {
Packit 6e6f77
        Win32ImageSectionHeader *pe_sections;
Packit 6e6f77
        Win32ImageDataDirectory *dir;
Packit 6e6f77
        Win32ImageNTHeaders *pe_header;
Packit 6e6f77
        int d;
Packit 6e6f77
Packit 6e6f77
        /* allocate new memory */
Packit 6e6f77
        fi->total_size = calc_vma_size(fi);
Packit 6e6f77
        if (fi->total_size <= 0) {
Packit 6e6f77
            /* calc_vma_size has reported error */
Packit 6e6f77
            return false;
Packit 6e6f77
        }
Packit 6e6f77
        fi->memory = xrealloc(fi->memory, fi->total_size);
Packit 6e6f77
Packit 6e6f77
        /* relocate memory, start from last section */
Packit 6e6f77
        pe_header = PE_HEADER(fi->memory);
Packit 6e6f77
        RETURN_IF_BAD_PE_SECTIONS(false, fi->memory);
Packit 6e6f77
        pe_sections = PE_SECTIONS(fi->memory);
Packit 6e6f77
Packit 6e6f77
        /* we don't need to do OFFSET checking for the sections.
Packit 6e6f77
         * calc_vma_size has already done that */
Packit 6e6f77
        for (d = pe_header->file_header.number_of_sections - 1; d >= 0 ; d--) {
Packit 6e6f77
            Win32ImageSectionHeader *pe_sec = pe_sections + d;
Packit 6e6f77
Packit 6e6f77
            if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
Packit 6e6f77
                continue;
Packit 6e6f77
Packit 6e6f77
            //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size)
Packit 6e6f77
Packit 6e6f77
            /* Protect against memory moves overwriting the section table */
Packit 6e6f77
            if ((uint8_t*)(fi->memory + pe_sec->virtual_address)
Packit 6e6f77
                < (uint8_t*)(pe_sections + pe_header->file_header.number_of_sections)) {
Packit 6e6f77
                warn(_("%s: invalid sections layout"), fi->name);
Packit 6e6f77
                return false;
Packit 6e6f77
            }
Packit 6e6f77
Packit 6e6f77
            RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data);
Packit 6e6f77
            RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data);
Packit 6e6f77
            if (pe_sec->virtual_address != pe_sec->pointer_to_raw_data) {
Packit 6e6f77
                memmove(fi->memory + pe_sec->virtual_address,
Packit 6e6f77
                    fi->memory + pe_sec->pointer_to_raw_data,
Packit 6e6f77
                    pe_sec->size_of_raw_data);
Packit 6e6f77
            }
Packit 6e6f77
        }
Packit 6e6f77
Packit 6e6f77
        /* find resource directory */
Packit 6e6f77
        dir = get_data_directory_entry (fi, IMAGE_DIRECTORY_ENTRY_RESOURCE);
Packit 6e6f77
        if (dir == NULL) return false;
Packit 6e6f77
        if (dir->size == 0) {
Packit 6e6f77
            warn(_("%s: file contains no resources"), fi->name);
Packit 6e6f77
            return false;
Packit 6e6f77
        }
Packit 6e6f77
Packit 6e6f77
        fi->first_resource = ((uint8_t *) fi->memory) + dir->virtual_address;
Packit 6e6f77
        fi->is_PE_binary = true;
Packit 6e6f77
        return true;
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    /* other (unknown) header signature was found */
Packit 6e6f77
    warn(_("%s: not a PE or NE library"), fi->name);
Packit 6e6f77
    return false;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
/* calc_vma_size:
Packit 6e6f77
 *   Calculate the total amount of memory needed for a 32-bit Windows
Packit 6e6f77
 *   module. Returns -1 if file was too small.
Packit 6e6f77
 */
Packit 6e6f77
static int
Packit 6e6f77
calc_vma_size (WinLibrary *fi)
Packit 6e6f77
{
Packit 6e6f77
    Win32ImageSectionHeader *seg;
Packit 6e6f77
    size_t c, segcount, size;
Packit 6e6f77
Packit 6e6f77
    size = 0;
Packit 6e6f77
    RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections);
Packit 6e6f77
    segcount = PE_HEADER(fi->memory)->file_header.number_of_sections;
Packit 6e6f77
Packit 6e6f77
    /* If there are no segments, just process file like it is.
Packit 6e6f77
     * This is (probably) not the right thing to do, but problems
Packit 6e6f77
     * will be delt with later anyway.
Packit 6e6f77
     */
Packit 6e6f77
    if (segcount == 0)
Packit 6e6f77
        return fi->total_size;
Packit 6e6f77
Packit 6e6f77
    RETURN_IF_BAD_PE_SECTIONS(-1, fi->memory);
Packit 6e6f77
    seg = PE_SECTIONS(fi->memory);
Packit 6e6f77
    RETURN_IF_BAD_POINTER(-1, *seg);
Packit 6e6f77
    
Packit 6e6f77
    for (c = 0 ; c < segcount ; c++) {
Packit 6e6f77
        RETURN_IF_BAD_POINTER(0, *seg);
Packit 6e6f77
Packit 6e6f77
        size = MAX(size, seg->virtual_address + seg->size_of_raw_data);
Packit 6e6f77
        /* I have no idea what misc.virtual_size is for... */
Packit 6e6f77
        size = MAX(size, seg->virtual_address + seg->misc.virtual_size);
Packit 6e6f77
        seg++;
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    return size;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
static WinResource *
Packit 6e6f77
find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id)
Packit 6e6f77
{
Packit 6e6f77
    int c, rescnt;
Packit 6e6f77
    WinResource *return_wr;
Packit 6e6f77
Packit 6e6f77
    wr = list_resources(fi, wr, &rescnt);
Packit 6e6f77
    if (wr == NULL)
Packit 6e6f77
        return NULL;
Packit 6e6f77
Packit 6e6f77
    for (c = 0 ; c < rescnt ; c++) {
Packit 6e6f77
        if (compare_resource_id (&wr[c], id)) {
Packit 6e6f77
            /* duplicate WinResource and return it */
Packit 6e6f77
            return_wr = xmalloc(sizeof(WinResource));
Packit 6e6f77
            memcpy(return_wr, &wr[c], sizeof(WinResource));
Packit 6e6f77
Packit 6e6f77
            /* free old WinResource */
Packit 6e6f77
            free(wr);
Packit 6e6f77
            return return_wr;
Packit 6e6f77
        }
Packit 6e6f77
    }
Packit 6e6f77
Packit 6e6f77
    return NULL;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
WinResource *
Packit 6e6f77
find_resource (WinLibrary *fi, const char *type, const char *name, const char *language, int *level)
Packit 6e6f77
{
Packit 6e6f77
    WinResource *wr;
Packit 6e6f77
Packit 6e6f77
    *level = 0;
Packit 6e6f77
    if (type == NULL)
Packit 6e6f77
        return NULL;
Packit 6e6f77
    wr = find_with_resource_array(fi, NULL, type);
Packit 6e6f77
    if (wr == NULL || !wr->is_directory)
Packit 6e6f77
        return wr;
Packit 6e6f77
Packit 6e6f77
    *level = 1;
Packit 6e6f77
    if (name == NULL)
Packit 6e6f77
        return wr;
Packit 6e6f77
    wr = find_with_resource_array(fi, wr, name);
Packit 6e6f77
    if (wr == NULL || !wr->is_directory)
Packit 6e6f77
        return wr;
Packit 6e6f77
Packit 6e6f77
    *level = 2;
Packit 6e6f77
    if (language == NULL)
Packit 6e6f77
        return wr;
Packit 6e6f77
    wr = find_with_resource_array(fi, wr, language);
Packit 6e6f77
    return wr;
Packit 6e6f77
}