Анти-отладочные и антиреверсивные методы внутри windows исполняемого файла - PullRequest
0 голосов
/ 05 апреля 2020

Я пытаюсь реализовать некоторые анти-отладочные / анти-реверсивные технические процедуры, чтобы предотвратить отладку / обращение моего (python) исполняемого файла, но когда я пытаюсь запустить его из x32dbg или python -m pdb они не работают, позволяя x32gdb / pdb получить доступ к моему коду и выполнить исполняемый файл / скрипт. Методы, которые я использую, написаны на с ++; Я импортирую код c ++ в мой python код через DLL, сгенерированную через Visual Studio 2019, и все работает нормально, что означает, что я могу вызывать функции в моей dll из исполняемого файла / python без каких-либо ошибок / исключений.

Я нашел методы в Интернете, я их не написал, но также не работает самая простая техника (функция isDebuggerPresent () из библиотеки debugapi.h windows), и это только вызов функции. Вот методы, которые я реализовал в моей dll

int isThereADebugger()
{
    if (IsDebuggerPresent())
    {
        cout << "Stop debugging program!" << endl;
        exit(-1);
    }
    return 0;
}


// Current PEB for 64bit and 32bit processes accordingly
PVOID GetPEB()
{
#ifdef _WIN64
    return (PVOID)__readgsqword(0x0C * sizeof(PVOID));
#else
    return (PVOID)__readfsdword(0x0C * sizeof(PVOID));
#endif
}

// Get PEB for WOW64 Process
PVOID GetPEB64()
{
    PVOID pPeb = 0;
#ifndef _WIN64

    BOOL isWow64 = FALSE;
    typedef BOOL(WINAPI* pfnIsWow64Process)(HANDLE hProcess, PBOOL isWow64);
    pfnIsWow64Process fnIsWow64Process = (pfnIsWow64Process)
        GetProcAddress(GetModuleHandleA("Kernel32.dll"), "IsWow64Process");
    if (fnIsWow64Process(GetCurrentProcess(), &isWow64))
    {
        if (isWow64)
        {
            pPeb = (PVOID)__readfsdword(0x0C * sizeof(PVOID));
            pPeb = (PVOID)((PBYTE)pPeb + 0x1000);
        }
    }

#endif
    return pPeb;
}

#define FLG_HEAP_ENABLE_TAIL_CHECK   0x10
#define FLG_HEAP_ENABLE_FREE_CHECK   0x20
#define FLG_HEAP_VALIDATE_PARAMETERS 0x40
#define NT_GLOBAL_FLAG_DEBUGGED (FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS)
void CheckNtGlobalFlag()
{
    PVOID pPeb = GetPEB();
    PVOID pPeb64 = GetPEB64();
    DWORD offsetNtGlobalFlag = 0;
#ifdef _WIN64
    offsetNtGlobalFlag = 0xBC;
#else
    offsetNtGlobalFlag = 0x68;
#endif
    DWORD NtGlobalFlag = *(PDWORD)((PBYTE)pPeb + offsetNtGlobalFlag);
    if (NtGlobalFlag & NT_GLOBAL_FLAG_DEBUGGED)
    {
        std::cout << "Stop debugging program!" << std::endl;
        exit(-1);
    }
    if (pPeb64)
    {
        DWORD NtGlobalFlagWow64 = *(PDWORD)((PBYTE)pPeb64 + 0xBC);
        if (NtGlobalFlagWow64 & NT_GLOBAL_FLAG_DEBUGGED)
        {
            std::cout << "Stop debugging program!" << std::endl;
            exit(-1);
        }
    }
}

PIMAGE_NT_HEADERS GetImageNtHeaders(PBYTE pImageBase)
{
    PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pImageBase;
    return (PIMAGE_NT_HEADERS)(pImageBase + pImageDosHeader->e_lfanew);
}

PIMAGE_SECTION_HEADER FindRDataSection(PBYTE pImageBase)
{
    static const std::string rdata = ".rdata";
    PIMAGE_NT_HEADERS pImageNtHeaders = GetImageNtHeaders(pImageBase);
    PIMAGE_SECTION_HEADER pImageSectionHeader = IMAGE_FIRST_SECTION(pImageNtHeaders);
    int n = 0;
    for (; n < pImageNtHeaders->FileHeader.NumberOfSections; ++n)
    {
        if (rdata == (char*)pImageSectionHeader[n].Name)
        {
            break;
        }
    }
    return &pImageSectionHeader[n];
}
void CheckGlobalFlagsClearInProcess()
{
    PBYTE pImageBase = (PBYTE)GetModuleHandle(NULL);
    PIMAGE_NT_HEADERS pImageNtHeaders = GetImageNtHeaders(pImageBase);
    PIMAGE_LOAD_CONFIG_DIRECTORY pImageLoadConfigDirectory = (PIMAGE_LOAD_CONFIG_DIRECTORY)(pImageBase
        + pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress);
    if (pImageLoadConfigDirectory->GlobalFlagsClear != 0)
    {
        std::cout << "Stop debugging program!" << std::endl;
        exit(-1);
    }
}
void CheckGlobalFlagsClearInFile()
{
    HANDLE hExecutable = INVALID_HANDLE_VALUE;
    HANDLE hExecutableMapping = NULL;
    PBYTE pMappedImageBase = NULL;
    __try
    {
        PBYTE pImageBase = (PBYTE)GetModuleHandle(NULL);
        PIMAGE_SECTION_HEADER pImageSectionHeader = FindRDataSection(pImageBase);
        TCHAR pszExecutablePath[MAX_PATH];
        DWORD dwPathLength = GetModuleFileName(NULL, pszExecutablePath, MAX_PATH);
        if (0 == dwPathLength) __leave;
        hExecutable = CreateFile(pszExecutablePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
        if (INVALID_HANDLE_VALUE == hExecutable) __leave;
        hExecutableMapping = CreateFileMapping(hExecutable, NULL, PAGE_READONLY, 0, 0, NULL);
        if (NULL == hExecutableMapping) __leave;
        pMappedImageBase = (PBYTE)MapViewOfFile(hExecutableMapping, FILE_MAP_READ, 0, 0,
            pImageSectionHeader->PointerToRawData + pImageSectionHeader->SizeOfRawData);
        if (NULL == pMappedImageBase) __leave;
        PIMAGE_NT_HEADERS pImageNtHeaders = GetImageNtHeaders(pMappedImageBase);
        PIMAGE_LOAD_CONFIG_DIRECTORY pImageLoadConfigDirectory = (PIMAGE_LOAD_CONFIG_DIRECTORY)(pMappedImageBase
            + (pImageSectionHeader->PointerToRawData
                + (pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress - pImageSectionHeader->VirtualAddress)));
        if (pImageLoadConfigDirectory->GlobalFlagsClear != 0)
        {
            std::cout << "Stop debugging program!" << std::endl;
            exit(-1);
        }
    }
    __finally
    {
        if (NULL != pMappedImageBase)
            UnmapViewOfFile(pMappedImageBase);
        if (NULL != hExecutableMapping)
            CloseHandle(hExecutableMapping);
        if (INVALID_HANDLE_VALUE != hExecutable)
            CloseHandle(hExecutable);
    }
}


int GetHeapFlagsOffset(bool x64)
{
    return x64 ?
        TRUE ? 0x70 : 0x14 : //x64 offsets
        TRUE ? 0x40 : 0x0C; //x86 offsets
}
int GetHeapForceFlagsOffset(bool x64)
{
    return x64 ?
        TRUE ? 0x74 : 0x18 : //x64 offsets
        TRUE ? 0x44 : 0x10; //x86 offsets
}
void CheckHeap()
{
    PVOID pPeb = GetPEB();
    PVOID pPeb64 = GetPEB64();
    PVOID heap = 0;
    DWORD offsetProcessHeap = 0;
    PDWORD heapFlagsPtr = 0, heapForceFlagsPtr = 0;
    BOOL x64 = FALSE;
#ifdef _WIN64
    x64 = TRUE;
    offsetProcessHeap = 0x30;
#else
    offsetProcessHeap = 0x18;
#endif
    heap = (PVOID) * (PDWORD_PTR)((PBYTE)pPeb + offsetProcessHeap);
    heapFlagsPtr = (PDWORD)((PBYTE)heap + GetHeapFlagsOffset(x64));
    heapForceFlagsPtr = (PDWORD)((PBYTE)heap + GetHeapForceFlagsOffset(x64));
    if (*heapFlagsPtr & ~HEAP_GROWABLE || *heapForceFlagsPtr != 0)
    {
        std::cout << "Stop debugging program!" << std::endl;
        exit(-1);
    }
    if (pPeb64)
    {
        heap = (PVOID) * (PDWORD_PTR)((PBYTE)pPeb64 + 0x30);
        heapFlagsPtr = (PDWORD)((PBYTE)heap + GetHeapFlagsOffset(true));
        heapForceFlagsPtr = (PDWORD)((PBYTE)heap + GetHeapForceFlagsOffset(true));
        if (*heapFlagsPtr & ~HEAP_GROWABLE || *heapForceFlagsPtr != 0)
        {
            std::cout << "Stop debugging program!" << std::endl;
            exit(-1);
        }
    }
}

void trapCheckFlag() {
    BOOL isDebugged = TRUE;
    __try
    {
        __asm
        {
            pushfd
            or dword ptr[esp], 0x100 // set the Trap Flag 
            popfd                    // Load the value into EFLAGS register
            nop
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        // If an exception has been raised – debugger is not present
        isDebugged = FALSE;
    }
    if (isDebugged)
    {
        std::cout << "Stop debugging program!" << std::endl;
        exit(-1);
    }
}

int isRemoteDebuggerPresent() {
    BOOL isDebuggerPresent = FALSE;
    if (CheckRemoteDebuggerPresent(GetCurrentProcess(), &isDebuggerPresent))
    {
        if (isDebuggerPresent)
        {
            std::cout << "Stop debugging program!" << std::endl;
            exit(-1);
        }
    }
    return 0;
}

typedef NTSTATUS(NTAPI* pfnNtQueryInformationProcess)(
    _In_      HANDLE           ProcessHandle,
    _In_      UINT             ProcessInformationClass,
    _Out_     PVOID            ProcessInformation,
    _In_      ULONG            ProcessInformationLength,
    _Out_opt_ PULONG           ReturnLength
    );
//const UINT ProcessDebugPort = 7;

int ntQueryInfoProc()
{
    pfnNtQueryInformationProcess NtQueryInformationProcess = NULL;
    NTSTATUS status;
    DWORD isDebuggerPresent = 0;
    HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));

    if (NULL != hNtDll)
    {
        NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");
        if (NULL != NtQueryInformationProcess)
        {
            status = NtQueryInformationProcess(
                GetCurrentProcess(),
                7,
                &isDebuggerPresent,
                sizeof(DWORD),
                NULL);
            if (status == 0x00000000 && isDebuggerPresent != 0)
            {
                std::cout << "Stop debugging program!" << std::endl;
                exit(-1);
            }
        }
    }
    return 0;
}

typedef NTSTATUS(NTAPI* pfnNtSetInformationThread)(
    _In_ HANDLE ThreadHandle,
    _In_ ULONG  ThreadInformationClass,
    _In_ PVOID  ThreadInformation,
    _In_ ULONG  ThreadInformationLength
    );
const ULONG ThreadHideFromDebugger = 0x11;

void HideFromDebugger()
{
    HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));
    pfnNtSetInformationThread NtSetInformationThread = (pfnNtSetInformationThread)
        GetProcAddress(hNtDll, "NtSetInformationThread");
    NTSTATUS status = NtSetInformationThread(GetCurrentThread(),
        ThreadHideFromDebugger, NULL, 0);
}


EXCEPTION_DISPOSITION ExceptionRoutine(
    PEXCEPTION_RECORD ExceptionRecord,
    PVOID             EstablisherFrame,
    PCONTEXT          ContextRecord,
    PVOID             DispatcherContext)
{
    if (EXCEPTION_INVALID_HANDLE == ExceptionRecord->ExceptionCode)
    {
        std::cout << "Stop debugging program!" << std::endl;
        exit(-1);
    }
    return ExceptionContinueExecution;
}

int handleTracing() {
    __asm
    {
        // set SEH handler
        push ExceptionRoutine
        push dword ptr fs : [0]
        mov  dword ptr fs : [0] , esp
    }
    CloseHandle((HANDLE)0xBAAD);
    __asm
    {
        // return original SEH handler
        mov  eax, [esp]
        mov  dword ptr fs : [0] , eax
        add  esp, 8
    }
    return 0;
}


#define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A
void dbgMessages() {
    WCHAR* outputString = (WCHAR*)L"Any text";
    ULONG_PTR args[4] = { 0 };
    args[0] = (ULONG_PTR)wcslen(outputString) + 1;
    args[1] = (ULONG_PTR)outputString;
    __try
    {
        RaiseException(DBG_PRINTEXCEPTION_WIDE_C, 0, 4, args);
        printf("Debugger detected");
        exit(-1);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("Debugger NOT detected");
    }
}


void DoSmth()
{
    Sleep(1000);
}

int timeApproach() {
    const int g_doSmthExecutionTime = 1050;

    SYSTEMTIME sysTimeStart;
    SYSTEMTIME sysTimeEnd;
    FILETIME timeStart, timeEnd;

    GetSystemTime(&sysTimeStart);
    DoSmth();
    GetSystemTime(&sysTimeEnd);
    SystemTimeToFileTime(&sysTimeStart, &timeStart);
    SystemTimeToFileTime(&sysTimeEnd, &timeEnd);
    double timeExecution = (timeEnd.dwLowDateTime - timeStart.dwLowDateTime) / 10000.0;
    if (timeExecution < g_doSmthExecutionTime)
    {
        std::cout << "Debugger not present";
    }
    else
    {
        std::cout << "Debugger present";
    }
    return 0;
}

В моем скрипте python я вызываю эти функции последовательно в точке входа, как

if __name__ == "__main__":
    antiDebugger = ctypes.CDLL('C:\\absolute\\path\\to\\antiDebugger.dll')
    antiDebugger.isThereADebugger()
    antiDebugger.CheckNtGlobalFlag()
    antiDebugger.CheckGlobalFlagsClearInProcess()
    antiDebugger.CheckGlobalFlagsClearInFile()
    antiDebugger.CheckHeap()
    antiDebugger.trapCheckFlag()
    antiDebugger.isRemoteDebuggerPresent()
    antiDebugger.ntQueryInfoProc()
    antiDebugger.timeApproach()
    antiDebugger.handleTracing()
    antiDebugger.HideFromDebugger()
    antiDebugger.dbgMessages()
    customFunction()

На самом деле, я также пытался поместите их в начало каждой функции в моем скрипте python, но это также не сработало.

Я генерирую исполняемый файл с pyarmor в сочетании с pyinstaller, используя опцию --onefile Моя версия windows x64 windows 10 Pro, в то время как моя python версия 3.8.2

Я знаю, что все эти методы могут быть слишком много, но я просто хочу, чтобы они работали, чтобы попытаться сломать их, конкретно исполняемая сторона. Может кто-нибудь сказать мне, как заставить эти методы работать?

...