Jump to content
View in the app

A better way to browse. Learn more.

Tuts 4 You

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

8 hours ago, The Binary Expert said:

您需要通过以下方式禁用 SharpOD 的选项@Xjun 使用这个插件

 

屏幕截图-146.png

 

@启动 它就像魔法一样。非常感谢您的努力。

顺便问一下,您是如何修改原始 ScyllaHide x64 插件的源代码的?

问候。

肖恩。

https://bbs.kanxue.com/thread-282244.htm

  • Replies 107
  • Views 40.4k
  • Created
  • Last Reply

Top Posters In This Topic

Most Popular Posts

  • 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 (Imp

  • Support for Win7 x64:  - Confirmed support for Win7 x64 SP1  - Maybe it also supports Win7 x64 SP0 [Olly v1.10 ScyllaHide] Win7 x64 SP1.zip [x32Dbg ScyllaHide] Win7 x64 SP1.zip Supp

  • VMProtect started using Heaven's gate to make it difficult to bypass Usermode Anti-Debug. VMP uses ZwQueryInformationProcess (ProcessWow64Information) to check if the running process is wow64,

Posted Images

  • Author

ahhhh! he modified ntdll's export table to trick VMP like the wine_get_version function exists! Very nice trick :D

 

3.8.8 is working.

 

capture.PNG.023829a87dc9cb1546d71819213ec2e8.PNG

Edited by karan

On 7/6/2024 at 12:46 AM, kuazi GA said:

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.

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 :D

 

3.8.8 is working.

 

capture.PNG.023829a87dc9cb1546d71819213ec2e8.PNG

@karan Is this vmprotect a cracked version?

Regards.

sean.

  • 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. :D
He can take my money with him!

2 minutes ago, karan said:

 

I bought it because I personally respect VMP developers. :D
He can take my money with him!

@karan Okay, I got it. Thanks.

Regards..

sean.

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?

  • 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

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.

 

 

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

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 √
  • Win10 x64 ×
  • Win11 x64 ×

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

@boot Could you help me compile the InjectorCLIx64.exe ? Just want to try it with ollydbg 64 !

Thanks

Edited by fReestYler

1 hour ago, fReestYler said:

InjectorCLIx64.exe

@boot  do you have IDA8.3  plugin in your collection?

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.

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 by kao

14 hours ago, RADIOX said:

he included them in his repostery in GitHub.

yes, exactly, good pointer, found and used

 

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 by TRISTAN Pro
Edit some word

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...

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?

  • 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".

:D

Edited by karan

  • 3 weeks later...
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 √
  • Win10 x64 ×
  • Win11 x64 ×

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.

  • 2 months later...

@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 by fReestYler

  • 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 by karan

you could build up ScyllaHide plugin with addons mentioned in this topic

it does the job

 

Create an account or sign in to comment

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.