parent
bda9b90c87
commit
f9fd850da9
@ -0,0 +1,18 @@
|
||||
---
|
||||
BasedOnStyle: Microsoft
|
||||
AlignAfterOpenBracket: Align
|
||||
AllowAllArgumentsOnNextLine: 'true'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
BreakBeforeBraces: Allman
|
||||
IndentWidth: '4'
|
||||
Language: Cpp
|
||||
NamespaceIndentation: All
|
||||
SpacesInAngles: 'true'
|
||||
SpacesInCStyleCastParentheses: 'true'
|
||||
SpacesInContainerLiterals: 'true'
|
||||
SpacesInParentheses: 'true'
|
||||
SpacesInSquareBrackets: 'true'
|
||||
UseTab: Never
|
||||
|
||||
...
|
@ -1 +1 @@
|
||||
Subproject commit bf5f30c360f7e9d87a0cdba82d70008fd64c5c1c
|
||||
Subproject commit 8051b171747ba1ce08cfefc4ca1f91dbd790ab4d
|
@ -1,237 +0,0 @@
|
||||
//
|
||||
// Registers on image load callback then applies vmhook to EAC
|
||||
//
|
||||
//
|
||||
|
||||
#include "scn.hpp"
|
||||
#include "shithook.hpp"
|
||||
#include "sha1.hpp"
|
||||
#include "md5.hpp"
|
||||
|
||||
//
|
||||
// game cheat offset flash backs...
|
||||
//
|
||||
|
||||
#define EAC_VM_HANDLE_OFFSET 0xE93D
|
||||
#define EAC_SHA1_OFFSET 0x4C00
|
||||
#define EAC_MD5_OFFSET 0x37378
|
||||
#define EAC_CRC32_OFFSET 0x27C8C
|
||||
#define EAC_IMAGE_BASE 0x140000000
|
||||
|
||||
#define DBG_PRINT(format, ...) \
|
||||
DbgPrintEx( DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL, \
|
||||
"[vmhook-eac [core number = %d]]" format, KeGetCurrentProcessorNumber(), __VA_ARGS__)
|
||||
|
||||
//
|
||||
// vm handler indexes for READQ...
|
||||
//
|
||||
|
||||
u8 readq_idxs[] = { 247, 215, 169, 159, 71, 60, 55, 43, 23 };
|
||||
|
||||
//
|
||||
// vm handler indexes for READDW
|
||||
//
|
||||
|
||||
u8 readdw_idxs[] = { 218, 180, 179, 178, 163, 137, 92, 22, 12 };
|
||||
|
||||
//
|
||||
// vm handler indexes for READB
|
||||
//
|
||||
|
||||
u8 readb_idxs[] = { 249, 231, 184, 160, 88, 85, 48, 9, 2 };
|
||||
|
||||
vm::hook_t* g_vmhook = nullptr;
|
||||
vm::handler::table_t* g_vm_table = nullptr;
|
||||
u64 __image_base = 0u, __image_size = 0u, __image_clone = 0u;
|
||||
inline_hook_t __crc32_hook, __sha1_hook, __md5_hook;
|
||||
|
||||
void*
|
||||
operator new(
|
||||
u64 size
|
||||
)
|
||||
{
|
||||
//
|
||||
// Could have also used ExAllocatePoolZero...
|
||||
//
|
||||
|
||||
return RtlZeroMemory(ExAllocatePool(NonPagedPool, size), size);
|
||||
}
|
||||
|
||||
void
|
||||
operator delete
|
||||
(
|
||||
void* ptr,
|
||||
u64 size
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(size);
|
||||
ExFreePool(ptr);
|
||||
}
|
||||
|
||||
__declspec(noinline)
|
||||
void hook_sha1(
|
||||
void *data, unsigned int len, void* result
|
||||
)
|
||||
{
|
||||
sha1_ctx ctx;
|
||||
sha1_init(&ctx);
|
||||
|
||||
if (scn::read_only(__image_base, (u64)data))
|
||||
{
|
||||
DBG_PRINT("sha1 hash data = 0x%p, len = 0x%x, result = 0x%p\n", data, len, result);
|
||||
sha1_update(&ctx, (unsigned char*)__image_clone + (((u64)data) - __image_base), len);
|
||||
sha1_final((unsigned char*)result, &ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
sha1_update(&ctx, (unsigned char*) data, len);
|
||||
sha1_final((unsigned char*)result, &ctx);
|
||||
}
|
||||
|
||||
void
|
||||
image_loaded(
|
||||
PUNICODE_STRING image_name,
|
||||
HANDLE pid,
|
||||
PIMAGE_INFO image_info
|
||||
)
|
||||
{
|
||||
//
|
||||
// PID is zero when the module being loaded is going into the kernel...
|
||||
//
|
||||
|
||||
if (!pid && wcsstr(image_name->Buffer, L"EasyAntiCheat.sys"))
|
||||
{
|
||||
if (g_vmhook && g_vm_table && __image_clone)
|
||||
delete g_vmhook, delete g_vm_table, ExFreePool((void*)__image_clone);
|
||||
|
||||
//
|
||||
// allocate memory for a g_vmhook, g_vm_table and then zero it...
|
||||
//
|
||||
|
||||
// > 0x00007FF77A233736 mov rcx, [r12+rax*8]
|
||||
// > 0x00007FF77A23373D ror rcx, 0x30 <--- decrypt vm handler entry...
|
||||
// > 0x00007FF77A233747 add rcx, r13
|
||||
// > 0x00007FF77A23374A jmp rcx
|
||||
vm::decrypt_handler_t _decrypt_handler =
|
||||
[](u64 val) -> u64
|
||||
{
|
||||
return _rotr64(val, 0x30);
|
||||
};
|
||||
|
||||
// > 0x00007FF77A233736 mov rcx, [r12+rax*8]
|
||||
// > 0x00007FF77A23373D ror rcx, 0x30 <--- inverse to encrypt vm handler entry...
|
||||
// > 0x00007FF77A233747 add rcx, r13
|
||||
// > 0x00007FF77A23374A jmp rcx
|
||||
vm::encrypt_handler_t _encrypt_handler =
|
||||
[](u64 val) -> u64
|
||||
{
|
||||
return _rotl64(val, 0x30);
|
||||
};
|
||||
|
||||
vm::handler::edit_entry_t _edit_entry =
|
||||
[](u64* entry_ptr, u64 val) -> void
|
||||
{
|
||||
//
|
||||
// disable write protect bit in cr0...
|
||||
//
|
||||
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 &= 0xfffffffffffeffff;
|
||||
__writecr0(cr0);
|
||||
_disable();
|
||||
}
|
||||
|
||||
*entry_ptr = val;
|
||||
|
||||
//
|
||||
// enable write protect bit in cr0...
|
||||
//
|
||||
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 |= 0x10000;
|
||||
_enable();
|
||||
__writecr0(cr0);
|
||||
}
|
||||
};
|
||||
|
||||
auto image_base = reinterpret_cast<u64>(image_info->ImageBase);
|
||||
auto handler_table_ptr = reinterpret_cast<u64*>(image_base + EAC_VM_HANDLE_OFFSET);
|
||||
|
||||
__image_clone = reinterpret_cast<u64>(ExAllocatePool(NonPagedPool, image_info->ImageSize));
|
||||
RtlCopyMemory((void*)__image_clone, (void*)image_base, image_info->ImageSize);
|
||||
|
||||
g_vm_table = new vm::handler::table_t(handler_table_ptr, _edit_entry);
|
||||
g_vmhook = new vm::hook_t(image_base, EAC_IMAGE_BASE, _decrypt_handler, _encrypt_handler, g_vm_table);
|
||||
__image_base = image_base, __image_size = image_info->ImageSize;
|
||||
|
||||
const auto callback = [](vm::registers* regs, u8 handler_idx)
|
||||
{
|
||||
const auto read_addr = reinterpret_cast<u64*>(regs->rbp)[0];
|
||||
|
||||
// shoot the tires right off the virtualized integrity checks in about 2 lines of code...
|
||||
if (scn::read_only(__image_base, read_addr))
|
||||
{
|
||||
DBG_PRINT(" READ(Q/DW/B) EasyAntiCheat.sys+0x%x\n", (read_addr - __image_base));
|
||||
reinterpret_cast<u64*>(regs->rbp)[0] = __image_clone + (read_addr - __image_base);
|
||||
}
|
||||
};
|
||||
|
||||
// install hooks on READQ virtual machine handlers...
|
||||
for (auto idx = 0u; idx < sizeof readq_idxs; ++idx)
|
||||
g_vm_table->set_callback(readq_idxs[idx], callback);
|
||||
|
||||
// install hooks on READDW virtual machine handlers...
|
||||
for (auto idx = 0u; idx < sizeof readdw_idxs; ++idx)
|
||||
g_vm_table->set_callback(readdw_idxs[idx], callback);
|
||||
|
||||
// install hooks on READB virtual machine handlers...
|
||||
for (auto idx = 0u; idx < sizeof readb_idxs; ++idx)
|
||||
g_vm_table->set_callback(readb_idxs[idx], callback);
|
||||
|
||||
//
|
||||
// hooks all vm handlers and starts callbacks...
|
||||
//
|
||||
g_vmhook->start();
|
||||
|
||||
// hook on sha1...
|
||||
make_inline_hook(&__sha1_hook,
|
||||
reinterpret_cast<void*>(
|
||||
image_base + EAC_SHA1_OFFSET), &hook_sha1, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
This is the entry routine for the vmhook-eac driver.
|
||||
|
||||
Arguments:
|
||||
drv_object - Pointer to driver object created by the system.
|
||||
reg_path - Receives the full registry path to the SERVICES
|
||||
node of the current control set.
|
||||
|
||||
Return Value:
|
||||
An NTSTATUS code.
|
||||
|
||||
--*/
|
||||
|
||||
extern "C"
|
||||
NTSTATUS
|
||||
DriverEntry( // entry called from ZwSwapCert...
|
||||
PDRIVER_OBJECT drv_object,
|
||||
PUNICODE_STRING reg_path
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(drv_object);
|
||||
UNREFERENCED_PARAMETER(reg_path);
|
||||
|
||||
//
|
||||
// This kernel driver cannot be unloaded so there is no unload routine...
|
||||
// This is because ZwSwapCert will cause the system to crash...
|
||||
//
|
||||
|
||||
DBG_PRINT("> Registering ImageLoad Callbacks...\n");
|
||||
return PsSetLoadImageNotifyRoutine(&image_loaded);
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
#include <intrin.h>
|
||||
#include <ntifs.h>
|
||||
#include <vmhook.hpp>
|
||||
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
|
||||
namespace scn
|
||||
{
|
||||
typedef struct _IMAGE_DOS_HEADER
|
||||
{
|
||||
/* 0x0000 */ unsigned short e_magic;
|
||||
/* 0x0002 */ unsigned short e_cblp;
|
||||
/* 0x0004 */ unsigned short e_cp;
|
||||
/* 0x0006 */ unsigned short e_crlc;
|
||||
/* 0x0008 */ unsigned short e_cparhdr;
|
||||
/* 0x000a */ unsigned short e_minalloc;
|
||||
/* 0x000c */ unsigned short e_maxalloc;
|
||||
/* 0x000e */ unsigned short e_ss;
|
||||
/* 0x0010 */ unsigned short e_sp;
|
||||
/* 0x0012 */ unsigned short e_csum;
|
||||
/* 0x0014 */ unsigned short e_ip;
|
||||
/* 0x0016 */ unsigned short e_cs;
|
||||
/* 0x0018 */ unsigned short e_lfarlc;
|
||||
/* 0x001a */ unsigned short e_ovno;
|
||||
/* 0x001c */ unsigned short e_res[ 4 ];
|
||||
/* 0x0024 */ unsigned short e_oemid;
|
||||
/* 0x0026 */ unsigned short e_oeminfo;
|
||||
/* 0x0028 */ unsigned short e_res2[ 10 ];
|
||||
/* 0x003c */ long e_lfanew;
|
||||
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; /* size: 0x0040 */
|
||||
|
||||
typedef struct _IMAGE_FILE_HEADER
|
||||
{
|
||||
/* 0x0000 */ unsigned short Machine;
|
||||
/* 0x0002 */ unsigned short NumberOfSections;
|
||||
/* 0x0004 */ unsigned long TimeDateStamp;
|
||||
/* 0x0008 */ unsigned long PointerToSymbolTable;
|
||||
/* 0x000c */ unsigned long NumberOfSymbols;
|
||||
/* 0x0010 */ unsigned short SizeOfOptionalHeader;
|
||||
/* 0x0012 */ unsigned short Characteristics;
|
||||
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; /* size: 0x0014 */
|
||||
|
||||
typedef struct _IMAGE_DATA_DIRECTORY
|
||||
{
|
||||
/* 0x0000 */ unsigned long VirtualAddress;
|
||||
/* 0x0004 */ unsigned long Size;
|
||||
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; /* size: 0x0008 */
|
||||
|
||||
typedef struct _IMAGE_OPTIONAL_HEADER64
|
||||
{
|
||||
/* 0x0000 */ unsigned short Magic;
|
||||
/* 0x0002 */ unsigned char MajorLinkerVersion;
|
||||
/* 0x0003 */ unsigned char MinorLinkerVersion;
|
||||
/* 0x0004 */ unsigned long SizeOfCode;
|
||||
/* 0x0008 */ unsigned long SizeOfInitializedData;
|
||||
/* 0x000c */ unsigned long SizeOfUninitializedData;
|
||||
/* 0x0010 */ unsigned long AddressOfEntryPoint;
|
||||
/* 0x0014 */ unsigned long BaseOfCode;
|
||||
/* 0x0018 */ unsigned __int64 ImageBase;
|
||||
/* 0x0020 */ unsigned long SectionAlignment;
|
||||
/* 0x0024 */ unsigned long FileAlignment;
|
||||
/* 0x0028 */ unsigned short MajorOperatingSystemVersion;
|
||||
/* 0x002a */ unsigned short MinorOperatingSystemVersion;
|
||||
/* 0x002c */ unsigned short MajorImageVersion;
|
||||
/* 0x002e */ unsigned short MinorImageVersion;
|
||||
/* 0x0030 */ unsigned short MajorSubsystemVersion;
|
||||
/* 0x0032 */ unsigned short MinorSubsystemVersion;
|
||||
/* 0x0034 */ unsigned long Win32VersionValue;
|
||||
/* 0x0038 */ unsigned long SizeOfImage;
|
||||
/* 0x003c */ unsigned long SizeOfHeaders;
|
||||
/* 0x0040 */ unsigned long CheckSum;
|
||||
/* 0x0044 */ unsigned short Subsystem;
|
||||
/* 0x0046 */ unsigned short DllCharacteristics;
|
||||
/* 0x0048 */ unsigned __int64 SizeOfStackReserve;
|
||||
/* 0x0050 */ unsigned __int64 SizeOfStackCommit;
|
||||
/* 0x0058 */ unsigned __int64 SizeOfHeapReserve;
|
||||
/* 0x0060 */ unsigned __int64 SizeOfHeapCommit;
|
||||
/* 0x0068 */ unsigned long LoaderFlags;
|
||||
/* 0x006c */ unsigned long NumberOfRvaAndSizes;
|
||||
/* 0x0070 */ struct _IMAGE_DATA_DIRECTORY DataDirectory[ 16 ];
|
||||
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; /* size: 0x00f0 */
|
||||
|
||||
typedef struct _IMAGE_NT_HEADERS64
|
||||
{
|
||||
/* 0x0000 */ unsigned long Signature;
|
||||
/* 0x0004 */ struct _IMAGE_FILE_HEADER FileHeader;
|
||||
/* 0x0018 */ struct _IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
||||
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; /* size: 0x0108 */
|
||||
|
||||
typedef struct _IMAGE_SECTION_HEADER
|
||||
{
|
||||
/* 0x0000 */ unsigned char Name[ 8 ];
|
||||
union
|
||||
{
|
||||
union
|
||||
{
|
||||
/* 0x0008 */ unsigned long PhysicalAddress;
|
||||
/* 0x0008 */ unsigned long VirtualSize;
|
||||
}; /* size: 0x0004 */
|
||||
} /* size: 0x0004 */ Misc;
|
||||
/* 0x000c */ unsigned long VirtualAddress;
|
||||
/* 0x0010 */ unsigned long SizeOfRawData;
|
||||
/* 0x0014 */ unsigned long PointerToRawData;
|
||||
/* 0x0018 */ unsigned long PointerToRelocations;
|
||||
/* 0x001c */ unsigned long PointerToLinenumbers;
|
||||
/* 0x0020 */ unsigned short NumberOfRelocations;
|
||||
/* 0x0022 */ unsigned short NumberOfLinenumbers;
|
||||
/* 0x0024 */ unsigned long Characteristics;
|
||||
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; /* size: 0x0028 */
|
||||
|
||||
//
|
||||
// just loops over EasyAntiCheat.sys section headers and determines if
|
||||
// the address in "ptr" lands within any readonly, non-discardable sections...
|
||||
//
|
||||
|
||||
bool read_only( u64 image_base, u64 ptr );
|
||||
} // namespace scn
|
@ -0,0 +1,293 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
SHA-1 in C
|
||||
By Steve Reid <steve@edmweb.com>
|
||||
100% Public Domain
|
||||
*/
|
||||
|
||||
using uint32_t = unsigned int;
|
||||
|
||||
typedef struct _sha1_ctx
|
||||
{
|
||||
uint32_t state[ 5 ];
|
||||
uint32_t count[ 2 ];
|
||||
unsigned char buffer[ 64 ];
|
||||
} sha1_ctx, *psha1_ctx;
|
||||
|
||||
void sha1_transform( uint32_t state[ 5 ], const unsigned char buffer[ 64 ] );
|
||||
|
||||
void sha1_init( sha1_ctx *context );
|
||||
|
||||
void sha1_update( sha1_ctx *context, const unsigned char *data, uint32_t len );
|
||||
|
||||
void sha1_final( unsigned char digest[ 20 ], sha1_ctx *context );
|
||||
|
||||
void sha1( char *hash_out, const char *str, int len );
|
||||
|
||||
#define SHA1HANDSOFF
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define rol( value, bits ) ( ( ( value ) << ( bits ) ) | ( ( value ) >> ( 32 - ( bits ) ) ) )
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define blk0( i ) \
|
||||
( block->l[ i ] = ( rol( block->l[ i ], 24 ) & 0xFF00FF00 ) | ( rol( block->l[ i ], 8 ) & 0x00FF00FF ) )
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
#define blk0( i ) block->l[ i ]
|
||||
#else
|
||||
#error "Endianness not defined!"
|
||||
#endif
|
||||
#define blk( i ) \
|
||||
( block->l[ i & 15 ] = rol( block->l[ ( i + 13 ) & 15 ] ^ block->l[ ( i + 8 ) & 15 ] ^ \
|
||||
block->l[ ( i + 2 ) & 15 ] ^ block->l[ i & 15 ], \
|
||||
1 ) )
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0( v, w, x, y, z, i ) \
|
||||
z += ( ( w & ( x ^ y ) ) ^ y ) + blk0( i ) + 0x5A827999 + rol( v, 5 ); \
|
||||
w = rol( w, 30 );
|
||||
#define R1( v, w, x, y, z, i ) \
|
||||
z += ( ( w & ( x ^ y ) ) ^ y ) + blk( i ) + 0x5A827999 + rol( v, 5 ); \
|
||||
w = rol( w, 30 );
|
||||
#define R2( v, w, x, y, z, i ) \
|
||||
z += ( w ^ x ^ y ) + blk( i ) + 0x6ED9EBA1 + rol( v, 5 ); \
|
||||
w = rol( w, 30 );
|
||||
#define R3( v, w, x, y, z, i ) \
|
||||
z += ( ( ( w | x ) & y ) | ( w & x ) ) + blk( i ) + 0x8F1BBCDC + rol( v, 5 ); \
|
||||
w = rol( w, 30 );
|
||||
#define R4( v, w, x, y, z, i ) \
|
||||
z += ( w ^ x ^ y ) + blk( i ) + 0xCA62C1D6 + rol( v, 5 ); \
|
||||
w = rol( w, 30 );
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
|
||||
inline void sha1_transform( uint32_t state[ 5 ], const unsigned char buffer[ 64 ] )
|
||||
{
|
||||
uint32_t a, b, c, d, e;
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char c[ 64 ];
|
||||
uint32_t l[ 16 ];
|
||||
} CHAR64LONG16;
|
||||
|
||||
#ifdef SHA1HANDSOFF
|
||||
CHAR64LONG16 block[ 1 ]; /* use array to appear as a pointer */
|
||||
|
||||
memcpy( block, buffer, 64 );
|
||||
#else
|
||||
/* The following had better never be used because it causes the
|
||||
* pointer-to-const buffer to be cast into a pointer to non-const.
|
||||
* And the result is written through. I threw a "const" in, hoping
|
||||
* this will cause a diagnostic.
|
||||
*/
|
||||
CHAR64LONG16 *block = ( const CHAR64LONG16 * )buffer;
|
||||
#endif
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[ 0 ];
|
||||
b = state[ 1 ];
|
||||
c = state[ 2 ];
|
||||
d = state[ 3 ];
|
||||
e = state[ 4 ];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0( a, b, c, d, e, 0 );
|
||||
R0( e, a, b, c, d, 1 );
|
||||
R0( d, e, a, b, c, 2 );
|
||||
R0( c, d, e, a, b, 3 );
|
||||
R0( b, c, d, e, a, 4 );
|
||||
R0( a, b, c, d, e, 5 );
|
||||
R0( e, a, b, c, d, 6 );
|
||||
R0( d, e, a, b, c, 7 );
|
||||
R0( c, d, e, a, b, 8 );
|
||||
R0( b, c, d, e, a, 9 );
|
||||
R0( a, b, c, d, e, 10 );
|
||||
R0( e, a, b, c, d, 11 );
|
||||
R0( d, e, a, b, c, 12 );
|
||||
R0( c, d, e, a, b, 13 );
|
||||
R0( b, c, d, e, a, 14 );
|
||||
R0( a, b, c, d, e, 15 );
|
||||
R1( e, a, b, c, d, 16 );
|
||||
R1( d, e, a, b, c, 17 );
|
||||
R1( c, d, e, a, b, 18 );
|
||||
R1( b, c, d, e, a, 19 );
|
||||
R2( a, b, c, d, e, 20 );
|
||||
R2( e, a, b, c, d, 21 );
|
||||
R2( d, e, a, b, c, 22 );
|
||||
R2( c, d, e, a, b, 23 );
|
||||
R2( b, c, d, e, a, 24 );
|
||||
R2( a, b, c, d, e, 25 );
|
||||
R2( e, a, b, c, d, 26 );
|
||||
R2( d, e, a, b, c, 27 );
|
||||
R2( c, d, e, a, b, 28 );
|
||||
R2( b, c, d, e, a, 29 );
|
||||
R2( a, b, c, d, e, 30 );
|
||||
R2( e, a, b, c, d, 31 );
|
||||
R2( d, e, a, b, c, 32 );
|
||||
R2( c, d, e, a, b, 33 );
|
||||
R2( b, c, d, e, a, 34 );
|
||||
R2( a, b, c, d, e, 35 );
|
||||
R2( e, a, b, c, d, 36 );
|
||||
R2( d, e, a, b, c, 37 );
|
||||
R2( c, d, e, a, b, 38 );
|
||||
R2( b, c, d, e, a, 39 );
|
||||
R3( a, b, c, d, e, 40 );
|
||||
R3( e, a, b, c, d, 41 );
|
||||
R3( d, e, a, b, c, 42 );
|
||||
R3( c, d, e, a, b, 43 );
|
||||
R3( b, c, d, e, a, 44 );
|
||||
R3( a, b, c, d, e, 45 );
|
||||
R3( e, a, b, c, d, 46 );
|
||||
R3( d, e, a, b, c, 47 );
|
||||
R3( c, d, e, a, b, 48 );
|
||||
R3( b, c, d, e, a, 49 );
|
||||
R3( a, b, c, d, e, 50 );
|
||||
R3( e, a, b, c, d, 51 );
|
||||
R3( d, e, a, b, c, 52 );
|
||||
R3( c, d, e, a, b, 53 );
|
||||
R3( b, c, d, e, a, 54 );
|
||||
R3( a, b, c, d, e, 55 );
|
||||
R3( e, a, b, c, d, 56 );
|
||||
R3( d, e, a, b, c, 57 );
|
||||
R3( c, d, e, a, b, 58 );
|
||||
R3( b, c, d, e, a, 59 );
|
||||
R4( a, b, c, d, e, 60 );
|
||||
R4( e, a, b, c, d, 61 );
|
||||
R4( d, e, a, b, c, 62 );
|
||||
R4( c, d, e, a, b, 63 );
|
||||
R4( b, c, d, e, a, 64 );
|
||||
R4( a, b, c, d, e, 65 );
|
||||
R4( e, a, b, c, d, 66 );
|
||||
R4( d, e, a, b, c, 67 );
|
||||
R4( c, d, e, a, b, 68 );
|
||||
R4( b, c, d, e, a, 69 );
|
||||
R4( a, b, c, d, e, 70 );
|
||||
R4( e, a, b, c, d, 71 );
|
||||
R4( d, e, a, b, c, 72 );
|
||||
R4( c, d, e, a, b, 73 );
|
||||
R4( b, c, d, e, a, 74 );
|
||||
R4( a, b, c, d, e, 75 );
|
||||
R4( e, a, b, c, d, 76 );
|
||||
R4( d, e, a, b, c, 77 );
|
||||
R4( c, d, e, a, b, 78 );
|
||||
R4( b, c, d, e, a, 79 );
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[ 0 ] += a;
|
||||
state[ 1 ] += b;
|
||||
state[ 2 ] += c;
|
||||
state[ 3 ] += d;
|
||||
state[ 4 ] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
#ifdef SHA1HANDSOFF
|
||||
memset( block, '\0', sizeof( block ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
|
||||
inline void sha1_init( sha1_ctx *context )
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->state[ 0 ] = 0x67452301;
|
||||
context->state[ 1 ] = 0xEFCDAB89;
|
||||
context->state[ 2 ] = 0x98BADCFE;
|
||||
context->state[ 3 ] = 0x10325476;
|
||||
context->state[ 4 ] = 0xC3D2E1F0;
|
||||
context->count[ 0 ] = context->count[ 1 ] = 0;
|
||||
}
|
||||
|
||||
/* Run your data through this. */
|
||||
|
||||
inline void sha1_update( sha1_ctx *context, const unsigned char *data, uint32_t len )
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
uint32_t j;
|
||||
|
||||
j = context->count[ 0 ];
|
||||
if ( ( context->count[ 0 ] += len << 3 ) < j )
|
||||
context->count[ 1 ]++;
|
||||
context->count[ 1 ] += ( len >> 29 );
|
||||
j = ( j >> 3 ) & 63;
|
||||
if ( ( j + len ) > 63 )
|
||||
{
|
||||
memcpy( &context->buffer[ j ], data, ( i = 64 - j ) );
|
||||
sha1_transform( context->state, context->buffer );
|
||||
for ( ; i + 63 < len; i += 64 )
|
||||
{
|
||||
sha1_transform( context->state, &data[ i ] );
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
memcpy( &context->buffer[ j ], &data[ i ], len - i );
|
||||
}
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
|
||||
inline void sha1_final( unsigned char digest[ 20 ], sha1_ctx *context )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
unsigned char finalcount[ 8 ];
|
||||
|
||||
unsigned char c;
|
||||
|
||||
#if 0 /* untested "improvement" by DHR */
|
||||
/* Convert context->count to a sequence of bytes
|
||||
* in finalcount. Second element first, but
|
||||
* big-endian order within element.
|
||||
* But we do it all backwards.
|
||||
*/
|
||||
unsigned char* fcp = &finalcount[8];
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
uint32_t t = context->count[i];
|
||||
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; t >>= 8, j++)
|
||||
*--fcp = (unsigned char)t
|
||||
}
|
||||
#else
|
||||
for ( i = 0; i < 8; i++ )
|
||||
{
|
||||
finalcount[ i ] = ( unsigned char )( ( context->count[ ( i >= 4 ? 0 : 1 ) ] >> ( ( 3 - ( i & 3 ) ) * 8 ) ) &
|
||||
255 ); /* Endian independent */
|
||||
}
|
||||
#endif
|
||||
c = 0200;
|
||||
sha1_update( context, &c, 1 );
|
||||
while ( ( context->count[ 0 ] & 504 ) != 448 )
|
||||
{
|
||||
c = 0000;
|
||||
sha1_update( context, &c, 1 );
|
||||
}
|
||||
sha1_update( context, finalcount, 8 ); /* Should cause a SHA1Transform() */
|
||||
for ( i = 0; i < 20; i++ )
|
||||
{
|
||||
digest[ i ] = ( unsigned char )( ( context->state[ i >> 2 ] >> ( ( 3 - ( i & 3 ) ) * 8 ) ) & 255 );
|
||||
}
|
||||
/* Wipe variables */
|
||||
memset( context, '\0', sizeof( *context ) );
|
||||
memset( &finalcount, '\0', sizeof( finalcount ) );
|
||||
}
|
||||
|
||||
inline void sha1( char *hash_out, const char *str, int len )
|
||||
{
|
||||
sha1_ctx ctx;
|
||||
unsigned int ii;
|
||||
|
||||
sha1_init( &ctx );
|
||||
for ( ii = 0; ii < len; ii += 1 )
|
||||
sha1_update( &ctx, ( const unsigned char * )str + ii, 1 );
|
||||
sha1_final( ( unsigned char * )hash_out, &ctx );
|
||||
hash_out[ 20 ] = '\0';
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
#include <ntifs.h>
|
||||
|
||||
typedef struct _inline_hook_t
|
||||
{
|
||||
unsigned char code[ 14 ];
|
||||
unsigned char jmp_code[ 14 ];
|
||||
|
||||
void *address;
|
||||
void *hook_address;
|
||||
} inline_hook_t, *pinline_hook_t;
|
||||
|
||||
void make_inline_hook( pinline_hook_t, void *, void *, bool );
|
||||
void enable_inline_hook( pinline_hook_t );
|
||||
void disable_inline_hook( pinline_hook_t );
|
||||
|
||||
inline void make_inline_hook( pinline_hook_t hook, void *hook_from, void *hook_to, bool install )
|
||||
{
|
||||
unsigned char jmp_code[ 14 ] = { 0xff, 0x25, 0x0, 0x0, 0x0, 0x0, // jmp QWORD PTR[rip + 0x0]
|
||||
|
||||
// jmp address...
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
||||
|
||||
// save original bytes, and hook related addresses....
|
||||
hook->address = hook_from;
|
||||
hook->hook_address = hook_to;
|
||||
memcpy( hook->code, hook_from, sizeof hook->code );
|
||||
|
||||
// setup hook...
|
||||
memcpy( jmp_code + 6, &hook_to, sizeof hook_to );
|
||||
memcpy( hook->jmp_code, jmp_code, sizeof jmp_code );
|
||||
if ( install )
|
||||
enable_inline_hook( hook );
|
||||
}
|
||||
|
||||
inline void enable_inline_hook( pinline_hook_t hook )
|
||||
{
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 &= 0xfffffffffffeffff;
|
||||
__writecr0( cr0 );
|
||||
_disable();
|
||||
}
|
||||
|
||||
memcpy( hook->address, hook->jmp_code, sizeof hook->jmp_code );
|
||||
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 |= 0x10000;
|
||||
_enable();
|
||||
__writecr0( cr0 );
|
||||
}
|
||||
}
|
||||
|
||||
inline void disable_inline_hook( pinline_hook_t hook )
|
||||
{
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 &= 0xfffffffffffeffff;
|
||||
__writecr0( cr0 );
|
||||
_disable();
|
||||
}
|
||||
|
||||
memcpy( hook->address, hook->code, sizeof hook->code );
|
||||
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 |= 0x10000;
|
||||
_enable();
|
||||
__writecr0( cr0 );
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
//
|
||||
// note: these vm handler indexes are for EasyAntiCheat.sys 6/23/2021...
|
||||
// when the driver gets re-vmprotected these vm handler indexes need to be updated...
|
||||
//
|
||||
// EAC_VM_HANDLE_OFFSET contains the offset from the module base to the vm handler table,
|
||||
// as of right now EAC only uses a single virtual machine in their VMProtect config so there
|
||||
// is only a single vm handler table...
|
||||
//
|
||||
// EAC_SHA1_OFFSET contains the offset from the module base to the sha1 function...
|
||||
// you can locate this function by searching for SHA1 magic numbers: 0x67452301, 0xEFCDAB89
|
||||
// 0x98BADCFE, 0x10325476, 0xC3D2E1F0...
|
||||
//
|
||||
// EAC_IMAGE_BASE contains the "ImageBase" value inside of the OptionalHeaders field of the NT
|
||||
// headers... This value gets updated with the actual module base of the driver once loaded into
|
||||
// memory... I didnt want to read it off disk so I just made it a macro here...
|
||||
//
|
||||
|
||||
|
||||
#include <scn.hpp>
|
||||
#include <sha1.hpp>
|
||||
#include <shithook.hpp>
|
||||
|
||||
//
|
||||
// game cheat offset flash backs...
|
||||
//
|
||||
|
||||
#define EAC_VM_HANDLE_OFFSET 0xE93D
|
||||
#define EAC_SHA1_OFFSET 0x4C00
|
||||
#define EAC_IMAGE_BASE 0x140000000
|
||||
|
||||
#define DBG_PRINT( format, ... ) \
|
||||
DbgPrintEx( DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL, "[vmhook-eac [core number = %d]]" format, \
|
||||
KeGetCurrentProcessorNumber(), __VA_ARGS__ )
|
||||
|
||||
//
|
||||
// vm handler indexes for READQ...
|
||||
//
|
||||
|
||||
inline u8 g_readq_idxs[] = { 247, 215, 169, 159, 71, 60, 55, 43, 23 };
|
||||
|
||||
//
|
||||
// vm handler indexes for READDW
|
||||
//
|
||||
|
||||
inline u8 g_readdw_idxs[] = { 218, 180, 179, 178, 163, 137, 92, 22, 12 };
|
||||
|
||||
//
|
||||
// vm handler indexes for READB
|
||||
//
|
||||
|
||||
inline u8 g_readb_idxs[] = { 249, 231, 184, 160, 88, 85, 48, 9, 2 };
|
||||
|
||||
inline vm::hook_t *g_vmhook = nullptr;
|
||||
inline vm::handler::table_t *g_vm_table = nullptr;
|
||||
inline u64 g_image_base = 0u, g_image_size = 0u, g_image_clone = 0u;
|
||||
inline inline_hook_t g_sha1_hook;
|
@ -1,29 +0,0 @@
|
||||
#include "scn.hpp"
|
||||
|
||||
namespace scn
|
||||
{
|
||||
bool read_only(u64 image_base, u64 ptr)
|
||||
{
|
||||
auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(image_base);
|
||||
auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS64>(
|
||||
reinterpret_cast<u64>(dos_header) + dos_header->e_lfanew);
|
||||
|
||||
auto section_count = nt_header->FileHeader.NumberOfSections;
|
||||
auto sections = reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
||||
reinterpret_cast<u64>(nt_header) + sizeof(u32) + sizeof(IMAGE_FILE_HEADER) +
|
||||
nt_header->FileHeader.SizeOfOptionalHeader);
|
||||
|
||||
|
||||
// for each section try and find the section that contains this pointer...
|
||||
for (auto idx = 0u; idx < section_count; ++idx)
|
||||
// if the section contains this pointer...
|
||||
if (ptr >= sections[idx].VirtualAddress + image_base &&
|
||||
ptr < sections[idx].VirtualAddress + image_base + sections[idx].Misc.VirtualSize)
|
||||
// returns true if the section isnt discardable and isnt writeable (I.E in memory and readonly)...
|
||||
return !(sections[idx].Characteristics & IMAGE_SCN_MEM_DISCARDABLE) &&
|
||||
!(sections[idx].Characteristics & IMAGE_SCN_MEM_WRITE);
|
||||
|
||||
// pointer isnt inside of the driver...
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
#pragma once
|
||||
#include <ntifs.h>
|
||||
#include <intrin.h>
|
||||
#include <vmhook.hpp>
|
||||
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
|
||||
namespace scn
|
||||
{
|
||||
typedef struct _IMAGE_DOS_HEADER
|
||||
{
|
||||
/* 0x0000 */ unsigned short e_magic;
|
||||
/* 0x0002 */ unsigned short e_cblp;
|
||||
/* 0x0004 */ unsigned short e_cp;
|
||||
/* 0x0006 */ unsigned short e_crlc;
|
||||
/* 0x0008 */ unsigned short e_cparhdr;
|
||||
/* 0x000a */ unsigned short e_minalloc;
|
||||
/* 0x000c */ unsigned short e_maxalloc;
|
||||
/* 0x000e */ unsigned short e_ss;
|
||||
/* 0x0010 */ unsigned short e_sp;
|
||||
/* 0x0012 */ unsigned short e_csum;
|
||||
/* 0x0014 */ unsigned short e_ip;
|
||||
/* 0x0016 */ unsigned short e_cs;
|
||||
/* 0x0018 */ unsigned short e_lfarlc;
|
||||
/* 0x001a */ unsigned short e_ovno;
|
||||
/* 0x001c */ unsigned short e_res[4];
|
||||
/* 0x0024 */ unsigned short e_oemid;
|
||||
/* 0x0026 */ unsigned short e_oeminfo;
|
||||
/* 0x0028 */ unsigned short e_res2[10];
|
||||
/* 0x003c */ long e_lfanew;
|
||||
} IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER; /* size: 0x0040 */
|
||||
|
||||
typedef struct _IMAGE_FILE_HEADER
|
||||
{
|
||||
/* 0x0000 */ unsigned short Machine;
|
||||
/* 0x0002 */ unsigned short NumberOfSections;
|
||||
/* 0x0004 */ unsigned long TimeDateStamp;
|
||||
/* 0x0008 */ unsigned long PointerToSymbolTable;
|
||||
/* 0x000c */ unsigned long NumberOfSymbols;
|
||||
/* 0x0010 */ unsigned short SizeOfOptionalHeader;
|
||||
/* 0x0012 */ unsigned short Characteristics;
|
||||
} IMAGE_FILE_HEADER, * PIMAGE_FILE_HEADER; /* size: 0x0014 */
|
||||
|
||||
typedef struct _IMAGE_DATA_DIRECTORY
|
||||
{
|
||||
/* 0x0000 */ unsigned long VirtualAddress;
|
||||
/* 0x0004 */ unsigned long Size;
|
||||
} IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY; /* size: 0x0008 */
|
||||
|
||||
typedef struct _IMAGE_OPTIONAL_HEADER64
|
||||
{
|
||||
/* 0x0000 */ unsigned short Magic;
|
||||
/* 0x0002 */ unsigned char MajorLinkerVersion;
|
||||
/* 0x0003 */ unsigned char MinorLinkerVersion;
|
||||
/* 0x0004 */ unsigned long SizeOfCode;
|
||||
/* 0x0008 */ unsigned long SizeOfInitializedData;
|
||||
/* 0x000c */ unsigned long SizeOfUninitializedData;
|
||||
/* 0x0010 */ unsigned long AddressOfEntryPoint;
|
||||
/* 0x0014 */ unsigned long BaseOfCode;
|
||||
/* 0x0018 */ unsigned __int64 ImageBase;
|
||||
/* 0x0020 */ unsigned long SectionAlignment;
|
||||
/* 0x0024 */ unsigned long FileAlignment;
|
||||
/* 0x0028 */ unsigned short MajorOperatingSystemVersion;
|
||||
/* 0x002a */ unsigned short MinorOperatingSystemVersion;
|
||||
/* 0x002c */ unsigned short MajorImageVersion;
|
||||
/* 0x002e */ unsigned short MinorImageVersion;
|
||||
/* 0x0030 */ unsigned short MajorSubsystemVersion;
|
||||
/* 0x0032 */ unsigned short MinorSubsystemVersion;
|
||||
/* 0x0034 */ unsigned long Win32VersionValue;
|
||||
/* 0x0038 */ unsigned long SizeOfImage;
|
||||
/* 0x003c */ unsigned long SizeOfHeaders;
|
||||
/* 0x0040 */ unsigned long CheckSum;
|
||||
/* 0x0044 */ unsigned short Subsystem;
|
||||
/* 0x0046 */ unsigned short DllCharacteristics;
|
||||
/* 0x0048 */ unsigned __int64 SizeOfStackReserve;
|
||||
/* 0x0050 */ unsigned __int64 SizeOfStackCommit;
|
||||
/* 0x0058 */ unsigned __int64 SizeOfHeapReserve;
|
||||
/* 0x0060 */ unsigned __int64 SizeOfHeapCommit;
|
||||
/* 0x0068 */ unsigned long LoaderFlags;
|
||||
/* 0x006c */ unsigned long NumberOfRvaAndSizes;
|
||||
/* 0x0070 */ struct _IMAGE_DATA_DIRECTORY DataDirectory[16];
|
||||
} IMAGE_OPTIONAL_HEADER64, * PIMAGE_OPTIONAL_HEADER64; /* size: 0x00f0 */
|
||||
|
||||
typedef struct _IMAGE_NT_HEADERS64
|
||||
{
|
||||
/* 0x0000 */ unsigned long Signature;
|
||||
/* 0x0004 */ struct _IMAGE_FILE_HEADER FileHeader;
|
||||
/* 0x0018 */ struct _IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
||||
} IMAGE_NT_HEADERS64, * PIMAGE_NT_HEADERS64; /* size: 0x0108 */
|
||||
|
||||
typedef struct _IMAGE_SECTION_HEADER
|
||||
{
|
||||
/* 0x0000 */ unsigned char Name[8];
|
||||
union
|
||||
{
|
||||
union
|
||||
{
|
||||
/* 0x0008 */ unsigned long PhysicalAddress;
|
||||
/* 0x0008 */ unsigned long VirtualSize;
|
||||
}; /* size: 0x0004 */
|
||||
} /* size: 0x0004 */ Misc;
|
||||
/* 0x000c */ unsigned long VirtualAddress;
|
||||
/* 0x0010 */ unsigned long SizeOfRawData;
|
||||
/* 0x0014 */ unsigned long PointerToRawData;
|
||||
/* 0x0018 */ unsigned long PointerToRelocations;
|
||||
/* 0x001c */ unsigned long PointerToLinenumbers;
|
||||
/* 0x0020 */ unsigned short NumberOfRelocations;
|
||||
/* 0x0022 */ unsigned short NumberOfLinenumbers;
|
||||
/* 0x0024 */ unsigned long Characteristics;
|
||||
} IMAGE_SECTION_HEADER, * PIMAGE_SECTION_HEADER; /* size: 0x0028 */
|
||||
|
||||
/// <summary>
|
||||
/// returns true if the ptr pointers to something in a section
|
||||
/// that is read only...
|
||||
/// </summary>
|
||||
/// <param name="image_base">module base of the driver...</param>
|
||||
/// <param name="ptr">a valid pointer that lands inside of the driver...</param>
|
||||
/// <returns>returns true if the ptr pointers to something in a section that is read only</returns>
|
||||
bool read_only(u64 image_base, u64 ptr);
|
||||
}
|
@ -1,316 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
SHA-1 in C
|
||||
By Steve Reid <steve@edmweb.com>
|
||||
100% Public Domain
|
||||
*/
|
||||
|
||||
using uint32_t = unsigned int;
|
||||
|
||||
typedef struct _sha1_ctx
|
||||
{
|
||||
uint32_t state[5];
|
||||
uint32_t count[2];
|
||||
unsigned char buffer[64];
|
||||
} sha1_ctx, * psha1_ctx;
|
||||
|
||||
void sha1_transform(
|
||||
uint32_t state[5],
|
||||
const unsigned char buffer[64]
|
||||
);
|
||||
|
||||
void sha1_init(
|
||||
sha1_ctx* context
|
||||
);
|
||||
|
||||
void sha1_update(
|
||||
sha1_ctx* context,
|
||||
const unsigned char* data,
|
||||
uint32_t len
|
||||
);
|
||||
|
||||
void sha1_final(
|
||||
unsigned char digest[20],
|
||||
sha1_ctx* context
|
||||
);
|
||||
|
||||
void sha1(
|
||||
char* hash_out,
|
||||
const char* str,
|
||||
int len);
|
||||
|
||||
|
||||
#define SHA1HANDSOFF
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&0x00FF00FF))
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
#define blk0(i) block->l[i]
|
||||
#else
|
||||
#error "Endianness not defined!"
|
||||
#endif
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
|
||||
void sha1_transform(
|
||||
uint32_t state[5],
|
||||
const unsigned char buffer[64]
|
||||
)
|
||||
{
|
||||
uint32_t a, b, c, d, e;
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char c[64];
|
||||
uint32_t l[16];
|
||||
} CHAR64LONG16;
|
||||
|
||||
#ifdef SHA1HANDSOFF
|
||||
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
|
||||
|
||||
memcpy(block, buffer, 64);
|
||||
#else
|
||||
/* The following had better never be used because it causes the
|
||||
* pointer-to-const buffer to be cast into a pointer to non-const.
|
||||
* And the result is written through. I threw a "const" in, hoping
|
||||
* this will cause a diagnostic.
|
||||
*/
|
||||
CHAR64LONG16* block = (const CHAR64LONG16*)buffer;
|
||||
#endif
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a, b, c, d, e, 0);
|
||||
R0(e, a, b, c, d, 1);
|
||||
R0(d, e, a, b, c, 2);
|
||||
R0(c, d, e, a, b, 3);
|
||||
R0(b, c, d, e, a, 4);
|
||||
R0(a, b, c, d, e, 5);
|
||||
R0(e, a, b, c, d, 6);
|
||||
R0(d, e, a, b, c, 7);
|
||||
R0(c, d, e, a, b, 8);
|
||||
R0(b, c, d, e, a, 9);
|
||||
R0(a, b, c, d, e, 10);
|
||||
R0(e, a, b, c, d, 11);
|
||||
R0(d, e, a, b, c, 12);
|
||||
R0(c, d, e, a, b, 13);
|
||||
R0(b, c, d, e, a, 14);
|
||||
R0(a, b, c, d, e, 15);
|
||||
R1(e, a, b, c, d, 16);
|
||||
R1(d, e, a, b, c, 17);
|
||||
R1(c, d, e, a, b, 18);
|
||||
R1(b, c, d, e, a, 19);
|
||||
R2(a, b, c, d, e, 20);
|
||||
R2(e, a, b, c, d, 21);
|
||||
R2(d, e, a, b, c, 22);
|
||||
R2(c, d, e, a, b, 23);
|
||||
R2(b, c, d, e, a, 24);
|
||||
R2(a, b, c, d, e, 25);
|
||||
R2(e, a, b, c, d, 26);
|
||||
R2(d, e, a, b, c, 27);
|
||||
R2(c, d, e, a, b, 28);
|
||||
R2(b, c, d, e, a, 29);
|
||||
R2(a, b, c, d, e, 30);
|
||||
R2(e, a, b, c, d, 31);
|
||||
R2(d, e, a, b, c, 32);
|
||||
R2(c, d, e, a, b, 33);
|
||||
R2(b, c, d, e, a, 34);
|
||||
R2(a, b, c, d, e, 35);
|
||||
R2(e, a, b, c, d, 36);
|
||||
R2(d, e, a, b, c, 37);
|
||||
R2(c, d, e, a, b, 38);
|
||||
R2(b, c, d, e, a, 39);
|
||||
R3(a, b, c, d, e, 40);
|
||||
R3(e, a, b, c, d, 41);
|
||||
R3(d, e, a, b, c, 42);
|
||||
R3(c, d, e, a, b, 43);
|
||||
R3(b, c, d, e, a, 44);
|
||||
R3(a, b, c, d, e, 45);
|
||||
R3(e, a, b, c, d, 46);
|
||||
R3(d, e, a, b, c, 47);
|
||||
R3(c, d, e, a, b, 48);
|
||||
R3(b, c, d, e, a, 49);
|
||||
R3(a, b, c, d, e, 50);
|
||||
R3(e, a, b, c, d, 51);
|
||||
R3(d, e, a, b, c, 52);
|
||||
R3(c, d, e, a, b, 53);
|
||||
R3(b, c, d, e, a, 54);
|
||||
R3(a, b, c, d, e, 55);
|
||||
R3(e, a, b, c, d, 56);
|
||||
R3(d, e, a, b, c, 57);
|
||||
R3(c, d, e, a, b, 58);
|
||||
R3(b, c, d, e, a, 59);
|
||||
R4(a, b, c, d, e, 60);
|
||||
R4(e, a, b, c, d, 61);
|
||||
R4(d, e, a, b, c, 62);
|
||||
R4(c, d, e, a, b, 63);
|
||||
R4(b, c, d, e, a, 64);
|
||||
R4(a, b, c, d, e, 65);
|
||||
R4(e, a, b, c, d, 66);
|
||||
R4(d, e, a, b, c, 67);
|
||||
R4(c, d, e, a, b, 68);
|
||||
R4(b, c, d, e, a, 69);
|
||||
R4(a, b, c, d, e, 70);
|
||||
R4(e, a, b, c, d, 71);
|
||||
R4(d, e, a, b, c, 72);
|
||||
R4(c, d, e, a, b, 73);
|
||||
R4(b, c, d, e, a, 74);
|
||||
R4(a, b, c, d, e, 75);
|
||||
R4(e, a, b, c, d, 76);
|
||||
R4(d, e, a, b, c, 77);
|
||||
R4(c, d, e, a, b, 78);
|
||||
R4(b, c, d, e, a, 79);
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
#ifdef SHA1HANDSOFF
|
||||
memset(block, '\0', sizeof(block));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
|
||||
void sha1_init(
|
||||
sha1_ctx* context
|
||||
)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Run your data through this. */
|
||||
|
||||
void sha1_update(
|
||||
sha1_ctx* context,
|
||||
const unsigned char* data,
|
||||
uint32_t len
|
||||
)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
uint32_t j;
|
||||
|
||||
j = context->count[0];
|
||||
if ((context->count[0] += len << 3) < j)
|
||||
context->count[1]++;
|
||||
context->count[1] += (len >> 29);
|
||||
j = (j >> 3) & 63;
|
||||
if ((j + len) > 63)
|
||||
{
|
||||
memcpy(&context->buffer[j], data, (i = 64 - j));
|
||||
sha1_transform(context->state, context->buffer);
|
||||
for (; i + 63 < len; i += 64)
|
||||
{
|
||||
sha1_transform(context->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
|
||||
void sha1_final(
|
||||
unsigned char digest[20],
|
||||
sha1_ctx* context
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
unsigned char finalcount[8];
|
||||
|
||||
unsigned char c;
|
||||
|
||||
#if 0 /* untested "improvement" by DHR */
|
||||
/* Convert context->count to a sequence of bytes
|
||||
* in finalcount. Second element first, but
|
||||
* big-endian order within element.
|
||||
* But we do it all backwards.
|
||||
*/
|
||||
unsigned char* fcp = &finalcount[8];
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
uint32_t t = context->count[i];
|
||||
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; t >>= 8, j++)
|
||||
*--fcp = (unsigned char)t
|
||||
}
|
||||
#else
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
|
||||
}
|
||||
#endif
|
||||
c = 0200;
|
||||
sha1_update(context, &c, 1);
|
||||
while ((context->count[0] & 504) != 448)
|
||||
{
|
||||
c = 0000;
|
||||
sha1_update(context, &c, 1);
|
||||
}
|
||||
sha1_update(context, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++)
|
||||
{
|
||||
digest[i] = (unsigned char)
|
||||
((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||
}
|
||||
/* Wipe variables */
|
||||
memset(context, '\0', sizeof(*context));
|
||||
memset(&finalcount, '\0', sizeof(finalcount));
|
||||
}
|
||||
|
||||
void sha1(
|
||||
char* hash_out,
|
||||
const char* str,
|
||||
int len)
|
||||
{
|
||||
sha1_ctx ctx;
|
||||
unsigned int ii;
|
||||
|
||||
sha1_init(&ctx);
|
||||
for (ii = 0; ii < len; ii += 1)
|
||||
sha1_update(&ctx, (const unsigned char*)str + ii, 1);
|
||||
sha1_final((unsigned char*)hash_out, &ctx);
|
||||
hash_out[20] = '\0';
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
#include <ntifs.h>
|
||||
|
||||
typedef struct _inline_hook_t
|
||||
{
|
||||
unsigned char code[14];
|
||||
unsigned char jmp_code[14];
|
||||
|
||||
void* address;
|
||||
void* hook_address;
|
||||
} inline_hook_t, * pinline_hook_t;
|
||||
|
||||
void make_inline_hook(pinline_hook_t, void*, void*, bool);
|
||||
void enable_inline_hook(pinline_hook_t);
|
||||
void disable_inline_hook(pinline_hook_t);
|
||||
|
||||
inline void make_inline_hook(pinline_hook_t hook, void* hook_from, void* hook_to, bool install)
|
||||
{
|
||||
unsigned char jmp_code[14] =
|
||||
{
|
||||
0xff, 0x25, 0x0, 0x0, 0x0, 0x0, // jmp QWORD PTR[rip + 0x0]
|
||||
|
||||
// jmp address...
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0
|
||||
};
|
||||
|
||||
// save original bytes, and hook related addresses....
|
||||
hook->address = hook_from;
|
||||
hook->hook_address = hook_to;
|
||||
memcpy(hook->code, hook_from, sizeof hook->code);
|
||||
|
||||
// setup hook...
|
||||
memcpy(jmp_code + 6, &hook_to, sizeof hook_to);
|
||||
memcpy(hook->jmp_code, jmp_code, sizeof jmp_code);
|
||||
if (install) enable_inline_hook(hook);
|
||||
}
|
||||
|
||||
inline void enable_inline_hook(pinline_hook_t hook)
|
||||
{
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 &= 0xfffffffffffeffff;
|
||||
__writecr0(cr0);
|
||||
_disable();
|
||||
}
|
||||
|
||||
memcpy(hook->address, hook->jmp_code, sizeof hook->jmp_code);
|
||||
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 |= 0x10000;
|
||||
_enable();
|
||||
__writecr0(cr0);
|
||||
}
|
||||
}
|
||||
|
||||
inline void disable_inline_hook(pinline_hook_t hook)
|
||||
{
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 &= 0xfffffffffffeffff;
|
||||
__writecr0(cr0);
|
||||
_disable();
|
||||
}
|
||||
|
||||
memcpy(hook->address, hook->code, sizeof hook->code);
|
||||
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 |= 0x10000;
|
||||
_enable();
|
||||
__writecr0(cr0);
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
#include <vmhook-eac.hpp>
|
||||
|
||||
void *operator new( u64 size )
|
||||
{
|
||||
//
|
||||
// Could have also used ExAllocatePoolZero...
|
||||
//
|
||||
|
||||
return RtlZeroMemory( ExAllocatePool( NonPagedPool, size ), size );
|
||||
}
|
||||
|
||||
void operator delete( void *ptr, u64 size )
|
||||
{
|
||||
UNREFERENCED_PARAMETER( size );
|
||||
ExFreePool( ptr );
|
||||
}
|
||||
|
||||
__declspec( noinline ) void hook_sha1( void *data, unsigned int len, void *result )
|
||||
{
|
||||
sha1_ctx ctx;
|
||||
sha1_init( &ctx );
|
||||
|
||||
//
|
||||
// if EAC is trying to sha1 hash any data in readonly sections...
|
||||
// then we hash the clone of the driver before it was patched...
|
||||
//
|
||||
// note: relocations are the same in the clone so those wont need to be handled...
|
||||
//
|
||||
|
||||
if ( scn::read_only( g_image_base, ( u64 )data ) )
|
||||
{
|
||||
DBG_PRINT( "sha1 hash data = 0x%p, len = 0x%x, result = 0x%p\n", data, len, result );
|
||||
sha1_update( &ctx, ( unsigned char * )g_image_clone + ( ( ( u64 )data ) - g_image_base ), len );
|
||||
sha1_final( ( unsigned char * )result, &ctx );
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// else simply sha1 hash the data and return back to EasyAntiCheat.sys....
|
||||
//
|
||||
|
||||
sha1_update( &ctx, ( unsigned char * )data, len );
|
||||
sha1_final( ( unsigned char * )result, &ctx );
|
||||
}
|
||||
|
||||
void image_loaded( PUNICODE_STRING image_name, HANDLE pid, PIMAGE_INFO image_info )
|
||||
{
|
||||
if ( !pid && wcsstr( image_name->Buffer, L"EasyAntiCheat.sys" ) )
|
||||
{
|
||||
if ( g_vmhook && g_vm_table && g_image_clone )
|
||||
delete g_vmhook, delete g_vm_table, ExFreePool( ( void * )g_image_clone );
|
||||
|
||||
// > 0x00007FF77A233736 mov rcx, [r12+rax*8]
|
||||
// > 0x00007FF77A23373D ror rcx, 0x30 <--- decrypt vm handler entry...
|
||||
// > 0x00007FF77A233747 add rcx, r13
|
||||
// > 0x00007FF77A23374A jmp rcx
|
||||
vm::decrypt_handler_t _decrypt_handler = []( u64 val ) -> u64 { return _rotr64( val, 0x30 ); };
|
||||
|
||||
// > 0x00007FF77A233736 mov rcx, [r12+rax*8]
|
||||
// > 0x00007FF77A23373D ror rcx, 0x30 <--- inverse to encrypt vm handler entry...
|
||||
// > 0x00007FF77A233747 add rcx, r13
|
||||
// > 0x00007FF77A23374A jmp rcx
|
||||
vm::encrypt_handler_t _encrypt_handler = []( u64 val ) -> u64 { return _rotl64( val, 0x30 ); };
|
||||
|
||||
vm::handler::edit_entry_t _edit_entry = []( u64 *entry_ptr, u64 val ) -> void {
|
||||
//
|
||||
// disable write protect bit in cr0...
|
||||
//
|
||||
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 &= 0xfffffffffffeffff;
|
||||
__writecr0( cr0 );
|
||||
_disable();
|
||||
}
|
||||
|
||||
*entry_ptr = val;
|
||||
|
||||
//
|
||||
// enable write protect bit in cr0...
|
||||
//
|
||||
|
||||
{
|
||||
auto cr0 = __readcr0();
|
||||
cr0 |= 0x10000;
|
||||
_enable();
|
||||
__writecr0( cr0 );
|
||||
}
|
||||
};
|
||||
|
||||
auto image_base = reinterpret_cast< u64 >( image_info->ImageBase );
|
||||
auto handler_table_ptr = reinterpret_cast< u64 * >( image_base + EAC_VM_HANDLE_OFFSET );
|
||||
|
||||
//
|
||||
// Clone the entire driver into a kernel pool, keep in mind relocations will also be
|
||||
// the same as the original driver! Dont call any code in this clone, only refer to it...
|
||||
//
|
||||
|
||||
g_image_clone = ( u64 )RtlCopyMemory( ExAllocatePool( NonPagedPool, image_info->ImageSize ),
|
||||
image_info->ImageBase, image_info->ImageSize );
|
||||
|
||||
//
|
||||
// allocate memory for a g_vmhook, and g_vm_table...
|
||||
//
|
||||
|
||||
g_vm_table = new vm::handler::table_t( handler_table_ptr, _edit_entry );
|
||||
g_vmhook = new vm::hook_t( image_base, EAC_IMAGE_BASE, _decrypt_handler, _encrypt_handler, g_vm_table );
|
||||
g_image_base = image_base, g_image_size = image_info->ImageSize;
|
||||
|
||||
const auto callback = []( vm::registers *regs, u8 handler_idx ) {
|
||||
const auto read_addr = reinterpret_cast< u64 * >( regs->rbp )[ 0 ];
|
||||
|
||||
// shoot the tires right off the virtualized integrity checks in about 2 lines of code...
|
||||
if ( scn::read_only( g_image_base, read_addr ) )
|
||||
{
|
||||
DBG_PRINT( " READ(Q/DW/B) EasyAntiCheat.sys+0x%x\n", ( read_addr - g_image_base ) );
|
||||
reinterpret_cast< u64 * >( regs->rbp )[ 0 ] = g_image_clone + ( read_addr - g_image_base );
|
||||
}
|
||||
};
|
||||
|
||||
// install hooks on READQ virtual machine handlers...
|
||||
for ( auto idx = 0u; idx < sizeof g_readq_idxs; ++idx )
|
||||
g_vm_table->set_callback( g_readq_idxs[ idx ], callback );
|
||||
|
||||
// install hooks on READDW virtual machine handlers...
|
||||
for ( auto idx = 0u; idx < sizeof g_readdw_idxs; ++idx )
|
||||
g_vm_table->set_callback( g_readdw_idxs[ idx ], callback );
|
||||
|
||||
// install hooks on READB virtual machine handlers...
|
||||
for ( auto idx = 0u; idx < sizeof g_readb_idxs; ++idx )
|
||||
g_vm_table->set_callback( g_readb_idxs[ idx ], callback );
|
||||
|
||||
//
|
||||
// hooks all vm handlers and starts callbacks...
|
||||
//
|
||||
g_vmhook->start();
|
||||
|
||||
// hook on sha1 since it executes outside of the virtual machine...
|
||||
// and does an integrity check on .text and .eac0...
|
||||
make_inline_hook( &g_sha1_hook, ( void * )( image_base + EAC_SHA1_OFFSET ), &hook_sha1, true );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// this entry point is called by ZwSwapCert...
|
||||
//
|
||||
|
||||
extern "C" NTSTATUS drv_entry( PDRIVER_OBJECT drv_object, PUNICODE_STRING reg_path )
|
||||
{
|
||||
UNREFERENCED_PARAMETER( drv_object );
|
||||
UNREFERENCED_PARAMETER( reg_path );
|
||||
|
||||
//
|
||||
// This kernel driver cannot be unloaded so there is no unload routine...
|
||||
// This is because ZwSwapCert will cause the system to crash...
|
||||
//
|
||||
|
||||
DBG_PRINT( "> registering on image load callbacks...\n" );
|
||||
return PsSetLoadImageNotifyRoutine( &image_loaded );
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#include <scn.hpp>
|
||||
|
||||
namespace scn
|
||||
{
|
||||
bool read_only( u64 image_base, u64 ptr )
|
||||
{
|
||||
auto dos_header = reinterpret_cast< PIMAGE_DOS_HEADER >( image_base );
|
||||
auto nt_header =
|
||||
reinterpret_cast< PIMAGE_NT_HEADERS64 >( reinterpret_cast< u64 >( dos_header ) + dos_header->e_lfanew );
|
||||
|
||||
auto section_count = nt_header->FileHeader.NumberOfSections;
|
||||
auto sections = reinterpret_cast< PIMAGE_SECTION_HEADER >( reinterpret_cast< u64 >( nt_header ) +
|
||||
sizeof( u32 ) + sizeof( IMAGE_FILE_HEADER ) +
|
||||
nt_header->FileHeader.SizeOfOptionalHeader );
|
||||
|
||||
// for each section try and find the section that contains this pointer...
|
||||
for ( auto idx = 0u; idx < section_count; ++idx )
|
||||
// if the section contains this pointer...
|
||||
if ( ptr >= sections[ idx ].VirtualAddress + image_base &&
|
||||
ptr < sections[ idx ].VirtualAddress + image_base + sections[ idx ].Misc.VirtualSize )
|
||||
// returns true if the section isnt discardable and isnt writeable (I.E in memory and readonly)...
|
||||
return !( sections[ idx ].Characteristics & IMAGE_SCN_MEM_DISCARDABLE ) &&
|
||||
!( sections[ idx ].Characteristics & IMAGE_SCN_MEM_WRITE );
|
||||
|
||||
// pointer isnt inside of the driver...
|
||||
return false;
|
||||
}
|
||||
} // namespace scn
|
Before Width: | Height: | Size: 513 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
Reference in new issue