Vortex0 in windows C; AKA a sample of Hell

cprogramming
vortex
windows

#1

Hello everyone! I’m nullbites.

Despite the name of the site, no, I am not affiliated (but I might be one day, so watch out mods).

Today we are going to look at Vortex0 (<-read that), a seemingly trivial problem that will actually throw you for a loop if you walk up to it with a puffed chest and easy expectations. I implemented a solution in Python and I got that done in a couple of hours after fiddling with struct.pack and struct.unpack on my Raspberry Pi for God knows how long.

That got me thinking… since that wasn’t too bad in Python; which is a “typeless” language, and since C programmers think “Strong Typing” is just pressing the keys harder, I thought “I got this; no problem.”

Oh boy was I wrong.

I come to you a week and a half later - with this dumb writeup as all I have to show for it. BTW call me out if I am wrong on anything!

I am going be to showing my code in chunks to discuss all the little parts that come together to make this monstrosity of a solution. “Monstrosity” I say? Yes I do say. I added error checking and optional debugging output. It’s pretty bad. It’s also all in main().

So in a way I come to you with a tutorial that is threefold. First is lessons learned with Socket Programming in general. Second is playing around with C types for useful effects, and third is how to deal with (and read) code quality that often shows up in production code.

Lets begin

// vor0_solve.cpp : Defines the entry point for the console application.
//

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

#define DEBUG 1

These are just compiler and linker directives to instruct windows on how to compile this program and link it to it’s own libraries. The #includes and our #define DEBUG 1 definition should be of note.

Now here is our deceleration of main and some useful variables:

int main(int argc, char *argv[])
{
	/* I don't know what your daddy taught you, but I always initalize my variables :| */
	WSADATA wsa;
	/* So that if we try any operations befoere reassignment we throw an error */
	SOCKET S = INVALID_SOCKET; 

	struct addrinfo *sock_info = NULL,
		resolv_helper; // again with this bullshit

	int res;

    /* recvbuf is the location in memory we will fetch the integer into */
	char recvbuf[4] = {0,0,0,0};  // initalize with zeros for safety 
	unsigned int data = 0; // data is the int we will use to process the incoming data
	unsigned int sum = 0; // sum is the accumulator we will send back as our answer
	/* casting a malloc call, WTH windows? */
	/* then again - it is just a macro to HeapAlloc() */
	char *sendbuf = (char*)malloc(4);  
	char answer[1024]; // lets not go to the heap, tis a silly place
	
	/*********************************************/
	/* these ptrs seem useless but they are used for *
	* memcpy calls l8r and are a safe and easy *
	* way to keep track of our data and what *
	* order it is in */
	/********************************************/
	unsigned int *sum_ptr = NULL;
	unsigned int *data_ptr = NULL;

If you have never made a socket connection to a remote server before here is a good time to stop and read up. It’s not required to have a low level system engineer or a network architect’s level of knowledge about networking to hack, but the best hackers are the ones that enjoy digging into and understanding how a system works. So why not get that good?

We’ll go into a lot of detail here. If you’ve never done Sockets on a windows machine (that is quite understandable), this should be a good start, but I recommend MSDN. There is actually some awesome stuff in there.

    /* Zeroize the sections of memory because 
	 * the kernel allocator doesn't wash it's hands */
	ZeroMemory(recvbuf, sizeof(recvbuf));
	ZeroMemory(answer, sizeof(answer));

	/* Start our WSA service */

Those function names are also fairly explanatory. That is for some more memory sensitization, I’d normally not do this much but networking and math with unitilized vars seems like a pretty bad combo.

	/* Here is a optional debug statment, changing 
	the #define value to 0 turns this off in code generation */
#if DEBUG
	printf("\nInitialising Winsock...\n\n");
#endif // This terminates the optional code in the preprocessor 

	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
	{
#if DEBUG //same as before don't be alarmed
		
        /* WSAGetLastError is what I like to refer to as a 
		* "Blackbox Function" its already written and I don't 
		* have to think about if it failes, because if it does
		* thats a windows bug, not me.*/
		printf("Failed. Error Code : %d", WSAGetLastError());
#endif
		return 1;
	}

Here we have 2 new things. Woah, the beer is kicking in…

Anyway: the #if DEBUG statement is a common preprocessor hack used to “printf() debug” as a professor of mine used to say. I’m sure he still calls it that, but he used to as well. It’s pretty easy to mess up printf() debugging because you have to match data types with your format parameter, you have to make sure the data supplied to said parameter won’t crash the program, and consider a dozen little implementation details that are likely to mess things up in the long run.

That being said, our single threaded program with all known data types is probably okay to debug this way.

The better technique for debugging is to step through with a debugger and to just not write shit code, but hey, we don’t always get that luxury.

The WSAStartup(…) function pulls in the windows networking DLL and initializes some things that need to be squared away before out lil’ program can talk to the outside world.

The best way to give detail on the WSA Service is straight from MSDN:

Windows Sockets 2 (Winsock) enables programmers to create advanced Internet, intranet, and other network-capable applications to transmit application data across the wire, independent of the network protocol being used. With Winsock, programmers are provided access to advanced Microsoft® Windows® networking capabilities such as multicast and Quality of Service (QoS).
Winsock follows the Windows Open System Architecture (WOSA) model; it defines a standard service provider interface (SPI) between the application programming interface (API), with its exported functions and the protocol stacks. It uses the sockets paradigm that was first popularized by Berkeley Software Distribution (BSD) UNIX. It was later adapted for Windows in Windows Sockets 1.1, with which Windows Sockets 2 applications are backward compatible. Winsock programming previously centered around TCP/IP. Some programming practices that worked with TCP/IP do not work with every protocol. As a result, the Windows Sockets 2 API adds functions where necessary to handle several protocols.

Now back to the code!

#if DEBUG // Notice this and understand
	printf("Initialised WSA service.\n");
#endif

	/* same deal as before */
	ZeroMemory(&resolv_helper, sizeof(resolv_helper));
    /* here we set up our addrinfo (address info) structure with 
     * information windows needs to connect to the remote server */
	resolv_helper.ai_family = AF_UNSPEC; // I don't know this one
	resolv_helper.ai_socktype = SOCK_STREAM; // A stream socket type is needed for TCP 
	resolv_helper.ai_protocol = IPPROTO_TCP; // This portion says "Hey windows lemme at that TCP stack fam"
	
	/* weird; windows takes ports as strings... */
	/* anyway here we load our addrinfo structures with the IP information of our hostname*/
	res = getaddrinfo("vortex.labs.overthewire.org", "5842", &resolv_helper, &sock_info); 
	if (res != 0) {
#if DEBUG // this should be understood at this point
		printf("getaddrinfo failed with error: %d\n", res);
#endif
		WSACleanup(); // free the resources in use as to not hold sockets with a dead program
		return 1;
	}

getaddrinfo(…) is a function used to resolve a hostname or IP address into a IP address. I say that both get “resolved” but the function knows that if an IP address is supplied to just load the struct with the provided address.

	/* here is where we actually create the Socket to connect to the serv with */
	S = socket(sock_info->ai_family, sock_info->ai_socktype,
		sock_info->ai_protocol);

	if (S == INVALID_SOCKET) { //If S is still INVALID_SOCKET, because that is what it started as...
#if DEBUG
		printf("socket failed with error: %ld\n", WSAGetLastError());
#endif
		WSACleanup();
		return 1;
	}

And now a Socket is born. In a UNIX like system this would be represented as a file descriptor. This however is windows C, so we must interact with this more like a data structure, or a class than a file descriptor.

OJ + Vodka = Screwdriver & awesome;

END OF PART 1, PART 2 WILL BE POSTED HERE TOMORROW


#2

I’m actually going to get part 2 finished tomorrow. I put in a few more hours at work and had errands today.

Sorry :frowning:


#3

Yeah, doing stuff with sockets in windows is painful. I wrote a helper class to do it at one point. If you like, I can dig it out.


#4

That would be awesome. Looks like I am more busy than I expected, so I’ll finish this up this weekend.

Is it C or C++? Also is it implemented via DLL?


#5

It’s actually part of a larger framework which I was working on a while back. You should be able to separate it from the rest of the code.

Don’t judge me for the bad coding style. I’m a much better coder than I was when I wrote the framework.


(system) #6

This topic was automatically closed after 30 days. New replies are no longer allowed.