diff --git a/GhostBanner.gif b/GhostBanner.gif new file mode 100644 index 0000000..b0d3490 Binary files /dev/null and b/GhostBanner.gif differ diff --git a/InjectLib/InjectDll.cpp b/InjectLib/InjectDll.cpp index bca83f9..7430aa6 100644 --- a/InjectLib/InjectDll.cpp +++ b/InjectLib/InjectDll.cpp @@ -30,8 +30,8 @@ UINT IPCSize = 0x100000; // 1Mb (Enough when Req-Rsp removed) //bool HideDllProxy = true; //bool HideDllProxyDsk = true; -bool SuspMainThAtLd = false; // Suspend main thread when loaded by GInjer -bool RstDskHiddenProxy = true; +bool SuspWaitAttachLd = true; // Suspend and report events before a debugger connected +bool RstDskHiddenProxy = true; bool AllowEjectOnDetach = false; //--------------------------------------- //PHOOK(ProcRtlRestoreContext) HookRtlRestoreContext; @@ -46,17 +46,17 @@ PHOOK(ProcNtTerminateThread) HookNtTerminateThread; PHOOK(ProcNtTerminateProcess) HookNtTerminateProcess; PHOOK(ProcNtContinue) HookNtContinue; -SHookLdrpInitialize LdrpInitHook; -SHookRtlDispatchException ExpDispHook; +NUNIHK::SHookLdrpInitialize LdrpInitHook; +NUNIHK::SHookRtlDispatchException ExpDispHook; DWORD ModInjFlags = 0; // If 0 then the module is loaded normally(With loader) // -1 if the module is hidden or a proxy //BYTE ProxyEncKey = 0; //PBYTE ProxyDllCopy = NULL; //DWORD ProxyDllSize = 0; -GhDbg::CDbgClient* Dbg = NULL; +NGhDbg::CDbgClient* Dbg = NULL; HANDLE hIpcTh = NULL; DWORD MainThId = 0; DWORD LastThID = -1; -DWORD LastExcThID = 0;; // Helps to reduce overhead of NtContinue hook +DWORD LastExcThID = 0; // Helps to reduce overhead of NtContinue hook //LPSTR LibPathName = NULL; // TODO: Add an option to not use a detectable hooks ("No detectable hooks") @@ -66,7 +66,7 @@ PBYTE ThisLibBase = NULL; PBYTE MainExeBase = NULL; //SIZE_T MainExeSize = 0; -alignas(16) BYTE ArrDbgClient[sizeof(GhDbg::CDbgClient)]; +alignas(16) BYTE ArrDbgClient[sizeof(NGhDbg::CDbgClient)]; wchar_t SysDirPath[MAX_PATH]; wchar_t StartUpDir[MAX_PATH]; @@ -74,12 +74,10 @@ wchar_t CfgFilePath[MAX_PATH]; wchar_t WorkFolder[MAX_PATH]; //=========================================================================== /* - NOTE: Only a SystemService(sysenter/int2E) type of functions is allowed to be used - + Only a SystemService(sysenter/int2E) type of functions is allowed to be used Can be loaded by: XDbgPlugin, GInjer, A target process somehow - Injector can load a DLL with LdrLoadDll or as '(HMODULE)Mod->ModuleBase, DLL_REFLECTIVE_LOAD, Mod' - Ginjer injects from a main thread + Ginjer injects from exe`s main thread */ // Reflective load: // hModule = Module Base @@ -91,23 +89,27 @@ BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ReasonCall, LPVOID lpReserved) // SModDesc* ModDesc = ModDescFromCurTh(); // NULL if loaded not by GInjer // NOTE: GInjer uses main thread SBlkDesc* BlkDesc = AddrToBlkDesc(ModDesc); SLdrDesc* LdrDesc = GetCurLdrDesc(BlkDesc); - UINT RemThFlags = (DWORD)hModule & InjLdr::RemThModMarker; // DLLMain has been passed to CreateRemoteThread/APC/ExistingThread (Where is only one argument available) // Normal HMODULE would be aligned at 0x1000 -#ifdef _DEBUG - if(ModDesc){LdrLogInit(ModDesc); LDRLOG("Hello from %08X: %ls", ModDesc->Flags, &ModDesc->ModulePath);} -#endif + UINT RemThFlags = (DWORD)hModule & NInjLdr::RemThModMarker; // DLLMain has been passed to CreateRemoteThread/APC/ExistingThread (Where is only one argument available) // Normal HMODULE would be aligned at 0x1000 if(RemThFlags || (ReasonCall >= DLL_REFLECTIVE_LOAD)) // NOTE: Variables get read in conditions even if these conditions is skipped // Either an own thread or APC callback of an existing thread // ReasonCall may be already outside of stack(Remote Thread)! { - DWORD InjFlg = (RemThFlags?RemThFlags:(ReasonCall & InjLdr::RemThModMarker)) << 24; // ReasonCall = (Flags >> 24)|0x100 // mfRunUAPC,mfRunRMTH,mfRunThHij,mfRawRMTH - bool NotOwnThread = (InjFlg & (InjLdr::mfRunUAPC|InjLdr::mfRunThHij)); + DWORD InjFlg = (ModDesc && (ReasonCall == DLL_REFLECTIVE_LOAD))?(NInjLdr::mfRunThHij):(((RemThFlags & NInjLdr::RemThModMarker)) << 24); + bool NotOwnThread = (InjFlg & (NInjLdr::mfRunUAPC|NInjLdr::mfRunThHij)); bool NotReusableTh = ModDesc || NotOwnThread; - if(InjFlg & InjLdr::mfRunUAPC) // Cannot reuse these threads + if(InjFlg & NInjLdr::mfRunUAPC) // Cannot reuse these threads { // // TODO: Prevent multi-entering from different threads when APC or Hijack injection method used // } - if(ModDesc)hModule = (HMODULE)InjLdr::ReflectiveRelocateSelf(hModule, (LdrDesc)?((PVOID)LdrDesc->NtDllBase):(NULL)); // Allocate to a new buffer // Loaded by GInjer - else hModule = (HMODULE)InjLdr::PEImageInitialize(hModule); // Relocate in current buffer (Must be large enough) // Loaded by a Debugger plugin + if(ModDesc) + { + hModule = (HMODULE)NInjLdr::ReflectiveRelocateSelf(hModule, (LdrDesc)?((PVOID)LdrDesc->NtDllBase):(NULL)); // Allocate to a new buffer // Loaded by GInjer. Current memory block will be deallocated by GInjer. Current thread is App`s main thread or Loader thread +#ifdef _DEBUG + LdrLogInit(ModDesc); + LDRLOG("Hello from %p, %08X", hModule, ModDesc->Flags); // LDRLOG("Hello from %p, %08X: %ls", hModule, ModDesc->Flags, &ModDesc->ModulePath); // '%ls' will crash if called before the process initioalization (Load before loader) +#endif + } + else hModule = (HMODULE)NInjLdr::PEImageInitialize(hModule); // Relocate in current buffer (Must be large enough) // Loaded by a Debugger plugin if(!NotReusableTh)hIpcTh = NtCurrentThread; // Can be changed later, before Start, if needed // A reusable injected remote thread // Assign globals after relocation if(ModDesc && !NotOwnThread)MainThId = NtCurrentThreadId(); // Main thread by GInjer ReasonCall = DLL_PROCESS_ATTACH; @@ -153,15 +155,15 @@ BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ReasonCall, LPVOID lpReserved) // DBGMSG("SysDirPath: %ls", &SysDirPath); /* { - NTSTATUS stat = GhDbg::CDbgClient::CreateIpcThread(&hIpcTh, NULL, TRUE); // <<<<<<<<< TEST !!!!!!!!!!!! + NTSTATUS stat = NGhDbg::CDbgClient::CreateIpcThread(&hIpcTh, NULL, TRUE); // <<<<<<<<< TEST !!!!!!!!!!!! } */ /* BOOL dres = true; if(!ModInjected && HideDllProxy) // NOTE: NO MORE DLL PROXY NEEDED { PVOID EntryPT = NULL; PVOID NewBase = NULL; - hIpcTh = CreateThread(NULL,0,&GhDbg::CDbgClient::IPCQueueThread,NULL,CREATE_SUSPENDED,NULL); // Some anticheats prevent creation of threads outside of any module - if(InjLdr::HideSelfProxyDll(hModule, GetModuleHandleA(ctENCSA("ntdll.dll")), (LPSTR)&SysDirPath, &NewBase, &EntryPT) > 0) // Are imports from our proxy DLL is already resolved by loader at this point? + hIpcTh = CreateThread(NULL,0,&NGhDbg::CDbgClient::IPCQueueThread,NULL,CREATE_SUSPENDED,NULL); // Some anticheats prevent creation of threads outside of any module + if(NInjLdr::HideSelfProxyDll(hModule, GetModuleHandleA(ctENCSA("ntdll.dll")), (LPSTR)&SysDirPath, &NewBase, &EntryPT) > 0) // Are imports from our proxy DLL is already resolved by loader at this point? { DBGMSG("Calling EP of a real DLL: Base=%p, EP=%p",hModule,EntryPT); dres = ((decltype(DLLMain)*)EntryPT)(hModule, ReasonCall, lpReserved); // Pass DLL_PROCESS_ATTACH notification @@ -196,7 +198,7 @@ BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ReasonCall, LPVOID lpReserved) // DBGMSG("Done hiding!"); } */ if(!InitApplication())return false; - if(ModInjFlags & InjLdr::mfRunRMTH){DBGMSG("Terminating injected thread(this): %u", NtCurrentThreadId()); NtTerminateThread(NtCurrentThread,0);} // Stack frame may be incorrect + if(ModInjFlags & NInjLdr::mfRunRMTH){DBGMSG("Terminating injected thread(this): %u", NtCurrentThreadId()); NtTerminateThread(NtCurrentThread,0);} // Stack frame may be incorrect return true; //dres; } break; @@ -232,7 +234,7 @@ void _stdcall LoadConfiguration(void) // Avoid any specific file access here f CJSonItem* Params = EnsureJsnParam(jsObject, "Parameters", &Root); LogMode = EnsureJsnParam((int)LogMode, "LogMode", Params)->GetValInt(); // lmCons;// IPCSize = EnsureJsnParam(IPCSize, "IPCSize", Params)->GetValInt(); - SuspMainThAtLd = EnsureJsnParam(SuspMainThAtLd, "SuspMainThAtLd", Params)->GetValBol(); + SuspWaitAttachLd = EnsureJsnParam(SuspWaitAttachLd, "SuspWaitAttachLd", Params)->GetValBol(); //HideDllProxy = EnsureJsnParam(HideDllProxy, "HideDllProxy", Params)->GetValBol(); //HideDllProxyDsk = EnsureJsnParam(HideDllProxyDsk, "HideDllProxyDsk", Params)->GetValBol(); AllowEjectOnDetach = EnsureJsnParam(AllowEjectOnDetach, "AllowEjectOnDetach", Params)->GetValBol(); @@ -267,7 +269,7 @@ void _stdcall SaveConfiguration(int BinFmt) CJSonItem* Params = EnsureJsnParam(jsObject, "Parameters", &Root); LogMode = SetJsnParamValue((int)LogMode, "LogMode", Params)->GetValInt(); IPCSize = SetJsnParamValue(IPCSize, "IPCSize", Params)->GetValInt(); - SuspMainThAtLd = SetJsnParamValue(SuspMainThAtLd, "SuspMainThAtLd", Params)->GetValBol(); + SuspWaitAttachLd = SetJsnParamValue(SuspWaitAttachLd, "SuspWaitAttachLd", Params)->GetValBol(); //HideDllProxy = SetJsnParamValue(HideDllProxy, "HideDllProxy", Params)->GetValBol(); //HideDllProxyDsk = SetJsnParamValue(HideDllProxyDsk, "HideDllProxyDsk", Params)->GetValBol(); AllowEjectOnDetach = SetJsnParamValue(AllowEjectOnDetach, "AllowEjectOnDetach", Params)->GetValBol(); @@ -293,7 +295,7 @@ void _stdcall SaveConfiguration(int BinFmt) bool _stdcall InitApplication(void) { DBGMSG("Enter"); - if(GhDbg::CDbgClient::IsExistForID(NtCurrentProcessId())){DBGMSG("Already injected!"); return false;} + if(NGhDbg::CDbgClient::IsExistForID(NtCurrentProcessId())){DBGMSG("Already injected!"); return false;} /*#ifdef _AMD64_ HookRtlRestoreContext.SetHook("RtlRestoreContext","ntdll.dll"); // NtContinue @@ -301,19 +303,19 @@ bool _stdcall InitApplication(void) HookKiUserExceptionDispatcher.SetHook("KiUserExceptionDispatcher","ntdll.dll"); HookLdrInitializeThunk.SetHook("LdrInitializeThunk","ntdll.dll"); */ - Dbg = new ((void*)&ArrDbgClient) GhDbg::CDbgClient(ThisLibBase); + Dbg = new ((void*)&ArrDbgClient) NGhDbg::CDbgClient(ThisLibBase); Dbg->UsrReqCallback = &DbgUsrReqCallback; ////////// LoadConfiguration(); DBGMSG("IPC created: IPCSize=%u",IPCSize); - PVOID pNtDll = GetNtDllBaseFast(); + PVOID pNtDll = NPEFMT::GetNtDllBaseFast(); DBGMSG("NtDllBase: %p",pNtDll); - HookNtMapViewOfSection.SetHook(GetProcAddr(pNtDll, ctENCSA("NtMapViewOfSection"))); // For DLLs list - HookNtUnmapViewOfSection.SetHook(GetProcAddr(pNtDll, ctENCSA("NtUnmapViewOfSection"))); // For DLLs list - HookNtGetContextThread.SetHook(GetProcAddr(pNtDll, ctENCSA("NtGetContextThread"))); // For DRx hiding - HookNtSetContextThread.SetHook(GetProcAddr(pNtDll, ctENCSA("NtSetContextThread"))); // For DRx hiding - HookNtTerminateThread.SetHook(GetProcAddr(pNtDll, ctENCSA("NtTerminateThread"))); // For Thread list update - HookNtTerminateProcess.SetHook(GetProcAddr(pNtDll, ctENCSA("NtTerminateProcess"))); // Importand for latest Windows 10 bugs - HookNtContinue.SetHook(GetProcAddr(pNtDll, ctENCSA("NtContinue"))); // For Thread list update // TODO: Replace with LdrInitializeThunk hook + HookNtMapViewOfSection.SetHook(NPEFMT::GetProcAddr(pNtDll, ctENCSA("NtMapViewOfSection"))); // For DLLs list + HookNtUnmapViewOfSection.SetHook(NPEFMT::GetProcAddr(pNtDll, ctENCSA("NtUnmapViewOfSection"))); // For DLLs list + HookNtGetContextThread.SetHook(NPEFMT::GetProcAddr(pNtDll, ctENCSA("NtGetContextThread"))); // For DRx hiding + HookNtSetContextThread.SetHook(NPEFMT::GetProcAddr(pNtDll, ctENCSA("NtSetContextThread"))); // For DRx hiding + HookNtTerminateThread.SetHook(NPEFMT::GetProcAddr(pNtDll, ctENCSA("NtTerminateThread"))); // For Thread list update + HookNtTerminateProcess.SetHook(NPEFMT::GetProcAddr(pNtDll, ctENCSA("NtTerminateProcess"))); // Importand for latest Windows 10 bugs + HookNtContinue.SetHook(NPEFMT::GetProcAddr(pNtDll, ctENCSA("NtContinue"))); // For Thread list update // TODO: Replace with LdrInitializeThunk hook ExpDispHook.SetHook(ProcExpDispBefore, ProcExpDispAfter); // Debugger core function LdrpInitHook.SetHook(ProcLdrpInitialize); // Optional: HookNtContinue can do the job but threads will be reported after initialization DBGMSG("Hooks set: hIpcTh=%p, MainThId=%u",hIpcTh, MainThId); @@ -339,21 +341,21 @@ void _stdcall UnInitApplication(void) DBGMSG("Hooks removed"); } //------------------------------------------------------------------------------------ -int _fastcall DbgUsrReqCallback(ShMem::CMessageIPC::SMsgHdr* Req, PVOID ArgA, UINT ArgB) +int _fastcall DbgUsrReqCallback(NShMem::CMessageIPC::SMsgHdr* Req, PVOID ArgA, UINT ArgB) { - if(Req->MsgID == GhDbg::miDbgGetConfigs) + if(Req->MsgID == NGhDbg::miDbgGetConfigs) { - ShMem::CArgPack<>* apo = (ShMem::CArgPack<>*)ArgA; -// apo->PushArgEx(HideDllProxy, "Hide Proxy DLL (After Restart)", GhDbg::CDbgClient::MakeCfgItemID(++ArgB,GhDbg::dtBool)); -// apo->PushArgEx(HideDllProxyDsk, "Hide Proxy DLL on Disk (After Restart)", GhDbg::CDbgClient::MakeCfgItemID(++ArgB,GhDbg::dtBool)); - if(!ModInjFlags)apo->PushArgEx(AllowEjectOnDetach, ctENCSA("Allow Eject On Detach"), GhDbg::CDbgClient::MakeCfgItemID(++ArgB,GhDbg::dtBool)); - if(!ModInjFlags){bool Nons = false; apo->PushArgEx(Nons, ctENCSA("Eject"), GhDbg::CDbgClient::MakeCfgItemID(++ArgB,GhDbg::dtBool));} + NShMem::CArgPack<>* apo = (NShMem::CArgPack<>*)ArgA; +// apo->PushArgEx(HideDllProxy, "Hide Proxy DLL (After Restart)", NGhDbg::CDbgClient::MakeCfgItemID(++ArgB,NGhDbg::dtBool)); +// apo->PushArgEx(HideDllProxyDsk, "Hide Proxy DLL on Disk (After Restart)", NGhDbg::CDbgClient::MakeCfgItemID(++ArgB,GhDbg::dtBool)); + if(!ModInjFlags)apo->PushArgEx(AllowEjectOnDetach, ctENCSA("Allow Eject On Detach"), NGhDbg::CDbgClient::MakeCfgItemID(++ArgB,NGhDbg::dtBool)); + if(!ModInjFlags){bool Nons = false; apo->PushArgEx(Nons, ctENCSA("Eject"), NGhDbg::CDbgClient::MakeCfgItemID(++ArgB,NGhDbg::dtBool));} return ArgB; } - if(Req->MsgID == GhDbg::miDbgSetConfigs) + if(Req->MsgID == NGhDbg::miDbgSetConfigs) { UINT CfgIdx = 0; - UINT Type = GhDbg::CDbgClient::ReadCfgItemID(ArgB, &CfgIdx); + UINT Type = NGhDbg::CDbgClient::ReadCfgItemID(ArgB, &CfgIdx); if(ArgA) { switch(CfgIdx) // New Process Injection @@ -373,7 +375,7 @@ int _fastcall DbgUsrReqCallback(ShMem::CMessageIPC::SMsgHdr* Req, PVOID ArgA, UI DBGMSG("Ejecting by user!"); UnInitApplication(); DBGMSG("Uninit done. Unmapping..."); - NtTerminateThread(NtCurrentThread, 0); //// InjLdr::UnmapAndTerminateSelf(ThisLibBase); // TODO: Self unmap or deallocate + NtTerminateThread(NtCurrentThread, 0); //// NInjLdr::UnmapAndTerminateSelf(ThisLibBase); // TODO: Self unmap or deallocate } break; } @@ -381,14 +383,14 @@ int _fastcall DbgUsrReqCallback(ShMem::CMessageIPC::SMsgHdr* Req, PVOID ArgA, UI SaveConfiguration(); return 0; } - if(Req->MsgID == GhDbg::miDbgDetachNtfy) + if(Req->MsgID == NGhDbg::miDbgDetachNtfy) { if(AllowEjectOnDetach && !ModInjFlags) { DBGMSG("Ejecting on Detach!"); UnInitApplication(); DBGMSG("Uninit done. Unmapping..."); - NtTerminateThread(NtCurrentThread, 0); //// InjLdr::UnmapAndTerminateSelf(ThisLibBase); // TODO: Self unmap or deallocate + NtTerminateThread(NtCurrentThread, 0); //// NInjLdr::UnmapAndTerminateSelf(ThisLibBase); // TODO: Self unmap or deallocate } } return 0; @@ -431,7 +433,7 @@ void NTAPI ProcLdrInitializeThunk(PVOID ArgA, PVOID ArgB, PVOID ArgC, PVOID ArgD void _stdcall ProcLdrpInitialize(volatile PCONTEXT Ctx, volatile PVOID NtDllBase) { DBGMSG("RetAddr=%p, Ctx=%p, NtDllBase=%p",_ReturnAddress(),Ctx,NtDllBase); -// if(Dbg && Dbg->IsActive()){LastThID = NtCurrentThreadId(); Dbg->TryAddCurrThread();} // LastThID prevents TryAddCurrThread from ProcNtContinue + if(Dbg && Dbg->IsActive() && (SuspWaitAttachLd || Dbg->IsDbgAttached())){LastThID = NtCurrentThreadId(); Dbg->TryAddCurrThread();} // LastThID prevents TryAddCurrThread from ProcNtContinue } //------------------------------------------------------------------------------------ /* x64 @@ -452,7 +454,7 @@ bool _cdecl ProcExpDispBefore(volatile PVOID ArgA, volatile PVOID ArgB, volatile { // DBGMSG("Code=%08X, Addr=%p, FCtx=%08X",((PEXCEPTION_RECORD)ArgA)->ExceptionCode, ((PEXCEPTION_RECORD)ArgA)->ExceptionAddress, ((PCONTEXT)ArgB)->ContextFlags); DWORD ThID = LastExcThID = NtCurrentThreadId(); - if(!Dbg || !Dbg->IsActive() || Dbg->IsDbgThreadID(ThID))return true; + if(!Dbg || !Dbg->IsActive() || Dbg->IsDbgThreadID(ThID) || !(SuspWaitAttachLd || Dbg->IsDbgAttached()))return true; if(Dbg->HandleException(ThID, (PEXCEPTION_RECORD)ArgA, (PCONTEXT)ArgB)){RetVal = (PVOID)TRUE; /*DBGMSG("Handled!");*/ return false;} // Handled by a debugger if(!Dbg->HideDbgState)return true; @@ -483,10 +485,10 @@ bool _cdecl ProcExpDispAfter(volatile PVOID ArgA, volatile PVOID ArgB, volatile NTSTATUS NTAPI ProcNtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) // NOTE: A detectable hook! { NTSTATUS res = HookNtMapViewOfSection.OrigProc(SectionHandle,ProcessHandle,BaseAddress,ZeroBits,CommitSize,SectionOffset,ViewSize,InheritDisposition,AllocationType,Win32Protect); // May return STATUS_IMAGE_NOT_AT_BASE - if((res >= 0) && BaseAddress && *BaseAddress && ViewSize && *ViewSize) // && Dbg && Dbg->IsActive() && GhDbg::IsCurrentProcess(ProcessHandle) && IsValidPEHeaderBlk(*BaseAddress, Dbg->IsMemAvailable(*BaseAddress))) // Try to get the module`s name? + if((res >= 0) && BaseAddress && *BaseAddress && ViewSize && *ViewSize) { DBGMSG("Module: Status=%08X, SectionHandle=%p, BaseAddress=%p, ViewSize=%08X, AllocationType=%08X, Win32Protect=%08X",res,SectionHandle,*BaseAddress,*ViewSize,AllocationType,Win32Protect); - if(Dbg && Dbg->IsActive() && (Win32Protect == PAGE_READWRITE) && NNTDLL::IsCurrentProcess(ProcessHandle) && IsValidPEHeaderBlk(*BaseAddress, Dbg->IsMemAvailable(*BaseAddress))) // <<< Duplicate mapping causes BPs to be set again and never removed if this module is already loaded(If this is not caused by LdrLoadDll)! + if(Dbg && Dbg->IsActive() && (Win32Protect == PAGE_READWRITE) && (SuspWaitAttachLd || Dbg->IsDbgAttached()) && NNTDLL::IsCurrentProcess(ProcessHandle) && NPEFMT::IsValidPEHeaderBlk(*BaseAddress, Dbg->IsMemAvailable(*BaseAddress))) // <<< Duplicate mapping causes BPs to be set again and never removed if this module is already loaded(If this is not caused by LdrLoadDll)! { Dbg->Report_LOAD_DLL_DEBUG_INFO(NtCurrentTeb(), *BaseAddress); // NOTE: This is done before PE configuration by LdrLoadDll // Events:TLS Callbacks must be disabled or xg4dbg will crash in 'cbLoadDll{ auto modInfo = ModInfoFromAddr(duint(base));}' (because it won`t check for NULL) if this mapping will be unmapped too soon } @@ -497,10 +499,10 @@ NTSTATUS NTAPI ProcNtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle //------------------------------------------------------------------------------------ NTSTATUS NTAPI ProcNtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) // NOTE: A detectable hook! { - if(NNTDLL::IsCurrentProcess(ProcessHandle) && IsValidPEHeaderBlk(BaseAddress, Dbg->IsMemAvailable(BaseAddress))) + if(NNTDLL::IsCurrentProcess(ProcessHandle) && NPEFMT::IsValidPEHeaderBlk(BaseAddress, Dbg->IsMemAvailable(BaseAddress))) { DBGMSG("BaseAddress=%p",BaseAddress); - if(Dbg && Dbg->IsActive() && Dbg->IsOtherConnections())Dbg->Report_UNLOAD_DLL_DEBUG_EVENT(NtCurrentTeb(), BaseAddress); + if(Dbg && Dbg->IsActive() && (SuspWaitAttachLd || Dbg->IsDbgAttached()) && Dbg->IsOtherConnections())Dbg->Report_UNLOAD_DLL_DEBUG_EVENT(NtCurrentTeb(), BaseAddress); } return HookNtUnmapViewOfSection.OrigProc(ProcessHandle,BaseAddress); } @@ -515,7 +517,7 @@ NTSTATUS NTAPI ProcNtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) NTSTATUS NTAPI ProcNtContinue(PCONTEXT ContextRecord, BOOLEAN TestAlert) // NOTE: A detectable hook! // NOTE: Too much overhead of exception processing with this(Twice 'GetThread' on breakpoints) { DWORD CurrThID = NtCurrentThreadId(); - if(Dbg && (CurrThID != LastThID) && (CurrThID != LastExcThID) && Dbg->IsActive()){LastThID=CurrThID; Dbg->TryAddCurrThread();} // Report this thread if it is not in list yet + if(Dbg && (CurrThID != LastThID) && (CurrThID != LastExcThID) && Dbg->IsActive() && (SuspWaitAttachLd || Dbg->IsDbgAttached())){LastThID=CurrThID; Dbg->TryAddCurrThread();} // Report this thread if it is not in list yet return HookNtContinue.OrigProc(ContextRecord, TestAlert); // Will not return } //------------------------------------------------------------------------------------ @@ -544,7 +546,7 @@ NTSTATUS NTAPI ProcNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus) DBGMSG("ProxyDll Restored: %s", (LPSTR)&DllPath); } } */ - if(Dbg && Dbg->IsActive() && (!ProcessHandle || (ProcessHandle == NtCurrentProcess))) + if(Dbg && Dbg->IsActive() && (!ProcessHandle || (ProcessHandle == NtCurrentProcess)) && (SuspWaitAttachLd || Dbg->IsDbgAttached())) { if(!ProcessHandle)Dbg->Report_EXIT_PROCESS_DEBUG_EVENT(NtCurrentTeb(),0); // (ProcessHandle==NULL) will terminate all other threads, including GhostDbg else UnInitApplication(); // Do not report EXIT_PROCESS_DEBUG_EVENT second time! @@ -558,7 +560,7 @@ NTSTATUS NTAPI ProcNtTerminateThread(HANDLE ThreadHandle, NTSTATUS ExitStatus) { PTEB teb = NULL; DBGMSG("ThreadHandle=%p",ThreadHandle); - if(Dbg && Dbg->IsActive() && (teb=NNTDLL::GetCurrProcessTEB(ThreadHandle))){ Dbg->Report_EXIT_THREAD_DEBUG_EVENT(teb,ExitStatus); } + if(Dbg && Dbg->IsActive() && (SuspWaitAttachLd || Dbg->IsDbgAttached()) && (teb=NNTDLL::GetCurrProcessTEB(ThreadHandle))){ Dbg->Report_EXIT_THREAD_DEBUG_EVENT(teb,ExitStatus); } DBGMSG("Terminating: %p, %u",teb,(teb?(UINT)teb->ClientId.UniqueThread:0)); return HookNtTerminateThread.OrigProc(ThreadHandle, ExitStatus); // TODO: Just call our own NtTerminateThread } @@ -567,14 +569,14 @@ NTSTATUS NTAPI ProcNtGetContextThread(HANDLE ThreadHandle, PCONTEXT Context) { ULONG ThID; NTSTATUS res = HookNtGetContextThread.OrigProc(ThreadHandle, Context); // TODO: Just call our own NtGetContextThread(What if it is hooked by someone)? - if(!res && Dbg && Dbg->IsActive() && Dbg->HideDbgState && (ThID=NNTDLL::GetCurrProcessThreadID(ThreadHandle)))Dbg->DebugThreadLoad(ThID, Context); // Load into CONTEXT a previously saved DRx instead of currently read ones + if(!res && Dbg && Dbg->IsActive() && Dbg->HideDbgState && (SuspWaitAttachLd || Dbg->IsDbgAttached()) && (ThID=NNTDLL::GetCurrProcessThreadID(ThreadHandle)))Dbg->DebugThreadLoad(ThID, Context); // Load into CONTEXT a previously saved DRx instead of currently read ones return res; } //------------------------------------------------------------------------------------ NTSTATUS NTAPI ProcNtSetContextThread(HANDLE ThreadHandle, PCONTEXT Context) // NOTE: A detectable hook! // Do not let DRx to be changed by this { ULONG ThID; - if(!Dbg || !Dbg->IsActive() || !Dbg->HideDbgState || !(ThID=NNTDLL::GetCurrProcessThreadID(ThreadHandle)))return HookNtSetContextThread.OrigProc(ThreadHandle, Context); // TODO: Just call our own NtSetContextThread + if(!Dbg || !Dbg->IsActive() || !Dbg->HideDbgState || !(SuspWaitAttachLd || Dbg->IsDbgAttached()) || !(ThID=NNTDLL::GetCurrProcessThreadID(ThreadHandle)))return HookNtSetContextThread.OrigProc(ThreadHandle, Context); // TODO: Just call our own NtSetContextThread CONTEXT FCtx; // Copy of CONTEXT where CONTEXT_DEBUG_REGISTERS is removed (CONTEXT_DEBUG_REGISTERS must be preserved in original Context in case it may be checked) Dbg->DebugThreadSave(ThID, Context); // Save any magic numbers which may be stored in debug registers to detect a debugger memcpy(&FCtx,Context,sizeof(CONTEXT)); diff --git a/InjectLib/InjectDll.h b/InjectLib/InjectDll.h index 8fcc6cc..d337049 100644 --- a/InjectLib/InjectDll.h +++ b/InjectLib/InjectDll.h @@ -14,15 +14,6 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -//#include -#include "Utils.h" -#include "UniHook.hpp" -#include "json.h" -#include "NtDllEx.hpp" -#include "CompileTime.hpp" -#include "InjDllLdr.hpp" -#include "GhostDbg.hpp" #include "..\..\GlobalInjector\GInjer\LoaderCode.h" //==================================================================================== @@ -34,7 +25,7 @@ void _stdcall LoadConfiguration(void); void _stdcall SaveConfiguration(int BinFmt=-1); void _stdcall UnInitApplication(void); bool _stdcall InitApplication(void); -int _fastcall DbgUsrReqCallback(ShMem::CMessageIPC::SMsgHdr* Req, PVOID ArgA, UINT ArgB); +int _fastcall DbgUsrReqCallback(NShMem::CMessageIPC::SMsgHdr* Req, PVOID ArgA, UINT ArgB); //------------------------------------------------------------------------------------ bool _cdecl ProcExpDispBefore(volatile PVOID ArgA, volatile PVOID ArgB, volatile PVOID ArgC, volatile PVOID ArgD, volatile PVOID RetVal); bool _cdecl ProcExpDispAfter(volatile PVOID ArgA, volatile PVOID ArgB, volatile PVOID ArgC, volatile PVOID ArgD, volatile PVOID RetVal); diff --git a/InjectLib/InjectDll.vcxproj b/InjectLib/InjectDll.vcxproj index d3c91f4..62786d1 100644 --- a/InjectLib/InjectDll.vcxproj +++ b/InjectLib/InjectDll.vcxproj @@ -359,10 +359,11 @@ copy /Y "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)BUILD\RELEASE\$(Solu + - + - + diff --git a/InjectLib/InjectDll.vcxproj.filters b/InjectLib/InjectDll.vcxproj.filters index 49aacea..4ef285b 100644 --- a/InjectLib/InjectDll.vcxproj.filters +++ b/InjectLib/InjectDll.vcxproj.filters @@ -35,12 +35,6 @@ Common - - Common - - - Common - Common @@ -68,5 +62,14 @@ Common + + Common + + + Common + + + Common + \ No newline at end of file diff --git a/NOTES.txt b/NOTES.txt index 3134a17..bb58ab6 100644 --- a/NOTES.txt +++ b/NOTES.txt @@ -32,9 +32,9 @@ TODO: IPC SRW locks Enable Config files IDA compatibility - Fix NativeCreateThread on latest Windows 10 Fix extreme slowness on Windows XP (Sync problem? Fix for GhostDrv) // https://communities.vmware.com/thread/466749 GInjer compatibility (Especially WOW64 debugging) + Wait for attach and ignore events until that (GInjer, requires config) ISSUES: Software breakpoints is very dangerous to set if not all threads are suspended on a Debug Event diff --git a/README.md b/README.md new file mode 100644 index 0000000..3ab6daa --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ + + + + +

+

GhostDbg

+

+ diff --git a/README.txt b/README.txt deleted file mode 100644 index 7247bf8..0000000 --- a/README.txt +++ /dev/null @@ -1,13 +0,0 @@ - -Noninvasive debugging plugin for X64Dbg - -You can rename injlib.dll as version, cryptsp, winspool and place it in some application`s directory before starting it. -X64DBG->Options->Preferences->Events:TLS Callbacks must be unchecked. -Limitations: You should not set any breakpoints to a WinAPI that is used by a debugger client itself. - -Have fun :) - - ----------------------------------- -Author: Vicshann -Email: vicshann@gmail.com diff --git a/XDbgPlugin/MainIcon.ico b/XDbgPlugin/MainIcon.ico new file mode 100644 index 0000000..af3b004 Binary files /dev/null and b/XDbgPlugin/MainIcon.ico differ diff --git a/XDbgPlugin/Resources.rc b/XDbgPlugin/Resources.rc index ef3c3c0..d426b2e 100644 --- a/XDbgPlugin/Resources.rc +++ b/XDbgPlugin/Resources.rc @@ -7,6 +7,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT #pragma code_page(1251) #endif //_WIN32 +1 ICON "MainIcon.ico" 5 ICON "LogoIcon.ico" MAINICON RCDATA "MainIcon.png" // ICON InjLib RCDATA INJLIBPATH diff --git a/XDbgPlugin/XDbgPlugin.cpp b/XDbgPlugin/XDbgPlugin.cpp index ce90046..4ba079d 100644 --- a/XDbgPlugin/XDbgPlugin.cpp +++ b/XDbgPlugin/XDbgPlugin.cpp @@ -19,8 +19,8 @@ #pragma comment(linker,"/NODEFAULTLIB") -typedef ShMem SHM; -typedef GhDbg XNI; +typedef NShMem SHM; +typedef NGhDbg XNI; // ---------- SETTINGS ------------------ bool PLogOnly = false; // Just log usage of Debug API @@ -28,7 +28,7 @@ bool PEnabled = false; // Enable the GhostDbg plugin bool AllowInject = true; // Allow to load inject DLL into a target process(Attach). Else only processes with already injected GhostDbg DLLs will be visible bool AllowInjNew = true; // Allow to load inject DLL into a target process(Create). bool SuspendProc = true; // It is safer to keep a target process suspended while IPC and GhostDbg Client initializing but some timeouts may be detected -UINT InjFlags = InjLdr::mfInjMap|InjLdr::mfRunRMTH|InjLdr::mfRawRMTH; +UINT InjFlags = NInjLdr::mfInjMap|NInjLdr::mfRunRMTH|NInjLdr::mfRawRMTH; UINT WaitForInj = 3000; //--------------------------------------- @@ -94,7 +94,7 @@ wchar_t WorkFolder[MAX_PATH]; //=========================================================================== BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ReasonCall, LPVOID lpReserved) -{ +{ switch (ReasonCall) { case DLL_PROCESS_ATTACH: @@ -110,7 +110,7 @@ BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ReasonCall, LPVOID lpReserved) NSTR::StrCopy(CfgFilePath, WorkFolder); NSTR::StrCopy(GetFileExt(CfgFilePath), L"ini"); - LoadConfiguration(); + LoadConfiguration(); if(LogMode & lmCons){AllocConsole();/*SetWinConsoleSizes(1000, 500, 1000, 500);*/} LOGMSG("Starting up... (Time=%016llX), Owner='%ls'", SysTimeToTime64(NNTDLL::GetSystemTime()), &StartUpDir); TrimFilePath(StartUpDir); @@ -131,7 +131,7 @@ BOOL APIENTRY DLLMain(HMODULE hModule, DWORD ReasonCall, LPVOID lpReserved) } //==================================================================================== void _stdcall LoadConfiguration(void) -{ +{ LogMode = INIRefreshValueInt(CFGSECNAME, L"LogMode", LogMode, CfgFilePath); PLogOnly = INIRefreshValueInt(CFGSECNAME, L"PLogOnly", PLogOnly, CfgFilePath); PEnabled = INIRefreshValueInt(CFGSECNAME, L"PEnabled", PEnabled, CfgFilePath); @@ -140,12 +140,15 @@ void _stdcall LoadConfiguration(void) SuspendProc = INIRefreshValueInt(CFGSECNAME, L"SuspendProc", SuspendProc, CfgFilePath); InjFlags = INIRefreshValueInt(CFGSECNAME, L"InjectFlags", InjFlags, CfgFilePath); WaitForInj = INIRefreshValueInt(CFGSECNAME, L"WaitForInj", WaitForInj, CfgFilePath); - - PVOID pNtDll = GetNtDllBaseFast(); + + LOGMSG("Initializing..."); + PVOID pNtDll = NPEFMT::GetNtDllBaseFast(); + LOGMSG("SystemNtDllBase: %p", pNtDll); NtDllSize = GetRealModuleSize(pNtDll); NtDllBase = VirtualAlloc(NULL,NtDllSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE); - memcpy(NtDllBase,pNtDll,NtDllSize); - LOGMSG("Clean copy of NtDll: %p", NtDllBase); + LOGMSG("CopyNtDllBase=%p, NtDllSize=%08X", NtDllBase, NtDllSize); + CopyValidModuleMem(pNtDll, NtDllBase, NtDllSize); // On Win7 x64 some regions of ntdll.dll are in reserved state + LOGMSG("Done"); } //------------------------------------------------------------------------------------ void _stdcall SaveConfiguration(void) @@ -190,8 +193,8 @@ void _cdecl MenuHandler(CBTYPE Type, PLUG_CB_MENUENTRY *info) SaveConfiguration(); break; case MENU_ID_USERAWTHREADS: - if(InjFlags & InjLdr::mfRawRMTH)InjFlags &= ~InjLdr::mfRawRMTH; - else InjFlags |= InjLdr::mfRawRMTH; + if(InjFlags & NInjLdr::mfRawRMTH)InjFlags &= ~NInjLdr::mfRawRMTH; + else InjFlags |= NInjLdr::mfRawRMTH; SaveConfiguration(); break; case MENU_ID_ABOUT: @@ -274,7 +277,7 @@ extern "C" __declspec(dllexport) void _cdecl plugsetup(PLUG_SETUPSTRUCT* setupSt plugin_menuentrysetchecked(PluginHandle,MENU_ID_CHK_CANINJ,AllowInject); plugin_menuentrysetchecked(PluginHandle,MENU_ID_CHK_CANINJNEW,AllowInjNew); plugin_menuentrysetchecked(PluginHandle,MENU_ID_SUSPPROCESS,SuspendProc); - plugin_menuentrysetchecked(PluginHandle,MENU_ID_USERAWTHREADS,InjFlags & InjLdr::mfRawRMTH); + plugin_menuentrysetchecked(PluginHandle,MENU_ID_USERAWTHREADS,InjFlags & NInjLdr::mfRawRMTH); ICONDATA ico; UINT ResSize = 0; @@ -418,7 +421,7 @@ int _stdcall InjectProcess(HANDLE hProcess, DWORD ProcessID) { CArr DllData; wchar_t DllPath[MAX_PATH]; - UINT Flags = InjFlags|InjLdr::mfRawMod|fmCryHdr|fmCryImp|fmCryExp|fmCryRes; // TODO: Inject method to cfg (Separated) + UINT Flags = InjFlags|NInjLdr::mfRawMod|NPEFMT::fmCryHdr|NPEFMT::fmCryImp|NPEFMT::fmCryExp|NPEFMT::fmCryRes; // TODO: Inject method to cfg (Separated) UINT ResSize = 0; PVOID InjLib = NULL; NSTR::StrCopy(DllPath, StartUpDir); @@ -438,7 +441,7 @@ int _stdcall InjectProcess(HANDLE hProcess, DWORD ProcessID) else InjLib = GetResource(hInst, "InjLib", RT_RCDATA, &ResSize); if(!InjLib || !ResSize){DBGMSG("No InjLib found!"); return -1;} bool POpened = (hProcess == NULL); - if(POpened)hProcess = InjLdr::OpenRemoteProcess(ProcessID, Flags, SuspendProc); + if(POpened)hProcess = NInjLdr::OpenRemoteProcess(ProcessID, Flags, SuspendProc); if(!hProcess)return -2; if(SuspendProc) { @@ -450,8 +453,8 @@ int _stdcall InjectProcess(HANDLE hProcess, DWORD ProcessID) } else hLstProc = hProcess; } - if(!POpened && NNTDLL::IsWinXPOrOlder())Flags &= ~InjLdr::mfRawRMTH; // On Windows XP this Csr unfriendly thread will catch a process initialization APC! // A DebugApi remote thread will also catch this APC and DebugApi threas is also not registered with Csr // On latest Win10 raw threads can`t be injected in notepad.exe (Access Denied) - int res = InjLdr::InjModuleIntoProcessAndExec(hProcess, InjLib, ResSize, Flags|InjLdr::mfResSyscall, 3, NULL, NULL, NtDllBase, 0x10000); // mfResSyscall is required to avoid self interception // Only .text(Data merged), .bss and .rdata + if(!POpened && NNTDLL::IsWinXPOrOlder())Flags &= ~NInjLdr::mfRawRMTH; // On Windows XP this Csr unfriendly thread will catch a process initialization APC! // A DebugApi remote thread will also catch this APC and DebugApi threas is also not registered with Csr // On latest Win10 raw threads can`t be injected in notepad.exe (Access Denied) + int res = NInjLdr::InjModuleIntoProcessAndExec(hProcess, InjLib, ResSize, Flags|NInjLdr::mfResSyscall, 3, NULL, NULL, NtDllBase, 0x10000); // mfResSyscall is required to avoid self interception // Only .text(Data merged), .bss and .rdata if(POpened && !SuspendProc)CloseHandle(hProcess); // Close after OpenRemoteProcess if(res < 0){DBGMSG("InjModuleIntoProcessAndExec failed with %i",res); if(SuspendProc)NtResumeProcess(hProcess); return -3;} // Cannot terminate without a specific permission for(int ctr=WaitForInj;ctr > 0;ctr-=100) diff --git a/XDbgPlugin/XDbgPlugin.h b/XDbgPlugin/XDbgPlugin.h index d657cf5..010aed2 100644 --- a/XDbgPlugin/XDbgPlugin.h +++ b/XDbgPlugin/XDbgPlugin.h @@ -14,12 +14,7 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include "Utils.h" -#include "UniHook.hpp" -#include "NtDllEx.hpp" -#include "GhostDbg.hpp" -#include "InjDllLdr.hpp" +#include "Common.hpp" //==================================================================================== #define CFGSECNAME L"Parameters" diff --git a/XDbgPlugin/XDbgPlugin.vcxproj b/XDbgPlugin/XDbgPlugin.vcxproj index a057d6f..c821095 100644 --- a/XDbgPlugin/XDbgPlugin.vcxproj +++ b/XDbgPlugin/XDbgPlugin.vcxproj @@ -352,8 +352,9 @@ copy /Y "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)BUILD\RELEASE\$(Solu - - + + + diff --git a/XDbgPlugin/XDbgPlugin.vcxproj.filters b/XDbgPlugin/XDbgPlugin.vcxproj.filters index 027f320..c596c47 100644 --- a/XDbgPlugin/XDbgPlugin.vcxproj.filters +++ b/XDbgPlugin/XDbgPlugin.vcxproj.filters @@ -35,18 +35,12 @@ Common - - Common - Common Common - - Common - Common @@ -59,6 +53,15 @@ Common + + Common + + + Common + + + Common +