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.