///////////////////////////////////////////////////////////////////////////////
// selfmod.cpp - cross platform self modifying binary PoC                    //
//                                                                           //
// Works by appending formatted data to the binary without                   //
// affecting binary execution.                                               //
//                                                                           //
// Author: iphelix                                                           //
///////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>
#include <ctime>

using namespace std;

bool readData (char filename[]) {
 // Check itself for previous runs and display collected data 
  bool data_flag = false;
  string line;
  ifstream inFile;
  inFile.open(filename, ios::in | ios::binary);
  if (inFile)
  {
    // Check for previously stored data by reading binary file
    // until signature data portion of the program is detected
    while (! inFile.eof() )
    {
      getline (inFile,line);
      if(data_flag) cout << line << endl;
      if(line.compare("===DATA===") == 0) {
         data_flag = true;
         cout << "This program was previously executed on:" << endl;
      }
    } 
    if(!data_flag) cout << "=================Congratulations!=================" 
                        << endl 
                        << "You are running this executable for the first time." 
                        << endl;
    
    inFile.close();
  }
  else 
  {
     cerr << "Can't open input file" << endl;
     exit(1);  
  }
  
  return data_flag;
}

void writeData (char filename[], bool data_flag, char* data) {
  // Save generated data back into binary file
  ofstream outFile;
  outFile.open(filename, ios::app | ios::binary);
  if (outFile)
  {
      if(!data_flag) outFile << endl << "===DATA===" << endl;
      outFile << data;
      outFile.close();
  }
  else 
  {
     cerr << "Can't open output file" << endl;
     exit(1);  
  }   
}

void binaryCopy(char filename1[], char filename2[]) {
	char *memblock;
	int num_of_bytes = 7563;	//any user specific number of bytes
	memblock = new char [num_of_bytes];

	ifstream inFile(filename1,ios::in | ios::binary);
	ofstream outFile(filename2,ios::out | ios::binary);
	
	if(!inFile.is_open())
	{
		cout<<"Can't open file for copying.\n";
		exit(1);
	}

	while(true)
	{
		inFile.read(memblock, num_of_bytes);
		num_of_bytes = inFile.gcount();
		if(num_of_bytes == 0)	break;
		outFile.write(memblock,num_of_bytes);
	}
    
	inFile.close();
	outFile.close();

   delete memblock;
}

int main ( int argc, const char* argv[] ) {
  char filename1[] = "selfmod.tmp";
  char filename2[] = "selfmod.exe";     
  bool data_flag = false;
  
  cout << "==================================================" << endl;
  cout << "  S E L F - M O D I F Y I N G  B I N A R Y  P O C " << endl;
  cout << "==================================================" << endl << endl;
  
  // remove temporary files
  if( remove("selfmod.tmp") != 0 ) {
      cout << "Can't remove temporary file" << endl;    
  }
    // rename original executable to temp name
  rename(filename2,filename1);
    // read previously stored data
  data_flag = readData(filename1);  
    // copy to new executable
  binaryCopy(filename1,filename2);   
     // record time and date when this binary was executed 
  time_t rawtime;
  time ( &rawtime );
  char* current_time = ctime (&rawtime);
  printf ( "The current local time is: %s", current_time );
    // modify a copy of original executable
  writeData(filename2, data_flag, current_time);  
  
  // remove temp file
  remove("selfmod.tmp");
  
  #ifdef WIN32
  system("pause");
  #endif
  
  return 0;
}
