No, no lo es y es bastante complejo de evitar.
En general, los Sandbox enganchan las API internas y ejecutan el código en el nivel más bajo en el anillo 3. Hablemos de la API de archivos, para empezar. Si está familiarizado con los lenguajes de programación de nivel inferior como C, C ++, etc., sabrá acerca de ReadFile
API. Por lo tanto, echemos un vistazo a ReadFile en un desmontaje.
ReadFile está situado como en la EAT (tabla de direcciones de exportación) en Kernel32.
KERNEL32.ReadFile - FF 25 8803D674 - jmp dword ptr [KERNEL32.PssWalkSnapshot+9588] { ->KERNELBASE.ReadFile }
Entonces, salta a KernelBase.dll a un ReadFile. No se preocupe por no entender todos los códigos de operación, solo esté interesado en las LLAMADAS.
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 }
Por lo tanto, la siguiente API de nivel que está más abajo es NtReadFile que se encuentra en 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
Este es un tipo especial de llamada llamada syscall que luego va a la SSDT (Tabla de Descriptores de Servicio del Sistema) que tiene las API de bajo nivel que se encuentran en el anillo 0, a las que no se puede acceder directamente a través del anillo 3 que no están a la vista.
Por lo tanto, las cajas de arena pueden usar una variedad de métodos de conexión, pero los más comunes son:
- Desvíos de memoria (JMP, PUSH RET, etc.)
- Enganchar tablas IAT
- VEH (improbable, ya que tiene un gran impacto en el rendimiento)
Entonces, solo para saber lo que sucede es que enganchamos el NtReadFile
que saltaría a nuestro código y tenemos control completo sobre lo que se ejecuta. Por ejemplo, digamos que va a filtrar cualquier archivo llamado SteveEnix. En nuestra función de trampolín (donde se ha enganchado y saltado el NtReadFile) podemos leer los parámetros y decidir llamarlos o no. Por lo tanto, se verá así:
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
}
Si la aplicación interna tiene acceso al uso de VirtualProtect
API o si la región de la memoria se lee y escribe, estos enlaces pueden eliminarse fácilmente.
Sin embargo, si baja un nivel aún más profundo al SSDT, que en x64 tiene PatchGuard para evitar estos ganchos, por lo que generalmente los entornos limitados no tocan el SSDT, entonces necesitará un controlador para cargar en el sistema para poder desemparejar el SSDT o parchelo con su propio gancho.