Goto sanos source index

//
// impdef.c
//
// Utility for generating import definitions for DLLs
//
// Copyright (C) 2011 Michael Ringgaard. 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 project 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 OWNER 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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <os/pe.h>

void *get_rva(char *dll, struct image_header *imghdr, unsigned long rva) {
  int i;

  // Find section containing the relative virtual address
  for (i = 0; i < imghdr->header.number_of_sections; i++) {
    struct image_section_header *sect = &imghdr->sections[i];
    if (sect->virtual_address <= rva && sect->virtual_address + sect->size_of_raw_data > rva) {
      return dll + sect->pointer_to_raw_data + (rva - sect->virtual_address);
    }
  }
  return NULL;
}

void *get_image_directory(char *dll, struct image_header *imghdr, int dir) {
  return get_rva(dll, imghdr, imghdr->optional.data_directory[dir].virtual_address);
}

int main(int argc, char *argv[]) {
  char *dll_filename;
  char *def_filename;
  char *dll;
  int fd;
  unsigned int size, i;
  struct stat st;
  struct dos_header *doshdr;
  struct image_header *imghdr;
  struct image_export_directory *expdir;
  unsigned long *names;
  unsigned short *ordinals;
  char *module_name;
  FILE *output;

  // Parse command line
  if (argc == 2) {
    dll_filename = argv[1];
    def_filename = NULL;
  } else if (argc == 3) { 
    dll_filename = argv[1];
    def_filename = argv[2];
  } else { 
    fprintf(stderr, "usage: impdef <dll> [<def>]\n");
    return 1;
  }
  
  // Load DLL image into memory
  fd = open(dll_filename, O_RDONLY | O_BINARY);
  if (fd < 0 || fstat(fd, &st) < 0) {
    perror(dll_filename);
    return 1;
  }
  size = st.st_size;
  dll = (char *) malloc(size);
  if (read(fd, dll, size) != size) {
    perror(dll_filename);
    free(dll);
    return 1;
  }
  close(fd);

  // Check PE file signature
  doshdr = (struct dos_header *) dll;
  imghdr = (struct image_header *) (dll + doshdr->e_lfanew);
  if (doshdr->e_lfanew > size || imghdr->signature != IMAGE_PE_SIGNATURE) {
    fprintf(stderr, "%s: Not a PE file\n", dll_filename);
    free(dll);
    return 1;
  }
  
  // Open output file.
  if (def_filename) {
    output = fopen(def_filename, "wb");
    if (output == NULL) {
      perror(def_filename);
      free(dll);
      return 1;
    }
  } else {
    output = stdout;
  }
  
  // Output exported functions.
  expdir = get_image_directory(dll, imghdr, IMAGE_DIRECTORY_ENTRY_EXPORT);
  module_name = get_rva(dll, imghdr, expdir->name);
  fprintf(output, "LIBRARY %s\r\n\r\nEXPORTS\r\n", module_name);
  names = get_rva(dll, imghdr, expdir->address_of_names);
  ordinals = get_rva(dll, imghdr, expdir->address_of_name_ordinals);
  for (i = 0; i < expdir->number_of_names; i++) {
    char *name = get_rva(dll, imghdr,  names[i]);
    fprintf(output, "%s@%d\r\n", name, ordinals[i]);
  }

  if (def_filename) fclose(output);
  free(dll);  
  return 0;
}