Just a little something
I have been writing on and off. It was originally meant to be a collaboration of
two of my prior tutorials, however, I'm starting to find it a bit ludicrous to
post a tutorial on "Making Trojans in C++" so I guess I won't really update it
so it fits the Trojan-writing side, but rather provide examples instead. If you
feel the need to post comments regarding my code, then go ahead - I appreciate
constructive criticism relating to my code, tutorial organization, or even
indentation as an effort to help me improve my own skills. Enjoy...
Implementing Winsock within your code
A tutorial by:
Mulciber
-Collaboration of my "Making trojans" and "Working with
Winsock" tutorials.
Content
-Part 1-
I. Introduction
II. Assumptions/requirements
III.
Starting out
IV. Creating sockets
V. Connecting and closing socket
-Part 2-
I. Binding and
listening
II. Receiving and sending
*YET TO BE FINISHED* - or not
III. Introduction to trojans
IV. Basic hiding techniques
V. Malicious functions
-Examples-
I. Chat program
II. Multi-threaded port scanner
III. Remote driver view
I. Introduction (Few notes,
assumptions, and requirements)
In this tutorial, I'll be covering the basis of Winsock, also
known as "windows sockets". What is a socket, you might ask?
Sockets are used to communicate with remote machines, by communicating I mean
sending data. The data can consist of an email,
an instant message, or anything equivalent/similar. Some applications that rely
on Winsock are the following: Trojans
(windows-based, obviously) remote key loggers, etc. With this notion, my
tutorial will be aimed at Winsock essentials, and
eventually incorporating its functions within a Trojan; no Trojan is more
powerful than YOURS because A) It would be
ludicrous if your Trojan didn't remain undetected for a longer period of time
and B) You're in control. You can tailor your
Trojan to do anything that extends to your capabilities/needs.
II.
Assumptions/requirements
Before you attempt this tutorial, I assume that you possess the following:
-Basic C/C++ knowledge
-An IDE/Compiler (I use code::blocks)
-A highly basic foundation consisting of network-related terms including ports,
IPs, etc.
-When you're writing the code presented in this tutorial, make sure that
***libwsock32*** is linked
-Winsock is not cross-platform. Surprisingly, people question whether you can
use Winsock under Linux
III.
Starting out (Loading the library, initializing sockets)
Open up your favorite IDE, and create a new project, linking to the necessary
lib file. Now, before we can start using the
Winsock functions, we need to initialize the library. This can be achieved with
one function:
Code:
WSAStartup()
WSAStartup() requires two parameters, the first being
WSAData, which contains information regarding the Winsock implement.
The second parameter required in the Winsock version that we expect to be
loaded. Along with loading initializing the
library, we can terminate its use with WSACleanup(). Let's take a look at the
following code:
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
*/Lobyte is set to two, hibyte is set to 0 */
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed";
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
}
Now, let's pretend that initialization has failed. Telling
the user "Startup failed" doesn't help much, now does it? They'll
be left discombobulated. So, it's better to provide at least some information.
We can do so by using the WSAGetLastError()
function, which will return an error code that the user can refer to on MSDN. We
can update our program as such:
Code:
std::cout<<"Startup failed, error code:
"<<WSAGetLastError();
Thus, at least the user will know what exactly occurred that prevented a
successful init.
IV. Creating sockets
Now that we have loaded the Winsock library, we can begin
using its various functions. Before we decide to connect (and
receive our own connections by listening) we first need to get a handle on a new
socket. Its parameters (3 in total) include
the address family, in which case we will be using AF_INET, which is the address
family of TCP (Transmission control
protocol) and UDP (User datagram protocol (or unreliable)). Its second parameter
defines the socket type to be used;
SOCK_STREAM or other known as a "streaming socket" is used for TCP, whereas
SOCK_DGRAM is used for UDP. I won't be going
into much detail regarding the advantages/differences between TCP and UDP,
however, to shortly sum them up: TCP is
connection-oriented, meaning a connection must be established before sending
data. TCP also makes sure the data reaches it
destination, whereas UDP isn't connection-oriented, nor does it have any
mechanism behind it which ensures reliable arrival.
Now, going back on topic, the third parameter specifies the protocol to be used,
which IS dependent on the address family. In
most cases, a 0 will suffice, or IPPROTO_TCP can be used. Here's an example of
declaring a socket:
Code:
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
If the socket initialization succeeds, then it will return a
handle to our new socket. If it fails, INVALID_SOCKET is
returned. So, let's update our prior program:
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed, error code: "<<WSAGetLastError();
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
if(kSock == INVALID_SOCKET){ //socket() returns INVALID_SOCKET if it fails, so
check the condition
std::cout<<"Socket init failed";
WSACleanup(); //Cleans up the library
return -1;
}
std::cout<<"Socket initialized\n";
}
V. Connecting
and closing sockets
Now that we have a new socket handle, we can specify the
members of the sockaddr_in structure. The struct contains the port
specification, in which we can connect to or listen on, the host that we plan on
connecting to, and the address family we
want to use. The port and the host needs to be converted to network byte order,
which can be achieved using hton() which
converts the port (e.g., 80) into network byte order, and inet_addr() which
converts the host into network byte order. So,
let's fill out the members of the sockaddr_in struct:
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed, error code: "<<WSAGetLastError();
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
if(kSock == INVALID_SOCKET){
std::cout<<"Socket init failed";
return -1;
}
std::cout<<"Socket initialized\n";
sockaddr_in sin;
sin.sin_port=htons(80);
sin.sin_addr.s_addr=inet_addr("127.0.0.1");
sin.sin_family=AF_INET;
}
In the upcoming, updated program, we will be connecting to
127.0.0.1:80 as the sockaddr_in structure members were properly
defined. The function we will use is connect(), which connects our socket with a
remote one. connect() takes three
parameters, the first one being the unconnected socket we want to connect. The
second parameter is the pointer to the
sockaddr_in struct which contains the host that we want to connect to, and the
third being the size of the sockaddr_in struct
(we will simply use sizeof()). If the connection fails, then SOCKET_ERROR is
returned.
Example of connect():
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed, error code: "<<WSAGetLastError(); //Returns error
code
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
if(kSock == INVALID_SOCKET){
std::cout<<"Socket init failed";
return -1;
}
std::cout<<"Socket initialized\n";
sockaddr_in sin;
sin.sin_port=htons(80); //Connect to port 80
sin.sin_addr.s_addr=inet_addr("127.0.0.1"); //Connect to localhost
sin.sin_family=AF_INET;
if(connect(kSock,(sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR){ //Check the
condition
std::cout<<"Connect failed, error: "<<WSAGetLastError(); //Returns error code
WSACleanup(); //Cleanup the library
return -1;
}
std::cout<<"Connection successful!\n";
closesocket(kSocket);
}
Considering if you don't have a web server installed and
listening, chances are you failed to connect, however, that doesn't
mean that we cannot alter, or rather create a new program that will listen on
port 80. While we will be moving on to
listening and binding, we also need to look at one more function. closesocket()
simply closes the handle to our socket.
SOCKET_ERROR is returned if it fails to close, otherwise, 0 is returned. You
should call this function after you're done
Connecting/Listening, as such:
Code:
std::cout<<"Connection successful!";
closesocket(kSock);
}
Using all the functions presented in this part, or rather
"chapter", we can create a fully functional, multi-threaded port
scanner that can loop through the users' inputted ports, which I will be
demonstrating in the example section.
-Part 2-
I. Binding and listening
In the part 1, we looked at initializing the library,
creating sockets, making our own connections, and terminating the
library and our socket handle(s). Now it's time to look at all of this, but
instead of connecting, we will be listening for
our own connections instead. To do so, we need to bind our socket to a defined
port, then use the listen() function to wait
for connections. To test whether or not our program succeeded, we can use the
command prompt. netstat -ano (o for PID, n for
numerical output, and a for displaying listening ports/active connections) does
the trick because we can refer to the PID of
our application using the task manager, then check whether or not the PID shows
up in the output, along with the defined
port.
To begin, we will be creating a new project. Once we have
achieved perfecting both projects, we can start playing around
'programming Trojans', but for now, we need to successfully program an
application that is capable of listening.
The code does not change at all, all the way up to connect(),
that is. Since I've already gone into detail in the prior
section, I'll briefly display the code, and discuss the one change that will be
made so far.
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed, error code: "<<WSAGetLastError(); //Returns error
code
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
if(kSock == INVALID_SOCKET){
std::cout<<"Socket init failed";
return -1;
}
std::cout<<"Socket initialized\n";
sockaddr_in sin;
sin.sin_port=htons(80);
sin.sin_addr.s_addr=INADDR_ANY;
sin.sin_family=AF_INET;
}
As you can see, the only blatant difference here is the
sin_addr member. Since we are not making any connections, but rather
listening, INADDR_ANY can be used. The next function required in order to listen
is bind(), which takes the exact same
parameters are connect(). We can update our program as such:
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed, error code: "<<WSAGetLastError(); //Returns error
code
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
if(kSock == INVALID_SOCKET){
std::cout<<"Socket init failed";
return -1;
}
std::cout<<"Socket initialized\n";
sockaddr_in sin;
sin.sin_port=htons(80);
sin.sin_addr.s_addr=INADDR_ANY;
sin.sin_family=AF_INET;
if(bind(kSock,(sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR){
std::cout<<"Failed to bind\n";
WSACleanup();
return -1;
}
std::cout<<"Bind successful!\n";
WSACleanup();
return 0;
}
If the socket fails to bind to port 80, try using
WSAGetLastError() along with the output "Failed to bind!". You can lookup
the error code on MSDN, which will provide information regarding the state
(perhaps a service was already listening on port
80?)
Using the listen() function, we can make our bound socket
listen for incoming connections. It takes two parameters, the first
being the bound socket that we wish to use, the second being maximum
connections. Let's update our program as such:
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed, error code: "<<WSAGetLastError(); //Returns error
code
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
if(kSock == INVALID_SOCKET){
std::cout<<"Socket init failed";
return -1;
}
std::cout<<"Socket initialized\n";
sockaddr_in sin;
sin.sin_port=htons(80);
sin.sin_addr.s_addr=INADDR_ANY;
sin.sin_family=AF_INET;
if(bind(kSock,(sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR){
std::cout<<"Failed to bind\n";
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Bind successful!\n";
while (listen(kSock, SOMAXCONN) == SOCKET_ERROR); //Loop in order to constantly
listen
/* set the number of connections to SOMAXCONN, in which case the provider
chooses a reasonable value (5 in Windows XP
Professional) */
SOCKET client;
int len = sizeof(sin);
client=accept(kSock, (sockaddr*)&sin, &len);
std::cout<<"Connection established!\n";
closesocket(client);
closesocket(kSock);
WSACleanup();
}
After calling listen() we created a new socket, client. When
a connection is established, our new socket connects to the
remote machine (since TCP is connection-oriented, both machines must connect)
whereas our old socket (kSock) listens for more
connections. Try running both programs (WinListen and WinConnect in my case) and
see if the connection is successful, and
whether you get a "Connection established" (WinListen) and "Connection
successful" (WinConnect) output or not.
II. Receiving and
sending
Now that we have finally implemented two, simple programs
capable of connecting and listening (phew!) we can send and receive
data, using two key functions send() and recv(). send() sends data from the
buffer on the socket, returning the number of
bytes sent. recv() receives the data from the socket (and sent by the foreign
machine) and stores it in the buffer.
Code:
send() takes four parameters:
socket - specifies which connected socket to send data on
buffer - holds the data to be sent
leng - length of data (use sizeof())
flags - specifies the way in which the call is made (irrelevant at this time)
recv() also takes four parameters:
socket - specifies which connected socket to receive data on
buffer - holds the received data
leng - length of data to be received
flags - specifies the way in which the call is made (irrelevant at this time)
As you can see, both functions are fairly comprehensible and similar. With this
notion, let's take a look at two sample
Applications:
-Win Connect-
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
char buf[256];
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed, error code: "<<WSAGetLastError(); //Returns error
code
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
if(kSock == INVALID_SOCKET){
std::cout<<"Socket init failed";
return -1;
}
std::cout<<"Socket initialized\n";
sockaddr_in sin;
sin.sin_port=htons(808); //Connect to port 80
sin.sin_addr.s_addr=inet_addr("127.0.0.1"); //Connect to localhost
sin.sin_family=AF_INET;
if(connect(kSock,(sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR){ //Check the
condition
std::cout<<"Connect failed, error: "<<WSAGetLastError(); //Returns error code
WSACleanup(); //Cleanup the library
return -1;
}
std::cout<<"Connection successful!\n";
recv(kSock, buf, sizeof(buf), 0); //Receive "Hello" from server
std::cout << buf;
closesocket(kSock);
return 0;
}
-Win Listen-
Code:
#include <windows.h> //Required for socket init
#include <iostream>
int main(){
char buf[] = "Hello\n";
WSAData wsdata; //Declare WSAData
WORD wsver=MAKEWORD(2, 0); //We want Winsock 2.0
int nret=WSAStartup(wsver, &wsdata); //Pass version 2.0 and pointer to implement
if(nret != 0){ //Init failed
/*A successful return value should be 0 */
std::cout<<"Startup failed, error code: "<<WSAGetLastError(); //Returns error
code
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Init success\n";
SOCKET kSock=socket(AF_INET, SOCK_STREAM, 0);
if(kSock == INVALID_SOCKET){
std::cout<<"Socket init failed";
return -1;
}
std::cout<<"Socket initialized\n";
sockaddr_in sin;
sin.sin_port=htons(808);
sin.sin_addr.s_addr=INADDR_ANY;
sin.sin_family=AF_INET;
if(bind(kSock,(sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR){
std::cout<<"Failed to bind\n";
WSACleanup(); //Cleanup Winsock library
return -1;
}
std::cout<<"Bind successful!\n";
while (listen(kSock, SOMAXCONN) == SOCKET_ERROR); //Loop in order to constantly
listen
/* set the number of connections to SOMAXCONN, in which case the provider
chooses a reasonable value (5 in Windows XP
Professional) */
SOCKET client;
int len = sizeof(sin);
client=accept(kSock, (sockaddr*)&sin, &len);
std::cout<<"Connection established!\n";
send(client, buf, sizeof(buf), 0); //Send "Hello"
closesocket(client); //Close both socket handles
closesocket(kSock);
WSACleanup();
return 0;
}
If all goes well, you should see "Hello" as the output on
your connecting program. In that case, you may try making a simple
chat application using send and recv(), along with all the other functions we
have explored. (I'll provide a GUI example at this end of this
tutorial...probably.)