/* Segment probe by sectorx of xor (http://xorteam.cjb.net)
 * 
 * This code will search an exectuable or core dump for a string, giving you
 * its exact location in the memory, its segment location, offset in segment
 * and segment type.
 * note: the struct 'types' may require some changing on other systems since
 *       I built this using the information on Linux's elf.h
 * 
 * --sectorx (sectorx@themarines.com)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <elf.h>
#include <fcntl.h>

#define MAX           4096
#define SEGMENT_TYPES 12 
#define VERSION       "1.0"

struct Description {
   char name[100];
   Elf32_Word num;
};

struct Description types[SEGMENT_TYPES] = 
{
   {"Program header table entry",    PT_NULL},
   {"Loadable program segment",      PT_LOAD},
   {"Dynamic linking information",PT_DYNAMIC},
   {"Program interpreter",         PT_INTERP},
   {"Auxiliary information",         PT_NOTE},
   {"Reserved",                     PT_SHLIB},
   {"Entry for header table itself", PT_PHDR},
   {"Number of defined types",        PT_NUM},
   {"Start of OS-specific",          PT_LOOS},
   {"End of OS-specific",            PT_HIOS},
   {"Start of processor-specific", PT_LOPROC},
   {"End of processor-specific",   PT_HIPROC}
};

int Define(Elf32_Word p_type)
{
   int i;
   for (i=0;i<SEGMENT_TYPES;i++) if (types[i].num == p_type) return i;
   return -1;
}

void Header(int fd)
{
   Elf32_Ehdr hdr;
   
   lseek(fd,0,SEEK_SET);
   read(fd,&hdr,sizeof(Elf32_Ehdr));
   printf("ELF Binary header:\n");
   printf("ident = \"%s\"\n",hdr.e_ident);
   printf("type = ");
   switch (hdr.e_type) {
    case 2:
      printf("Exec\n");
      break;
    case 4:
      printf("Core\n");
      break;
    default:
      printf("Invalid\n");
      exit(1);
      break;
   }
   printf("\n");
}

int Where(int fd) { return(lseek(fd,0,SEEK_CUR)); }

int Segment(int fd, char *str)
{
   Elf32_Phdr seg;
   long int pos;
   int type;
   
   read(fd,&seg,sizeof(Elf32_Phdr));
   type = Define(seg.p_type);
   if (type<0) return 0;
   if (seg.p_filesz == 0) goto Eof;
   
   pos = Where(fd);
     {
	const int size = seg.p_filesz;
	int i;
	char buf[size];
	
	memset(&buf,0,size);
	if (lseek(fd,seg.p_offset,SEEK_SET)!=seg.p_offset) { printf("Error.\n "); goto Eof; }
	if (read(fd,&buf,size)!=size) { printf("Error.\n "); goto Eof; }
	for (i=0;i<size;i++) if (buf[i]==0) buf[i]=1;
	buf[size-1]='\0';
	if (strstr(buf, str)) {
	   char *ptr = strstr(buf,str);
	   ptr-=buf;
	   printf("*** Query found:\n");
	   printf("Segment type  : %s\n", types[type].name);
	   printf("Segment start : 0x%x\n",seg.p_vaddr);
	   printf("Location      : 0x%x\n",ptr+seg.p_vaddr);
	   printf("Offset        : %d\n",ptr);
	}
     }
   if (lseek(fd,pos,SEEK_SET)!=pos) {
      perror("Unable to return to initial position ");
      exit(1);
   }
   
   Eof: ;
   return 1;
}

int main(int argc, char *argv[])
{
   int fd;
   
   printf("Segment probe v%s by sectorx of xor (http://xorteam.cjb.net)\n",VERSION);
   printf("- thanks to duke for helping me start coding this\n\n");
   if (argc < 3) {
      printf("usage: %s <elf> <string to search>\n",argv[0]);
      exit(1);
   }
   
   fd = open(argv[1],O_RDONLY);
   if (fd<0) {
      perror("open() ");
      return;
   }
   Header(fd);
   printf("Searching segments for requested string ...\n",argv[1]);
   while (Segment(fd,argv[2])>0);
   close(fd);
}
