Extracting IP from getaddrinfo call

Summary

This short post documents tracking down the IP address location and value resolved by the getaddrinfo function call with the help of x64dbg.

Tools

To follow along you will need to build 32-bit WinSock server and client provided by Microsoft and x64dbg.

Getaddrinfo

The getaddrinfo function resolves the provided hostname to the IP address and its prototype is:

INT WSAAPI getaddrinfo(
  [in, optional] PCSTR           pNodeName,
  [in, optional] PCSTR           pServiceName,
  [in, optional] const ADDRINFOA *pHints,
  [out]          PADDRINFOA      *ppResult
);

The third parameter passed to getaddrinfo is the pointer to the addrinfo structure that contains data about the socket type the caller supports. And the fourth parameter is the pointer to where the address of the returned addrinfo structure will be stored after the getaddrinfo execution. The addrinfo structure is defined like so:

typedef struct addrinfo {
  int             ai_flags;
  int             ai_family;
  int             ai_socktype;
  int             ai_protocol;
  size_t          ai_addrlen;
  char            *ai_canonname;
  struct sockaddr *ai_addr;
  struct addrinfo *ai_next;
} ADDRINFOA, *PADDRINFOA;

The sockaddr structure for TCP/IP looks like this:

struct sockaddr {
        ushort  sa_family;
        char    sa_data[14];
};

struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};

Getaddrinfo and x64dbg

Now let's start the server app provided by MSDN and open the client app in x64dbg.

To provide the command line arguments to the client app in x64dbg I updated the main input parameters before the main started to execute. The argc value was changed from 0x1 to 0x2 and the command line stored in argv was updated to look like this path_to_client.exe localhost:

x64dbg: we need to update argc and argv passed to main
x64dbg: argv before the update
x64dbg: argv after the update

Now we can step into main and follow along until we hit the call to getaddrinfo which is preceded by the call to ZeroMemory preparing the hints buffer:

x64dbg after ZeroMemory execution. Dump window shows the zeroed out hints buffer. 

Once ZeroMemory (or memset running behind the scene) is executed we have a hints buffer of type addrinfo that needs to be populated before we execute getaddrinfo:

x64dbg: ai_family, ai_socktype and ai_protocol of the hints buffer are now set

Now the parameters for getaddrinfo are pushed on the stack. In the image below 0x009FFCF0 will store the address of the addrinfo res structure, 0x009FFCBC stores the hints buffer that was populated above, 0x00437B80 stores the port value and the last parameter pushed on the stack is 0x00000000 since we will be resolving the localhost hostname:

x64dbg: getaddringo parameters are pushed on the stack

After the getaddrinfo execution the 0x009FFCF0 address stores the address of the returned res structure of type addrinfo  (0x00EA1D28 ):

x64dbg: 0x00EA1D28 returned after getaddinfo execution

Let's follow it in memory and break down the data returned:

(4 bytes) int ai_flags; 00 00 00 00
          int ai_family; 02 00 00 00 (AF_INET)
          int ai_socktype; 01 00 00 00 (SOCK_STREAM)
          int ai_protocol; 06 00 00 00 (TCP)
          size_t ai_addrlen; 10 00 00 00 (16 bytes)
          char *ai_canonname; 00 00 00 00
          struct sockaddr *ai_addr; 58 7E EA 00 (0x00EA7E58)
          struct sockaddr *ai_next; 00 00 00 00
x64dbg: addrinfo structure at 0x00EA1D28 memory address

The returned IP address is stored in ai_addr member of the addrinfo structure at memory address 0x00EA7E58 so we need to follow it in memory to get the actual IP address value:

x64dbg: sockaddr structure at 0x00EA7E58 memory address

Data stored at aforementioned 0x00EA7E58 memory address represent the sockaddr structure for TCP/IP. Let's break it down too:

short sin_family;  02 00
u_short sin_port;  69 87 (hex value for our 27015 default port)
struct in_addr sin_addr; 7F 00 00 01 (IP value in hex form)
char sin_zero[8]

So 0x7F000001 is the returned IP value but it is in hex form and we probably want to convert it:

0x7F000001 binary form is:
01111111 00000000 00000000 00000001
or if you convert each 8 bits into decimal
127 0 0 1

So here you go. The localhost hostname was resolved to 127.0.0.1 IP as expected by the call to getaddrinfo =)

References