VEH Handling (Danilo?)

Windows specific forum
Mike Yurgalavage
Enthusiast
Enthusiast
Posts: 118
Joined: Thu May 17, 2007 8:35 pm
Location: USA

VEH Handling (Danilo?)

Post by Mike Yurgalavage »

I see that Danilo posted this code here:

http://www.forums.purebasic.com/english ... 12&t=49903

I see precious little about VEH and purebasic examples.

I need to take this a bit further. I have software that thousands of users use. Sometimes there are problems on their systems (some users) that are hard to track down, since I am not on their computer. It would be great to make a debugging program that can be used to get feedback from the users.

Specifically it would be a program that works as a debugger for ANOTHER program.

here are some core ideas for this program.

1) allows creation of VEH breakpoints of a running executable FROM the 'debugger' program.
2) allow dump of all registers (including xmm0 and floating point)
3) possible reroute if EIP/RIP register to a different address (i.e. debugger may reroute the flow of the program to codecave or .dll which has verified values for testing).
4) would have to be 'smart' to know which exceptions were user created and which are part of the normal program...

imagine the situation:
1) user runs our software
2) they claim the software crashes when they do so and so. info from crash tells us to try veh at certain location in program memory
3) we can give them offset from the program base (i.e. 0x400000 is base we would tell them to create exception at 0x401950)
4) they use an interface to enter 401950 breakpoint and the program stops there due to VEH, and then the program dumps a list of all the registers at that breakpointed spot.
5) possibly the debugger can then set EIP at that time to a different address which will move program flow to a code cave or .dll that has possible fix to try and get past crash.

I am very good at accessing other process, etc. and programming in general on purebasic. I have almost NO experience in breakpoints, exceptions, or VEH.

is something like this possible? rather than setting up VEH, displaying registers, and changing registers on the purebasic program itself, can this be easily done on another process FROM the purebasic program?

any help with this would be most appreciated. I really don't need a full blown program, just something that will help me to learn how to do this.

I can create a program that has an error on purpose to use for testing.

what the test program would have would be:
1) opens window
2) user presses button
3) division by 0 on purpose to crash program
4) exit button

then we can locate the address that has the bad divison and using VEH

1) breakpoint there
2) change register holding the 0 from 0 to 1
3) have program flow continue to get past

remember there would be a test program with the error, and then the 'debug' program which accesses the test program, sets up the VEH, changes the register, and then automatically resumes program flow.

do you think any of you can help with this? I am having trouble with the API and concepts involved here..
Mike Yurgalavage
Enthusiast
Enthusiast
Posts: 118
Joined: Thu May 17, 2007 8:35 pm
Location: USA

Re: VEH Handling (Danilo?)

Post by Mike Yurgalavage »

Here is a code snippet in C where a .dll sets this up when it is injected to break at $401000..
So you HAVE to do this via .dll injection? there is no way to set up things via a single 'debug' program that writes to the running process?

Code: Select all

#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
 
const DWORD func_addr = 0x00401000;
const DWORD func_addr_offset = func_addr + 0x1;
 
void print_parameters(PCONTEXT debug_context) {
    printf("EAX: %X EBX: %X ECX: %X EDX: %X\n",
        debug_context->Eax, debug_context->Ebx, debug_context->Ecx, debug_context->Edx);
    printf("ESP: %X EBP: %X\n",
        debug_context->Esp, debug_context->Ebp);
    printf("ESI: %X EDI: %X\n",
        debug_context->Esi, debug_context->Edi);
    printf("Parameters\n"
        "HWND: %X\n"
        "text: %s\n"
        "length: %i\n",
        (HWND)(*(DWORD*)(debug_context->Esp + 0x4)),
        (char*)(*(DWORD*)(debug_context->Esp + 0x8)),
        (int)(*(DWORD*)(debug_context->Esp + 0xC)));
 
}
 
void modify_text(PCONTEXT debug_context) {
    char* text = (char*)(*(DWORD*)(debug_context->Esp + 0x8));
    int length = strlen(text);
    _snprintf(text, length, "REPLACED");
}
 
void __declspec(naked) change_text_stub(void) {
    __asm {
        push ebp
        jmp [func_addr_offset]
    }
}
 
LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
    if(ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
        if((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == func_addr) {
            PCONTEXT debug_context = ExceptionInfo->ContextRecord;
            printf("Breakpoint hit!\n");
            print_parameters(debug_context);
            modify_text(debug_context);
            debug_context->Eip = (DWORD)&change_text_stub;
            return EXCEPTION_CONTINUE_EXECUTION;
        }
    }
    return EXCEPTION_CONTINUE_SEARCH;
}
 
void set_breakpoints(void) {
    HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if(hTool32 != INVALID_HANDLE_VALUE) {
        THREADENTRY32 thread_entry32;
        thread_entry32.dwSize = sizeof(THREADENTRY32);
        FILETIME exit_time, kernel_time, user_time;
        FILETIME creation_time;
        FILETIME prev_creation_time;
        prev_creation_time.dwLowDateTime = 0xFFFFFFFF;
        prev_creation_time.dwHighDateTime = INT_MAX;
        HANDLE hMainThread = NULL;
        if(Thread32First(hTool32, &thread_entry32)) {
            do {
                if(thread_entry32.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(thread_entry32.th32OwnerProcessID)
                    && thread_entry32.th32OwnerProcessID == GetCurrentProcessId()
                    && thread_entry32.th32ThreadID != GetCurrentThreadId()) {
                        HANDLE hThread = OpenThread(THREAD_SET_CONTEXT | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
                            FALSE, thread_entry32.th32ThreadID);
                        GetThreadTimes(hThread, &creation_time, &exit_time, &kernel_time, &user_time);
                        if(CompareFileTime(&creation_time, &prev_creation_time) == -1) {
                            memcpy(&prev_creation_time, &creation_time, sizeof(FILETIME));
                            if(hMainThread != NULL)
                                CloseHandle(hMainThread);
                            hMainThread = hThread;
                        }
                        else
                            CloseHandle(hThread);
                }
                thread_entry32.dwSize = sizeof(THREADENTRY32);
            } while(Thread32Next(hTool32, &thread_entry32));
            (void)SetUnhandledExceptionFilter(ExceptionFilter);
            CONTEXT thread_context = {CONTEXT_DEBUG_REGISTERS};
            thread_context.Dr0 = func_addr;
            thread_context.Dr7 = (1 << 0);
            SetThreadContext(hMainThread, &thread_context);
            CloseHandle(hMainThread);
        }
        CloseHandle(hTool32);
    }
}
 
int APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
    if(reason == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hModule);
        if(AllocConsole()) {
            freopen("CONOUT$", "w", stdout);
            SetConsoleTitle(L"Console");
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
            printf("DLL loaded.\n");
        }
        set_breakpoints();
    }
    return TRUE;
}
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: VEH Handling (Danilo?)

Post by IdeasVacuum »

The snag that I think you are trying to capture is where your app crashes/hangs because of something another app does (or the OS). In my experience, that "other app" is often an Anti-Virus/Anti Malware app - many of them are simply terrible.

What you could do is have your app keep a plain text log of
(a) Basic info such as RAM Size, Free Disk Space etc.
(b) The processes running at the same time as your app
(c) What command/event in your app the User just triggered.

My theory is that the User would then only have to send the log file to you and that would contain enough clues. If you expect much more, even when trying to help them, they might resist or fail to be diligent.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Mike Yurgalavage
Enthusiast
Enthusiast
Posts: 118
Joined: Thu May 17, 2007 8:35 pm
Location: USA

Re: VEH Handling (Danilo?)

Post by Mike Yurgalavage »

those are good ideas, IdeasVaccuum! I may take that into consideration!

However, I am set in that I want to be able to create a debugger type program that can set VEH breakpoints and etc. in a target process. In fact, I am willing to pay for someone to help create this sort of thing, if need be. I am hoping the experts can come in here and chime in on this stuff. Usually there is 4 or 5 people that are up for a challenge like this, instead of the usual "how do I set a font in a gadget button" type questions..

Where are all the big guns?! The PureBasic community is the best!

best,
Mike
Post Reply