/*	 Faketime wraps a user program and feed it with user-specified fake system time
		so that it can be used forever without any "licence expired" problem
	 

    Copyright (C) 2007 Eric You XU, Washington University ( youxu [@T] wustl.edu ) 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA


*/

#include <sys/ptrace.h>
#include <asm/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <linux/user.h>

/*
Register layout defined linux/user.h, but actually in 
 asm-$(arch)/user.h

struct user_regs_struct {
        long ebx, ecx, edx, esi, edi, ebp, eax;
        unsigned short ds, __ds, es, __es;
        unsigned short fs, __fs, gs, __gs;
        long orig_eax, eip;
        unsigned short cs, __cs;
        long eflags, esp;
        unsigned short ss, __ss;
};
*/


/* Note that EAX now is RAX in x86-64
 	we can also find the actural offset for any register
 	from <asm-$(arch)/ptrace-abi.h>
#define RAX 24
*/

#define ORIG_RAX 120
/* ORIG_RAX stores the number of syscall */

#define SYS_TIME 13
/* Machine specific syscall number is defined in 
	unistd.h */

#define back_to_future 1175737392

/* Time is stored as a long interger in C, you can get 
	current time via time(NULL). Thus, it's very easy to 
	get a long integer denoting some time in the past. 
	
	Python/Java can also be helpful in figuring this out 
	
	If you don't know how, just keep in mind that 
	Dec. 1, 2007 is about 1196476452. 
	One day interval = 60*60*24 = 86400 [Time flies fast]
*/
	
char* host_program = "your program's name here";
/* Make modifications for these two lines, then 
	compile it via
		gcc faketime.c -o faketime
	use it via 
		./faketime
*/

int main(int argc, char** argv)
{

	pid_t child;
    long orig_rax, eax;
    int i;
    
    printf("argc: %d\n", argc);
    for (i=0; i<argc; i++)
    	printf("argv: %s\n", argv[i]);
    	
	struct user_regs_struct regs;
	int status;
    int insyscall = 0;
    child = fork();
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execv(host_program, argv);
    }
    
    else {
       while(1) {
          wait(&status);
          if(WIFEXITED(status))
              break;
          orig_rax = ptrace(PTRACE_PEEKUSER,
                     child, ORIG_RAX, NULL);
    
          // printf("SYSCALL %d\n", orig_rax);
          if(orig_rax == SYS_TIME ) { /* Intercept SYS_TIME syscall */
             if(insyscall == 0) { /* Syscall entry */
                insyscall = 1;
             }
         	 else { /* Syscall exit */
					ptrace(PTRACE_GETREGS, child, 0, &regs);
				    /* We can also use 
				    	ptrace(PTRACE_SETREGS, child ,RAX, &back_to_future); 
					but it doesn't work. There might be some tricky here */
					regs.rax = back_to_future; 
					ptrace(PTRACE_SETREGS, child, 0, &regs);
            }
          } // End if with SYS_TIME 
       	  ptrace(PTRACE_SYSCALL, child, NULL, NULL);
     }
   }
   return 0;
}


