Posted October 31, 20177 yr Difficulty : 6Language : C++Platform : WindowsOS Version : All Packer / Protector : Safengine Description : hi,friends . I reversed the VMP3.1.2 (build 886) anti debug method and improved this method. You need to use the debugger to bypass his tooltip Screenshot : success screenshot: file : XAntiDebug2.rar Edited October 31, 20177 yr by Xjun
October 31, 20177 yr There seems to be a problem with the screenshot, please can you reattach. Thank you... Ted.
November 6, 20177 yr Author Everyone seems not interested in challenging this process, I decided to open source I improved the anti-debugging method
November 6, 20177 yr Solution Thanks for sharing @Xjun! Quick summary: IsDebuggerPresent CheckRemoteDebuggerPresent CloseHandle(0xDEADC0DE) ZwQueryInformationProcess(ProcessDebugObjectHandle), called correctly crc32 check on direct syscall ZwQueryInformationProcess(ProcessDebugObjectHandle), called with ReturnLength == ProcessInformation I think TitanHide fails on the last check only, is this correct?
November 7, 20177 yr Author 3 hours ago, mrexodia said: Thanks for sharing @Xjun! Quick summary: IsDebuggerPresent CheckRemoteDebuggerPresent CloseHandle(0xDEADC0DE) ZwQueryInformationProcess(ProcessDebugObjectHandle), called correctly crc32 check on direct syscall ZwQueryInformationProcess(ProcessDebugObjectHandle), called with ReturnLength == ProcessInformation I think TitanHide fails on the last check only, is this correct? Yes TitanHide plugin Only the last time will be detected. Other case also have this problem . Let's take a look at the WindowsResearchKernel source code case ProcessDebugObjectHandle : // if (ProcessInformationLength != sizeof (HANDLE)) { return STATUS_INFO_LENGTH_MISMATCH; } st = ObReferenceObjectByHandle (ProcessHandle, PROCESS_QUERY_INFORMATION, PsProcessType, PreviousMode, &Process, NULL); if (!NT_SUCCESS (st)) { return st; } st = DbgkOpenProcessDebugPort (Process, PreviousMode, &DebugPort); if (!NT_SUCCESS (st)) { DebugPort = NULL; } ObDereferenceObject (Process); // // Either of these may cause an access violation. The // exception handler will return access violation as // status code. No further cleanup needs to be done. // try { *(PHANDLE) ProcessInformation = DebugPort; if (ARGUMENT_PRESENT (ReturnLength)) { *ReturnLength = sizeof (HANDLE); } } except (EXCEPTION_EXECUTE_HANDLER) { if (DebugPort != NULL) { ObCloseHandle (DebugPort, PreviousMode); } return GetExceptionCode (); } return st; case ProcessDebugFlags : if (ProcessInformationLength != sizeof (ULONG)) { return STATUS_INFO_LENGTH_MISMATCH; } st = ObReferenceObjectByHandle (ProcessHandle, PROCESS_QUERY_INFORMATION, PsProcessType, PreviousMode, &Process, NULL); if (!NT_SUCCESS (st)) { return st; } try { *(PULONG) ProcessInformation = (Process->Flags&PS_PROCESS_FLAGS_NO_DEBUG_INHERIT)?0:PROCESS_DEBUG_INHERIT; if (ARGUMENT_PRESENT (ReturnLength) ) { *ReturnLength = sizeof(HANDLE); } } except (EXCEPTION_EXECUTE_HANDLER) { st = GetExceptionCode (); } ObDereferenceObject (Process); return st; Look *ReturnLength = sizeof (HANDLE); Many anti debug plug-ins first call the original function, then * (HANDLE *) ProcessInformation = NULL; And windows system is the last *ReturnLength = sizeof (HANDLE);
November 7, 20177 yr Very insightful, thanks a lot! I created issues on ScyllaHide and TitanHide and fixed the implementations of NtQuerySystemInformation and NtQueryInformationProcess, but I don't really know how to handle this for NtQueryObject... Should I just read the size from ReturnLength before overwriting the other buffers and then restore it afterwards or should I do something else? The research kernel has pretty weird handling for invalid ReturnLength addresses so I'm not entirely sure. How did you handle this in your driver? Also, is this actually used in VMProtect or is this your POC?
November 7, 20177 yr NtQueryObject should work the same in principle, it's just a longer function. Taking only ObjectTypeInformation (paying $1 to whoever tells me how to format C++ on this forum): ULONG TempReturnLength; switch( ObjectInformationClass ) { // ...lots of cases... case ObjectTypeInformation: // // Call a local worker routine // Status = ObQueryTypeInfo( ObjectType, (POBJECT_TYPE_INFORMATION)ObjectInformation, ObjectInformationLength, &TempReturnLength ); break; default: // // To get to this point we must have had an object and the // information class is not defined, so we should dereference the // object and return to our user the bad status // ObDereferenceObject( Object ); return( STATUS_INVALID_INFO_CLASS ); } // // Now if the caller asked for a return length we'll set it from // our local copy // try { if (ARGUMENT_PRESENT( ReturnLength ) ) { *ReturnLength = TempReturnLength; } } except( EXCEPTION_EXECUTE_HANDLER ) { // // Fall through, since we cannot undo what we have done. // } ObQueryTypeInfo actually writes to TempReturnLength before doing anything else, but TempReturnLength is a KM-only variable until it is copied back to the caller at the end, so the final order of writes to user mode is the same.
November 10, 20177 yr On 31/10/2017 at 2:44 AM, Xjun said: Difficulty : 6Language : C++Platform : WindowsOS Version : All Packer / Protector : Safengine Description : hi,friends . I reversed the VMP3.1.2 (build 886) anti debug method and improved this method. You need to use the debugger to bypass his tooltip Screenshot : success screenshot: file : XAntiDebug2.rar Thanks for sharing. I would like to comment, that since this version of the protection you created, copies the index of ZwQueryInformationProcess to the SSDT directly from the ntdll.dll file itself, and does not rely on hard coded values, then this is a great improvement over vmprotect's own version which can be easily fooled by changing the windows OS build number to an unsupported random number.. I guess that randomly locating the newly created syscall function in a none fixed memory area is implemented to prevent static patching. Great work.
November 15, 20177 yr Author On 2017/11/8 at 2:49 AM, mrexodia said: Very insightful, thanks a lot! I created issues on ScyllaHide and TitanHide and fixed the implementations of NtQuerySystemInformation and NtQueryInformationProcess, but I don't really know how to handle this for NtQueryObject... Should I just read the size from ReturnLength before overwriting the other buffers and then restore it afterwards or should I do something else? The research kernel has pretty weird handling for invalid ReturnLength addresses so I'm not entirely sure. How did you handle this in your driver? Also, is this actually used in VMProtect or is this your POC? This is what I learned from VMP! In my humble opinion .When you call the original function, you should first save the returnLenght and check whether it is empty. After processing ProcessDebugObjectHandle, restore the returnLenght. The rest is the same.
November 15, 20177 yr My fix commit is here: https://github.com/mrexodia/TitanHide/commit/3bb2af068278ca64d67f4ca109bb56121d946131 I didn't have a VM to test it yet on your exe, but I'm pretty sure it will work
November 16, 20177 yr Author 4 hours ago, mrexodia said: My fix commit is here: https://github.com/mrexodia/TitanHide/commit/3bb2af068278ca64d67f4ca109bb56121d946131 I didn't have a VM to test it yet on your exe, but I'm pretty sure it will work nice . You’re very professional.
Create an account or sign in to comment