#include        "defs.h"

ULONG_PTR       pLdrInitializeThunk;
ULONG_PTR       pKiUserExceptionDispatcher;
ULONG_PTR       pKiUserApcDispatcher;
ULONG_PTR       pKiUserCallbackDispatcher;
ULONG_PTR       pKiFastSystemCallRet;
ULONG_PTR       pRtlUserThreadStart;
ULONG_PTR       pEtwpNotificationThread;
ULONG_PTR       pLdrHotPatchRoutine;
ULONG_PTR       pKiRaiseUserExceptionDispatcher;
ULONG_PTR       pExpInterlockedPopEntrySListEnd;
ULONG_PTR       pExpInterlockedPopEntrySListFault;
ULONG_PTR       pExpInterlockedPopEntrySListResume;

ULONG_PTR       pLdrInitializeThunkShadow;
ULONG_PTR       pKiUserExceptionDispatcherShadow;
ULONG_PTR       pKiUserApcDispatcherShadow;
ULONG_PTR       pKiUserCallbackDispatcherShadow;
ULONG_PTR       pKiFastSystemCallRetShadow;
ULONG_PTR       pRtlUserThreadStartShadow; 
ULONG_PTR       pEtwpNotificationThreadShadow;
ULONG_PTR       pLdrHotPatchRoutineShadow;
ULONG_PTR       pKiRaiseUserExceptionDispatcherShadow;
ULONG_PTR       pExpInterlockedPopEntrySListEndShadow;
ULONG_PTR       pExpInterlockedPopEntrySListFaultShadow;
ULONG_PTR       pExpInterlockedPopEntrySListResumeShadow;

ULONG_PTR       pNtContinue;
ULONG_PTR       pNtTerminateThread;
ULONG_PTR       pNtMapViewOfSection;
ULONG_PTR       pNtUnmapViewOfSection;
ULONG_PTR       pNtAllocateVirtualMemory;
ULONG_PTR       pNtFreeVirtualMemory;
ULONG_PTR       pNtProtectVirtualMemory;
ULONG_PTR       pNtQueryVirtualMemory;
ULONG_PTR       pNtCallbackReturn;
ULONG_PTR       pNtRaiseException;
ULONG_PTR       pNtTerminateProcess;
ULONG_PTR       pNtCreateProcess;
ULONG_PTR       pNtCreateProcessEx;
ULONG_PTR       pNtCreateUserProcess;
ULONG_PTR       pNtSuspendThread;


ULONG_PTR       NtContinue_sn;
ULONG_PTR       NtTerminateThread_sn;
ULONG_PTR       NtMapViewOfSection_sn;
ULONG_PTR       NtUnmapViewOfSection_sn;
ULONG_PTR       NtCallbackReturn_sn;
ULONG_PTR       NtRaiseException_sn;
ULONG_PTR       NtAllocateVirtualMemory_sn;
ULONG_PTR       NtFreeVirtualMemory_sn;
ULONG_PTR       NtProtectVirtualMemory_sn; 
ULONG_PTR       NtTerminateProcess_sn;
ULONG_PTR       NtCreateProcess_sn;
ULONG_PTR       NtCreateProcessEx_sn;
ULONG_PTR       NtCreateUserProcess_sn;
ULONG_PTR       NtSuspendThread_sn;

ULONG_PTR       LdrInitializeThunkHook;
ULONG_PTR       KiUserApcDispatcherHook;
ULONG_PTR       KiUserExceptionDispatcherHook;
ULONG_PTR       KiUserCallbackDispatcherHook;

ULONG_PTR       g_vm_enter;
ULONG_PTR       g_vm_exit;
ULONG_PTR       g_vm_sysenter_enter;
ULONG_PTR       g_vm_sysenter_buffer;
ULONG_PTR       g_vm_int2e_vm_enter;
ULONG_PTR       g_vm_syscall_ret;

LIST      image_list_head;
LIST      vmmap_list_head;

/**************************************************
 * Base and end of this image, needed thus I can
 * check if exception happened in this code.
 **************************************************/
ULONG_PTR       trace_base;
ULONG_PTR       trace_end;
ULONG_PTR       g_ntdllbase;
ULONG_PTR       g_ntdllend;

ULONG           b_log_now;
/**************************************************
 * Full NT path to this dll
 **************************************************/
WCHAR   g_wsTraceNtPath[MAX_PATH + MAX_PATH];
WCHAR   g_wsNtdllNtPath[MAX_PATH + MAX_PATH];

/******************************************
 * temp code, never use it as PEB is is not
 * iniialized at LdrInitializeThunk
 ******************************************/
PVOID   get_ntdllbase(){
        ULONG_PTR       imagebase;
        
        imagebase = (ULONG_PTR)__readfsdword(0x30);
        imagebase = *(PULONG_PTR)(imagebase + 0x0C);
        imagebase = *(PULONG_PTR)(imagebase + 0x0C);
        imagebase = *(PULONG_PTR)(imagebase);
        imagebase = *(PULONG_PTR)(imagebase + 0x18);
        return (PVOID)imagebase;
}   

PVOID   get_imagebase(){
        ULONG_PTR       imagebase;
        imagebase = (ULONG_PTR)__readfsdword(0x30);
        imagebase = *(PULONG_PTR)(imagebase + 0x08);
        return (PVOID)imagebase;
}

BOOL    TestBit(unsigned long bitmap, unsigned long bit){
        if (bitmap & (1 << bit)) return TRUE;
        return FALSE;
}

ULONG   get_currentthreadid(){
        return __readfsdword(0x24);
}

ULONG   get_currentprocessid(){
        return __readfsdword(0x20);
}   

HANDLE  get_currentprocess(){
        return (HANDLE)(ULONG_PTR)-1;
}

HANDLE  get_getcurrentthread(){
        return (HANDLE)(ULONG_PTR)-2;
}  

//always called from current thread...
VOID    InitThread(__in dwThreadId){
        CLIENT_ID     cid;
        THREAD_BASIC_INFORMATION tbi;
        HANDLE        hThread;
        ULONG         cbNeeded;
        ULONG_PTR     StackBase;
        ULONG_PTR     StackLimit;
        NTSTATUS      status;
        OBJECT_ATTRIBUTES oa;
        
        context       *pctx;
        
        pctx = (context *)__readfsdword(TEB_THREAD_CONTEXT);
        if (pctx) return;
        
        pctx = dlmalloc(sizeof(context));
        memset(pctx, 0, sizeof(context));
        
        __writefsdword(TEB_THREAD_CONTEXT, (ULONG_PTR)pctx);
        
        pctx->teb               = __readfsdword(0x18);
        pctx->thread_stack_base = (ULONG_PTR)dlmalloc(THREAD_STACK_SIZE);
        if (pctx->thread_stack_base == 0){
                DbgPrint(("%s -- failed to allocate stack for thread", __FUNCTION__));
                __asm jmp $
        }
        pctx->thread_stack      = pctx->thread_stack_base + THREAD_STACK_TOP;
        pctx->psyscall_ret      = dlmalloc(0);  //later it will be freed, as this is no used anymore at all...
        pctx->syscall_ret_depth = 0;
                
}

typedef int (*func)();
WCHAR   *g_wsTargetFullPath; //[MAX_PATH + MAX_PATH];

DWORD   WINAPI TestThread(__in PVOID lpArgument){
        STARTUPINFO         sinfo;
        PROCESS_INFORMATION pinfo;
        BOOL                b_ret;
        
        memset(&sinfo, 0, sizeof(sinfo));
        memset(&pinfo, 0, sizeof(pinfo));
                
        b_ret = CreateProcess(0,                                                                                 
                              g_wsTargetFullPath, 
                              0,
                              0,
                              0,
                              0,
                              0,
                              0,
                              &sinfo,
                              &pinfo);
        if (!b_ret){
                DbgPrint(("Failed to start sub process : %S", g_wsTargetFullPath));
        }
        return 0;
}

VOID    BuildEntryCode(__in void *pbuff, __in void *EntryPoint){
        pbuff = asm_push_reg(pbuff, REG_ESP);
        pbuff = asm_pushad(pbuff);
        pbuff = asm_pushfd(pbuff);
        pbuff = asm_push_imm32(pbuff, (unsigned long)EntryPoint);
        pbuff = asm_push_reg(pbuff, REG_ESP); 
        
        
        pbuff = asm_push_imm32(pbuff, 0);
        pbuff = asm_jmp_mem32(pbuff, (unsigned long)&g_traceInitThread);            
}


VOID    BuildVmEnter(__in void *pbuff){
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ecx), REG_ECX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_edx), REG_EDX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ebx), REG_EBX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_esp), REG_ESP);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ebp), REG_EBP);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_esi), REG_ESI);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_edi), REG_EDI);
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_ESP, REG_EAX, FIELD_OFFSET(context, thread_stack));
        pbuff = asm_pushfd(pbuff);
        pbuff = asm_pop_reg(pbuff, REG_ECX);
        pbuff = asm_push_imm32(pbuff, 0x246);
        pbuff = asm_popfd(pbuff);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_eflags), REG_ECX);
        pbuff = asm_push_reg(pbuff, REG_EAX);
        pbuff = asm_push_imm32(pbuff, 0);
        make_jmp(pbuff, traceProcessNextBuffer);
}
                
VOID    BuildVmExit(__in void *pbuff){
        pbuff = asm_add_fs_prefix(pbuff);
        pbuff = asm_mov_reg_mem32(pbuff, REG_EAX, TEB_THREAD_CONTEXT);
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_ECX, REG_EAX, FIELD_OFFSET(context, reg_eflags));
        pbuff = asm_push_reg(pbuff, REG_ECX);
        pbuff = asm_popfd(pbuff);
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_ECX, REG_EAX, FIELD_OFFSET(context, reg_ecx)); 
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_EDX, REG_EAX, FIELD_OFFSET(context, reg_edx)); 
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_EBX, REG_EAX, FIELD_OFFSET(context, reg_ebx));         
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_ESP, REG_EAX, FIELD_OFFSET(context, reg_esp)); 
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_EBP, REG_EAX, FIELD_OFFSET(context, reg_ebp)); 
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_ESI, REG_EAX, FIELD_OFFSET(context, reg_esi)); 
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_EDI, REG_EAX, FIELD_OFFSET(context, reg_edi));
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_EAX, REG_EAX, FIELD_OFFSET(context, reg_eax));
        pbuff = asm_add_fs_prefix(pbuff);
        pbuff = asm_jmp_mem32(pbuff, TEB_THREAD_JMP);       
} 

VOID    BuildSysEnterBuffer(__in void *pbuff){
        /*******************************************
         * Don't intercept sysenter via ret to here
         * as I hook KiFastSystemCallRet
         *******************************************/
        //pbuff = asm_mov_reg_mem32_imm(pbuff, REG_EDX, 0, (unsigned long)pbuff + 10 + 2);        //size of mov [edx+0], pbuff and sysenter
        pbuff = asm_sysenter(pbuff);
        pbuff = asm_add_fs_prefix(pbuff);
        pbuff = asm_mov_mem32_reg(pbuff, TEB_THREAD_SAVE_EAX, REG_EAX);
        pbuff = asm_add_fs_prefix(pbuff);
        pbuff = asm_mov_reg_mem32(pbuff, REG_EAX, TEB_THREAD_CONTEXT);
        if (trace_base != 0)
                pbuff = asm_mov_reg_mem32_imm(pbuff, REG_EAX, FIELD_OFFSET(context, reg_eip), (unsigned long)pKiFastSystemCallRetShadow); //pKiFastSystemCallRet);   
        else
                pbuff = asm_mov_reg_mem32_imm(pbuff, REG_EAX, FIELD_OFFSET(context, reg_eip), (unsigned long)pKiFastSystemCallRet);   
        make_jmp(pbuff, (void *)g_vm_sysenter_enter);            
} 

/************************************************************
 * ntdll.dll KiFastSystemCallRet points to ret, and we need
 * to catch this. What I do, is to hook KiFastSystemCallRet
 * with jmp and process it...
 ************************************************************/
VOID    BuildKiFastSystemCallRet(__in void *pbuff){
        pbuff   =       asm_add_fs_prefix(pbuff);
        pbuff   =       asm_mov_mem32_reg(pbuff, TEB_THREAD_SAVE_EAX, REG_EAX);
        pbuff   =       asm_add_fs_prefix(pbuff);
        pbuff   =       asm_mov_reg_mem32(pbuff, REG_EAX, TEB_THREAD_CONTEXT);
        if (trace_base != 0)
                pbuff = asm_mov_reg_mem32_imm(pbuff, REG_EAX, FIELD_OFFSET(context, reg_eip), (unsigned long)pKiFastSystemCallRetShadow);
        else
                pbuff = asm_mov_reg_mem32_imm(pbuff, REG_EAX, FIELD_OFFSET(context, reg_eip), (unsigned long)pKiFastSystemCallRet);
        make_jmp(pbuff, (void *)g_vm_sysenter_enter);
}            

VOID    BuildVmSysenterEnter(__in void *pbuff){
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ecx), REG_ECX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_edx), REG_EDX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ebx), REG_EBX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_esp), REG_ESP);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ebp), REG_EBP);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_esi), REG_ESI);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_edi), REG_EDI);
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_ESP, REG_EAX, FIELD_OFFSET(context, thread_stack));
        pbuff = asm_pushfd(pbuff);
        pbuff = asm_pop_reg(pbuff, REG_ECX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_eflags), REG_ECX);
        pbuff = asm_push_reg(pbuff, REG_EAX);
        pbuff = asm_push_imm32(pbuff, 0);
        make_jmp(pbuff, tracePostSysenter);
}

VOID    BuildVmInt2eEnter(__in void *pbuff){
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ecx), REG_ECX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_edx), REG_EDX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ebx), REG_EBX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_esp), REG_ESP);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_ebp), REG_EBP);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_esi), REG_ESI);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_edi), REG_EDI);
        pbuff = asm_mov_reg_reg_mem32(pbuff, REG_ESP, REG_EAX, FIELD_OFFSET(context, thread_stack));
        pbuff = asm_pushfd(pbuff);
        pbuff = asm_pop_reg(pbuff, REG_ECX);
        pbuff = asm_mov_reg_mem32_reg(pbuff, REG_EAX, FIELD_OFFSET(context, reg_eflags), REG_ECX);
        pbuff = asm_push_reg(pbuff, REG_EAX);
        pbuff = asm_push_imm32(pbuff, 0);
        make_jmp(pbuff, tracePostInt2e);
}

lock_t  dllmain_lock;
ULONG   dllmain_init_done;

VOID __fastcall DllMainInject(pinject_struct pinject){
        PVOID             ntdllbase;
        PIMAGE_DOS_HEADER pmz;
        PPEHEADER32       pe32;
        ULONG_PTR         hooks;
        DWORD             dwOldProt;
        HANDLE            hEvent;
        
        
        acquire_spin_lock(&dllmain_lock);
        if (dllmain_init_done == 1) goto __Exit0;
        ntdllFix(pinject->ntdllbase);
        /***************************************************
         * remap ntdll for a process, thus it won't be able
         * to see our hooks... it's already remapped by
         * do_inject
         ***************************************************/
        //peRemapNtdll((void *)REBASED_NTDLL_BASE);
        peRebaseDll((void *)REBASED_NTDLL_BASE, REBASED_NTDLL_BASE); 
                                        
        memcpy(g_wsTraceNtPath, pinject->wsTraceNtPath, sizeof(g_wsTraceNtPath));
        memcpy(g_wsNtdllNtPath, pinject->wsNtdllNtPath, sizeof(g_wsNtdllNtPath));
        
        ntdllbase = pinject->ntdllbase;
        g_ntdllbase = (ULONG_PTR)ntdllbase;
        pmz = (PIMAGE_DOS_HEADER)g_ntdllbase;
        pe32= (PPEHEADER32)(g_ntdllbase + pmz->e_lfanew);
        g_ntdllend  = g_ntdllbase + pe32->pe_sizeofimage;
        
        ntVirtualProtect(pinject->LdrInitializeThunk, pinject->LdrInitializeThunk_hooklen, PAGE_EXECUTE_READWRITE, &dwOldProt);
        memcpy(pinject->LdrInitializeThunk, pinject->LdrInitializeThunk_oldbytes, pinject->LdrInitializeThunk_hooklen);
        ntVirtualProtect(pinject->LdrInitializeThunk, pinject->LdrInitializeThunk_hooklen, dwOldProt, &dwOldProt);
        
        init_lock();
        InitializeListHead(&image_list_head);
        InitializeListHead(&vmmap_list_head);
        
        trace_base = (ULONG_PTR)pinject->tracebase;
        
        pmz = (PIMAGE_DOS_HEADER)trace_base;
        pe32= (PPEHEADER32)((ULONG_PTR)pmz->e_lfanew + trace_base);
        
        trace_end  = trace_base + pe32->pe_sizeofimage;
        
        imageAdd(get_imagebase());
        imageAdd(ntdllbase);
        imageAdd((void *)REBASED_NTDLL_BASE);
        
        xed_tables_init();        
        
        pLdrInitializeThunkShadow                = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "LdrInitializeThunk");
        pKiUserExceptionDispatcherShadow         = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "KiUserExceptionDispatcher");
        pKiUserApcDispatcherShadow               = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "KiUserApcDispatcher");
        pKiUserCallbackDispatcherShadow          = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "KiUserCallbackDispatcher");
        pKiFastSystemCallRetShadow               = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "KiFastSystemCallRet");
        pRtlUserThreadStartShadow                = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "RtlUserThreadStart");
        pEtwpNotificationThreadShadow            = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "EtwpNotificationThread"); 
        pLdrHotPatchRoutineShadow                = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "LdrHotPatchRoutine"); 
        pKiRaiseUserExceptionDispatcherShadow    = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "KiRaiseUserExceptionDispatcher"); 
        pExpInterlockedPopEntrySListEndShadow    = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "ExpInterlockedPopEntrySListEnd"); 
        pExpInterlockedPopEntrySListFaultShadow  = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "ExpInterlockedPopEntrySListFault");
        pExpInterlockedPopEntrySListResumeShadow = (ULONG_PTR)getprocaddress((PVOID)REBASED_NTDLL_BASE, "ExpInterlockedPopEntrySListResume");
        
        
        pLdrInitializeThunk                = (ULONG_PTR)getprocaddress(ntdllbase, "LdrInitializeThunk");
        pKiUserExceptionDispatcher         = (ULONG_PTR)getprocaddress(ntdllbase, "KiUserExceptionDispatcher");
        pKiUserApcDispatcher               = (ULONG_PTR)getprocaddress(ntdllbase, "KiUserApcDispatcher");
        pKiUserCallbackDispatcher          = (ULONG_PTR)getprocaddress(ntdllbase, "KiUserCallbackDispatcher");
        pRtlUserThreadStart                = (ULONG_PTR)getprocaddress(ntdllbase, "RtlUserThreadStart");
        pEtwpNotificationThread            = (ULONG_PTR)getprocaddress(ntdllbase, "EtwpNotificationThread"); 
        pLdrHotPatchRoutine                = (ULONG_PTR)getprocaddress(ntdllbase, "LdrHotPatchRoutine"); 
        pKiRaiseUserExceptionDispatcher    = (ULONG_PTR)getprocaddress(ntdllbase, "KiRaiseUserExceptionDispatcher"); 
        pExpInterlockedPopEntrySListEnd    = (ULONG_PTR)getprocaddress(ntdllbase, "ExpInterlockedPopEntrySListEnd"); 
        pExpInterlockedPopEntrySListFault  = (ULONG_PTR)getprocaddress(ntdllbase, "ExpInterlockedPopEntrySListFault");
        pExpInterlockedPopEntrySListResume = (ULONG_PTR)getprocaddress(ntdllbase, "ExpInterlockedPopEntrySListResume");
        
        
        pNtContinue                = (ULONG_PTR)getprocaddress(ntdllbase, "NtContinue");
        pNtTerminateThread         = (ULONG_PTR)getprocaddress(ntdllbase, "NtTerminateThread");
        pKiFastSystemCallRet       = (ULONG_PTR)getprocaddress(ntdllbase, "KiFastSystemCallRet");
        pNtTerminateThread         = (ULONG_PTR)getprocaddress(ntdllbase, "NtTerminateThread");
        pNtMapViewOfSection        = (ULONG_PTR)getprocaddress(ntdllbase, "NtMapViewOfSection");
        pNtUnmapViewOfSection      = (ULONG_PTR)getprocaddress(ntdllbase, "NtUnmapViewOfSection");
        pNtCallbackReturn          = (ULONG_PTR)getprocaddress(ntdllbase, "NtCallbackReturn");
        pNtRaiseException          = (ULONG_PTR)getprocaddress(ntdllbase, "NtRaiseException");
        pNtAllocateVirtualMemory   = (ULONG_PTR)getprocaddress(ntdllbase, "NtAllocateVirtualMemory");
        pNtFreeVirtualMemory       = (ULONG_PTR)getprocaddress(ntdllbase, "NtFreeVirtualMemory");
        pNtProtectVirtualMemory    = (ULONG_PTR)getprocaddress(ntdllbase, "NtProtectVirtualMemory");
        pNtTerminateProcess        = (ULONG_PTR)getprocaddress(ntdllbase, "NtTerminateProcess");
        pNtCreateProcess           = (ULONG_PTR)getprocaddress(ntdllbase, "NtCreateProcess");
        pNtCreateProcessEx         = (ULONG_PTR)getprocaddress(ntdllbase, "NtCreateProcessEx");
        pNtCreateUserProcess       = (ULONG_PTR)getprocaddress(ntdllbase, "NtCreateUserProcess");
        pNtSuspendThread           = (ULONG_PTR)getprocaddress(ntdllbase, "NtSuspendThread");
        
        g_vm_enter           = (ULONG_PTR)dlmalloc(0x50);
        g_vm_exit            = (ULONG_PTR)dlmalloc(0x50);
        g_vm_sysenter_enter  = (ULONG_PTR)dlmalloc(0x50);
        g_vm_sysenter_buffer = (ULONG_PTR)dlmalloc(0x50);
        g_vm_int2e_vm_enter  = (ULONG_PTR)dlmalloc(0x50);
        g_vm_syscall_ret     = (ULONG_PTR)dlmalloc(0x50);
        
        BuildVmEnter        ((void *)g_vm_enter);
        BuildVmExit         ((void *)g_vm_exit);
        BuildVmSysenterEnter((void *)g_vm_sysenter_enter);
        BuildSysEnterBuffer ((void *)g_vm_sysenter_buffer);
        BuildVmInt2eEnter   ((void *)g_vm_int2e_vm_enter);
        BuildKiFastSystemCallRet((void *)g_vm_syscall_ret);
        
        NtContinue_sn              = *(ULONG_PTR *)(pNtContinue + 1);
        NtTerminateThread_sn       = *(ULONG_PTR *)(pNtTerminateThread + 1);
        NtMapViewOfSection_sn      = *(ULONG_PTR *)(pNtMapViewOfSection + 1);
        NtUnmapViewOfSection_sn    = *(ULONG_PTR *)(pNtUnmapViewOfSection + 1);
        NtCallbackReturn_sn        = *(ULONG_PTR *)(pNtCallbackReturn + 1);
        NtRaiseException_sn        = *(ULONG_PTR *)(pNtRaiseException + 1);
        NtAllocateVirtualMemory_sn = *(ULONG_PTR *)(pNtAllocateVirtualMemory + 1);
        NtFreeVirtualMemory_sn     = *(ULONG_PTR *)(pNtFreeVirtualMemory + 1);
        NtProtectVirtualMemory_sn  = *(ULONG_PTR *)(pNtProtectVirtualMemory + 1);
        NtTerminateProcess_sn      = *(ULONG_PTR *)(pNtTerminateProcess + 1);
        NtCreateProcess_sn         = *(ULONG_PTR *)(pNtCreateProcess + 1);
        if (pNtCreateProcessEx)
                NtCreateProcessEx_sn       = *(ULONG_PTR *)(pNtCreateProcessEx + 1);
        if (pNtCreateUserProcess)
                NtCreateUserProcess_sn     = *(ULONG_PTR *)(pNtCreateUserProcess + 1);
        NtSuspendThread_sn         = *(ULONG_PTR *)(pNtSuspendThread + 1);
        
        /**********************************************
         * we have already built trace buffers, thus we
         * can hook entry points
         **********************************************/
        hooks = (ULONG_PTR)dlmalloc(0x100); //ntVirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                       
        BuildEntryCode((PVOID)(hooks + HOOK_LDRINITIALIZETHUNK)       , (void *)pLdrInitializeThunkShadow);
        BuildEntryCode((PVOID)(hooks + HOOK_KIUSEREXCEPTIONDISPATCHER), (void *)pKiUserExceptionDispatcherShadow);
        BuildEntryCode((PVOID)(hooks + HOOK_KIUSERAPCDISPATCHER)      , (void *)pKiUserApcDispatcherShadow);
        BuildEntryCode((PVOID)(hooks + HOOK_KIUSERCALLBACKDISPATCHER) , (void *)pKiUserCallbackDispatcherShadow);
        
        LdrInitializeThunkHook          = (hooks + HOOK_LDRINITIALIZETHUNK);       
        KiUserExceptionDispatcherHook   = (hooks + HOOK_KIUSEREXCEPTIONDISPATCHER);
        KiUserApcDispatcherHook         = (hooks + HOOK_KIUSERAPCDISPATCHER);
        KiUserCallbackDispatcherHook    = (hooks + HOOK_KIUSERCALLBACKDISPATCHER);

        //build exec buffers for shadow ntdll.dll, this is needed thus we dont have to take care of removing
        //hooks from our entry points... weeheeee...
        //not needed anymore as we are going straight into real stuff... (these code blocks are generated
        //at runtime, so we actually don't save any time...
        //traceBuildBbl((unsigned char *)pLdrInitializeThunkShadow);
        //traceBuildBbl((unsigned char *)pKiUserExceptionDispatcherShadow);
        //traceBuildBbl((unsigned char *)pKiUserApcDispatcherShadow);
        //traceBuildBbl((unsigned char *)pKiUserCallbackDispatcherShadow);
        
        Hook((PVOID)pLdrInitializeThunk         , (PVOID)(hooks + HOOK_LDRINITIALIZETHUNK)       , NULL);
        Hook((PVOID)pKiUserExceptionDispatcher  , (PVOID)(hooks + HOOK_KIUSEREXCEPTIONDISPATCHER), NULL);
        Hook((PVOID)pKiUserApcDispatcher        , (PVOID)(hooks + HOOK_KIUSERAPCDISPATCHER)      , NULL);
        Hook((PVOID)pKiUserCallbackDispatcher   , (PVOID)(hooks + HOOK_KIUSERCALLBACKDISPATCHER) , NULL);
        Hook((PVOID)pKiFastSystemCallRet        , (PVOID)g_vm_syscall_ret, NULL);

        hEvent = pinject->hEvent;        
        NtSetEvent(hEvent, NULL);
        NtClose(hEvent);
        
        dllmain_init_done = 1;
__Exit0:
        release_spin_lock(&dllmain_lock);
        //NtTerminateThread(CURRENT_THREAD, 0);
        NtWaitForSingleObject(CURRENT_THREAD, FALSE, NULL);
}

int __cdecl wmain(){
        void    *p1;
        unsigned char          *p;
        PVOID   ntdllbase;
        DWORD           dwOldProt;
        ULONG_PTR       hooks;
        PIMAGE_DOS_HEADER       pmz;
        PPEHEADER32             pe32;
        pimage_struct           pimage;
        HANDLE                  hThreads[2];
        int     argc;
        wchar_t **argv;
        WCHAR   *wsCmdLine;
        size_t  len;
               
        wsCmdLine = GetCommandLine();
        argv = CommandLineToArgvW(GetCommandLine(), &argc);
        
        if (argc >= 2){
                wsCmdLine = wcschr(wsCmdLine, ' ');
                while (*wsCmdLine == ' ')
                        wsCmdLine++;
                len = wcslen(wsCmdLine) + 1;
                len *= sizeof(WCHAR);
                
                g_wsTargetFullPath = dlmalloc(len);
                memset(g_wsTargetFullPath, 0, len);
                
                wcsncpy(g_wsTargetFullPath, wsCmdLine, len/sizeof(WCHAR));
                        
                //memset(g_wsTargetFullPath, 0, sizeof(g_wsTargetFullPath));        
                //wcsncpy(g_wsTargetFullPath, argv[1], MAX_PATH + MAX_PATH); 
        }else{
                NtTerminateProcess((HANDLE)(ULONG_PTR)-1, 0);
        }
                        
        init_lock();
        
        InitializeListHead(&image_list_head);
        InitializeListHead(&vmmap_list_head);
                
        imageAdd(get_imagebase());
        imageAdd(get_ntdllbase());        
                        
        xed_tables_init();
        ntdllbase = get_ntdllbase();
        g_ntdllbase = (ULONG_PTR)ntdllbase;
        
        ntdllFix(ntdllbase);
        
        pLdrInitializeThunk        = (ULONG_PTR)getprocaddress(ntdllbase, "LdrInitializeThunk");
        pKiUserExceptionDispatcher = (ULONG_PTR)getprocaddress(ntdllbase, "KiUserExceptionDispatcher");
        pKiUserApcDispatcher       = (ULONG_PTR)getprocaddress(ntdllbase, "KiUserApcDispatcher");
        pKiUserCallbackDispatcher  = (ULONG_PTR)getprocaddress(ntdllbase, "KiUserCallbackDispatcher");
        pNtContinue                = (ULONG_PTR)getprocaddress(ntdllbase, "NtContinue");
        pNtTerminateThread         = (ULONG_PTR)getprocaddress(ntdllbase, "NtTerminateThread");
        pKiFastSystemCallRet       = (ULONG_PTR)getprocaddress(ntdllbase, "KiFastSystemCallRet");
        pNtTerminateThread         = (ULONG_PTR)getprocaddress(ntdllbase, "NtTerminateThread");
        pNtMapViewOfSection        = (ULONG_PTR)getprocaddress(ntdllbase, "NtMapViewOfSection");
        pNtUnmapViewOfSection      = (ULONG_PTR)getprocaddress(ntdllbase, "NtUnmapViewOfSection");
        pNtCallbackReturn          = (ULONG_PTR)getprocaddress(ntdllbase, "NtCallbackReturn");
        pNtRaiseException          = (ULONG_PTR)getprocaddress(ntdllbase, "NtRaiseException");
        pNtAllocateVirtualMemory   = (ULONG_PTR)getprocaddress(ntdllbase, "NtAllocateVirtualMemory");
        pNtFreeVirtualMemory       = (ULONG_PTR)getprocaddress(ntdllbase, "NtFreeVirtualMemory");
        pNtProtectVirtualMemory    = (ULONG_PTR)getprocaddress(ntdllbase, "NtProtectVirtualMemory");
        pNtTerminateProcess        = (ULONG_PTR)getprocaddress(ntdllbase, "NtTerminateProcess");
        pNtCreateProcess           = (ULONG_PTR)getprocaddress(ntdllbase, "NtCreateProcess");
        pNtCreateProcessEx         = (ULONG_PTR)getprocaddress(ntdllbase, "NtCreateProcessEx");
        pNtCreateUserProcess       = (ULONG_PTR)getprocaddress(ntdllbase, "NtCreateUserProcess");
        
        
        
        //ptrace_LdrInitializeThunk        = traceBuildTraceBuffer((PVOID)pLdrInitializeThunk);
        //ptrace_KiUserExceptionDispatcher = traceBuildTraceBuffer((PVOID)pKiUserExceptionDispatcher);
        //ptrace_KiUserApcDispatcher       = traceBuildTraceBuffer((PVOID)pKiUserApcDispatcher);
        //ptrace_KiUserCallbackDispatcher  = traceBuildTraceBuffer((PVOID)pKiUserCallbackDispatcher);
        //ptrace_KiFastSystemCallRet       = traceBuildTraceBuffer((PVOID)pKiFastSystemCallRet);
        
        g_vm_enter           = (ULONG_PTR)dlmalloc(0x50);
        g_vm_exit            = (ULONG_PTR)dlmalloc(0x50);
        g_vm_sysenter_enter  = (ULONG_PTR)dlmalloc(0x50);
        g_vm_sysenter_buffer = (ULONG_PTR)dlmalloc(0x50);
        g_vm_int2e_vm_enter  = (ULONG_PTR)dlmalloc(0x50);
        
        BuildVmEnter        ((void *)g_vm_enter);
        BuildVmExit         ((void *)g_vm_exit);
        BuildVmSysenterEnter((void *)g_vm_sysenter_enter);
        BuildSysEnterBuffer ((void *)g_vm_sysenter_buffer);
        BuildVmInt2eEnter   ((void *)g_vm_int2e_vm_enter);
        
        NtContinue_sn              = *(ULONG_PTR *)(pNtContinue + 1);
        NtTerminateThread_sn       = *(ULONG_PTR *)(pNtTerminateThread + 1);
        NtMapViewOfSection_sn      = *(ULONG_PTR *)(pNtMapViewOfSection + 1);
        NtUnmapViewOfSection_sn    = *(ULONG_PTR *)(pNtUnmapViewOfSection + 1);
        NtCallbackReturn_sn        = *(ULONG_PTR *)(pNtCallbackReturn + 1);
        NtRaiseException_sn        = *(ULONG_PTR *)(pNtRaiseException + 1);
        NtAllocateVirtualMemory_sn = *(ULONG_PTR *)(pNtAllocateVirtualMemory + 1);
        NtFreeVirtualMemory_sn     = *(ULONG_PTR *)(pNtFreeVirtualMemory + 1);
        NtProtectVirtualMemory_sn  = *(ULONG_PTR *)(pNtProtectVirtualMemory + 1);
        NtTerminateProcess_sn      = *(ULONG_PTR *)(pNtTerminateProcess + 1);
        NtCreateProcess_sn         = *(ULONG_PTR *)(pNtCreateProcess + 1);
        if (pNtCreateProcessEx)
                NtCreateProcessEx_sn       = *(ULONG_PTR *)(pNtCreateProcessEx + 1);
        if (pNtCreateUserProcess)
                NtCreateUserProcess_sn     = *(ULONG_PTR *)(pNtCreateUserProcess + 1);
        
        
        /**********************************************
         * we have already built trace buffers, thus we
         * can hook entry points
         **********************************************/
        hooks = (ULONG_PTR)dlmalloc(0x100); //ntVirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
               
        BuildEntryCode((PVOID)(hooks + HOOK_LDRINITIALIZETHUNK)       , (void *)pLdrInitializeThunk);
        BuildEntryCode((PVOID)(hooks + HOOK_KIUSEREXCEPTIONDISPATCHER), (void *)pKiUserExceptionDispatcher);
        BuildEntryCode((PVOID)(hooks + HOOK_KIUSERAPCDISPATCHER)      , (void *)pKiUserApcDispatcher);
        BuildEntryCode((PVOID)(hooks + HOOK_KIUSERCALLBACKDISPATCHER) , (void *)pKiUserCallbackDispatcher);
        
        LdrInitializeThunkHook          = (hooks + HOOK_LDRINITIALIZETHUNK);       
        KiUserExceptionDispatcherHook   = (hooks + HOOK_KIUSEREXCEPTIONDISPATCHER);
        KiUserApcDispatcherHook         = (hooks + HOOK_KIUSERAPCDISPATCHER);
        KiUserCallbackDispatcherHook    = (hooks + HOOK_KIUSERCALLBACKDISPATCHER);
        
        traceBuildBbl((unsigned char *)pLdrInitializeThunk, FALSE);
        traceBuildBbl((unsigned char *)pKiUserExceptionDispatcher, FALSE);
        traceBuildBbl((unsigned char *)pKiUserApcDispatcher, FALSE);
        traceBuildBbl((unsigned char *)pKiUserCallbackDispatcher, FALSE);
        
        //__debugbreak();
        Hook((PVOID)pLdrInitializeThunk         , (PVOID)(hooks + HOOK_LDRINITIALIZETHUNK)       , NULL);
        Hook((PVOID)pKiUserExceptionDispatcher  , (PVOID)(hooks + HOOK_KIUSEREXCEPTIONDISPATCHER), NULL);
        Hook((PVOID)pKiUserApcDispatcher        , (PVOID)(hooks + HOOK_KIUSERAPCDISPATCHER)      , NULL);
        Hook((PVOID)pKiUserCallbackDispatcher   , (PVOID)(hooks + HOOK_KIUSERCALLBACKDISPATCHER) , NULL);
        //traceBuildExecBuffer(traceBuildTraceBuffer((PVOID)pLdrInitializeThunk));
        
        memset(g_wsTraceNtPath, 0, sizeof(g_wsTraceNtPath));
        wcscpy(g_wsTraceNtPath, L"\\??\\");
        GetModuleFileName(get_imagebase(), &g_wsTraceNtPath[4], MAX_PATH + MAX_PATH - 4);
        memset(g_wsNtdllNtPath, 0, sizeof(g_wsNtdllNtPath));
        wcscpy(g_wsNtdllNtPath, L"\\??\\");
        GetModuleFileName(get_ntdllbase(), &g_wsNtdllNtPath[4], MAX_PATH + MAX_PATH - 4);
        
        hThreads[0] = CreateThread(0, 0, TestThread, NULL, 0, NULL);
        //hThreads[1] = CreateThread(0, 0, TestThread, NULL, 0, NULL);
        //WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
        WaitForSingleObject(hThreads[0], INFINITE);
        CloseHandle(hThreads[0]);
        //CloseHandle(hThreads[1]);
        
        NtTerminateProcess(get_currentprocess(), 0);
}