Search code examples
c++hookcode-injection

Possible to hook IAT function by ordinal?


I am messing around with some dll injection / function hooking. I am able to hook functions of the import address table by name, by comparing the name of the function in the IAT. (Getting IMAGE_THUNK_DATA and reading the value)

But when the application I am injecting into is importing the functions by ordinal I will not have success with that approach. For example sometimes when I check IMAGE_THUNK_DATA* thunkData->u1.Function it appears to be some ordinal number.

Now to my question: Is there a way to get the ordinal number of, for example, the Sleep function ( https://msdn.microsoft.com/de-de/library/windows/desktop/ms686298(v=vs.85).aspx ) and check if the value in the IAT is equal to that ordinal number? For example something like this:

if (IMAGE_SNAP_BY_ORDINAL(thunkData->u1.Function)) {
    //check if u1.Function is my desired ordinal number of sleep
}

Or is the ordinal number in the IAT of my application I am injecting into not the same as the ordinal number of the Sleep function in the original dll?

I hope you understand what I mean.


Solution

  • of course possible hook function by ordinal, but if we know this ordinal.

    in general ordinals is not stable. so for example Sleep have different ordinals in every windows version. even more - in the same widows version it have different ordinals in x86 and x64 versions of kernel32.dll - but are Sleep imported by ordinal in your application ? i 100% sure that not.

    however some ordinals is stable, in some dlls (like ws2_32.dll or oleaut32.dll ). how we can know which ordinals is stable (can be using) ? let think - we use linking someimport.lib for import functions from some.dll - and in this import LIB and containing info how import function - by name or by ordinal. so you need get info from LIB file. this can be done by command:

    link.exe -dump /EXPORTS "somepath\somelib.lib" > somelib.log

    let for example take ws2_32.lib - i run

    link.exe -dump /EXPORTS "my path\x64\ws2_32.lib" > ws2_32.log

       ordinal    name
              ?WSApSetPostRoutine@@YAHPEAX@Z (int __cdecl WSApSetPostRoutine(void *))
              FreeAddrInfoEx
              FreeAddrInfoExW
              FreeAddrInfoW
              GetAddrInfoExA
              GetAddrInfoExCancel
              GetAddrInfoExOverlappedResult
              GetAddrInfoExW
              GetAddrInfoW
              GetHostNameW
              GetNameInfoW
              InetNtopW
              InetPtonW
              SetAddrInfoExA
              SetAddrInfoExW
       500    WEP
              WPUCompleteOverlappedRequest
              WPUGetProviderPathEx
              WSAAccept
              WSAAddressToStringA
              WSAAddressToStringW
              WSAAdvertiseProvider
       102    WSAAsyncGetHostByAddr
       103    WSAAsyncGetHostByName
       105    WSAAsyncGetProtoByName
       104    WSAAsyncGetProtoByNumber
       107    WSAAsyncGetServByName
       106    WSAAsyncGetServByPort
       101    WSAAsyncSelect
       108    WSACancelAsyncRequest
       113    WSACancelBlockingCall
       116    WSACleanup
              WSACloseEvent
              WSAConnect
              WSAConnectByList
              WSAConnectByNameA
              WSAConnectByNameW
              WSACreateEvent
              WSADuplicateSocketA
              WSADuplicateSocketW
              WSAEnumNameSpaceProvidersA
              WSAEnumNameSpaceProvidersExA
              WSAEnumNameSpaceProvidersExW
              WSAEnumNameSpaceProvidersW
              WSAEnumNetworkEvents
              WSAEnumProtocolsA
              WSAEnumProtocolsW
              WSAEventSelect
       111    WSAGetLastError
              WSAGetOverlappedResult
              WSAGetQOSByName
              WSAGetServiceClassInfoA
              WSAGetServiceClassInfoW
              WSAGetServiceClassNameByClassIdA
              WSAGetServiceClassNameByClassIdW
              WSAHtonl
              WSAHtons
              WSAInstallServiceClassA
              WSAInstallServiceClassW
              WSAIoctl
       114    WSAIsBlocking
              WSAJoinLeaf
              WSALookupServiceBeginA
              WSALookupServiceBeginW
              WSALookupServiceEnd
              WSALookupServiceNextA
              WSALookupServiceNextW
              WSANSPIoctl
              WSANtohl
              WSANtohs
              WSAPoll
              WSAProviderCompleteAsyncCall
              WSAProviderConfigChange
              WSARecv
              WSARecvDisconnect
              WSARecvFrom
              WSARemoveServiceClass
              WSAResetEvent
              WSASend
              WSASendDisconnect
              WSASendMsg
              WSASendTo
       109    WSASetBlockingHook
              WSASetEvent
       112    WSASetLastError
              WSASetServiceA
              WSASetServiceW
              WSASocketA
              WSASocketW
       115    WSAStartup
              WSAStringToAddressA
              WSAStringToAddressW
              WSAUnadvertiseProvider
       110    WSAUnhookBlockingHook
              WSAWaitForMultipleEvents
              WSCDeinstallProvider
              WSCDeinstallProvider32
              WSCDeinstallProviderEx
              WSCEnableNSProvider
              WSCEnableNSProvider32
              WSCEnumNameSpaceProviders32
              WSCEnumNameSpaceProvidersEx32
              WSCEnumProtocols
              WSCEnumProtocols32
              WSCEnumProtocolsEx
              WSCGetApplicationCategory
              WSCGetApplicationCategoryEx
              WSCGetProviderInfo
              WSCGetProviderInfo32
              WSCGetProviderPath
              WSCGetProviderPath32
              WSCInstallNameSpace
              WSCInstallNameSpace32
              WSCInstallNameSpaceEx
              WSCInstallNameSpaceEx2
              WSCInstallNameSpaceEx32
              WSCInstallProvider
              WSCInstallProvider64_32
              WSCInstallProviderAndChains64_32
              WSCInstallProviderEx
              WSCSetApplicationCategory
              WSCSetApplicationCategoryEx
              WSCSetProviderInfo
              WSCSetProviderInfo32
              WSCUnInstallNameSpace
              WSCUnInstallNameSpace32
              WSCUnInstallNameSpaceEx2
              WSCUpdateProvider
              WSCUpdateProvider32
              WSCUpdateProviderEx
              WSCWriteNameSpaceOrder
              WSCWriteNameSpaceOrder32
              WSCWriteProviderOrder
              WSCWriteProviderOrder32
              WSCWriteProviderOrderEx
              WahCloseApcHelper
              WahCloseHandleHelper
              WahCloseNotificationHandleHelper
              WahCloseSocketHandle
              WahCloseThread
              WahCompleteRequest
              WahCreateHandleContextTable
              WahCreateNotificationHandle
              WahCreateSocketHandle
              WahDestroyHandleContextTable
              WahDisableNonIFSHandleSupport
              WahEnableNonIFSHandleSupport
              WahEnumerateHandleContexts
              WahInsertHandleContext
              WahNotifyAllProcesses
              WahOpenApcHelper
              WahOpenCurrentThread
              WahOpenHandleHelper
              WahOpenNotificationHandleHelper
              WahQueueUserApc
              WahReferenceContextByHandle
              WahRemoveHandleContext
              WahWaitForNotification
              WahWriteLSPEvent
       151    __WSAFDIsSet
         1    accept
         2    bind
         3    closesocket
         4    connect
              freeaddrinfo
              getaddrinfo
        51    gethostbyaddr
        52    gethostbyname
        57    gethostname
              getnameinfo
         5    getpeername
        53    getprotobyname
        54    getprotobynumber
        55    getservbyname
        56    getservbyport
         6    getsockname
         7    getsockopt
         8    htonl
         9    htons
        11    inet_addr
        12    inet_ntoa
              inet_ntop
              inet_pton
        10    ioctlsocket
        13    listen
        14    ntohl
        15    ntohs
        16    recv
        17    recvfrom
        18    select
        19    send
        20    sendto
        21    setsockopt
        22    shutdown
        23    socket
    

    if we view ordinal not empty - API will be imported by ordinal (if PE build by linking with this lib) if empty - will be import by name. so say for example WSAStartup will be imported by ordinal 115 (0x73) when WSASocketW will be imported by name. if Microsoft library (ws2_32.lib) exported WSAStartup by ordinal 115 - this mean in ALL windows (x64) versions WSAStartup must be exported with same ordinal 115 - otherwise huge count of applications linked with this official lib - not started or crashed in runtime. so in future, some another version of ws2_32.lib can begin import WSAStartup by name, but all windows ws2_32.dll already must always export WSAStartup with 115 ordinal.

    if you check kernel32.lib you can view that ordinals column all empty - so no any grantee about say Sleep ordinal - and it really very volatile.

    so how need write code, for example detect WSAStartup import entry ?

    #define WSAStartup_Ordinal 115
    
    PVOID hmod;
    PIMAGE_IMPORT_DESCRIPTOR piid;
    ULONG size/* size of IMPORT directory*/, d;
    // assume hmod, piid, size already initialized
    
    while ((INT)size >= sizeof(IMAGE_IMPORT_DESCRIPTOR) && (d = piid->Name))
    {
        PCSTR name = RtlOffsetToPointer(hmod, d);
    
        if (!_stricmp(name, "ws2_32.dll"))
        {
            if (d = piid->FirstThunk)
            {
                PIMAGE_THUNK_DATA FirstThunk = (PIMAGE_THUNK_DATA)RtlOffsetToPointer(hmod, d);
    
                if (d = piid->OriginalFirstThunk)
                {
                    PIMAGE_THUNK_DATA OriginalFirstThunk = (PIMAGE_THUNK_DATA)RtlOffsetToPointer(hmod, d);
    
                    while (ULONG_PTR Ordinal = OriginalFirstThunk->u1.Ordinal)
                    {
                        ULONG_PTR Function = 0;
    
                        if (IMAGE_SNAP_BY_ORDINAL(Ordinal))
                        {
                            if (IMAGE_ORDINAL(Ordinal) == WSAStartup_Ordinal) // 115
                            {
                                Function = FirstThunk->u1.Function;
                            }
                        }
                        else
                        {
                            if (!strcmp((PCSTR)((PIMAGE_IMPORT_BY_NAME)RtlOffsetToPointer(hmod, Ordinal))->Name, "WSAStartup"))
                            {
                                Function = FirstThunk->u1.Function;
                            }
                        }
    
                        if (Function)
                        {
                            __nop();
                        }
                    }
                }
            }
        }
    
        size -= sizeof(IMAGE_IMPORT_DESCRIPTOR), piid++;
    }