【问题标题】:Possible to hook IAT function by ordinal?可以按序号挂钩IAT功能吗?
【发布时间】:2017-01-22 15:37:15
【问题描述】:

我在搞乱一些 dll 注入/函数挂钩。通过比较 IAT 中函数的名称,我可以按名称挂钩导入地址表的函数。 (获取IMAGE_THUNK_DATA并读取值)

但是当我注入的应用程序按序号导入函数时,我不会用这种方法成功。例如,有时当我检查 IMAGE_THUNK_DATA* thunkData->u1.Function 时,它似乎是一些序数。

现在我的问题是:有没有办法获取例如 Sleep 函数 (https://msdn.microsoft.com/de-de/library/windows/desktop/ms686298(v=vs.85).aspx) 的序数并检查 IAT 中的值是否等于该序数? 例如这样的:

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

或者我注入的应用程序的 IAT 中的序号与原始 dll 中 Sleep 函数的序号不同?

希望你明白我的意思。

【问题讨论】:

  • @user - 你完全错了 - 序数不稳定。我们不能将序数用于睡眠 - 它在不同的 Windows 版本中有所不同。
  • @RbMm 哦,好的,谢谢。如果说 Sleep 是按序号导入的,是否有其他解决方案可以通过 IAT 挂钩该功能?
  • 睡眠从不被序数导入 - 这是不正确的。但是我当然知道解决方案

标签: c++ hook code-injection


【解决方案1】:

当然可以通过序数实现钩子函数,但是如果我们知道这个序数。

一般来说序数是不稳定的。例如Sleep 在每个 Windows 版本中都有不同的序数。甚至更多 - 在相同的寡妇版本中,它在 x86 和 x64 版本的 kernel32.dll 中具有不同的序数 - 但是 Sleep 在您的应用程序中按序数导入?我 100% 确定不是。

但是,在某些 dll 中,某些序数是稳定的(例如 ws2_32.dlloleaut32.dll )。我们如何知道哪些序数是稳定的(可以使用)?让我们想一想 - 我们使用链接 someimport.libsome.dll 导入函数 - 并在此导入 LIB 并包含如何导入函数的信息 - 按名称或按序号。所以你需要从LIB 文件中获取信息。这可以通过命令来完成:

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

例如以ws2_32.lib - 我运行

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

如果我们查看 ordinal 不为空 - API 将按序号导入(如果 PE 通过与此 lib 链接构建)如果为空 - 将按名称导入。例如,WSAStartup 将按序号 115 (0x73) 导入,而 WSASocketW 将按名称导入。如果 Microsoft 库 (ws2_32.lib) 按序号 115 导出 WSAStartup - 这意味着在所有 Windows (x64) 版本中 WSAStartup 必须 使用相同的序号 115 导出 - 否则将有大量应用程序与这个官方库 - 未在运行时启动或崩溃。所以将来,ws2_32.lib 的其他版本可以开始按名称导入 WSAStartup,但所有窗口 ws2_32.dll 已经必须始终以 115 序号导出 WSAStartup

如果您检查 kernel32.lib,您可以查看该序数列全为空 - 所以没有任何受赠者说 Sleep ordinal - 它真的非常不稳定。

那么需要怎么写代码,比如检测WSAStartupimport 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++;
}

【讨论】:

  • 哇,谢谢你的回答:) 嗯,你是对的,实际上我要挂钩的函数是 ws2_32.sendto,但我在 IAT 中找不到它的名称,所以我猜它是导入的按序数。我将继续阅读您的代码,直到我 100% 理解它,但谢谢哥们:)
  • @User90234 - sendto 有序数 20 - 查看我粘贴的表格
  • 刚刚用你的指南修改了我的函数,工作得很好,谢谢伙计:) 我再问你一件事:如果两个函数实际上有相同的序数会发生什么?就像 sendto 有序数 20 而另一个 dll 的其他一些功能也有序数 20?那会发生什么?
  • 在同一个 dll 中只能是这个序数的一个函数。你在检查 dll 名称吗?
  • 哦,错过了那部分......似乎合乎逻辑,现在明白了:) 你可能知道,虽然现在很离题,为什么如果我覆盖 IAT 的函数,游戏会崩溃,但是当我覆盖我的测试应用程序的 IAT 功能时,一切正常吗?是否有一些我不知道的保护措施?我已经将内存保护更改为 READ_WRITE 访问。很抱歉打扰你这么久
猜你喜欢
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 2011-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多