Test Foro de elhacker.net SMF 2.1

Programación => Programación General => ASM => Mensaje iniciado por: _Enko en 3 Diciembre 2011, 22:29 PM

Título: [Codigo] Pequeño Servidor HTTP
Publicado por: _Enko en 3 Diciembre 2011, 22:29 PM
Código (asm) [Seleccionar]

;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.
Título: Re: [Codigo] Pequeño Servidor HTTP
Publicado por: Eternal Idol en 5 Diciembre 2011, 21:20 PM
Si llama a ExitThread terminas el hilo trabajador ese, mala idea. Lo ideal es que nunca llames a esa funcion, con retornar es suficiente (fijate que codigo se ejecuta justo despues cuando retornas de un hilo creado con CreateThread).
Título: Re: [Codigo] Pequeño Servidor HTTP
Publicado por: _Enko en 5 Diciembre 2011, 23:20 PM
Hola, la idea es que no es un hilo solo.

Es decir, para cada conexion nueva, se genera un hilo nuevo. Y cuando se desconecta el usuario, creo que tendria que terminar el hilo.

la tecnica es super saturable. 100 peticiones equivaldrian a 100 hilos.

Por eso creo que cada vez que el hilo hace su trabajo, deberia terminarlo.
(Hilo creado con CreateThread)

Citar
Si llama a ExitThread terminas el hilo trabajador ese, mala idea.
con usar ret, el hilo es eliminado?
Título: Re: [Codigo] Pequeño Servidor HTTP
Publicado por: Eternal Idol en 5 Diciembre 2011, 23:29 PM
Con hilo trabajador me refiero al que procesa el work item que encolas con QueueUserWorkItem (Queues a work item to a worker thread in the thread pool), el punto es que el hilo trabajador no lo creaste vos y tampoco lo tenes que terminar (un hilo trabajador de estos es, simplificando, un bucle esperando a que haya un work item en la cola para llamar al  LPTHREAD_START_ROUTINE del mismo y continuar el bucle en cuanto este retorne). Con usar ret le devolves el control al hilo trabajador y su bucle, en el caso de un hilo creado con CreateThread la funcion a la que retornas llama a ExitThread inmediatamente. Es asi:

Código (asm) [Seleccionar]
kernel32!BaseThreadInitThunk:
755c3388 8bff            mov     edi,edi
755c338a 55              push    ebp
755c338b 8bec            mov     ebp,esp
755c338d 85c9            test    ecx,ecx
755c338f 0f85752e0000    jne     kernel32!BaseThreadInitThunk+0x15 (755c620a)
755c3395 ff7508          push    dword ptr [ebp+8]
755c3398 ffd2            call    edx ;el LPTHREAD_START_ROUTINE
755c339a 50              push    eax
755c339b ff1504075c75    call    dword ptr [kernel32!_imp__RtlExitUserThread (755c0704)] ds:002b:755c0704={ntdll!RtlExitUserThread (77e2d598)}
Título: Re: [Codigo] Pequeño Servidor HTTP
Publicado por: _Enko en 5 Diciembre 2011, 23:38 PM
A... no habia entendido "hilo trabajador"....

QueueUserWorkItem, solo se usa RET. Confirmado :)


Gracias Nuevamente.
Título: Re: [Codigo] Pequeño Servidor HTTP
Publicado por: Eternal Idol en 5 Diciembre 2011, 23:41 PM
De nadas  :)