No, no non lo è ed è piuttosto complesso da prevenire.
In genere, Sandbox associa le API interne e esegue il codice a un livello più basso nell'anello 3. Parliamo dell'API dei file per cominciare. Se conosci i linguaggi di programmazione di livello inferiore come C, C ++ e così via, conoscerai l'API ReadFile
. Quindi, esaminiamo ReadFile in un disassemblaggio.
ReadFile si trova come in EAT (Export Address table) in Kernel32.
KERNEL32.ReadFile - FF 25 8803D674 - jmp dword ptr [KERNEL32.PssWalkSnapshot+9588] { ->KERNELBASE.ReadFile }
Quindi, passa a KernelBase.dll su un ReadFile. Non preoccuparti di non comprendere tutti gli opcode ma solo di essere interessati ai CALL.
KERNELBASE.ReadFile - 8B FF - mov edi,edi
KERNELBASE.ReadFile+2- 55 - push ebp
KERNELBASE.ReadFile+3- 8B EC - mov ebp,esp
KERNELBASE.ReadFile+5- 6A FE - push -02 { 254 }
KERNELBASE.ReadFile+7- 68 A806D576 - push KERNELBASE.ReadFile+B8 { [FFFFFFFE] }
KERNELBASE.ReadFile+C- 68 5098D576 - push KERNELBASE.OutputDebugStringA+C0 { [8B55FF8B] }
KERNELBASE.ReadFile+11- 64 A1 00000000 - mov eax,fs:[00000000] { 0 }
KERNELBASE.ReadFile+17- 50 - push eax
KERNELBASE.ReadFile+18- 83 EC 18 - sub esp,18 { 24 }
KERNELBASE.ReadFile+1B- 53 - push ebx
KERNELBASE.ReadFile+1C- 56 - push esi
KERNELBASE.ReadFile+1D- 57 - push edi
KERNELBASE.ReadFile+1E- A1 683BE076 - mov eax,[KERNELBASE.dll+C3B68] { [1EB677D9] }
KERNELBASE.ReadFile+23- 31 45 F8 - xor [ebp-08],eax
KERNELBASE.ReadFile+26- 33 C5 - xor eax,ebp
KERNELBASE.ReadFile+28- 50 - push eax
KERNELBASE.ReadFile+29- 8D 45 F0 - lea eax,[ebp-10]
KERNELBASE.ReadFile+2C- 64 A3 00000000 - mov fs:[00000000],eax { 0 }
KERNELBASE.ReadFile+32- 89 65 E8 - mov [ebp-18],esp
KERNELBASE.ReadFile+35- C7 45 E0 00000000 - mov [ebp-20],00000000 { 0 }
KERNELBASE.ReadFile+3C- C7 45 E4 00000000 - mov [ebp-1C],00000000 { 0 }
KERNELBASE.ReadFile+43- 8B 75 14 - mov esi,[ebp+14]
KERNELBASE.ReadFile+46- 85 F6 - test esi,esi
KERNELBASE.ReadFile+48- 74 06 - je KERNELBASE.ReadFile+50
KERNELBASE.ReadFile+4A- C7 06 00000000 - mov [esi],00000000 { 0 }
KERNELBASE.ReadFile+50- 8B 5D 08 - mov ebx,[ebp+08]
KERNELBASE.ReadFile+53- 83 FB F4 - cmp ebx,-0C { 244 }
KERNELBASE.ReadFile+56- 0F83 60D30400 - jae KERNELBASE.InterlockedExchangeAdd+528C
KERNELBASE.ReadFile+5C- 8B 7D 18 - mov edi,[ebp+18]
KERNELBASE.ReadFile+5F- 85 FF - test edi,edi
KERNELBASE.ReadFile+61- 75 71 - jne KERNELBASE.ReadFile+D4
KERNELBASE.ReadFile+63- 57 - push edi
KERNELBASE.ReadFile+64- 57 - push edi
KERNELBASE.ReadFile+65- FF 75 10 - push [ebp+10]
KERNELBASE.ReadFile+68- FF 75 0C - push [ebp+0C]
KERNELBASE.ReadFile+6B- 8D 45 E0 - lea eax,[ebp-20]
KERNELBASE.ReadFile+6E- 50 - push eax
KERNELBASE.ReadFile+6F- 57 - push edi
KERNELBASE.ReadFile+70- 57 - push edi
KERNELBASE.ReadFile+71- 57 - push edi
KERNELBASE.ReadFile+72- 53 - push ebx
KERNELBASE.ReadFile+73- FF 15 5C66E076 - call dword ptr [KERNELBASE.dll+C665C] { ->ntdll.NtReadFile }
KERNELBASE.ReadFile+79- 8B C8 - mov ecx,eax
KERNELBASE.ReadFile+7B- 81 F9 03010000 - cmp ecx,00000103 { 259 }
KERNELBASE.ReadFile+81- 0F84 B9D30400 - je KERNELBASE.InterlockedExchangeAdd+5310
KERNELBASE.ReadFile+87- 85 C9 - test ecx,ecx
KERNELBASE.ReadFile+89- 0F88 380A0000 - js KERNELBASE.GetModuleHandleExW+277
KERNELBASE.ReadFile+8F- 85 F6 - test esi,esi
KERNELBASE.ReadFile+91- 74 05 - je KERNELBASE.ReadFile+98
KERNELBASE.ReadFile+93- 8B 45 E4 - mov eax,[ebp-1C]
KERNELBASE.ReadFile+96- 89 06 - mov [esi],eax
KERNELBASE.ReadFile+98- B8 01000000 - mov eax,00000001 { 1 }
KERNELBASE.ReadFile+9D- 8B 4D F0 - mov ecx,[ebp-10]
KERNELBASE.ReadFile+A0- 64 89 0D 00000000 - mov fs:[00000000],ecx { 0 }
KERNELBASE.ReadFile+A7- 59 - pop ecx
KERNELBASE.ReadFile+A8- 5F - pop edi
KERNELBASE.ReadFile+A9- 5E - pop esi
KERNELBASE.ReadFile+AA- 5B - pop ebx
KERNELBASE.ReadFile+AB- 8B E5 - mov esp,ebp
KERNELBASE.ReadFile+AD- 5D - pop ebp
KERNELBASE.ReadFile+AE- C2 1400 - ret 0014 { 20 }
Quindi, l'API di livello successivo che è più in basso è NtReadFile che si trova in ntdll.dll.
ntdll.NtReadFile - B8 05001A00 - mov eax,001A0005 { [0] }
ntdll.ZwReadFile+5- 64 FF 15 C0000000 - call fs:[000000C0]
ntdll.ZwReadFile+C- C2 2400 - ret 0024 { 36 }
ntdll.ZwReadFile+F- 90 - nop
Questo è un tipo speciale di chiamata di syscall che va quindi a SSDT (System Descriptor Table) che ha le API di basso livello che si trovano nell'anello 0 che non è accessibile direttamente tramite l'anello 3 diverso da syscall che sono esposte.
Quindi, le sandbox possono utilizzare una gamma di metodi di aggancio ma i più comuni sono:
- Deviazioni di memoria (JMP, PUSH RET e così via)
- Agganciare tabelle IAT
- VEH (Improbabile, dal momento che ha un strong impatto sulle prestazioni)
Quindi, solo per sapere cosa sta succedendo vorremmo agganciare il NtReadFile
che salverebbe al nostro codice e avremo il controllo completo su ciò che viene eseguito. Ad esempio, supponiamo che filtrerai qualsiasi file chiamato SteveEnix. Nella nostra funzione trampolino (dove NtReadFile è stato agganciato e saltato) possiamo leggere i parametri e decidere se chiamarlo o meno. Quindi, assomiglierà a questo:
NTSYSAPI NTSTATUS NTAPI t_NtReadFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN PLARGE_INTEGER ByteOffset OPTIONAL,
IN PULONG Key OPTIONAL )
{
// Your check on buffer to filter files or whatever you want and return an error or call the original function
}
Se l'applicazione interna ha accesso all'utilizzo di VirtualProtect
API o l'area di memoria viene letta e scritta, questi hook possono essere facilmente rimossi.
Tuttavia, se si abbassa un livello ancora più profondo per l'SSDT che su x64 ha PatchGuard per prevenire questi hook, quindi in genere le sandbox non toccano SSDT, allora è necessario caricare un driver nel sistema per poterlo sbloccare. SSDT o patch con il proprio gancio.