You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用WithDLL注入Detours钩子DLL失败:未导出序号#1错误解决咨询

问题:withdll.exe提示“DLL未导出序号#1”的解决方法

问题描述

使用Microsoft Detours实现进程挂钩DLL时,运行withdll.exe注入出现以下错误:

B:>withdll.exe /d:[...]\IniHook.dll HookTarget.exe
withdll.exe: 错误:[...]\IniHook.dll 未导出序号#1。
             请查看Detours.chm中的DetourCreateProcessWithDllEx帮助条目。

无法找到Detours.chm文档,现需明确问题原因及修复方案。

用户提供的挂钩DLL代码如下:

#include "pch.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <detours.h>
#include <iostream>

#pragma comment(lib, "detours.lib")

typedef DWORD(WINAPI* GetPrivateProfileStringW_t)(LPCWSTR app, LPCWSTR key, LPCWSTR def, LPWSTR result, DWORD size, LPCWSTR file_name);

GetPrivateProfileStringW_t TrueGetPrivateProfileStringW = nullptr;

DWORD WINAPI HookedGetPrivateProfileStringW(LPCWSTR app, LPCWSTR key, LPCWSTR def, LPWSTR result, DWORD size, LPCWSTR file_name)
{
    std::wcout << L"GetPrivateProfileStringW called." << L"\n";
    return TrueGetPrivateProfileStringW(app, key, def, result, size, file_name);
}

BOOL APIENTRY DllMain(HMODULE module, DWORD  reason, LPVOID _)
{
    switch (reason)
    {
    case DLL_THREAD_ATTACH:
    case DLL_PROCESS_ATTACH:
        DetourTransactionBegin();
        TrueGetPrivateProfileStringW = (GetPrivateProfileStringW_t)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetPrivateProfileStringW");
        DetourAttach(&(PVOID&)TrueGetPrivateProfileStringW, HookedGetPrivateProfileStringW);
        DetourTransactionCommit();
        break;
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        DetourTransactionBegin();
        DetourDetach(&(PVOID&)TrueGetPrivateProfileStringW, HookedGetPrivateProfileStringW);
        DetourTransactionCommit();
        break;
    }
    return TRUE;
}

问题原因

withdll.exe的/d注入参数有硬性要求:被注入的DLL必须导出序号为1的函数。这是因为它内部调用DetourCreateProcessWithDllEx时,默认会尝试调用DLL中序号1的导出函数完成初始化(未指定自定义入口点时)。当前DLL没有任何导出函数,因此触发该错误。

修复方案

方案一:给DLL添加序号为1的导出函数

不需要修改withdll的调用命令,只需在DLL中添加一个空的导出函数,并确保它的导出序号为1,两种实现方式任选其一:

方式1:使用.def配置文件

在项目中新建一个IniHook.def文件,内容如下:

LIBRARY IniHook
EXPORTS
    DllInit @1

然后在代码中添加对应的空函数:

// 仅满足withdll的导出要求,无需实际逻辑
extern "C" __declspec(dllexport) void DllInit()
{
}

编译时链接器会自动读取.def文件,将DllInit函数导出为序号1。

方式2:通过代码直接指定导出序号

无需额外配置文件,在代码中添加如下函数声明与实现:

// 直接指定导出序号为1
extern "C" __declspec(dllexport) __declspec(allocate(".text$1")) void DllInit()
{
}

或者在代码中添加编译指令,同样可以实现导出:

#pragma comment(linker, "/EXPORT:DllInit,@1,NONAME")

// 空实现的导出函数
extern "C" void DllInit()
{
}

方案二:修改withdll调用命令,指定自定义入口点

如果不想添加多余函数,可以修改withdll的命令格式,明确指定DLL的入口点(需确保该函数已导出):

withdll.exe /d:IniHook.dll,DllInit HookTarget.exe

注:此方式要求DllInit是已导出的函数,本质和方案一类似,只是显式指定了入口点而非依赖默认的序号1。

额外代码优化建议

当前代码在DLL_THREAD_ATTACH事件中也执行了挂钩操作,这会导致每个线程创建时重复调用DetourAttach,引发错误。应仅在DLL_PROCESS_ATTACH时进行挂钩,修改后的DllMain如下:

BOOL APIENTRY DllMain(HMODULE module, DWORD  reason, LPVOID _)
{
    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
        DetourTransactionBegin();
        TrueGetPrivateProfileStringW = (GetPrivateProfileStringW_t)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetPrivateProfileStringW");
        DetourAttach(&(PVOID&)TrueGetPrivateProfileStringW, HookedGetPrivateProfileStringW);
        DetourTransactionCommit();
        break;
    case DLL_PROCESS_DETACH:
        DetourTransactionBegin();
        DetourDetach(&(PVOID&)TrueGetPrivateProfileStringW, HookedGetPrivateProfileStringW);
        DetourTransactionCommit();
        break;
    }
    return TRUE;
}

内容的提问来源于stack exchange,提问作者Thomas W.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 22:19:50