Código
;modificar szRoot para indicar la ubicacion del servidor, default C:\Server
;msvcrt no viene en el paquete de fasm, la crean con la utilidad dll2inc
;o hacen los include a mano^^
format PE Console
entry start
include '%fasminc%/win32a.inc'
include '%fasminc%/macro/if.inc'
MAX_QUEUE equ 100 ;max namber of pending connections
BUFFER_SIZE equ 2048 ;max size of the header sent by the client
MAX_URL_SIZE equ 1024 ;max size of url in the header send
SHOW_DETAILED_MSG equ TRUE ;set TRUE if want to see the full client message
section '.data' data readable writeable
wsa WSADATA
port dd 80
szPause db "PAUSE",0
h404 db "HTTP/1.1 404 Not Found",13,10,"Server: EnkoHttpServer 1.0.0.0 ",13,10,13,10,"<HTML><BODY>404 Not Found</BODY></HTML>",13,10
.size = $ - h404
h200 db "HTTP/1.1 200 OK",13,10,"Server: EnkoHttpServer 1.0.0.0 ",13,10,"Allow: GET",13,10,13,10
.size = $ - h200
szRoot db "C:\Server",0
szSlashes db '/\',0
szSlash db '\',0
szTockens db " ",13,10,0
szError db "ERROR: %i",13,10,0
szDot db ".",0
szFileNotExists db "File Not Exists",13,10,0
szInt db "%i",0
szFile db "FILE: %s",13,10,0
szClient db "Client IP: %s",13,10,0
szRequest db "REQUEST: %s",13,10,0
szStatus db "STATUS: %s",13,10,0
szString db "%s",0
szEndLine db 13,10,0
.size = $ - szEndLine
szBr db "<br>",0
szIndex db "index.html",0
szFileSent db "File Sent ok",13,10,0
.size = $ - szBr
wSocketVersion dd 0x0101
transmiteBuffer dd h200,h200.size,NULL,NULL
thread dd ?
peer dd ?
peerAddr sockaddr_in
sizePeerAddr dd sizeof.sockaddr_in
sock dd ?
sock_addr sockaddr_in
szBuffer db 32 dup ?
szIp db 16 dup ?
section '.code' code readable executable
start:
;inicializacion socket
invoke WSAStartup, [wSocketVersion], wsa
invoke socket,AF_INET,SOCK_STREAM,NULL
mov [sock],eax
mov [sock_addr.sin_family], AF_INET
invoke htons,[port]
mov [sock_addr.sin_port],ax
mov [sock_addr.sin_addr],NULL
invoke bind, [sock], sock_addr,sizeof.sockaddr_in
.if eax <> 0
invoke WSAGetLastError
cinvoke printf, szError, eax
.endif
invoke listen, [sock],MAX_QUEUE
;activamos la escucha del socket
accepted:
invoke accept, [sock],peerAddr,sizePeerAddr
mov [peer],eax
stdcall ipToString,[peerAddr.sin_addr],szIp
cinvoke printf, szClient,szIp
;nuevo hilo para cada conexion
invoke CreateThread, NULL,NULL, resolveConnection,[peer],NULL,NULL
;o mejor la funcion de abajo, ayudaria a la estabilidad y contra ataques DOS
;invoke QueueUserWorkItem, resolveConnection, [peer], NULL ;WT_EXECUTEDEFAUL
jmp accepted
invoke ExitProcess,0
;hilo que resuelve las peticiones
proc resolveConnection, lpParam
local lpeer: DWORD, lbuffer: DWORD, lurl: DWORD, lfile: DWORD
mov eax, [lpParam] Dermatoesqueleto mov [lpeer],eax
cinvoke malloc, BUFFER_SIZE
mov [lbuffer],eax
invoke recv, [lpeer],[lbuffer],BUFFER_SIZE,0
;vemos si hay un mensaje en el buffer y continuamos
.if eax <> 0
mov ebx,[lbuffer]
mov byte [ebx+eax],0
.if SHOW_DETAILED_MSG
cinvoke printf,szRequest, [lbuffer]
.endif
cinvoke strtok, [lbuffer], szTockens
.if eax <> 0
;solamente respondemos al mensaje GET
.if dword[eax] = "GET"
;url sring allocation
;buscamos la url en la peticion GET
;solamente las peticiones que terminan con alguna extensión
cinvoke malloc, MAX_URL_SIZE
mov [lurl],eax
cinvoke strcpy, [lurl],szRoot
cinvoke strtok, NULL, szTockens
cinvoke strcat,[lurl],eax
mov ebx,eax
cinvoke strlen, eax
mov edx,eax
dec edx
.repeat
dec eax
cmp byte[ebx+eax],"/"
.if ZERO?
mov byte[ebx+eax],"\"
.endif
.until eax = 0
.if byte[ebx+edx] = "\"
cinvoke strcat,[lurl],szIndex
.endif
cinvoke printf, szFile, [lurl]
;ya tenemos el nombre del archivo, ahora lo abrimos desde el disco
invoke CreateFile,[lurl],GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,0
;si el archivo existe, lo enviamos
.if eax <> INVALID_HANDLE_VALUE
mov [lfile],eax
invoke GetFileSize, [lfile],NULL
invoke TransmitFile, [lpeer],[lfile],eax,NULL,NULL,transmiteBuffer,NULL
.if eax
;escribimos en la consola el detalle
cinvoke printf, szStatus, szFileSent
.endif
invoke CloseHandle, [lfile]
.else
;no existe el archivo, error 404
cinvoke printf, szStatus, szFileNotExists
invoke send, [lpeer], h404, h404.size, 0
.endif
cinvoke free, [lurl]
.endif
.endif
.endif
.exit:
cinvoke free, [lbuffer]
invoke CloseHandle, [lpeer]
invoke ExitThread
ret
endp
;convertimos DWORD ip a una cadena
proc ipToString, ip, string
local buffer: DWORD
mov ebx, [ip]
mov esi,4
mov eax,[string]
mov byte [eax],0
.repeat
xor eax,eax
mov al,bl
cinvoke sprintf,[buffer],szInt,eax
cinvoke strcat,[string],[buffer]
cinvoke strcat,[string],szDot
shr ebx,8
dec esi
.until esi=0
cinvoke strlen, [string]
mov ebx, [string]
mov byte[ebx+eax-1],0
mov byte[buffer],0
ret
endp
section '.idata' import data readable writeable
library kernel32,'KERNEL32.DLL',\
user32,'USER32.DLL',\
msvcrt,'msvcrt.dll',\
wsock32, 'WSOCK32.DLL'
include '%fasminc%\api\kernel32.inc'
include '%fasminc%\api\user32.inc'
include '%fasminc%\api\msvcrt.inc'
include '%fasminc%\api\wsock32.inc'
El codigo funciona bastante bien. Si la url es complicada es probable que no la pueda resolver. En canto a saturacion o DDOS, sumamente susceptible.
Screenshot
http://i41.tinypic.com/5lxyfk.png
hay una duda que tengo:
Si se usa CreateThreade es necesario usar ExitThread... hasta ahi bien.
Ahora, si se usa QueueUserWorkItem, ¿Hace falta?
en la msdn no especifica, hice la prueba y aparentemente no. Ya que si se usa, en una prueba rapida se nota que deja de funcionar la segunda vez que se llama.
Saludos.










Autor



En línea






