Search code examples
winapiassemblyx86winsockmasm32

Winsock-bind function error In MASM(32 BIT asm)


First of all, Im sorry for my bad english, english isn't my first language. So, I'm trying to write chat program in Assembly 32 BIT, MASM.

Right Now, I'm writing the server side code, So far I used the WSAStartUp and Socket - Windows API functions, and Now im trying to use the Bind function.

The link for the bind function: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737550(v=vs.85).aspx

This is the code that I have written so far(My problem is written after the code):

.386 
.MODEL Flat, STDCALL 
option casemap:none 

include \masm32\include\windows.inc 
include \masm32\include\Ws2_32.inc
includelib \masm32\lib\Ws2_32.lib
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

.DATA 

Success db 'WSAStartUp Succseed!',0
NO_Success db 'WSAStartUp NOT Succseed....',0
Socketsu db 'Socket :(:(:(:(',0
SocketSuccess db 'Socket Success!! :)',0
Bindno db 'Bind Error',0
Bindyes db 'Bind Success! :)',0
LocalIP db "127.0.0.1",0
port dd 8020

.DATA? 

wsadata db 400 dup (?)      ;WSADATA struct that hold the information about the Windows Sockets implementation.(info ret from WSATSTARTUP)
flag dw ?
ListenSocket dd ?
SockAddrStruct db 30 dup (?)
;so sockaddr_in <?> 
sockaddrs db 16 dup (?)

.CONST 
    wVersionRequested equ 0101h
.CODE 
   main:
;-------------------WSAStartUp-----------------------;
        ;Initialize the work with winsock (WS StartUp = WINSOCK START UP)

             invoke WSAStartup,wVersionRequested, offset wsadata        
            .if eax!=0
                invoke MessageBoxA,NULL,offset NO_Success,offset NO_Success,MB_OK 
                jmp End_Program
            .else
                invoke MessageBoxA,NULL,offset Success,offset Success,MB_OK 
            .endif

;-------------------Socket-----------------------;

    ;AF_INET - address family(in format: host,port) to likboa the type of addresses that the socket can communicate with

    invoke socket,AF_INET,SOCK_STREAM,IPPROTO_TCP
    .IF eax==INVALID_SOCKET
        invoke MessageBoxA,NULL,offset Socketsu,offset Socketsu,MB_OK 
        jmp End_Program
     .else
       invoke MessageBoxA,NULL,offset SocketSuccess,offset SocketSuccess,MB_OK
       mov [ListenSocket],eax
    .ENDIF
;-------------------Bind-------------------------;
;SockAddr Struct:

mov eax,AF_INET
mov [dword ptr sockaddrs],eax
invoke htons,[port]
mov [dword ptr sockaddrs+2],eax
invoke inet_addr,[dword ptr LocalIP]   
mov [dword ptr sockaddrs+4],eax
invoke bind,SIZEOF sockaddrs,offset sockaddrs,ListenSocket

.if eax==0
    invoke MessageBoxA,NULL,offset Bindyes,offset Bindyes,MB_OK
.else
    invoke MessageBoxA,NULL,offset Bindno,offset Bindno,MB_OK
.endif


End_Program:
        invoke ExitProcess,0 
end main

I don't know what is the problem. But when I run the code I'm getting the MessageBox that I Built that says:Bind Error.

I guess that this is a problem in sockaddrs struct (the way that I put values in to it). But I don't know what do I need to change and how to fix it.

I thought maybe to use WSAGetLastError Function to see what is the Error but I don't know how to print the value that the function returns and see what is the error(I can't put in the invoke MessageBox, a parameter EAX(the register that hold the value that returns)) .

So can someone help me fix the problem In the 'Bind' part?


Solution

  • WSAGetLastError

    You have a couple questions. I'll start by giving you one method of retrieving a message representing the last WSAGetLastError (it also works with GetLastError). The Win32 API way is to use FormatMessage to convert the error message code returned by WSAGetLastError. Information from MSDN on FormatMessage can be found here, along with an example similar to the code we'll use. It is defined as:

    DWORD WINAPI FormatMessage(

    In DWORD dwFlags,
    In_opt LPCVOID lpSource,
    In DWORD dwMessageId,
    In DWORD dwLanguageId,
    Out LPTSTR lpBuffer,
    In DWORD nSize,
    In_opt va_list *Arguments
    );

    In your .DATA? area, add a variable to store the buffer pointer that we'll return from FormatMessage:

    lpErrorMsg  dd  ? 
    

    To then retrieve and display the last WSA error you can use something like this after a socket related call (like bind):

    .if eax==SOCKET_ERROR
        invoke WSAGetLastError
        invoke FormatMessageA, FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, eax, LANG_NEUTRAL, offset lpErrorMsg, 0, NULL
        invoke MessageBoxA,NULL,lpErrorMsg,offset Bindno,MB_OK
    .endif
    

    Bug Fixing

    There are a number of problems in your code. The first one I observed was that port need to be a 32 bit Integer so it should be defined as:

    port dd 8020
    

    Without this change htons will not work properly as it is expecting a 32-bit Integer.

    The next bug is here:

    invoke MessageBoxA,NULL,offset SocketSuccess,offset SocketSuccess,MB_OK
    mov [ListenSocket],eax
    

    You are clobbering eax by calling MessageBoxA first. You probably meant to save it first:

    mov [ListenSocket],eax
    invoke MessageBoxA,NULL,offset SocketSuccess,offset SocketSuccess,MB_OK
    

    There appear to be a number of issues in this code:

    mov eax,AF_INET
    mov [dword ptr sockaddrs],eax
    

    This is incorrect as it works with 32-bit Integer and we need a WORD(16-bit). It should be:

    mov ax,AF_INET
    mov [word ptr sockaddrs],ax
    

    This also required to use a 16-bit WORD to be stored at sockaddrs+2 :

    invoke htons,[port]
    mov [dword ptr sockaddrs+2],eax
    

    So should have been:

    invoke htons,[port]
    mov [word ptr sockaddrs+2],ax
    

    This is incorrect since we don't want to de-reference what is at LocalIP, we just want LocalIP's address:

    invoke inet_addr,[dword ptr LocalIP]   
    mov [dword ptr sockaddrs+4],eax
    

    So this seems to be more correct:

    invoke inet_addr, offset LocalIP   
    mov [dword ptr sockaddrs+4],eax
    

    You then mixed up the parameters to bind. You had:

    invoke bind,SIZEOF sockaddrs,offset sockaddrs,ListenSocket
    

    It should have been:

    invoke bind,ListenSocket,offset sockaddrs,SIZEOF sockaddrs
    

    Easier way to work with sockaddr_in

    MASM32 defines a sockaddr_in with all the fields defined. To make working with this structure easier and to make the code more readable, you might want to consider altering SockAddrStruct to be defined as (and zeroed out):

    SockAddrStruct sockaddr_in <0>
    

    With SockAddrStruct defined this way you can now change your socket code to read something like this:

    ;-------------------Bind-------------------------;
    ;SockAddr Struct:
    
    mov SockAddrStruct.sin_family,AF_INET
    invoke htons, [port]
    mov SockAddrStruct.sin_port,ax
    invoke inet_addr, offset LocalIP   
    mov SockAddrStruct.sin_addr.S_un.S_addr, eax
    invoke bind,ListenSocket,offset SockAddrStruct,SIZEOF SockAddrStruct