/*

Linux Binary File Joiner v0.1 (beta)

Author:	   	__GiReX__
MySite:    	girex.altervista.org
CompleteDate:	03/04/2008

Released under the terms of condition of GNU License

*/

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#define  JOINER_SIZE 14000   

/* La grandezza in byte (arrotondata) del joiner compilato */
/* Modificare in caso sia superiore */

const char match_str[] =  /* @@@AAA@@@ */
{
    0x00,
    0x40, 0x40, 0x40,
    0x41, 0x41, 0x41,
    0x40, 0x40, 0x40,
    0x00
};


void usage(char *prog)
{
     printf("Usage:  %s  <first_exe> <second_exe>\n", prog);
     printf("\t./joined.bin # For run the 2 joined executables\n");
}

void banner()
{
     printf("Linux Binary File Joiner v0.1 (beta)\n");
     printf("Released under GNU public license\n");
     printf("Coded by __GiReX__\n\n");
}
     
int check_size(char *me)
{
  struct stat info;
	
    if(stat(me, &info) != 0)
    {
	 printf("Unable to retrieve infos about myself\n");
	 return 1;
    }

    if(info.st_size < JOINER_SIZE) 
    {  
         return 0;
    }

  return 1;
}

int write_exe(char *me, unsigned long int off1, unsigned long int off2)
{
  int fd, my_fd, i = 0; 
  static int first = 0;
  char nome_file[25] = {0}, byte = 0;
 
    if(first == 0) strcpy(nome_file, "./first_exe.bin"); 
    else strcpy(nome_file, "./second_exe.bin");
    
    if((my_fd = open(me, O_RDONLY)) < 0)
    {
	      printf("Unable to open myself in read mode\n");
	      return 1;
    }

    if((fd = open(nome_file, O_CREAT | O_WRONLY | O_APPEND | O_TRUNC, 0777)) < 0)
    {
	  printf("Unable to open %s in write mode\n");
	  return 1;
    }

    for(i = 0; i <= off1; i++)
    {
	 read(my_fd, &byte, 1);
    }

    while(i <= off2)
    {
         read(my_fd, &byte, 1);
	 write(fd, &byte, 1);
         i++;
    }

    close(my_fd);
    close(fd);
    first++;

  return 0;
} 

int split_file(char *me)
{
  unsigned long int i = 0;
  int my_fd, match = 0, offset[5] = {0, 0, 0, 0, 0 };
  char byte = 0x00, buff[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

    if((my_fd = open(me, O_RDONLY)) < 0)
    {
	  printf("Unable to open myself in read mode\n");
	  return 1;
    }

    for(i = 0; read(my_fd, &byte, 1) > 0; i++)
    {						/* ciclo for no eh :P */
	  buff[8] = buff[7];
	  buff[7] = buff[6];
	  buff[6] = buff[5];
	  buff[5] = buff[4];
	  buff[4] = buff[3];
	  buff[3] = buff[2];
	  buff[2] = buff[1];
	  buff[1] = buff[0];
	  buff[0] = byte;
		  
	  if(
              buff[0] == 0x40  &&
              buff[1] == 0x40  &&
	      buff[2] == 0x40  &&
	      buff[3] == 0x41  &&
	      buff[4] == 0x41  &&
	      buff[5] == 0x41  &&
	      buff[6] == 0x40  &&
	      buff[7] == 0x40  &&
	      buff[8] == 0x40  )
          {
		match++;
		offset[match - 1] = i;

		if(match == 3)
		{
		      if(write_exe(me, offset[1] + 1, offset[2] - 9) != 0) return 1;
		}
          }

     }

     if(match < 3)
     {
	    printf("Unable to split file joined\n");
	    return 0;
     }

     if(match >= 3)
     {
            if(write_exe(me, offset[2] + 1, i) != 0) return 1;
     } 
     
     close(my_fd);

  return 0;
}

 
int main(int argc, char **argv)
{
  pid_t pid[2];
  char byte = 0;
  int my_fd, fd1, fd2, fd3;

    if(argc < 3)
    { 		
       	  if(check_size(argv[0]) == 0)	
	  {
		banner();
	        usage(argv[0]);
	        return 1;
	  }

     	  if(split_file(argv[0]) == 0)	
	  {
	      pid[0] = fork();		

		if(pid[0] < 0)
		{
		      printf("Errore nella creazione di un processo figlio\n");
		      return 1;
		}
		if(pid[0] == 0)
		{
		      execl("first_exe.bin","first_exe.bin", NULL);
		      exit(0);
		}
		if(pid[0] > 0)
		{
		   pid[1] = fork();
                      
		      if(pid[1] < 0)
		      {
		            printf("Errore nella creazione di un processo figlio\n");
		            return 1;
		      }
		      if(pid[1] == 0)
		      {
		            execl("second_exe.bin","second_exe.bin", NULL);
		            exit(0);
		      }
		      if(pid[1] > 0)
		      {
			    waitpid(pid[0], (int*) 0, 0);
			    waitpid(pid[1], (int*) 0, 0);
		      }

                   printf("I due eseguibili joinati sono stati eseguiti con successo\n");
		}

	      return 0;
          }
          else  return 1;
    }
    
    banner();

    if((fd3 = open("joined.bin", O_CREAT | O_WRONLY | O_APPEND | O_TRUNC, 0777)) < 0)
    {
	  printf("Unable to open output file\n");
	  return 1;
    }

    if((my_fd = open(argv[0], O_RDONLY)) < 0)
    {
	  printf("Unable to open mdsfyself in read mode\n");
	  return 1;
    }

    while(read(my_fd, &byte, 1) > 0)
    {
	  write(fd3, &byte, 1);
    }

    close(my_fd);
    write(fd3, match_str, 11);

    if((fd1 = open(argv[1], O_RDONLY)) < 0)
    {
	  printf("Unable to open %s in read mode\n", argv[1]);
	  return 1;
    }
  
    while(read(fd1, &byte, 1) > 0)
    {
  	  write(fd3, &byte, 1);
    }     

    close(fd1);
    write(fd3, match_str, 11);

    if((fd2 = open(argv[2], O_RDONLY)) < 0)
    {
	  printf("Unable to open %s in read mode\n", argv[2]);
	  return 1;
    }
  
    while(read(fd2, &byte, 1) > 0)
    {
	  write(fd3, &byte, 1);
    } 
    
    close(fd2);
    write(fd3, match_str, 1);
    close(fd3);
 
    printf("File joined.bin successfull created\n");

  return 0;
}





