what you don't know can hurt you

reducebind.c

reducebind.c
Posted Jan 27, 2003
Authored by teso, scut | Site team-teso.net

This utility converts a dynamically link Linux IA32 ELF binary to a static binary.

systems | linux
MD5 | 51bd11bc0ce5e38a9cb6933d910de716

reducebind.c

Change Mirror Download
/* reducebind.c - dynamic to static binary conversion utility
*
* by scut
*
* BETA SOFTWARE, USE ON YOUR OWN RISK
*
* x86/linux only so far. some binaries segfault deep in their code, but this
* does not seem to relate to the binary size. some binaries that have a 19mb
* size statically linked (qt designer for example ;) work, some small
* binaries, such as bash do not work.
*/

#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <elf.h>

#define VERSION "0.1.0"

/*** local prototypes */
static void elf_dump_new (pid_t pid, const char *pathname_new,
const char *pathname_old);
static void file_advance_roundup (FILE *fp, unsigned int padding);
static Elf32_Addr elf_get_entrypoint (const char *pathname);


int
main (int argc, char *argv[], char *envp[])
{
char * pathname;
char * f_argv[2];
pid_t fpid; /* child pid, gets ptraced */
struct user regs; /* PTRACE pulled registers */
Elf32_Addr entry;
char * output = "output";

fprintf (stderr, "reducebind version "VERSION"\n\n");

if (argc < 2) {
fprintf (stderr, "usage: %s <binary> [output]\n\n", argv[0]);

exit (EXIT_FAILURE);
}
pathname = argv[1];
if (argc >= 3)
output = argv[2];

entry = elf_get_entrypoint (pathname);

fpid = fork ();
if (fpid < 0) {
perror ("fork");
exit (EXIT_FAILURE);
}

/* child process.
*/
if (fpid == 0) {
if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) {
perror ("ptrace PTRACE_TRACEME");
exit (EXIT_FAILURE);
}
fprintf (stderr, " child: TRACEME set\n");

fprintf (stderr, " child: executing: %s\n", pathname);
close (1);
dup2 (2, 1);

/* prepare arguments and environment.
*/
f_argv[0] = pathname;
f_argv[1] = NULL;

putenv ("LD_BIND_NOW=1");
execve (f_argv[0], f_argv, envp);

/* failed ? */
perror ("execve");
exit (EXIT_FAILURE);
}

wait (NULL);

memset (&regs, 0, sizeof (regs));

if (ptrace (PTRACE_GETREGS, fpid, NULL, &regs) < 0) {
perror ("ptrace PTRACE_GETREGS");
exit (EXIT_FAILURE);
}
fprintf (stderr, "(%d) [0x%08lx] first stop\n", fpid, regs.regs.eip);
fprintf (stderr, "(%d) tracing until entry point is reached (0x%08x)\n",
fpid, entry);

while (regs.regs.eip != entry) {
if (ptrace (PTRACE_SINGLESTEP, fpid, NULL, NULL) < 0) {
perror ("ptrace PTRACE_SINGLESTEP");
exit (EXIT_FAILURE);
}
wait (NULL);

memset (&regs, 0, sizeof (regs));
if (ptrace (PTRACE_GETREGS, fpid, NULL, &regs) < 0) {
perror ("ptrace PTRACE_GETREGS");
exit (EXIT_FAILURE);
}
fprintf (stderr, "\r(%d) [0x%08lx]", fpid, regs.regs.eip);
}

fprintf (stderr, "\n(%d) entry point reached\n", fpid);
fprintf (stderr, "(%d) dumping process memory to new ELF ET_EXEC file\n",
fpid);

elf_dump_new (fpid, output, pathname);

exit (EXIT_SUCCESS);
}


static void
elf_dump_new (pid_t pid, const char *pathname_new, const char *pathname_old)
{
FILE * fpn;
FILE * fpo;
FILE * mapsfp;
char maps_pathname[32];
char map_line[256];
Elf32_Ehdr eh;
Elf32_Phdr phdr[128];
unsigned int pn; /* program header table index */


fpn = fopen (pathname_new, "wb");
fpo = fopen (pathname_old, "rb");
if (fpn == NULL || fpo == NULL) {
perror ("fopen output ELF file creation");
exit (EXIT_FAILURE);
}

if (fread (&eh, sizeof (eh), 1, fpo) != 1) {
perror ("fread ELF header");
exit (EXIT_FAILURE);
}
fclose (fpo);

/* kill header values */
eh.e_shoff = 0x0; /* we do not need any sections for loading */
eh.e_shnum = 0;
eh.e_shstrndx = 0;

/* the program header table will be fixed later */
eh.e_phoff = 0;
eh.e_phnum = 0;

fwrite (&eh, sizeof (eh), 1, fpn);

snprintf (maps_pathname, sizeof (maps_pathname) - 1,
"/proc/%d/maps", pid);
maps_pathname[sizeof (maps_pathname) - 1] = '\0';
mapsfp = fopen (maps_pathname, "r");
if (mapsfp == NULL) {
perror ("fopen map file");
exit (EXIT_FAILURE);
}

while (1) {
Elf32_Phdr * ph;
unsigned int addr_start,
addr_end,
addr_walker;
char map_perm[8];
unsigned char data_saved[sizeof (unsigned long int)];


memset (map_line, '\0', sizeof (map_line));
if (fgets (map_line, sizeof (map_line) - 1, mapsfp) == NULL)
break;
map_line[sizeof (map_line) - 1] = '\0';

fprintf (stderr, "%s", map_line);
if (sscanf (map_line, "%08x-%08x %7[rwxp-] ",
&addr_start, &addr_end, map_perm) != 3)
{
perror ("invalid map-line");

exit (EXIT_FAILURE);
}

/* we do not need the stack in here.
*/
if (addr_end == 0xc0000000)
continue;

file_advance_roundup (fpn, PAGE_SIZE);

ph = &phdr[eh.e_phnum];
eh.e_phnum += 1;
memset (ph, 0x00, sizeof (Elf32_Phdr));

ph->p_type = PT_LOAD;
ph->p_offset = ftell (fpn);
ph->p_vaddr = addr_start;
ph->p_paddr = 0x0;
ph->p_filesz = ph->p_memsz = addr_end - addr_start;
ph->p_flags = 0;
if (map_perm[0] == 'r')
ph->p_flags |= PF_R;
if (map_perm[1] == 'w')
ph->p_flags |= PF_W;
if (map_perm[2] == 'x')
ph->p_flags |= PF_X;
ph->p_align = PAGE_SIZE;

/* save segment data, assuming addr is page aligned
*/
for (addr_walker = 0 ; addr_walker < (addr_end - addr_start);
addr_walker += sizeof (data_saved))
{
errno = 0;

*((unsigned long int *) &data_saved[0]) =
ptrace (PTRACE_PEEKDATA, pid,
addr_start + addr_walker, NULL);

if (errno == 0 && fwrite (&data_saved[0],
sizeof (data_saved), 1, fpn) != 1)
{
perror ("fwrite segment");

exit (EXIT_FAILURE);
} else if (errno != 0) {
fprintf (stderr,
"[0x%08x] invalid PTRACE_PEEKDATA\n",
addr_start + addr_walker);

exit (EXIT_FAILURE);
}
}
}

fclose (mapsfp);

/* now write program header table
*/
file_advance_roundup (fpn, PAGE_SIZE);
eh.e_phoff = ftell (fpn);

for (pn = 0 ; pn < eh.e_phnum ; ++pn) {
if (fwrite (&phdr[pn], sizeof (Elf32_Phdr), 1, fpn) != 1) {
perror ("fwrite program header");
exit (EXIT_FAILURE);
}
}

fseek (fpn, 0, SEEK_SET);
if (fwrite (&eh, sizeof (Elf32_Ehdr), 1, fpn) != 1) {
perror ("fwrite final ELF header");
exit (EXIT_FAILURE);
}

fclose (fpn);
chmod (pathname_new, 0700);
}


static void
file_advance_roundup (FILE *fp, unsigned int padding)
{
unsigned int pos;

pos = ftell (fp);
if (pos % padding == 0)
return;

pos %= padding;
pos = padding - pos;

fseek (fp, pos, SEEK_CUR);
}


static Elf32_Addr
elf_get_entrypoint (const char *pathname)
{
FILE * fp;
Elf32_Ehdr eh;


fp = fopen (pathname, "rb");
if (fp == NULL) {
perror ("fopen input ELF file");
exit (EXIT_FAILURE);
}

if (fread (&eh, sizeof (eh), 1, fp) != 1) {
perror ("fread");
exit (EXIT_FAILURE);
}

fclose (fp);

return (eh.e_entry);
}


Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

February 2019

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Feb 1st
    22 Files
  • 2
    Feb 2nd
    9 Files
  • 3
    Feb 3rd
    2 Files
  • 4
    Feb 4th
    15 Files
  • 5
    Feb 5th
    50 Files
  • 6
    Feb 6th
    24 Files
  • 7
    Feb 7th
    15 Files
  • 8
    Feb 8th
    6 Files
  • 9
    Feb 9th
    1 Files
  • 10
    Feb 10th
    1 Files
  • 11
    Feb 11th
    22 Files
  • 12
    Feb 12th
    25 Files
  • 13
    Feb 13th
    16 Files
  • 14
    Feb 14th
    32 Files
  • 15
    Feb 15th
    15 Files
  • 16
    Feb 16th
    10 Files
  • 17
    Feb 17th
    0 Files
  • 18
    Feb 18th
    0 Files
  • 19
    Feb 19th
    0 Files
  • 20
    Feb 20th
    0 Files
  • 21
    Feb 21st
    0 Files
  • 22
    Feb 22nd
    0 Files
  • 23
    Feb 23rd
    0 Files
  • 24
    Feb 24th
    0 Files
  • 25
    Feb 25th
    0 Files
  • 26
    Feb 26th
    0 Files
  • 27
    Feb 27th
    0 Files
  • 28
    Feb 28th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2019 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close