Article 12765 of alt.sources:
Path: nntpd.lkg.dec.com!crl.dec.com!crl.dec.com!caen!sol.ctr.columbia.edu!news.mindlink.net!van-bc!vanbc.wimsey.com!vanbc.wimsey.com!not-for-mail
From: markh@vanbc.wimsey.com (Mark C. Henderson)
Newsgroups: alt.sources
Subject: unstrip Solaris 2.4 SPARC dynamically linked binaries
Date: 29 Aug 1995 20:37:33 -0700
Organization: Online at Wimsey Information Services Inc - Vancouver, Canada
Lines: 416
Message-ID: <420mdt$j8l@vanbc.wimsey.com>
NNTP-Posting-Host: vanbc.wimsey.com

This is an alpha version of unstrip, which recovers some symbolic
information from the dynamic symbol table of the binary, and makes it
available to be used with a debugger such as adb, gdb, or dbx.


/* 
 * a quick and dirty hack to "unstrip" a Solaris 2.4 ELF SPARC binary
 * This program recovers some symbolic information from the dynamic
 * symbol table of the binary, and creates a new symbol table section
 * with that data.
 *
 * to compile: gcc -o unstrip unstrip.c  (or use /opt/SUNWspro/bin/cc)
 *
 * This can often be useful when reverse engineering dynamically linked
 * binaries, e.g. to find out what is going on when they dump core
 *
 * inspired by unstrip for Sun OS 4.1.x by P.Kranenburg <pk@cs.few.eur.nl>
 *
 * Author: Mark C. Henderson <markh@wimsey.bc.ca>
 * Placed in the public domain by the author. 29 August 95
 *
 * Version 0.21 -- alpha version -- USE AT YOUR OWN RISK
 *
 * BUGS: Probably several. Please report them to markh@wimsey.bc.ca.
 *
 * N.B. If this program malfunctions it can corrupt the binary you run
 *      it on. Please make backup copies.
 *
 * lightly tested with adb, /opt/SUNWspro/bin/dbx, and gdb 4.14
 */

#include <elf.h>
#include <sys/elf_SPARC.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define MAXSECTIONS 128

Elf32_Shdr sht[MAXSECTIONS];
unsigned char *secnames[MAXSECTIONS];
unsigned char *symtable;
unsigned char *stringtable;
unsigned char *shstringtable;
unsigned char *new_shstringtable;
unsigned char s[] = "\0.strtab\0.symtab\0\0\0\0\0\0\0\0\0\0";
main(argc,argv) 
int argc; 
char *argv[];
{
    Elf32_Ehdr hdr,newhdr;
    Elf32_Shdr newshdr,newshdr1,newshdr2;
    int need_new_shstringtable = 0; 
    unsigned int i;
    int pad = 0, pad1 = 0, pad0 = 0, pad2 = 0;
    int sto = (-1), sto1 = (-1);
    int c;
    FILE *chan;
    int symflag = 0;
    size_t size;
    int dyn = (-1);
    int stringidx = (-1);

    if (argc < 2) {
            fprintf(stderr, "usage: %s file\n",argv[0]);
            exit(1);
    }
    chan = fopen(argv[1],"r+");

    if (!chan) {
            fprintf(stderr, "cannot open %s\n", argv[1]);
            exit(1);
    }
    if (fread(&hdr,sizeof(hdr),1,chan) < 0) {
        fprintf(stderr, "not an ELF file\n");
        exit(1);
    }
    if (    (hdr.e_ident[0] != ELFMAG0) ||
                    (hdr.e_ident[1] != ELFMAG1) ||
                    (hdr.e_ident[2] != ELFMAG2) ||
                    (hdr.e_ident[3] != ELFMAG3)     ) {
            fprintf(stderr, "not an ELF file\n");
            exit(1);
    }
    if (hdr.e_ident[4] != ELFCLASS32) {
            fprintf(stderr, "not a 32 bit object\n");
            exit(1);
    }
    if (hdr.e_type != ET_EXEC) {
            fprintf(stderr, "not an executable file\n");
            exit(1);
    }
    if (!hdr.e_shoff) {
            fprintf(stderr, "file has no section header table\n");
            exit(1);
    }
    if (hdr.e_shnum > MAXSECTIONS) {
            fprintf(stderr, "%s has %d sections. maximum is %d\n", 
                argv[1],hdr.e_shnum, MAXSECTIONS);
            fprintf(stderr, 
                "increase MAXSECTIONS in unstrip.c and recompile\n");
            exit(1);
    }
    if (fseek(chan,hdr.e_shoff,SEEK_SET) < 0) {
            fprintf(stderr, "fseek failed\n"); 
            exit(1);
    }
    for (i=0; i < hdr.e_shnum ; i++) {
            fread(&sht[i], sizeof(Elf32_Shdr),1,chan);
            if (sht[i].sh_type == SHT_DYNSYM) dyn = i;
            if (sht[i].sh_type == SHT_SYMTAB) symflag++;
    }
    if (symflag) {
        fprintf(stderr, "file is not stripped - already has symbol table \n");
        exit(1);
    }
    if (dyn < 0) {
        fprintf(stderr, "file is not dynamically linked\n");
        exit(1);
    }

   /* get section name string table */
   if (hdr.e_shstrndx != SHN_UNDEF) { 
        if (fseek(chan, sht[hdr.e_shstrndx].sh_offset, SEEK_SET) < 0) {
            perror("fseek failed (shstr)"); exit(1);
        }
        if (!(shstringtable = malloc(sht[hdr.e_shstrndx].sh_size))) {
            fprintf(stderr, "malloc failed\n"); exit(1);
        }
        if (fread(shstringtable, 1, sht[hdr.e_shstrndx].sh_size, chan) 
           < sht[hdr.e_shstrndx].sh_size) {
            perror("fread failed (str)"); exit(1);
        }
   }
   else
      shstringtable = NULL;  /* no section name string table */

   /* now get the section names themselves */
   if (shstringtable) {
       for (i=0; i < hdr.e_shnum ; i++) {
            int len = strlen(&shstringtable[sht[i].sh_name]);
            secnames[i] = malloc(len+1);
            strncpy(secnames[i],&shstringtable[sht[i].sh_name], len + 1);
            if (sht[i].sh_type == SHT_STRTAB && 
                (sht[i].sh_flags & SHF_ALLOC) &&
                !strcmp(secnames[i],".dynstr"))
                    stringidx = i;  /* index of dynamic string table */
       }
   }
   else {
       for (i=0; i < hdr.e_shnum ; i++) {
            /* best guess as to location of dynamic string table */
            if (sht[i].sh_type == SHT_STRTAB && (sht[i].sh_flags & SHF_ALLOC))
                    stringidx = i;  
            secnames[i] = (unsigned char *)"";
       }
   }

   /* get dynamic symbol table */
   if (sht[dyn].sh_size) {
        if (fseek(chan, sht[dyn].sh_offset, SEEK_SET) < 0) {
            perror("fseek failed (dyn)"); exit(1);
        }
        if (!(symtable = malloc(sht[dyn].sh_size))) {
            fprintf(stderr, "malloc failed\n"); exit(1);
        }
        if (fread(symtable, 1, sht[dyn].sh_size, chan) < sht[dyn].sh_size) {
            perror("fread failed (dyn)"); exit(1);
        }
    }
    else {
        fprintf(stderr, "dynamic symbol table has zero size\n");
        exit(1);
    }

    /* get string table */
    if ((stringidx >= 0) && sht[stringidx].sh_size) {
        if (fseek(chan, sht[stringidx].sh_offset, SEEK_SET) < 0) {
            perror("fseek failed (str)"); exit(1);
        }
        if (!(stringtable = malloc(sht[stringidx].sh_size))) {
            fprintf(stderr, "malloc failed\n"); exit(1);
        }
        if (fread(stringtable, 1, sht[stringidx].sh_size, chan) 
           < sht[stringidx].sh_size) {
            perror("fread failed (str)"); exit(1);
        }
     }
    else {
        fprintf(stderr, "warning: string table has zero size\n");
        stringidx = (-1);   /* just to be sure */
        exit(1);
    }

    /* find offset to .symtab and .strtab in section name string table */
    if (shstringtable) {
        for (i=0; i < sht[hdr.e_shstrndx].sh_size - 8; i++) {    
            if (!strncmp(&shstringtable[i],".symtab",8)) {
                sto = i;
                break;
            }
        }
        for (i=0; i < sht[hdr.e_shstrndx].sh_size - 8; i++) {    
            if (!strncmp(&shstringtable[i],".strtab",8)) {
                sto1 = i;
                break;
            }
        }
    }

    if (sto < 0 || sto1 < 0) {
        /* This is annoying. Sometimes the sh_stringtable doesn't contain
           one or both of .symtab or .strtab */
        need_new_shstringtable = 1;
        new_shstringtable = malloc(sht[hdr.e_shstrndx].sh_size + 24 );
        if (!new_shstringtable) {
            fprintf(stderr, "malloc failed\n"); exit(1);
        }
        memcpy(new_shstringtable,shstringtable,sht[hdr.e_shstrndx].sh_size);
        for (i=0; i < 19 ; i++) 
            *(new_shstringtable + sht[hdr.e_shstrndx].sh_size + i) = s[i];

        memcpy(&newshdr2,&sht[hdr.e_shstrndx],sizeof(newshdr2));
        newshdr2.sh_size += 19;
        sto1 = sht[hdr.e_shstrndx].sh_size + 1;
        sto = sht[hdr.e_shstrndx].sh_size + 9;
        fseek(chan, 0, SEEK_END);
        newshdr2.sh_offset = ftell(chan);
        if (newshdr2.sh_addralign > 1) {
            pad0 = newshdr2.sh_addralign - (newshdr2.sh_offset
                % newshdr2.sh_addralign);
            newshdr2.sh_offset += pad0;
        }
        else
            pad0 = 0;
        for (i=0; i < pad0; i++)
            putc(0,chan);
        if (ftell(chan) != newshdr2.sh_offset) {
            fprintf(stderr, "internal error (new_shstringtable)\n");
            exit(1);
        }
        if (fwrite(new_shstringtable, (unsigned int)newshdr2.sh_size, 
          1, chan) < 1) {
            perror("fwrite failed (new_shstringtable)");
            exit(1);
        }
    }

    if (stringidx < 0) {

        memcpy(&newhdr,&hdr,sizeof(newhdr));
        memcpy(&newshdr,&sht[dyn],sizeof(newshdr));

        /* go to end of file */
        fseek(chan, 0, SEEK_END);
        newhdr.e_shoff = ftell(chan);

        /* get new offset for section header table */
        if (newhdr.e_shoff % 8)
            pad2 = 8 - (newhdr.e_shoff % 8);
        else
            pad2 = 0;
        newhdr.e_shoff += pad2;
        for (i=0; i<pad2; i++)
            putc(0,chan);

        newhdr.e_shnum++;

        /* write new section header table */
        for (i=0; i < hdr.e_shnum ; i++) {
            if (need_new_shstringtable && i == hdr.e_shstrndx) {
                if (fwrite(&newshdr2, sizeof(Elf32_Shdr),1,chan) < 1) {
                    perror("fwrite failed");
                    exit(1);
                }
            }
            else {
                if (fwrite(&sht[i], sizeof(Elf32_Shdr),1,chan) < 1) {
                    perror("fwrite failed");
                    exit(1);
                }
            }
        }
        newshdr.sh_type = SHT_SYMTAB;
        if (newshdr.sh_addralign > 1)
            pad = newshdr.sh_addralign - ((newhdr.e_shoff + newhdr.e_shnum 
                * newhdr.e_shentsize) % (newshdr.sh_addralign)); 
        else
            pad = 0;
        
        newshdr.sh_offset = (newhdr.e_shoff + newhdr.e_shnum * 
            newhdr.e_shentsize) + pad; 
        if (sto >= 0)
            newshdr.sh_name = sto;
        if (fwrite(&newshdr, sizeof(Elf32_Shdr),1,chan) < 1) {
            perror("fwrite failed (newshdr)");
            exit(1);
        }
        for (i=0; i<pad; i++)
            putc(0,chan);
        if (fwrite(symtable, newshdr.sh_size, 1, chan) < 1) {
            perror("fwrite failed (symtable)");
            exit(1);
        }
        rewind(chan);
        if (fwrite(&newhdr,sizeof(newhdr),1,chan) < 1) {
            perror("fwrite failed (elfhdr)");
            exit(1);
        }
    }
    else {
        memcpy(&newhdr,&hdr,sizeof(newhdr));
        memcpy(&newshdr,&sht[dyn],sizeof(newshdr));
        memcpy(&newshdr1,&sht[stringidx],sizeof(newshdr1));

        /* go to end of file */
        fseek(chan, 0, SEEK_END);
        newhdr.e_shoff = ftell(chan);

        /* get new offset for section header table */
        if (newhdr.e_shoff % 8)
            pad2 = 8 - (newhdr.e_shoff % 8);
        else
            pad2 = 0;
        newhdr.e_shoff += pad2;
        for (i=0; i<pad2; i++)
            putc(0,chan);

        newhdr.e_shnum+=2;  /* two new sections */

        /* write new section header table */
        for (i=0; i < hdr.e_shnum ; i++) {
            if (need_new_shstringtable && i == hdr.e_shstrndx) {
                if (fwrite(&newshdr2, sizeof(Elf32_Shdr),1,chan) < 1) {
                    perror("fwrite failed");
                    exit(1);
                }
            }
            else {
                if (fwrite(&sht[i], sizeof(Elf32_Shdr),1,chan) < 1) {
                    perror("fwrite failed");
                    exit(1);
                }
            }
        }
        newshdr.sh_type = SHT_SYMTAB;
		newshdr.sh_flags = 0;
        newshdr1.sh_type = SHT_STRTAB;  /* redundant */
        newshdr.sh_link = newhdr.e_shnum - 1;
        newshdr.sh_flags = 0;
        newshdr1.sh_flags = 0;
        if (sto >= 0)
            newshdr.sh_name = sto;
        if (sto1 >= 0)
            newshdr1.sh_name = sto1;

        newshdr.sh_offset = newhdr.e_shoff + newhdr.e_shnum 
            * newhdr.e_shentsize;
        
        if (newshdr.sh_addralign > 1) {
            pad = newshdr.sh_addralign - (newshdr.sh_offset 
                % newshdr.sh_addralign);
            newshdr.sh_offset += pad;
        }
        newshdr1.sh_offset = newshdr.sh_offset + newshdr.sh_size;
        if (newshdr1.sh_addralign > 1) {
            pad1 = newshdr1.sh_addralign - (newshdr1.sh_offset 
                % newshdr1.sh_addralign);
            newshdr1.sh_offset += pad1;
        }
        if (fwrite(&newshdr, sizeof(Elf32_Shdr),1,chan) < 1) {
            perror("fwrite failed (newshdr)");
            exit(1);
        }
        if (fwrite(&newshdr1, sizeof(Elf32_Shdr),1,chan) < 1) {
            perror("fwrite failed (newshdr1)");
            exit(1);
        }
        for (i=0; i < pad ; i++) 
            putc(0,chan);

        if (ftell(chan) != newshdr.sh_offset) {
            fprintf(stderr, "internal error (1)\n");
            fprintf(stderr, "%08x != %08x\n", ftell(chan), newshdr.sh_offset);
            exit(1);
        }
    
        if (fwrite(symtable, newshdr.sh_size, 1, chan) < 1) {
            perror("fwrite failed (symtable)");
            exit(1);
        }
        for (i=0; i < pad1 ; i++) 
            putc(0,chan);

        if (ftell(chan) != newshdr1.sh_offset) {
            fprintf(stderr, "internal error (2)\n");
            fprintf(stderr, "%08x != %08x\n", ftell(chan), newshdr1.sh_offset);
            exit(1);
        }
        if (fwrite(stringtable, newshdr1.sh_size, 1, chan) < 1) {
            perror("fwrite failed (symtable)");
            exit(1);
        }
        rewind(chan);
        if (fwrite(&newhdr,sizeof(newhdr),1,chan) < 1) {
            perror("fwrite failed (elfhdr)");
            exit(1);
        }
    }
    fclose(chan);
}
-- 
Mark Henderson -- markh@wimsey.bc.ca, henderso@netcom.com, mch@squirrel.com
PGP 1024/C58015E3 fingerprint=21 F6 AF 2B 6A 8A 0B E1 A1 2A 2A 06 4A D5 92 46
cryptography archive maintainer  --  ftp://ftp.wimsey.com/pub/crypto
ftp://ftp.netcom.com/pub/he/henderso/change-sun-hostid-1.4.9.tar.gz


