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
:
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:
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
:
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:
After the getaddrinfo
execution the 0x009FFCF0
address stores the address of the returned res
structure of type addrinfo
(0x00EA1D28
):
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
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:
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
=)