#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

typedef HANDLE  (__stdcall *tOpenProcess)(DWORD,BOOL,DWORD);
typedef BOOL    (__stdcall *tCheckRemoteDebuggerPresent)(HANDLE,PBOOL);
typedef int     (__stdcall *tMessageBox)(HWND,LPCSTR,LPCSTR,UINT);
typedef BOOL    (__stdcall *tCloseHandle)(HANDLE);
typedef void    (__stdcall *tSleep)(DWORD);
typedef BOOL    (__stdcall *tTerminateProcess)(HANDLE,UINT);

struct pblock
{
    int pid;

    // from kernel32
    tOpenProcess OpenProcess;
    tCheckRemoteDebuggerPresent CheckRemoteDebuggerPresent;
    tCloseHandle CloseHandle;
    tSleep Sleep;
    tTerminateProcess TerminateProcess;
};

void __declspec(naked) mondbg(pblock *pb)
{
    _asm 
    {
        push ebp
        mov ebp,esp
    }
    while (1)
    {
        pb->Sleep(1000);
        HANDLE h = pb->OpenProcess(PROCESS_ALL_ACCESS, FALSE, pb->pid);
        if (h == NULL)
            break;

        BOOL b = 0;
        pb->CheckRemoteDebuggerPresent(h, &b);
        if (b)
            pb->TerminateProcess(h, 0);
        pb->CloseHandle(h);
    }

    __asm 
    {
        nop
        nop
        nop
        nop
        pop ebp
        ret
    }
}

int main(int argc, char **argv)
{
    if (argc < 3)
    {
        printf("usage: mondbg <pid to montior> <pid to do the monitoring>\n");
        return 1;
    }

    HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, atoi(argv[2]));
    if (h == NULL)
    {
        fprintf(stderr, "can't open process to do the monitoring\n");
        return 1;
    }

    struct pblock pb;
    pb.pid = atoi(argv[1]);
    HMODULE hm = GetModuleHandle("KERNEL32.DLL");
    pb.OpenProcess                = (tOpenProcess)                  GetProcAddress(hm, "OpenProcess");
    pb.CheckRemoteDebuggerPresent = (tCheckRemoteDebuggerPresent)   GetProcAddress(hm, "CheckRemoteDebuggerPresent");
    pb.CloseHandle                = (tCloseHandle)                  GetProcAddress(hm, "CloseHandle");
    pb.Sleep                      = (tSleep)                        GetProcAddress(hm, "Sleep");
    pb.TerminateProcess           = (tTerminateProcess)             GetProcAddress(hm, "TerminateProcess");

    int len_mondbg;
    for (len_mondbg = 0; ; len_mondbg++)
    {
        unsigned int *p = (unsigned int*)((char*)mondbg + len_mondbg);
        if (*p == 0x90909090)
            break;
    }
    len_mondbg += 10;

    LPVOID mem = VirtualAllocEx(h, NULL, len_mondbg + sizeof(pblock), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (mem == NULL)
    {
        fprintf(stderr, "cannot alloc memory for mon\n");
        CloseHandle(h);
        return 1;
    }

    DWORD written;
    if (WriteProcessMemory(h, mem, mondbg, len_mondbg, &written) == 0)
    {
        fprintf(stderr, "cannot write memory for mon\n");
        CloseHandle(h);
        return 1;
    }

    if (WriteProcessMemory(h, (char*)mem + len_mondbg, &pb, sizeof(pb), &written) == 0)
    {
        fprintf(stderr, "cannot write memory 2 for mon\n");
        CloseHandle(h);
        return 1;
    }

    if (CreateRemoteThread(h, NULL, 0, (LPTHREAD_START_ROUTINE)mem, (char*)mem + len_mondbg, 0, NULL) == NULL)
    {
        fprintf(stderr, "cannot create remote thread for mon\n");
        CloseHandle(h);
        return 1;
    }

    printf("done\n");
    return 0;
}
