> For the complete documentation index, see [llms.txt](https://blog.0x4.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blog.0x4.xyz/bypassing-windows-protection-mechanisms/bypass-avs-via-ordinals.md).

# Bypass AVs via Ordinals

Let’s get in, Microsoft says:

> You can specify the `entry-point name` by supplying a string indicating the name of the DLL containing the entry point, or you can identify the `entry point by its ordinal`.

So, this means that we have two ways to define the DllImport attribute to call a method by entry-point name (method name) or the ordinal number for the method.

Let me explain it practically so that things will be apparent to you. We will go with MessageBoxExW as example

Syntax

```
int MessageBoxExW(
  [in, optional] HWND    hWnd,
  [in, optional] LPCWSTR lpText,
  [in, optional] LPCWSTR lpCaption,
  [in]           UINT    uType,
  [in]           WORD    wLanguageId
);
```

Now we want to write C# code to call the MessageBoxExW method from user32.dll via P/Invoke.

```csharp
using System;
using System.Runtime.InteropServices;

namespace Test
{
    public class Example
    {

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "MessageBoxExW")]
        static extern int MessageBoxEx(IntPtr hWnd, string lpText, string lpCaption, uint uType, ushort wLanguageId);

        public static void Main()
        {
            MessageBoxEx(new IntPtr(0), "Hello World!", "P/Invoke", 0, 0);
        }
    }
}
```

Compile and run it.

<figure><img src="https://1238199223-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MgKo2XdVCwjHarqCSff%2Fuploads%2FUik91UKFmMb4UWYY4g8v%2F1.png?alt=media&amp;token=521b4da3-19bf-4c61-a240-39c91f46d4dd" alt=""><figcaption></figcaption></figure>

Upload it to Virustotal. Don't focus on whether it was detected as malicious or not. If we go into details, we will see that Virustotal detected our method in the `Unmanaged Method List` section.

<figure><img src="https://1238199223-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MgKo2XdVCwjHarqCSff%2Fuploads%2FlTtLSWUa5zxvimWTmyds%2F2.png?alt=media&amp;token=fa4f156d-f4fb-4045-ae74-df32c4c2b577" alt=""><figcaption></figcaption></figure>

What do you think will happen if some AVs detect methods like <mark style="color:red;">VirtualAlloc</mark> or <mark style="color:red;">MiniDumpWriteDump</mark> ? Exactly 😀

So, now let’s use ordinal as an entry-point.

### Ordinals

You can get the ordinal number from the Export Address Table of a DLL (user32.dll) can be viewed by using [Dependency Walker](https://www.dependencywalker.com/).

First, we need to use Dependency Walker to get the ordinal number for the <mark style="color:red;">MessageBoxExW</mark> method.

`File` → `Open` <mark style="color:red;">C:\Windows\System32\user32.dll</mark>.

In the Function section, we are looking for MessageBoxExW. On the left side, you will see the ordinal number.

The ordinal number for <mark style="color:red;">MessageBoxExW</mark> is <mark style="color:red;">2153</mark>. You can use it as EntryPoint Instead of the method name.

<figure><img src="https://1238199223-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MgKo2XdVCwjHarqCSff%2Fuploads%2F6PZ29xnwDyOd7Diqxrra%2F3.png?alt=media&amp;token=2d3583cf-6d56-4445-92df-990a9b2fb7ce" alt=""><figcaption></figcaption></figure>

<mark style="color:red;">`Ensure you're using the correct ordinal numbers for your target, since they can differ between Windows versions.`</mark>

```csharp
using System;
using System.Runtime.InteropServices;

namespace Test
{
    public class Example
    {

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "#2153")]
        static extern int MessageBoxEx(IntPtr hWnd, string lpText, string lpCaption, uint uType, ushort wLanguageId);

        public static void Main()
        {
            MessageBoxEx(new IntPtr(0), "Hello World!", "P/Invoke", 0, 0);
        }
    }
}
```

<figure><img src="https://1238199223-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MgKo2XdVCwjHarqCSff%2Fuploads%2Fo26V23jFvJxruo3AzGMW%2F4.png?alt=media&amp;token=4c0361bc-069f-44a7-a7b5-5518bedbe74f" alt=""><figcaption></figcaption></figure>

One more time, let’s upload it to Virustotal.

<figure><img src="https://1238199223-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MgKo2XdVCwjHarqCSff%2Fuploads%2FeYY7u2tg7TPne6y3p063%2F5.png?alt=media&amp;token=5370fbbc-1acd-4740-a9d4-ffed5e45cddc" alt=""><figcaption></figcaption></figure>

As shown in the picture, there is no method name.

This approach allows you to bypass some AVs that looking for method names.

### References

{% embed url="<https://secureyourit.co.uk/wp/2020/04/15/ordinal-numbers-and-vba-can-be-fun-who-knew/>" %}

{% embed url="<https://www.intechopen.com/chapters/54671>" %}

{% embed url="<https://toddcullumresearch.com/2017/03/13/winapi-ordinals/>" %}

{% embed url="<https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportattribute.entrypoint?view=net-6.0>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxexw>" %}

{% embed url="<https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke>" %}

{% embed url="<https://docs.microsoft.com/en-us/cpp/build/exporting-from-a-dll?view=msvc-170>" %}
