• XSS.stack #1 – первый литературный журнал от юзеров форума

Sandbox Detector by CPU ratios

Бафомет

⁶⁶⁶
Premium
Регистрация
23.07.2023
Сообщения
179
Реакции
468
Гарант сделки
20
Депозит
0.1192
This code only supports x86.

Compiled with i686-w64-mingw32-gcc sandbox.c -s -O3
  • Wine on i7-1165G7 (all cores enabled): 0.26
  • Wine on i7-1165G7 (all cores except 1 parked): 0.24
  • Native Windows 10 on Pentium Gold 4425Y: 4.19
  • Native Windows 10 on Intel i5-5200U: 0.35
  • Windows 7 on KVM (1 core): 9.07
  • Windows 7 on KVM (8 cores): 9.89
  • Triage Windows 7: 6.59
  • any.run Windows 7: 48.79
  • Triage Windows 10 1703: 6.09
  • Triage Windows 10 2004: 7.23
  • VirusTotal Microsoft Sysinternals: 30.91
  • VirusTotal Jujubox: 157.27
  • VirusTotal Zenbox: 6.13
Benchmark of 5 is perfect to avoid all of them.

C:
#include <windows.h>
#include <stdio.h>
#include <math.h>
#define THRESHOLD 5.0
#define ITERATIONS 1000000
int notdone, c;
DWORD WINAPI fp(void* data) {
    while(notdone){
        for(int i=0;i<10;i++) asm(".byte 0xd9\n\t.byte 0xf9"); //FYL2XP1
        c++;
    }
    return 0;
}

int main(){
    notdone=1;
    c=0;
    HANDLE thread = CreateThread(NULL, 0, fp, NULL, 0, NULL);
    for(int i=0;i<ITERATIONS;i++) asm("push %eax\n\tpush %ebx\n\tpush %ecx\n\tpush %edx\n\txor %eax, %eax\n\t.byte 0x0f\n\t.byte 0xa2\n\tpop %edx\n\tpop %ecx\n\tpop %ebx\n\tpop %eax"); //CPUID
    notdone=0;
    WaitForSingleObject(thread, INFINITE);
    c*=10;
    double ration = ((double)c)/((double)ITERATIONS);
    printf("c=%d, ratio=%f\n", c, ration);
    if(ration > THRESHOLD) printf("SANDBOX DETECTED!!!\n");
    double fscore = ((tanh(ration-THRESHOLD)+1)/2)*100;
    printf("%f%% confident sandbox\n", fscore);
    return 0;
}
 
wait, you mean 32 bit?

Sorry, x86 arch which means 32-bit processors. You are right as well. I might not explained it well.

So yes, the assembly instructions use 32 bits registers.

I found this code very interesting because it have a lot of options to consider different types of sandboxes, finding that a benchmark of 5 will bypass those scanners while providing full utility for real enviroments such ESXi and similar. The results has been tested and they have been confirmed on that case, providing a good benchmark starting point.
 
Isn't adding x64 support as trivial as remapping it to the appropriate registers e->r? Very interesting techinque.

C:
#include <windows.h>
#include <stdio.h>
#include <math.h>

#define THRESHOLD 5.0
#define ITERATIONS 1000000

volatile int notdone;
volatile int c;

DWORD WINAPI fp(void* data) {
    while (notdone) {
        for (int i = 0; i < 10; i++) {
            asm volatile(".byte 0xd9, 0xf9"); // FYL2XP1 instruction
        }
        c++;
    }
    return 0;
}

int main() {
    notdone = 1;
    c = 0;
    HANDLE thread = CreateThread(NULL, 0, fp, NULL, 0, NULL);

    for (int i = 0; i < ITERATIONS; i++) {
#ifdef __x86_64__
        asm volatile(
            "xor %%rax, %%rax\n\t"
            "cpuid\n\t"
            :
            :
            : "rax", "rbx", "rcx", "rdx"
        );
#else
        asm volatile(
            "xor %%eax, %%eax\n\t"
            "cpuid\n\t"
            :
            :
            : "eax", "ebx", "ecx", "edx"
        );
#endif
    }

    notdone = 0;
    WaitForSingleObject(thread, INFINITE);

    c *= 10;
    double ratio = ((double)c) / ((double)ITERATIONS);
    printf("c=%d, ratio=%f\n", c, ratio);

    if (ratio > THRESHOLD)
        printf("SANDBOX DETECTED!!!\n");

    double fscore = ((tanh(ratio - THRESHOLD) + 1) / 2) * 100;
    printf("%f%% confident sandbox\n", fscore);

    return 0;
}
 
Isn't adding x64 support as trivial as remapping it to the appropriate registers e->r? Very interesting techinque.

C:
#include <windows.h>
#include <stdio.h>
#include <math.h>

#define THRESHOLD 5.0
#define ITERATIONS 1000000

volatile int notdone;
volatile int c;

DWORD WINAPI fp(void* data) {
    while (notdone) {
        for (int i = 0; i < 10; i++) {
            asm volatile(".byte 0xd9, 0xf9"); // FYL2XP1 instruction
        }
        c++;
    }
    return 0;
}

int main() {
    notdone = 1;
    c = 0;
    HANDLE thread = CreateThread(NULL, 0, fp, NULL, 0, NULL);

    for (int i = 0; i < ITERATIONS; i++) {
#ifdef __x86_64__
        asm volatile(
            "xor %%rax, %%rax\n\t"
            "cpuid\n\t"
            :
            :
            : "rax", "rbx", "rcx", "rdx"
        );
#else
        asm volatile(
            "xor %%eax, %%eax\n\t"
            "cpuid\n\t"
            :
            :
            : "eax", "ebx", "ecx", "edx"
        );
#endif
    }

    notdone = 0;
    WaitForSingleObject(thread, INFINITE);

    c *= 10;
    double ratio = ((double)c) / ((double)ITERATIONS);
    printf("c=%d, ratio=%f\n", c, ratio);

    if (ratio > THRESHOLD)
        printf("SANDBOX DETECTED!!!\n");

    double fscore = ((tanh(ratio - THRESHOLD) + 1) / 2) * 100;
    printf("%f%% confident sandbox\n", fscore);

    return 0;
}

Exactly, adding x64 support to the provided x32 code is indeed mostly about remapping registers. The idea can be easily implemented :).

Personally I found this concept the best one to avoid this demonic sandboxes :P.

Glad you find it intereting, mathematically its one of the best approachments that I know.
 
Последнее редактирование:
Isn't adding x64 support as trivial as remapping it to the appropriate registers e->r? Very interesting techinque.

C:
#include <windows.h>
#include <stdio.h>
#include <math.h>

#define THRESHOLD 5.0
#define ITERATIONS 1000000

volatile int notdone;
volatile int c;

DWORD WINAPI fp(void* data) {
    while (notdone) {
        for (int i = 0; i < 10; i++) {
            asm volatile(".byte 0xd9, 0xf9"); // FYL2XP1 instruction
        }
        c++;
    }
    return 0;
}

int main() {
    notdone = 1;
    c = 0;
    HANDLE thread = CreateThread(NULL, 0, fp, NULL, 0, NULL);

    for (int i = 0; i < ITERATIONS; i++) {
#ifdef __x86_64__
        asm volatile(
            "xor %%rax, %%rax\n\t"
            "cpuid\n\t"
            :
            :
            : "rax", "rbx", "rcx", "rdx"
        );
#else
        asm volatile(
            "xor %%eax, %%eax\n\t"
            "cpuid\n\t"
            :
            :
            : "eax", "ebx", "ecx", "edx"
        );
#endif
    }

    notdone = 0;
    WaitForSingleObject(thread, INFINITE);

    c *= 10;
    double ratio = ((double)c) / ((double)ITERATIONS);
    printf("c=%d, ratio=%f\n", c, ratio);

    if (ratio > THRESHOLD)
        printf("SANDBOX DETECTED!!!\n");

    double fscore = ((tanh(ratio - THRESHOLD) + 1) / 2) * 100;
    printf("%f%% confident sandbox\n", fscore);

    return 0;
}
But there's a little more to be thankful for: the default x87 control word masks exceptions, so a random/garbage input to fyl2xp1 will just set a status bit and keep going. So there's not an explicit need for fninit.)
And yes, on MinGW64 or clang‐clang it’s “remap e* to r*” but on VS 64bit you have to do intrinsics (or link external .asm code).
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх