You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
12 KiB
404 lines
12 KiB
#pragma once
|
|
#include <fltKernel.h>
|
|
#include <intrin.h>
|
|
|
|
namespace clonestd {
|
|
// STRUCT TEMPLATE remove_reference
|
|
template <class _Ty>
|
|
struct remove_reference
|
|
{
|
|
using type = _Ty;
|
|
};
|
|
|
|
template <class _Ty>
|
|
struct remove_reference<_Ty &>
|
|
{
|
|
using type = _Ty;
|
|
};
|
|
|
|
template <class _Ty>
|
|
struct remove_reference<_Ty &&>
|
|
{
|
|
using type = _Ty;
|
|
};
|
|
|
|
template <class _Ty>
|
|
using remove_reference_t = typename remove_reference<_Ty>::type;
|
|
|
|
// STRUCT TEMPLATE remove_const
|
|
template <class _Ty>
|
|
struct remove_const
|
|
{ // remove top-level const qualifier
|
|
using type = _Ty;
|
|
};
|
|
|
|
template <class _Ty>
|
|
struct remove_const<const _Ty>
|
|
{
|
|
using type = _Ty;
|
|
};
|
|
|
|
template <class _Ty>
|
|
using remove_const_t = typename remove_const<_Ty>::type;
|
|
} // namespace clonestd
|
|
|
|
namespace kli {
|
|
constexpr auto Time = __TIME__;
|
|
constexpr auto Seed = static_cast<unsigned long long>(Time[7]) + static_cast<unsigned long long>(Time[6]) * 10 +
|
|
static_cast<unsigned long long>(Time[4]) * 60 + static_cast<unsigned long long>(Time[3]) * 600 +
|
|
static_cast<unsigned long long>(Time[1]) * 3600 +
|
|
static_cast<unsigned long long>(Time[0]) * 36000;
|
|
constexpr auto Seed2 = static_cast<unsigned long long>(Time[7]) + static_cast<unsigned long long>(Time[6]) * 10 +
|
|
static_cast<unsigned long long>(Time[4]) * 60;
|
|
constexpr auto Seed3 = static_cast<unsigned long long>(Time[7]) + static_cast<unsigned long long>(Time[5]) * 10 +
|
|
static_cast<unsigned long long>(Time[2]) * 60;
|
|
constexpr auto Seed4 = static_cast<unsigned long long>(Time[7]) + static_cast<unsigned long long>(Time[3]) * 10 +
|
|
static_cast<unsigned long long>(Time[1]) * 60;
|
|
|
|
namespace cache {
|
|
constexpr unsigned long long base_init = Seed3;
|
|
inline unsigned long long base = base_init;
|
|
} // namespace cache
|
|
|
|
namespace hash {
|
|
namespace detail {
|
|
template <typename Size>
|
|
struct fnv_constants;
|
|
|
|
template <>
|
|
struct fnv_constants<unsigned int>
|
|
{
|
|
constexpr static unsigned int default_offset_basis = 0x811C9DC5UL;
|
|
constexpr static unsigned int prime = 0x01000193UL;
|
|
};
|
|
|
|
template <>
|
|
struct fnv_constants<unsigned long long>
|
|
{
|
|
constexpr static unsigned long long default_offset_basis = 0xCBF29CE484222325ULL;
|
|
constexpr static unsigned long long prime = 0x100000001B3ULL;
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
// Dumb hack to force a constexpr value to be evaluated in compiletime
|
|
template <typename Type, Type Value>
|
|
struct force_cx
|
|
{
|
|
constexpr static auto value = Value;
|
|
};
|
|
|
|
template <typename Type, typename Char>
|
|
__forceinline constexpr Type
|
|
hash_fnv1a(const Char *str)
|
|
{
|
|
Type val = detail::fnv_constants<Type>::default_offset_basis;
|
|
|
|
// random
|
|
val += Seed;
|
|
|
|
for (; *str != static_cast<Char>(0); ++str)
|
|
{
|
|
Char c = *str;
|
|
val ^= static_cast<Type>(c);
|
|
val *= static_cast<Type>(detail::fnv_constants<Type>::prime);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
#define KLI_HASH_RTS(str) \
|
|
(::kli::hash:: \
|
|
hash_fnv1a<unsigned long long, clonestd::remove_const_t<clonestd::remove_reference_t<decltype(*(str))>>>( \
|
|
(str)))
|
|
|
|
#define KLI_HASH_STR(str) \
|
|
(::kli::hash::force_cx< \
|
|
unsigned long long, \
|
|
::kli::hash:: \
|
|
hash_fnv1a<unsigned long long, clonestd::remove_const_t<clonestd::remove_reference_t<decltype(*(str))>>>( \
|
|
(str))>::value)
|
|
|
|
} // namespace hash
|
|
|
|
namespace crypto {
|
|
typedef struct s_rc4_state
|
|
{
|
|
int x, y;
|
|
unsigned char m[256];
|
|
} rc4_state;
|
|
|
|
__forceinline void
|
|
rc4_init_key(rc4_state *s, unsigned char *key, int length)
|
|
{
|
|
int i, j, k, a;
|
|
|
|
unsigned char *m;
|
|
|
|
s->x = 0;
|
|
s->y = 0;
|
|
m = s->m;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
m[i] = (unsigned char)i;
|
|
}
|
|
|
|
j = k = 0;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
a = m[i];
|
|
j = (unsigned char)(j + a + key[k]);
|
|
m[i] = m[j];
|
|
m[j] = (unsigned char)a;
|
|
if (++k >= length)
|
|
k = 0;
|
|
}
|
|
}
|
|
|
|
__forceinline void
|
|
rc4_crypt(rc4_state *s, unsigned char *data, int length)
|
|
{
|
|
int i, x, y, a, b;
|
|
|
|
unsigned char *m;
|
|
|
|
x = s->x;
|
|
y = s->y;
|
|
m = s->m;
|
|
|
|
for (i = 0; i < length; i++)
|
|
{
|
|
x = (unsigned char)(x + 1);
|
|
a = m[x];
|
|
y = (unsigned char)(y + a);
|
|
m[x] = b = m[y];
|
|
m[y] = (unsigned char)a;
|
|
data[i] ^= m[(unsigned char)(a + b)];
|
|
}
|
|
|
|
s->x = x;
|
|
s->y = y;
|
|
}
|
|
|
|
__forceinline void
|
|
rc4_crypt_all_in_once(unsigned char *key_buff, unsigned long key_len, unsigned char *enc_buff, unsigned long enc_len)
|
|
{
|
|
rc4_state state;
|
|
rc4_init_key(&state, key_buff, key_len);
|
|
rc4_crypt(&state, enc_buff, enc_len);
|
|
}
|
|
|
|
template <typename Type>
|
|
__forceinline Type
|
|
RC4Base(Type Ptr)
|
|
{
|
|
unsigned long long rc4_key = Seed2;
|
|
unsigned long long rc4_data = Seed4;
|
|
crypto::rc4_crypt_all_in_once(
|
|
(unsigned char *)(&rc4_key), sizeof(rc4_key), (unsigned char *)(&rc4_data), sizeof(rc4_data));
|
|
return (Type)((unsigned long long)Ptr ^ rc4_data);
|
|
}
|
|
|
|
template <typename Type>
|
|
__forceinline Type
|
|
RC4Func(Type Ptr)
|
|
{
|
|
unsigned long long rc4_key = Seed4;
|
|
unsigned long long rc4_data = Seed2;
|
|
crypto::rc4_crypt_all_in_once(
|
|
(unsigned char *)(&rc4_key), sizeof(rc4_key), (unsigned char *)(&rc4_data), sizeof(rc4_data));
|
|
return (Type)((unsigned long long)Ptr ^ rc4_data);
|
|
}
|
|
|
|
} // namespace crypto
|
|
|
|
namespace detail {
|
|
typedef struct _IMAGE_DOS_HEADER
|
|
{ // DOS .EXE header
|
|
unsigned short e_magic; // Magic number
|
|
unsigned short e_cblp; // Bytes on last page of file
|
|
unsigned short e_cp; // Pages in file
|
|
unsigned short e_crlc; // Relocations
|
|
unsigned short e_cparhdr; // GetSize of header in paragraphs
|
|
unsigned short e_minalloc; // Minimum extra paragraphs needed
|
|
unsigned short e_maxalloc; // Maximum extra paragraphs needed
|
|
unsigned short e_ss; // Initial (relative) SS value
|
|
unsigned short e_sp; // Initial SP value
|
|
unsigned short e_csum; // Checksum
|
|
unsigned short e_ip; // Initial IP value
|
|
unsigned short e_cs; // Initial (relative) CS value
|
|
unsigned short e_lfarlc; // File address of relocation table
|
|
unsigned short e_ovno; // Overlay number
|
|
unsigned short e_res[4]; // Reserved words
|
|
unsigned short e_oemid; // OEM identifier (for e_oeminfo)
|
|
unsigned short e_oeminfo; // OEM information; e_oemid specific
|
|
unsigned short e_res2[10]; // Reserved words
|
|
int e_lfanew; // File address of new exe header
|
|
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
|
|
|
|
typedef struct _IMAGE_FILE_HEADER
|
|
{
|
|
unsigned short Machine;
|
|
unsigned short NumberOfSections;
|
|
unsigned int TimeDateStamp;
|
|
unsigned int PointerToSymbolTable;
|
|
unsigned int NumberOfSymbols;
|
|
unsigned short SizeOfOptionalHeader;
|
|
unsigned short Characteristics;
|
|
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
|
|
|
|
typedef struct _IMAGE_DATA_DIRECTORY
|
|
{
|
|
unsigned int VirtualAddress;
|
|
unsigned int Size;
|
|
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
|
|
|
|
typedef struct _IMAGE_OPTIONAL_HEADER64
|
|
{
|
|
unsigned short Magic;
|
|
unsigned char MajorLinkerVersion;
|
|
unsigned char MinorLinkerVersion;
|
|
unsigned int SizeOfCode;
|
|
unsigned int SizeOfInitializedData;
|
|
unsigned int SizeOfUninitializedData;
|
|
unsigned int AddressOfEntryPoint;
|
|
unsigned int BaseOfCode;
|
|
unsigned long long ImageBase;
|
|
unsigned int SectionAlignment;
|
|
unsigned int FileAlignment;
|
|
unsigned short MajorOperatingSystemVersion;
|
|
unsigned short MinorOperatingSystemVersion;
|
|
unsigned short MajorImageVersion;
|
|
unsigned short MinorImageVersion;
|
|
unsigned short MajorSubsystemVersion;
|
|
unsigned short MinorSubsystemVersion;
|
|
unsigned int Win32VersionValue;
|
|
unsigned int SizeOfImage;
|
|
unsigned int SizeOfHeaders;
|
|
unsigned int CheckSum;
|
|
unsigned short Subsystem;
|
|
unsigned short DllCharacteristics;
|
|
unsigned long long SizeOfStackReserve;
|
|
unsigned long long SizeOfStackCommit;
|
|
unsigned long long SizeOfHeapReserve;
|
|
unsigned long long SizeOfHeapCommit;
|
|
unsigned int LoaderFlags;
|
|
unsigned int NumberOfRvaAndSizes;
|
|
IMAGE_DATA_DIRECTORY DataDirectory[16];
|
|
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
|
|
|
|
typedef struct _IMAGE_NT_HEADERS64
|
|
{
|
|
unsigned int Signature;
|
|
IMAGE_FILE_HEADER FileHeader;
|
|
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
|
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
|
|
|
|
typedef struct _IMAGE_EXPORT_DIRECTORY
|
|
{
|
|
unsigned int Characteristics;
|
|
unsigned int TimeDateStamp;
|
|
unsigned short MajorVersion;
|
|
unsigned short MinorVersion;
|
|
unsigned int Name;
|
|
unsigned int Base;
|
|
unsigned int NumberOfFunctions;
|
|
unsigned int NumberOfNames;
|
|
unsigned int AddressOfFunctions; // RVA from base of image
|
|
unsigned int AddressOfNames; // RVA from base of image
|
|
unsigned int AddressOfNameOrdinals; // RVA from base of image
|
|
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
|
|
|
|
__declspec(naked) __forceinline unsigned long long get_kernel_base()
|
|
{
|
|
_asm {
|
|
mov rax, qword ptr gs:[18h]
|
|
mov rcx, [rax+38h]
|
|
mov rax, 0FFFFFFFFFFFFF000h
|
|
and rax, [rcx+4h]
|
|
jmp while_begin
|
|
search_begin:
|
|
add rax, 0FFFFFFFFFFFFF000h
|
|
while_begin:
|
|
xor ecx, ecx
|
|
jmp search_cmp
|
|
search_next:
|
|
add rcx, 1
|
|
cmp rcx, 0FF9h
|
|
jz search_begin
|
|
search_cmp:
|
|
cmp byte ptr[rax+rcx], 48h
|
|
jnz search_next
|
|
cmp byte ptr[rax+rcx+1], 8Dh
|
|
jnz search_next
|
|
cmp byte ptr[rax+rcx+2], 1Dh
|
|
jnz search_next
|
|
cmp byte ptr[rax+rcx+6], 0FFh
|
|
jnz search_next
|
|
mov r8d,[rax+rcx+3]
|
|
lea edx,[rcx+r8]
|
|
add edx, eax
|
|
add edx, 7
|
|
test edx, 0FFFh
|
|
jnz search_next
|
|
mov rdx, 0FFFFFFFF00000000h
|
|
and rdx, rax
|
|
add r8d, eax
|
|
lea eax,[rcx+r8]
|
|
add eax, 7
|
|
or rax, rdx
|
|
ret
|
|
}
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
__forceinline unsigned long long
|
|
find_kernel_export(unsigned long long export_hash)
|
|
{
|
|
if (cache::base == cache::base_init)
|
|
{
|
|
cache::base = crypto::RC4Base(detail::get_kernel_base());
|
|
}
|
|
|
|
const auto dos_header = (detail::PIMAGE_DOS_HEADER)crypto::RC4Base(cache::base);
|
|
const auto nt_headers = (detail::PIMAGE_NT_HEADERS64)(crypto::RC4Base(cache::base) + dos_header->e_lfanew);
|
|
const auto export_directory = (detail::PIMAGE_EXPORT_DIRECTORY)(
|
|
crypto::RC4Base(cache::base) + nt_headers->OptionalHeader.DataDirectory[0].VirtualAddress);
|
|
|
|
const auto address_of_functions =
|
|
(unsigned int *)(crypto::RC4Base(cache::base) + export_directory->AddressOfFunctions);
|
|
const auto address_of_names = (unsigned int *)(crypto::RC4Base(cache::base) + export_directory->AddressOfNames);
|
|
const auto address_of_name_ordinals =
|
|
(unsigned short *)(crypto::RC4Base(cache::base) + export_directory->AddressOfNameOrdinals);
|
|
|
|
for (unsigned int i = 0; i < export_directory->NumberOfNames; ++i)
|
|
{
|
|
const auto export_entry_name = (char *)(crypto::RC4Base(cache::base) + address_of_names[i]);
|
|
const auto export_entry_hash = KLI_HASH_RTS(export_entry_name);
|
|
|
|
// address_of_functions is indexed through an ordinal
|
|
// address_of_name_ordinals gets the ordinal through our own index - i.
|
|
if (export_entry_hash == export_hash)
|
|
{
|
|
auto func = crypto::RC4Base(cache::base) + address_of_functions[address_of_name_ordinals[i]];
|
|
return crypto::RC4Func(func);
|
|
}
|
|
}
|
|
|
|
return 0ULL;
|
|
}
|
|
|
|
// once
|
|
#define KLI_CALL(name, ...) \
|
|
((decltype(&name))(kli::crypto::RC4Func(kli::find_kernel_export(KLI_HASH_STR(#name)))))(__VA_ARGS__)
|
|
|
|
// cached
|
|
#define KLI_CACHED_DEF(name) decltype(&name) KLI##name = nullptr
|
|
#define KLI_CACHED_SET(name) KLI##name = (decltype(&name))(kli::find_kernel_export(KLI_HASH_STR(#name)))
|
|
#define KLI_CACHED_CALL(name, ...) ((decltype(&name))(kli::crypto::RC4Func(KLI##name)))(__VA_ARGS__)
|
|
|
|
} // namespace kli
|