Nytro Posted June 3, 2011 Report Posted June 3, 2011 Cinchy Assembly Web ServerAn efficient and simple web server written in x86(by sterling stuart stein (s³))A web server written in x86 assembly language. It only includes basic functions, respondes to GET requests, supports file download. A very good example of code.Read more: Cinchy Assembly Web Server - An efficient and simple web server written in x86Cinchy serverMain program by: S³ <scubed@frontiernet.net>Ext routine by: r.c. volgers <r.volgers@hccnet.nl>Bug reports by:Juvenile Delinquent <nervgaz@nervgaz.net> Buffer overflowJonathan Donitz <jon_donitz@hotmail.com> 64k cut-off and forgot to reset buffer sizeSpecial thanks to:Iczelion <iczelion@galaxycorp.com> for making it Windows 2000 compatible!SpaceCommander / ByTeGeiZ <SpaceCommander@ByTeGeiZ.de> for information about the directory browse dialog and long file names and for telling me that ".." worked in the URL.Other additions:Makes sure that it is the GET commandCan resume download (tested with Go!Zilla)If directory, will redirect to include /Recognizes %HH as hexadecimalTells you your IP address and namePlease send me (S³) e-mail! I like getting responses!How to use:Set up a directory for use by the server (for example: C:\WebPage)Run the program and click on "Pick Dir" and select your directory.Check the "Dir enabled" box if you want to allow directory viewingby clients, otherwise "dir/index.htm" will be used instead.If it is sending the file as the wrong type, use regedit andset/create a key in HKEY_CLASSES_ROOT of ".ext" (where ext is thefile extension) to "Content Type" with the type (such as"application/x-zip-compressed")To access from another computer, type in your IP address or,over a LAN, the computer name.Read more: Cinchy Assembly Web Server - An efficient and simple web server written in x86.386.model flat,stdcalloption casemap:noneWinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD ;Create dialog and handle msgWndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD ;Main window functionCut PROTO :DWORD,:DWORD,:DWORD,:BYTE ;Cut off end of stringStrLen PROTO :DWORD ;Find length of stringStrCmp PROTO :DWORD,:DWORD ;Compare two stringsStrCpy PROTO :DWORD,:DWORD ;Copy a stringStrCat PROTO :DWORD,:DWORD ;String1+=String2Ext PROTO ;Find MIME type for extensionResuming PROTO ;Look for resume dataFillList PROTO :DWORD,:DWORD ;DIR into Listbox and sendRemoveHex PROTO :DWORD,:DWORD ;Converts %HH to charactersInsertHex PROTO :DWORD,:DWORD ;Converts characters to %HHFromHex PROTO :BYTE ;Converts hex digit to byteinclude \masm32\include\windows.incinclude \masm32\include\user32.incincludelib \masm32\lib\user32.libinclude \masm32\include\kernel32.incincludelib \masm32\lib\kernel32.libinclude \masm32\include\shell32.incincludelib \masm32\lib\shell32.libinclude \masm32\include\wsock32.incincludelib \masm32\lib\wsock32.libinclude \masm32\include\advapi32.incincludelib \masm32\lib\advapi32.lib.dataClassName db "DLGCLASS",0DlgName db "Form1",0IcoName db "i",0DefPath db "C:",0DefName db "index.htm",0Star db "*.*",0DTitle db "Select base webpage directory:",0Get db "GET",0Content db "Content Type",0Msg200 db "HTTP/1.1 200 OK",13,10 db "Expires: 0",13,10 db "Last-Modified: 0",13,10 db "Accept-Range: bytes",13,10 db "Content-Type: %s",13,10 db "Content-Length: %lu",13,10,13,10,0Msg206 db "HTTP/1.1 206 Partial Content",13,10 db "Expires: 0",13,10 db "Last-Modified: 0",13,10 db "Accept-Range: bytes",13,10 db "Content-Type: %s",13,10 db "Content-Range: bytes=%lu-%lu/%lu",13,10 db "Content-Length: %lu",13,10,13,10,0Msg404 db "HTTP/1.1 404 Not Found",13,10 db "Expires: 0",13,10 db "Last-Modified: 0",13,10 db "Accept-Range: bytes",13,10 db "Content-Type: text/html",13,10 db "Content-Length: 124",13,10,13,10 db "<TITLE>404 error</TITLE><B>Error 404: Page not found</B>",13,10 db "The URL does not exist. Check the link and your spelling.",0Redir db "HTTP/1.1 301 Moved Permanently",13,10 db "Location: %s",13,10,0Range db "range: bytes",0Str0 db "<TITLE>Directory of ",0Str1 db "</TITLE>",13,10,0Str2 db "File:<BR><BR>",13,10,13,10,0Str3 db 13,10,"<BR>Directory:<BR><BR>",13,10,13,10,0Str4 db "<A HREF=",34,0Str5 db 34,62,0Str6 db "</A><BR>",13,10,0HTML db "text/html",0Type0 db "text/plain",0hFile dd 0hSock1 dd 0hReg dd 0pType dd 0bi BROWSEINFO <0,0,0,offset DTitle,BIF_RETURNONLYFSDIRS,0,0,0>.data?hInstance HINSTANCE ?CommandLine LPSTR ?Count dd ?Exist dd ?FSize dd ?FOffset dd ?RFlag dd ?hDlg dd ? ;HandleshFind dd ?hMem dd ?pMem dd ?BufSize dd ?NotUsed dd ?RSBuf db 1024 dup(?) ;String buffersBuf1 db 1024 dup(?)Buf2 db 1024 dup(?)Buf3 db 1024 dup(?)Buf4 db 1024 dup(?)Path db 512 dup(?)wsadata WSADATA <> ;WinSockSA sockaddr_in <>fd WIN32_FIND_DATA <>.constWM_SOCKET equ WM_USER+256.codeprogram:INVOKE GetModuleHandle,0mov hInstance,eaxINVOKE GetCommandLinemov CommandLine,eaxINVOKE WinMain,hInstance,0,CommandLine,SW_SHOWDEFAULTINVOKE ExitProcess,eaxWinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORDLOCAL wc:WNDCLASSEXLOCAL msg:MSGmov wc.cbSize,SIZEOF WNDCLASSEXmov wc.style,CS_HREDRAW or CS_VREDRAWmov wc.lpfnWndProc,OFFSET WndProcmov wc.cbClsExtra,0mov wc.cbWndExtra,DLGWINDOWEXTRApush hInstpop wc.hInstancemov wc.hbrBackground,COLOR_BTNFACE+1mov wc.lpszClassName,OFFSET ClassNamemov wc.lpszMenuName,0INVOKE LoadIcon,hInstance,offset IcoNamemov wc.hIcon,eaxmov wc.hIconSm,eaxINVOKE LoadCursor,0,IDC_ARROWmov wc.hCursor,eaxINVOKE WSAStartup,101h,offset wsadata ;Use WinSock v1.1INVOKE RegisterClassEx,addr wc ;Make Dialog box.INVOKE CreateDialogParam,hInstance,offset DlgName,0,0,0mov hDlg,eaxINVOKE ShowWindow,hDlg,SW_SHOWNORMALINVOKE UpdateWindow,hDlg.WHILE TRUE ;Main window loop INVOKE GetMessage,addr msg,0,0,0 .BREAK .IF (!eax) INVOKE TranslateMessage,addr msg INVOKE DispatchMessage,addr msg.ENDWINVOKE WSACleanup ;Done with WinSockmov eax,msg.wParamretWinMain endpWndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM.IF uMsg==WM_DESTROY INVOKE closesocket,hSock1 INVOKE PostQuitMessage,0.ELSEIF uMsg==WM_SHOWWINDOW INVOKE SendDlgItemMessage,hWnd,1000,WM_SETTEXT,0,offset DefPath INVOKE gethostname,offset Buf1,1024 ;Get name INVOKE SendDlgItemMessage,hWnd,1004,WM_SETTEXT,0,offset Buf1 INVOKE gethostbyname,addr Buf1 mov eax,[eax+12] mov eax,[eax] ;Get IP address mov eax,[eax] INVOKE inet_ntoa,eax INVOKE SendDlgItemMessage,hWnd,1005,WM_SETTEXT,0,eax INVOKE socket,PF_INET,SOCK_STREAM,IPPROTO_TCP mov hSock1,eax ;Configure listening socket mov SA.sin_family,AF_INET mov SA.sin_addr.S_un.S_addr,INADDR_ANY INVOKE htons,80 mov SA.sin_port,ax INVOKE WSAAsyncSelect,hSock1,hWnd,WM_SOCKET,FD_ACCEPT INVOKE bind,hSock1,offset SA,sizeof SA INVOKE listen,hSock1,5 ;Listen for connections.ELSEIF uMsg==WM_COMMAND mov eax,wParam .IF ax==1003 mov Buf4,0 ;Prompt for directory INVOKE SHBrowseForFolder,addr bi .IF eax==0 xor eax,eax ret .ENDIF ;Turn return value into pathname INVOKE SHGetPathFromIDList,eax,offset Buf4 .IF Buf4==0 xor eax,eax ret .ENDIF .IF Buf4[3]==0 ;If C:\ change to C: mov Buf4[2],0 .ENDIF INVOKE StrLen,offset Buf4 mov ecx,eax mov al,"\" mov edi,offset Buf4@@@5: repnz scasb jnz @@@6 mov BYTE PTR[edi-1],"/" jmp @@@5@@@6: INVOKE SendDlgItemMessage,hWnd,1000,WM_SETTEXT,0,offset Buf4 .ENDIF.ELSEIF uMsg==WM_SOCKET mov eax,lParam and eax,0FFFFh .IF ax==FD_ACCEPT INVOKE accept,hSock1,0,0 INVOKE WSAAsyncSelect,eax,hWnd,WM_SOCKET,FD_READ or FD_CLOSE .ELSEIF ax==FD_READ INVOKE recv,wParam,offset RSBuf,1024,0 mov al,32 mov ecx,10 lea edi,RSBuf repnz scasb dec edi push edi mov BYTE PTR[edi],0 INVOKE StrCmp,offset RSBuf,offset Get .IF eax==1 ;If command other than GET, ignore. INVOKE closesocket,wParam xor eax,eax ret .ENDIF pop edi mov BYTE PTR[edi],32 INVOKE Cut,offset RSBuf,offset Buf2,4,32 INVOKE RemoveHex,offset Buf2,offset Buf1 INVOKE StrLen,offset Buf1 mov ecx,eax mov edi,offset Buf1 ;Make sure there is no ../ mov al,"."@@@7: repnz scasb jnz @@@8 cmp BYTE PTR[edi],"." jnz @@@7 cmp BYTE PTR[edi+1],"/" jnz @@@7 jmp Bad@@@8: mov Exist,0 ;Must determine request type dec edi .IF BYTE PTR[edi]=="/" ;Therefore, directory INVOKE StrCpy,offset Buf1,offset Buf3 INVOKE SendDlgItemMessage,hWnd,1000,WM_GETTEXT,512,offset Path INVOKE StrCpy,offset Path,offset Buf2 INVOKE StrCat,offset Buf2,offset Buf1 INVOKE SendDlgItemMessage,hDlg,1002,BM_GETCHECK,0,0 .IF eax==0 INVOKE StrCat,offset Buf2,offset DefName jmp Index .ENDIF INVOKE wsprintfA,offset Buf1,offset Msg200,offset HTML,30000 INVOKE StrLen,offset Buf1 INVOKE send,wParam,offset Buf1,eax,0 ;Send header INVOKE StrLen,offset Str0 INVOKE send,wParam,offset Str0,eax,0 INVOKE StrLen,offset Buf2 INVOKE send,wParam,offset Buf2,eax,0 INVOKE StrLen,offset Str1 INVOKE send,wParam,offset Str1,eax,0 INVOKE StrCat,offset Buf2,offset Star ;Get files INVOKE FillList,0,wParam INVOKE FillList,16,wParam INVOKE closesocket,wParam ;Done sending listing inc Exist .ELSE ;File INVOKE SendDlgItemMessage,hWnd,1000,WM_GETTEXT,512,offset Path INVOKE StrCpy,offset Path,offset Buf2 INVOKE StrCat,offset Buf2,offset Buf1Index: INVOKE GetFileAttributes,offset Buf2 cmp eax,-1 jz Bad ;File doesn't exist and eax,16 .IF eax!=0 ;File was actually a directory, without a /. INVOKE InsertHex,offset Buf1,offset Buf2 INVOKE StrLen,offset Buf2 lea ebx,Buf2 ;So, redirect add eax,ebx mov BYTE PTR[eax],"/" mov BYTE PTR[eax+1],0 INVOKE wsprintf,offset Buf1,offset Redir,offset Buf2 INVOKE StrLen,offset Buf1 INVOKE send,wParam,offset Buf1,eax,0 INVOKE closesocket,wParam xor eax,eax ret .ENDIF INVOKE CreateFile,offset Buf2,GENERIC_READ,0,0,OPEN_EXISTING,0,0 mov hFile,eax INVOKE GetFileSize,hFile,0 mov FSize,eax INVOKE Ext INVOKE Resuming ;Check for range and if resume sending mov eax,FOffset .IF RFlag==0 INVOKE wsprintfA,offset Buf1,offset Msg200,pType,FSize .ELSE mov ebx,FSize sub FSize,eax mov ecx,ebx dec ecx INVOKE wsprintfA,offset Buf1,offset Msg206,pType,FOffset,ecx, ebx,FSize .ENDIF INVOKE StrLen,offset Buf1 INVOKE send,wParam,offset Buf1,eax,0 INVOKE GlobalAlloc,0,FSize ;Get memory to store file mov hMem,eax ;for sending. INVOKE GlobalLock,hMem mov pMem,eax INVOKE SetFilePointer,hFile,FOffset,0,FILE_BEGIN INVOKE ReadFile,hFile,pMem,FSize,offset NotUsed,0 INVOKE send,wParam,pMem,FSize,0 INVOKE GlobalUnlock,hMem INVOKE GlobalFree,hMem INVOKE closesocket,wParam INVOKE CloseHandle,hFile ;Done with file and socket too. inc Exist .ENDIF .IF Exist==0Bad: INVOKE StrLen,offset Msg404 ;Bad request. Send 404 error. INVOKE send,wParam,offset Msg404,eax,0 INVOKE closesocket,wParam .ENDIF .ELSEIF ax==FD_CLOSE INVOKE closesocket,wParam .ENDIF.ELSE INVOKE DefWindowProc,hWnd,uMsg,wParam,lParam ret.ENDIFxor eax,eaxretWndProc endpCut PROC SRC:DWORD,DST:DWORD,OS:DWORD,EC:BYTEmov eax,OSadd SRC,eaxmov al,ECmov ecx,-1mov edi,SRCrepnz scasbnot ecxdec ecx.IF ecx>1010 ;Buffer overflow: Truncate (414) mov ecx,1020.ENDIFmov esi,SRCmov edi,DSTrep movsbmov BYTE PTR[edi],0retCut ENDPStrLen PROC SRC:DWORDmov ecx,-1mov edi,SRCmov al,0repnz scasbmov eax,ecxnot eaxdec eaxretStrLen ENDPStrCpy proc SRC:LPSTR,DST:LPSTRINVOKE StrLen,SRCadd eax,2mov ecx,eaxmov esi,SRCmov edi,DSTrep movsbretStrCpy endpStrCat proc S1:DWORD,S2:DWORDINVOKE StrLen,S2add eax,2push eaxINVOKE StrLen,S1mov edi,S1add edi,eaxmov esi,S2pop ecxrep movsbretStrCat endpStrCmp PROC SRC:DWORD,DST:DWORDINVOKE StrLen,SRCinc eaxmov ecx,eaxmov esi,SRCmov edi,DSTrepz cmpsbmov eax,1jnz Next ;zf set or not from repzdec eaxNext:retStrCmp endpExt PROClea esi,Buf2mov ebx,esi@0: lodsb ;Search string for '.', ending at 0. .IF al=="." mov ebx,esi .ENDIF cmp al,0 jnz @0dec ebx ;Open Registry to look for MIME type for extension.INVOKE RegOpenKeyEx,HKEY_CLASSES_ROOT,ebx,0,KEY_READ,offset hRegcmp eax,0jnz @1 ;Get MIME typemov BufSize,1024INVOKE RegQueryValueEx,hReg,offset Content,0,0,offset Buf4,offset BufSizecmp eax,0jnz @1 ;Done with RegistryINVOKE RegCloseKey,hReglea eax,Buf4mov pType,eaxret@1: ;If not found, return default.INVOKE RegCloseKey,hReglea eax,Type0mov pType,eaxretExt ENDPResuming PROC ;Set FOffsetmov FOffset,0mov RFlag,0lea esi,RSBuflea edi,Range@2: mov ch,[esi] .IF ch<91 && ch>64 ;Lower case add ch,32 .ENDIF .IF [edi]==ch ;Look for substring inc edi cmp BYTE PTR[edi],0 jz @3 .ELSE lea edi,Range .ENDIF inc esi cmp BYTE PTR[esi],0 jnz @2 ret@3: add esi,2 ;Turn string at [esi] into value in eax.xor eax,eax ;Only works for "Range: bytes=x-" formatxor ebx,ebxmov ecx,10mov RFlag,1@4:mov bl,[esi]sub bl,48inc esi.IF bl<10 mul ecx add eax,ebx jmp @4.ENDIFmov FOffset,eaxretResuming ENDPFillList PROC DirF:DWORD,hSck:DWORDINVOKE SendDlgItemMessage,hDlg,1001,LB_RESETCONTENT,0,0INVOKE FindFirstFile,offset Buf2,offset fd.IF eax==-1 ret.ENDIFmov hFind,eax@@@1: mov eax,fd.dwFileAttributes and eax,16 ;Show directories if DirF .IF eax==DirF xor eax,eax .IF fd.cFileName=="." .IF fd.cFileName[1]==0 || (fd.cFileName[1]=="." && fd.cFileName[2]==0) inc eax .ENDIF .ENDIF .IF eax==0 INVOKE SendDlgItemMessage,hDlg,1001,LB_ADDSTRING,0, offset fd.cFileName .ENDIF .ENDIF INVOKE FindNextFile,hFind,offset fd cmp eax,1 jz @@@1INVOKE FindClose,hFindINVOKE SendDlgItemMessage,hDlg,1001,LB_GETCOUNT,0,0.IF eax==0 ret.ENDIFmov Count,eax.IF DirF==16 lea edx,Str3.ELSE lea edx,Str2.ENDIFINVOKE StrLen,edxINVOKE send,hSck,edx,eax,0mov pType,0@@@2:INVOKE StrLen,offset Str4 ;Send hyperlink to fileINVOKE send,hSck,offset Str4,eax,0INVOKE SendDlgItemMessage,hDlg,1001,LB_GETTEXT,pType,offset Buf1.IF DirF==16 ;Add / to directories mov edx,offset Buf1 INVOKE StrLen,edx add eax,edx mov BYTE PTR[eax],"/" inc eax mov BYTE PTR[eax],0.ENDIFINVOKE InsertHex,offset Buf1,offset Buf3INVOKE StrLen,offset Buf3INVOKE send,hSck,offset Buf3,eax,0INVOKE StrLen,offset Str5INVOKE send,hSck,offset Str5,eax,0INVOKE StrLen,offset Buf1INVOKE send,hSck,offset Buf1,eax,0INVOKE StrLen,offset Str6INVOKE send,hSck,offset Str6,eax,0inc pTypemov eax,Countcmp pType,eaxjnz @@@2retFillList ENDPRemoveHex PROC SRC:DWORD,DST:DWORDmov esi,SRCdec esimov edi,DSTxor eax,eax@@@3: inc esi mov al,[esi] .IF al=="\" mov al,"/" .ENDIF .IF al==0 stosb ret .ENDIF .IF al=="%" INVOKE FromHex,[esi+1] .IF al==-1 mov al,"%" stosb jmp @@@3 .ENDIF mov bl,al INVOKE FromHex,[esi+2] .IF al==-1 mov al,"%" stosb jmp @@@3 .ENDIF shl bl,4 add al,bl add esi,2 .ENDIF stosb jmp @@@3RemoveHex ENDPInsertHex PROC SRC:DWORD,DST:DWORDmov esi,SRCdec esimov edi,DSTxor eax,eax@@@4: inc esi mov al,[esi] .IF al==0 stosb ret .ENDIF .IF al<"(" || al>"~" mov dl,al mov al,"%" stosb mov al,dl shr al,4 .IF al<10 add al,48 .ELSE add al,55 .ENDIF stosb mov al,dl and al,15 .IF al<10 add al,48 .ELSE add al,55 .ENDIF .ENDIF stosb jmp @@@4InsertHex ENDPFromHex PROC Char:BYTEmov al,Char.IF al>="0" && al<="9" sub al,48 ret.ENDIF.IF al>="a" && al<="f" sub al,87 ret.ENDIF.IF al>="A" && al<="F" sub al,55 ret.ENDIFmov al,-1retFromHex ENDPend program(source site: http://lingcog.iit.edu/~scubed/projects.xml)Read more: http://www.intel-assembler.it/portale/5/cinchy-x86-web-server/a-basic-asm-web-server.asp#ixzz1ODJlDs1qSursa: Cinchy Assembly Web Server - An efficient and simple web server written in x86 Quote