Üye
Giriş
1) x86
DLL'imizi process global exception table eklememiz gereken fonksiyonun exportlanmaması işimizi zorlaştırıyor. Neyse ki ntdll.dll PDB file erişimimiz var, bunu RtlInsertInvertedFunctionTable offseti için ayrıştırmamız gerekiyor eğer Windows 7 kullanıyorsanız LdrpInvertedFunctionTable'a da ihtiyacınız olacaktır.
Şimdi bu sembollerin offsetlerini aldıktan sonra, işe başlayabiliriz.
Bu fonksiyon hakkında bilmeniz gereken ilk şey, fastcall kullanarak function call işlemini gerçekleştirmemiz gerektiğidir. Bu ilk 2 parametrenin sırasıyla ecx ve edx'e taşınması gerektiği anlamına gelir.
Windows 7'e fonksiyon buna benziyor
Windows 8 ve üzerinde
Bu fonksiyonu çağırmak çok kolaydır
Windows 7
Windows 8 ve üzeri
x86 SEH Manual Map Örneği
2) x64
Burada Microsoft işimizi zorlaştırmıyor ve bize exportlanan RtlAddFunctionTable fonksiyonunu veriyor. Bu fonksiyonu MSDN'de bulabilirsiniz.
Bu fonksiyon şu şekildedir
Buradaki function table parametresi DLL'in PE headerlarında bulunan exception table'ın sanal adresini ifade eder.
Manual Maplenen Driverlarda SEH Kullanımı
Son olarak compilerda üretilen SEH fonksiyonuna basit bir tersine mühendislik işlemi uygulayarak bulduklarım
1) x86
DLL'imizi process global exception table eklememiz gereken fonksiyonun exportlanmaması işimizi zorlaştırıyor. Neyse ki ntdll.dll PDB file erişimimiz var, bunu RtlInsertInvertedFunctionTable offseti için ayrıştırmamız gerekiyor eğer Windows 7 kullanıyorsanız LdrpInvertedFunctionTable'a da ihtiyacınız olacaktır.
Şimdi bu sembollerin offsetlerini aldıktan sonra, işe başlayabiliriz.
Bu fonksiyon hakkında bilmeniz gereken ilk şey, fastcall kullanarak function call işlemini gerçekleştirmemiz gerektiğidir. Bu ilk 2 parametrenin sırasıyla ecx ve edx'e taşınması gerektiği anlamına gelir.
Windows 7'e fonksiyon buna benziyor
C++:
VOID
RtlInsertInvertedFunctionTable (PINVERTED_FUNCTION_TABLE InvertedTable, PVOID ImageBase, ULONG SizeOfImage)
Windows 8 ve üzerinde
C++:
VOID
RtlInsertInvertedFunctionTable (PVOID ImageBase, ULONG SizeOfImage)
Now
Bu fonksiyonu çağırmak çok kolaydır
Windows 7
C++:
RtlInsertInvertedFunctionTable(ldrpInvertedFunctionTableAddress, dllBaseAddress, dllSize)
Windows 8 ve üzeri
C++:
RtlInsertInvertedFunctionTable(dllBaseAddress, dllSize)
x86 SEH Manual Map Örneği
C++:
#include <Windows.h>
#if !defined(_X86_)
#error Only x86
#endif
struct EH4_SCOPETABLE_RECORD
{
int EnclosingLevel;
void *FilterFunc;
void *HandlerFunc;
};
struct EH4_SCOPETABLE
{
int GSCookieOffset;
int GSCookieXOROffset;
int EHCookieOffset;
int EHCookieXOROffset;
struct EH4_SCOPETABLE_RECORD ScopeRecord[];
};
struct EH4_EXCEPTION_REGISTRATION_RECORD
{
void *SavedESP;
EXCEPTION_POINTERS *ExceptionPointers;
EXCEPTION_REGISTRATION_RECORD SubRecord;
EH4_SCOPETABLE* EncodedScopeTable;
unsigned int TryLevel;
};
extern "C" LPVOID __ImageBase;
extern "C" ULONG_PTR __security_cookie;
DWORD GetSizeOfImage( void );
void* g_ImageStartAddr = nullptr;
void* g_ImageEndAddr = nullptr;
LONG NTAPI ExceptionHandler(_EXCEPTION_POINTERS *ExceptionInfo)
{
PVOID ExceptionAddress = ExceptionInfo->ExceptionRecord->ExceptionAddress;
if ( ExceptionAddress < g_ImageStartAddr || ExceptionAddress > g_ImageEndAddr )
return EXCEPTION_CONTINUE_SEARCH;
DWORD RegisterESP = ExceptionInfo->ContextRecord->Esp;
EXCEPTION_REGISTRATION_RECORD* pFs = (EXCEPTION_REGISTRATION_RECORD*) __readfsdword( 0 );
if ( (DWORD_PTR)pFs > (RegisterESP-0x10000) && (DWORD_PTR)pFs < (RegisterESP+0x10000) )
{
EXCEPTION_ROUTINE* ExceptionHandlerRoutine = pFs->Handler;
if ( ExceptionHandlerRoutine > g_ImageStartAddr && ExceptionHandlerRoutine < g_ImageEndAddr )
{
EXCEPTION_DISPOSITION ExceptionDisposition = ExceptionHandlerRoutine( ExceptionInfo->ExceptionRecord, pFs, ExceptionInfo->ContextRecord, nullptr );
if ( ExceptionDisposition == ExceptionContinueExecution )
return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
DWORD __stdcall MainThread( LPVOID lpvReserved )
{
UNREFERENCED_PARAMETER( lpvReserved );
g_ImageStartAddr = &__ImageBase;
g_ImageEndAddr = (char*)g_ImageStartAddr + GetSizeOfImage();
AddVectoredExceptionHandler( 1, ExceptionHandler );
__try{
*(DWORD*)0x123 = 0x1337;
}__except(EXCEPTION_EXECUTE_HANDLER){
MessageBoxA( 0, "__except","__except",0);
};
return TRUE;
}
DWORD APIENTRY DllMain (HMODULE hModule, DWORD dwReason, LPVOID lpvReserved )
{
if (dwReason == DLL_PROCESS_ATTACH)
CreateThread( NULL, NULL, MainThread, lpvReserved, NULL, NULL );
return TRUE;
}
DWORD GetSizeOfImage( void )
{
IMAGE_DOS_HEADER* ImageDosHeader = (IMAGE_DOS_HEADER*)&__ImageBase;
if ( !ImageDosHeader || ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
return NULL;
IMAGE_NT_HEADERS* ImageNtHeaders = (PIMAGE_NT_HEADERS)( (char*)ImageDosHeader + ImageDosHeader->e_lfanew );
if ( ImageNtHeaders->Signature != IMAGE_NT_SIGNATURE )
return NULL;
return ImageNtHeaders->OptionalHeader.SizeOfImage;
}
#pragma region _EHStructs
struct SCOPETABLE_ENTRY
{
unsigned int enclosing_level;
unsigned int filter;
unsigned int specific_handler;
};
struct EXCEPTION_REGISTRATION_COMMON
{
BYTE gap0[8];
unsigned int scopetable;
unsigned int trylevel;
};
struct EH3_EXCEPTION_REGISTRATION
{
struct EH3_EXCEPTION_REGISTRATION *Next;
EXCEPTION_ROUTINE* ExceptionHandler;
SCOPETABLE_ENTRY* ScopeTable;
DWORD TryLevel;
};
struct CPPEH_RECORD
{
DWORD old_esp;
EXCEPTION_POINTERS *exc_ptr;
EH3_EXCEPTION_REGISTRATION registration;
};
struct EXCEPTION_REGISTRATION
{
unsigned int prev;
unsigned int handler;
};
#pragma endregion EHStructs
2) x64
Burada Microsoft işimizi zorlaştırmıyor ve bize exportlanan RtlAddFunctionTable fonksiyonunu veriyor. Bu fonksiyonu MSDN'de bulabilirsiniz.
Bu fonksiyon şu şekildedir
C++:
BOOLEAN RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable, DWORD EntryCount, DWORD64 BaseAddress);
Buradaki function table parametresi DLL'in PE headerlarında bulunan exception table'ın sanal adresini ifade eder.
Manual Maplenen Driverlarda SEH Kullanımı
C:
#pragma once
#include <ntimage.h>
#include <ntifs.h>
#include <intrin.h>
#define UNW_FLAG_EHANDLER 1
typedef struct _RUNTIME_FUNCTION
{
ULONG BeginAddress;
ULONG EndAddress;
ULONG UnwindData;
} RUNTIME_FUNCTION, * PRUNTIME_FUNCTION;
typedef struct _C_SCOPE_TABLE_ENTRY
{
ULONG Begin;
ULONG End;
ULONG Handler;
ULONG Target;
} C_SCOPE_TABLE_ENTRY, * PC_SCOPE_TABLE_ENTRY;
typedef struct _C_SCOPE_TABLE
{
ULONG NumEntries;
C_SCOPE_TABLE_ENTRY Table[ 1 ];
} C_SCOPE_TABLE, * PC_SCOPE_TABLE;
extern "C" NTSYSAPI PEXCEPTION_ROUTINE RtlVirtualUnwind(
LONG HandlerType,
DWORD64 ImageBase,
DWORD64 ControlPc,
PRUNTIME_FUNCTION FunctionEntry,
PCONTEXT ContextRecord,
PVOID * HandlerData,
PDWORD64 EstablisherFrame,
PVOID ContextPointers
);
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace SEH
{
static RUNTIME_FUNCTION* LookupPrivateFunctionEntry( ULONG64 Rip )
{
IMAGE_NT_HEADERS* NtHdrs = ( IMAGE_NT_HEADERS* ) ( PUCHAR( &__ImageBase ) + __ImageBase.e_lfanew );
IMAGE_DATA_DIRECTORY& ExceptionDirectory = NtHdrs->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXCEPTION ];
RUNTIME_FUNCTION* FunctionTableIt = ( RUNTIME_FUNCTION* ) ( PUCHAR( &__ImageBase ) + ExceptionDirectory.VirtualAddress );
RUNTIME_FUNCTION* FunctionTableEnd = ( RUNTIME_FUNCTION* ) ( PUCHAR( &__ImageBase ) + ExceptionDirectory.VirtualAddress + ExceptionDirectory.Size );
Rip -= ( ULONG64 ) &__ImageBase;
while ( FunctionTableIt < FunctionTableEnd )
{
if ( FunctionTableIt->BeginAddress <= Rip && Rip < FunctionTableIt->EndAddress )
return FunctionTableIt;
else
FunctionTableIt++;
}
return nullptr;
}
static LONG HandleException( CONTEXT* ContextRecord, EXCEPTION_RECORD* ExceptionRecord )
{
if ( RUNTIME_FUNCTION* RtFn = SEH::LookupPrivateFunctionEntry( ContextRecord->Rip ) )
{
ULONG ExceptionRva = ContextRecord->Rip - ( ULONG64 ) &__ImageBase;
CONTEXT ContextRecordVt = *ContextRecord;
PVOID HandlerData = nullptr;
ULONG64 EstablisherFrame = 0;
EXCEPTION_ROUTINE* Routine = RtlVirtualUnwind(
UNW_FLAG_EHANDLER,
( ULONG64 ) &__ImageBase,
ContextRecord->Rip,
RtFn,
&ContextRecordVt,
&HandlerData,
&EstablisherFrame,
nullptr
);
if ( Routine )
{
C_SCOPE_TABLE* ScopeTable = ( C_SCOPE_TABLE* ) HandlerData;
for ( int i = 0; i < ScopeTable->NumEntries; i++ )
{
if ( ScopeTable->Table[ i ].Begin <= ExceptionRva && ExceptionRva < ScopeTable->Table[ i ].End )
{
if ( ScopeTable->Table[ i ].Handler == 1 )
{
ContextRecordVt.Rsp -= 0x8;
*( ULONG64* ) ContextRecordVt.Rsp = ContextRecordVt.Rip;
ContextRecordVt.Rsp -= 0x28;
ContextRecordVt.Rip = ( ULONG64 ) &__ImageBase + ScopeTable->Table[ i ].Target;
ContextRecordVt.Rax = ExceptionRecord->ExceptionCode;
*ContextRecord = ContextRecordVt;
return EXCEPTION_CONTINUE_EXECUTION;
}
else
{
__debugbreak();
}
}
}
}
}
return EXCEPTION_EXECUTE_HANDLER;
}
};
C++:
Initializer( SEH::HandleException, TRUE );
Son olarak compilerda üretilen SEH fonksiyonuna basit bir tersine mühendislik işlemi uygulayarak bulduklarım
C++:
#define EH_EXCEPTION_NUMBER ('msc' | 0xE0000000)
EXCEPTION_DISPOSITION __cdecl _except_handler4(_EXCEPTION_RECORD *ExceptionRecord, EXCEPTION_REGISTRATION_RECORD *EstablisherFrame, _CONTEXT *ContextRecord, PVOID DispatcherContext)
{
EH4_EXCEPTION_REGISTRATION_RECORD* EH4 = CONTAINING_RECORD( EstablisherFrame, EH4_EXCEPTION_REGISTRATION_RECORD, SubRecord );
void* EH4_END = EH4+1;
EH4_SCOPETABLE* ScopeTable = (EH4_SCOPETABLE *)(__security_cookie ^ (DWORD)EH4->EncodedScopeTable);
/////////////////////////////////////////////////////////////////////////////////////////////////
if ( ScopeTable->GSCookieOffset != -2 )
__security_check_cookie( *(DWORD*)(ScopeTable->GSCookieXOROffset + (DWORD)EH4_END)
/*XOR*/ ^ *(DWORD*)(ScopeTable->GSCookieOffset + (DWORD)EH4_END) );
__security_check_cookie( *(DWORD*)(ScopeTable->EHCookieXOROffset + (DWORD)EH4_END)
/*XOR*/ ^ *(DWORD*)(ScopeTable->EHCookieOffset + (DWORD)EH4_END) );
/////////////////////////////////////////////////////////////////////////////////////////////////
EXCEPTION_DISPOSITION HandlerResult = ExceptionContinueSearch;
if ( ExceptionRecord->ExceptionFlags & 0x66 )
{
if ( EH4->TryLevel == -2 )
return ExceptionContinueSearch;
_EH4_LocalUnwind((DWORD)EstablisherFrame, -2, (DWORD)EH4_END, (DWORD)&__security_cookie);
}
else
{
EXCEPTION_POINTERS ExceptionPointers = {};
ExceptionPointers.ExceptionRecord = ExceptionRecord;
ExceptionPointers.ContextRecord = ContextRecord;
EH4->ExceptionPointers = &ExceptionPointers;
bool v13 = false;
DWORD LastTryLevel = EH4->TryLevel;
if ( LastTryLevel == -2 )
return ExceptionContinueSearch;
do
{
void* FilterFunc = ScopeTable->ScopeRecord[LastTryLevel].FilterFunc;
int EnclosingLevel = ScopeTable->ScopeRecord[LastTryLevel].EnclosingLevel;
EH4_SCOPETABLE_RECORD* pScopeRecord = &ScopeTable->ScopeRecord[LastTryLevel];
if ( FilterFunc )
{
int FilterResult = _EH4_CallFilterFunc(FilterFunc, EH4_END);
v13 = true;
if ( FilterResult < 0 )
{
HandlerResult = ExceptionContinueExecution;
goto LABEL_23;
}
if ( FilterResult > 0 )
{
if ( ExceptionRecord->ExceptionCode == EH_EXCEPTION_NUMBER
&& _pDestructExceptionObject
&& _IsNonwritableInCurrentImage((char *)&_pDestructExceptionObject) )
{
_pDestructExceptionObject(ExceptionRecord, 1);
}
_EH4_GlobalUnwind2(EstablisherFrame, ExceptionRecord);
if ( EH4->TryLevel != LastTryLevel )
{
_EH4_LocalUnwind(EH4_END, &__security_cookie);
}
EH4->TryLevel = EnclosingLevel;
/////////////////////////////////////////////////////////////////////////////////////////////////
//Stack integrity checks:
if ( ScopeTable->GSCookieOffset != -2 )
__security_check_cookie( *(DWORD*)(ScopeTable->GSCookieXOROffset + (DWORD)EH4_END)
/*XOR*/ ^ *(DWORD*)(ScopeTable->GSCookieOffset + (DWORD)EH4_END) );
__security_check_cookie( *(DWORD*)(ScopeTable->EHCookieXOROffset + (DWORD)EH4_END)
/*XOR*/ ^ *(DWORD*)(ScopeTable->EHCookieOffset + (DWORD)EH4_END) );
/////////////////////////////////////////////////////////////////////////////////////////////////
_EH4_TransferToHandler(pScopeRecord->HandlerFunc, EH4_END);
__debugbreak();
_crt_debugger_hook();
}
}
else
{
v13 = true;
}
LastTryLevel = EnclosingLevel;
}
while ( LastTryLevel != -2 );
if ( !v13 )
return HandlerResult;
}
LABEL_23:
/////////////////////////////////////////////////////////////////////////////////////////////////
if ( ScopeTable->GSCookieOffset != -2 )
__security_check_cookie( *(DWORD*)(ScopeTable->GSCookieXOROffset + (DWORD)EH4_END)
^ *(DWORD*)(ScopeTable->GSCookieOffset + (DWORD)EH4_END) );
__security_check_cookie( *(DWORD*)(ScopeTable->EHCookieXOROffset + (DWORD)EH4_END)
/*XOR*/ ^ *(DWORD*)(ScopeTable->EHCookieOffset + (DWORD)EH4_END) );
/////////////////////////////////////////////////////////////////////////////////////////////////
return HandlerResult;
}
Son düzenleme: