July 5, 20241 yr 8 hours ago, The Binary Expert said: 您需要通过以下方式禁用 SharpOD 的选项@Xjun 使用这个插件 @启动 它就像魔法一样。非常感谢您的努力。 顺便问一下,您是如何修改原始 ScyllaHide x64 插件的源代码的? 问候。 肖恩。 https://bbs.kanxue.com/thread-282244.htm
July 7, 20241 yr Author ahhhh! he modified ntdll's export table to trick VMP like the wine_get_version function exists! Very nice trick 3.8.8 is working. Edited July 7, 20241 yr by karan
July 7, 20241 yr On 7/6/2024 at 12:46 AM, kuazi GA said: https://bbs.kanxue.com/thread-282244.htm This method has some shortcomings. If compiling a 32-bit ScyllaHide plugin, although it can bypass VMP's Anti-DeBug on Win7 x64 SP1, it does not work on Win10/11 x64.
July 7, 20241 yr 36 minutes ago, karan said: ahhhh! he modified ntdll's export table to trick VMP like the wine_get_version function exists! Very nice trick 3.8.8 is working. @karan Is this vmprotect a cracked version? Regards. sean.
July 7, 20241 yr Author 10 minutes ago, The Binary Expert said: @karan Is this vmprotect a cracked version? Regards. sean. I bought it because I personally respect VMP developers. He can take my money with him!
July 7, 20241 yr 2 minutes ago, karan said: I bought it because I personally respect VMP developers. He can take my money with him! @karan Okay, I got it. Thanks. Regards.. sean.
July 7, 20241 yr 46 minutes ago, boot said: If compiling a 32-bit ScyllaHide plugin, although it can bypass VMP's Anti-DeBug on Win7 x64 SP1, it does not work on Win10/11 x64. Haven't tried yet but I don't see a (theoretical) reason why it should not work on Win10/11 x64. Can you explain that?
July 7, 20241 yr Author 44 minutes ago, kao said: Haven't tried yet but I don't see a (theoretical) reason why it should not work on Win10/11 x64. Can you explain that? I tested the original author's code and found that it doesn't seem to bypass the protection properly on x86 systems. VMProtect does not appear to search through the entire Export Table to find the desired function. So, I modified the code to overwrite the last export function of ntdll.dll with wine_get_version and then place the original function right after it. As a result, the bypass worked successfully! void AddWineFunctionName(HANDLE hProcess) { BYTE* remote_ntdll = (BYTE*)GetModuleBaseRemote(hProcess, L"ntdll.dll"); if (!remote_ntdll) return; SIZE_T readed = 0; IMAGE_DOS_HEADER dos_header; ReadProcessMemory(hProcess, remote_ntdll, &dos_header, sizeof(IMAGE_DOS_HEADER), &readed); if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) return; IMAGE_NT_HEADERS pe_header; ReadProcessMemory(hProcess, (BYTE*)remote_ntdll + dos_header.e_lfanew, &pe_header, sizeof(IMAGE_NT_HEADERS), &readed); if (pe_header.Signature != IMAGE_NT_SIGNATURE) return; DWORD export_adress = pe_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; if (!export_adress) return; DWORD export_size = pe_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; BYTE* new_export_table = (BYTE*)VirtualAllocEx(hProcess, remote_ntdll + 0x1000000, export_size + 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); IMAGE_EXPORT_DIRECTORY export_directory; ReadProcessMemory(hProcess, remote_ntdll + export_adress, &export_directory, sizeof(IMAGE_EXPORT_DIRECTORY), &readed); BYTE* tmp_table = (BYTE*)malloc(export_size + 0x1000); if (tmp_table == nullptr) return; // Copy functions table BYTE* new_functions_table = new_export_table; ReadProcessMemory(hProcess, remote_ntdll + export_directory.AddressOfFunctions, tmp_table, export_directory.NumberOfFunctions * sizeof(DWORD), &readed); WriteProcessMemory(hProcess, new_functions_table, tmp_table, export_directory.NumberOfFunctions * sizeof(DWORD), &readed); g_log.LogInfo(L"[VMPBypass] new_functions_table: %p", new_functions_table); // Copy ordinal table BYTE* new_ordinal_table = new_functions_table + export_directory.NumberOfFunctions * sizeof(DWORD) + 0x100; ReadProcessMemory(hProcess, remote_ntdll + export_directory.AddressOfNameOrdinals, tmp_table, export_directory.NumberOfNames * sizeof(WORD), &readed); WriteProcessMemory(hProcess, new_ordinal_table, tmp_table, export_directory.NumberOfNames * sizeof(WORD), &readed); g_log.LogInfo(L"[VMPBypass] new_ordinal_table: %p", new_ordinal_table); // Copy name table BYTE* new_name_table = new_ordinal_table + export_directory.NumberOfNames * sizeof(WORD) + 0x100; ReadProcessMemory(hProcess, remote_ntdll + export_directory.AddressOfNames, tmp_table, export_directory.NumberOfNames * sizeof(DWORD), &readed); WriteProcessMemory(hProcess, new_name_table, tmp_table, export_directory.NumberOfNames * sizeof(DWORD), &readed); g_log.LogInfo(L"[VMPBypass] new_name_table: %p", new_name_table); free(tmp_table); tmp_table = nullptr; // Setup new name & name offset BYTE* wine_func_addr = new_name_table + export_directory.NumberOfNames * sizeof(DWORD) + 0x100; WriteProcessMemory(hProcess, wine_func_addr, "wine_get_version\x00", 17, &readed); DWORD wine_func_offset = (DWORD)(wine_func_addr - remote_ntdll); WriteProcessMemory(hProcess, new_name_table + export_directory.NumberOfNames * sizeof(DWORD), &wine_func_offset, 4, &readed); // Set fake ordinal WORD last_ordinal = export_directory.NumberOfNames; WriteProcessMemory(hProcess, new_ordinal_table + export_directory.NumberOfNames * sizeof(WORD), &last_ordinal, 2, &readed); // Get address of GetCurrentTeb function to be placed after the new function BYTE* get_current_teb = reinterpret_cast<BYTE*>(GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCurrentTeb")); DWORD get_current_teb_offset = (DWORD)(get_current_teb - remote_ntdll); // Set new function address (wine_get_version) and GetCurrentTeb function address DWORD new_function_offset = get_current_teb_offset; WriteProcessMemory(hProcess, new_functions_table + export_directory.NumberOfFunctions * sizeof(DWORD), &new_function_offset, 4, &readed); // Setup new directory export_directory.NumberOfNames++; export_directory.NumberOfFunctions++; DWORD name_table_offset = (DWORD)(new_name_table - remote_ntdll); export_directory.AddressOfNames = name_table_offset; DWORD function_table_offset = (DWORD)(new_functions_table - remote_ntdll); export_directory.AddressOfFunctions = function_table_offset; DWORD ordinal_table_offset = (DWORD)(new_ordinal_table - remote_ntdll); export_directory.AddressOfNameOrdinals = ordinal_table_offset; // Change the offset of header data DWORD old_prot; VirtualProtectEx(hProcess, remote_ntdll + export_adress, sizeof(IMAGE_EXPORT_DIRECTORY), PAGE_EXECUTE_READWRITE, &old_prot); WriteProcessMemory(hProcess, remote_ntdll + export_adress, &export_directory, sizeof(IMAGE_EXPORT_DIRECTORY), &readed); VirtualProtectEx(hProcess, remote_ntdll + export_adress, sizeof(IMAGE_EXPORT_DIRECTORY), old_prot, &old_prot); } I confirmed that my Windows 10 version works fine. cheers! ScyllaHide_x86.zip
July 7, 20241 yr 55 minutes ago, karan said: VMProtect does not appear to search through the entire Export Table to find the desired function. That's correct. It does binary search (see the implementation here), as the names in the export table are supposed to be ordered lexically. The code in https://bbs.kanxue.com/thread-282244.htm doesn't take that into account. However, this hasn't changed between Win7/Win10/Win11 - if it worked on one system, it should have worked on all of them.
July 7, 20241 yr I think the issue has to do with ntdll differences between Win7 vs Win10/11. Keep in mind the WinSDK is free to change and there are many times where they don't maintain backwards compatibility on internal APIs, unlike the normal WinAPI
July 8, 20241 yr 10 hours ago, kao said: Win7/Win10/Win11 - if it worked on one system, it should have worked on all of them. I have already conducted testing before, and if you compile the 32-bit plugin according to the original source code provided here (https://bbs.kanxue.com/thread-282244.htm). Original 32-bit (Imperfect Version).zip This plugin is effective on Win7 x64 SP1; But it fails in Win10/11 x64. e.g. VMP_3.8.7_x86_32-bit.vmp.exe Win7 x64 SP1 √ Spoiler Win7_x64_SP1_2024-07-08_114815.mp4 Win10 x64 × Spoiler Win10_x64_2024-07-08_114324.mp4 Win11 x64 × Spoiler Win11_x64_2024-07-08_115629.mp4 By recompiling the 32-bit plugin according to the modified code provided by karan, the above issue has been resolved. The revised and recompiled complete version is now uploaded as follows, and has been tested to be effective in Win7/10/11 x64. ScyllaHide_2024_x86_x64_v0.002.zip
July 13, 20241 yr @boot Could you help me compile the InjectorCLIx64.exe ? Just want to try it with ollydbg 64 ! Thanks Edited July 13, 20241 yr by fReestYler
July 13, 20241 yr 1 hour ago, fReestYler said: InjectorCLIx64.exe Spoiler InjectorCLIx64.exe (1.33 MB)
July 13, 20241 yr 6 hours ago, jackyjask said: @boot do you have IDA8.3 plugin in your collection? I think are available in the forum a nice guy shared already the most useful plugins and also he included them in his repostery in GitHub.
July 13, 20241 yr 11 hours ago, jackyjask said: IDA8.3 plugin IIRC, you can use the generic injector with IDA. Check the docs and let us know, if you test it.. Edited July 13, 20241 yr by kao
July 14, 20241 yr 14 hours ago, RADIOX said: he included them in his repostery in GitHub. yes, exactly, good pointer, found and used
July 14, 20241 yr On 7/7/2024 at 6:58 PM, karan said: I tested the original author's code and found that it doesn't seem to bypass the protection properly on x86 systems. VMProtect does not appear to search through the entire Export Table to find the desired function. So, I modified the code to overwrite the last export function of ntdll.dll with wine_get_version and then place the original function right after it. As a result, the bypass worked successfully! void AddWineFunctionName(HANDLE hProcess) { BYTE* remote_ntdll = (BYTE*)GetModuleBaseRemote(hProcess, L"ntdll.dll"); if (!remote_ntdll) return; SIZE_T readed = 0; IMAGE_DOS_HEADER dos_header; ReadProcessMemory(hProcess, remote_ntdll, &dos_header, sizeof(IMAGE_DOS_HEADER), &readed); if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) return; IMAGE_NT_HEADERS pe_header; ReadProcessMemory(hProcess, (BYTE*)remote_ntdll + dos_header.e_lfanew, &pe_header, sizeof(IMAGE_NT_HEADERS), &readed); if (pe_header.Signature != IMAGE_NT_SIGNATURE) return; DWORD export_adress = pe_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; if (!export_adress) return; DWORD export_size = pe_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; BYTE* new_export_table = (BYTE*)VirtualAllocEx(hProcess, remote_ntdll + 0x1000000, export_size + 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); IMAGE_EXPORT_DIRECTORY export_directory; ReadProcessMemory(hProcess, remote_ntdll + export_adress, &export_directory, sizeof(IMAGE_EXPORT_DIRECTORY), &readed); BYTE* tmp_table = (BYTE*)malloc(export_size + 0x1000); if (tmp_table == nullptr) return; // Copy functions table BYTE* new_functions_table = new_export_table; ReadProcessMemory(hProcess, remote_ntdll + export_directory.AddressOfFunctions, tmp_table, export_directory.NumberOfFunctions * sizeof(DWORD), &readed); WriteProcessMemory(hProcess, new_functions_table, tmp_table, export_directory.NumberOfFunctions * sizeof(DWORD), &readed); g_log.LogInfo(L"[VMPBypass] new_functions_table: %p", new_functions_table); // Copy ordinal table BYTE* new_ordinal_table = new_functions_table + export_directory.NumberOfFunctions * sizeof(DWORD) + 0x100; ReadProcessMemory(hProcess, remote_ntdll + export_directory.AddressOfNameOrdinals, tmp_table, export_directory.NumberOfNames * sizeof(WORD), &readed); WriteProcessMemory(hProcess, new_ordinal_table, tmp_table, export_directory.NumberOfNames * sizeof(WORD), &readed); g_log.LogInfo(L"[VMPBypass] new_ordinal_table: %p", new_ordinal_table); // Copy name table BYTE* new_name_table = new_ordinal_table + export_directory.NumberOfNames * sizeof(WORD) + 0x100; ReadProcessMemory(hProcess, remote_ntdll + export_directory.AddressOfNames, tmp_table, export_directory.NumberOfNames * sizeof(DWORD), &readed); WriteProcessMemory(hProcess, new_name_table, tmp_table, export_directory.NumberOfNames * sizeof(DWORD), &readed); g_log.LogInfo(L"[VMPBypass] new_name_table: %p", new_name_table); free(tmp_table); tmp_table = nullptr; // Setup new name & name offset BYTE* wine_func_addr = new_name_table + export_directory.NumberOfNames * sizeof(DWORD) + 0x100; WriteProcessMemory(hProcess, wine_func_addr, "wine_get_version\x00", 17, &readed); DWORD wine_func_offset = (DWORD)(wine_func_addr - remote_ntdll); WriteProcessMemory(hProcess, new_name_table + export_directory.NumberOfNames * sizeof(DWORD), &wine_func_offset, 4, &readed); // Set fake ordinal WORD last_ordinal = export_directory.NumberOfNames; WriteProcessMemory(hProcess, new_ordinal_table + export_directory.NumberOfNames * sizeof(WORD), &last_ordinal, 2, &readed); // Get address of GetCurrentTeb function to be placed after the new function BYTE* get_current_teb = reinterpret_cast<BYTE*>(GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCurrentTeb")); DWORD get_current_teb_offset = (DWORD)(get_current_teb - remote_ntdll); // Set new function address (wine_get_version) and GetCurrentTeb function address DWORD new_function_offset = get_current_teb_offset; WriteProcessMemory(hProcess, new_functions_table + export_directory.NumberOfFunctions * sizeof(DWORD), &new_function_offset, 4, &readed); // Setup new directory export_directory.NumberOfNames++; export_directory.NumberOfFunctions++; DWORD name_table_offset = (DWORD)(new_name_table - remote_ntdll); export_directory.AddressOfNames = name_table_offset; DWORD function_table_offset = (DWORD)(new_functions_table - remote_ntdll); export_directory.AddressOfFunctions = function_table_offset; DWORD ordinal_table_offset = (DWORD)(new_ordinal_table - remote_ntdll); export_directory.AddressOfNameOrdinals = ordinal_table_offset; // Change the offset of header data DWORD old_prot; VirtualProtectEx(hProcess, remote_ntdll + export_adress, sizeof(IMAGE_EXPORT_DIRECTORY), PAGE_EXECUTE_READWRITE, &old_prot); WriteProcessMemory(hProcess, remote_ntdll + export_adress, &export_directory, sizeof(IMAGE_EXPORT_DIRECTORY), &readed); VirtualProtectEx(hProcess, remote_ntdll + export_adress, sizeof(IMAGE_EXPORT_DIRECTORY), old_prot, &old_prot); } I confirmed that my Windows 10 version works fine. cheers! ScyllaHide_x86.zip 307.15 kB · 16 downloads I don't know coding and understand this code but I see they import some api and try to protect one function which I was protected in my old loader at that times because they have src code of code and can devirtualized with it. I mean after virtualized some function they still virtualized the part of code. @boot would yuo like send one example of vmp latest version with api redirection for the vb please ? Mazotoa daholy😁 TP-Mada. Edited July 14, 20241 yr by TRISTAN Pro Edit some word
July 19, 20241 yr On 7/8/2024 at 12:08 PM, boot said: The revised and recompiled complete version is now uploaded as follows, and has been tested to be effective in Win7/10/11 x64. I tried to rebuild ScyllaHide using some old versions of project code to make it compatible with Windows XP 32-bit/x86. I think XP is a classic OS...
July 21, 20241 yr Hey, I'm new to this. I'm testing this with vmprotected game, it does not show debugger present error but it shows `File corrupted! This program has been manipulated and maybe it's infected by a Virus or cracked. This file won't work anymore` anyone have similar issue?
July 22, 20241 yr Author O~~K.. VMProtect has been updated now! The latest version changed to find the "wine_get_host_version" function instead of "wine_get_version". Edited July 22, 20241 yr by karan
August 9, 20241 yr On 7/8/2024 at 1:08 PM, boot said: I have already conducted testing before, and if you compile the 32-bit plugin according to the original source code provided here (https://bbs.kanxue.com/thread-282244.htm). Original 32-bit (Imperfect Version).zip This plugin is effective on Win7 x64 SP1; But it fails in Win10/11 x64. e.g. VMP_3.8.7_x86_32-bit.vmp.exe 856 kB · 12 downloads Win7 x64 SP1 √ Reveal hidden contents Win7_x64_SP1_2024-07-08_114815.mp4 1.46 MB · 0 downloads Win10 x64 × Reveal hidden contents Win10_x64_2024-07-08_114324.mp4 2.08 MB · 0 downloads Win11 x64 × Reveal hidden contents Win11_x64_2024-07-08_115629.mp4 1.9 MB · 0 downloads By recompiling the 32-bit plugin according to the modified code provided by karan, the above issue has been resolved. The revised and recompiled complete version is now uploaded as follows, and has been tested to be effective in Win7/10/11 x64. ScyllaHide_2024_x86_x64_v0.002.zip 1.77 MB · 52 downloads @boot View this video. Can I debug the vmprotected .net executable with your one? Regards. sean.
October 23, 2024Oct 23 @karan Could you help me compile a 32 bit unpackme with kernel + user mode ? (for the latest version (3.9.1) if it is possible !) Just want to try it with SharpOD v0.6e ! Thanks Edited October 23, 2024Oct 23 by fReestYler
October 25, 2024Oct 25 Author On 10/23/2024 at 11:54 PM, fReestYler said: @karan Could you help me compile a 32 bit unpackme with kernel + user mode ? (for the latest version (3.9.1) if it is possible !) Just want to try it with SharpOD v0.6e ! Thanks Sharp OD is no longer bypassed, I think that have to use TitanHide now. and, Bypassing Anti-Debug using wine-related functions also no longer works. Edited October 25, 2024Oct 25 by karan
October 25, 2024Oct 25 you could build up ScyllaHide plugin with addons mentioned in this topic it does the job
Create an account or sign in to comment