windows 如何重命名 DLL 但仍允许 EXE 找到它?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/280485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 05:41:24  来源:igfitidea点击:

How do I rename a DLL but still allow the EXE to find it?

windowsdllnative

提问by pauldoo

We have a DLL which is produced in house, and for which we have the associated static LIB of stubs.

我们有一个内部生成的 DLL,并且我们有相关的存根静态 LIB。

We also have an EXE which uses this DLL using the simple method of statically linking to the DLL's LIB file (ie, not manually using LoadLibrary).

我们还有一个使用这个 DLL 的 EXE,它使用静态链接到 DLL 的 LIB 文件的简单方法(即,不手动使用 LoadLibrary)。

When we deploy the EXE we'd like the DLL file name to be changed for obfuscation reasons (at customer's request).

当我们部署 EXE 时,我们希望出于混淆原因(应客户要求)更改 DLL 文件名。

How can we do this so that our EXE still finds the DLL automagically?

我们如何才能做到这一点,以便我们的 EXE 仍能自动找到 DLL?

I have tried renaming the DLL and LIB files (after they were built to their normal name), then changing the EXE project settings to link with the renamed LIB. This fails at runtime, as I guess the name of the DLL is baked into the LIB file, and not simply guessed at by the linker replacing ".lib" with ".dll".

我尝试重命名 DLL 和 LIB 文件(在将它们构建为正常名称之后),然后更改 EXE 项目设置以与重命名的 LIB 链接。这在运行时会失败,因为我猜 DLL 的名称被放入 LIB 文件中,而不是简单地由链接器将“.lib”替换为“.dll”来猜测。

In general, we do not want to apply this obfuscation to all uses of the DLL, so we'd like to keep the current DLL project output files are they are.

通常,我们不想将这种混淆应用于 DLL 的所有用途,因此我们希望保留当前的 ​​DLL 项目输出文件。

I'm hoping that there will be a method whereby we can edit the DLL's LIB file, and replace the hardcoded name of the DLL file with something else. In which case this could be done entirely within the EXE project (perhaps as a pre-build step).

我希望有一种方法可以让我们编辑 DLL 的 LIB 文件,并用其他东西替换 DLL 文件的硬编码名称。在这种情况下,这可以完全在 EXE 项目中完成(也许作为预构建步骤)。



Update: I find that Delay Loading does not work, as my DLL contains exported C++ classes. See this article.

更新:我发现延迟加载不起作用,因为我的 DLL 包含导出的 C++ 类。请参阅这篇文章

Are there any alternatives?

有没有其他选择?

回答by QAZ

Here is a nice alternative approach: delay loading.

这是一个不错的替代方法:延迟加载

When building your application, link it all as you would with the original DLL name (but set the origional dll to be delay loaded).

构建应用程序时,将其全部链接到原始 DLL 名称(但将原始 dll 设置为延迟加载)。

You then deploy the DLL renamed as per your customers request.

然后根据客户的要求部署重命名的 DLL。

Your EXE will attempt to locate the DLL using the original name and not the renamed version so will fail, however with delay loading you can intercept this fail and load the renamed version yourself and then have the native windows loader resolve everything as if nothing changed.

您的 EXE 将尝试使用原始名称而不是重命名的版本来定位 DLL,因此会失败,但是通过延迟加载,您可以拦截此失败并自己加载重命名的版本,然后让本机 Windows 加载程序解析所有内容,就好像没有任何更改一样。

Read the article Linker Support for Delay-Loaded DLLsand see the Delay Hook example.

阅读文章Linker Support for Delay-Loaded DLLs并查看Delay Hook 示例

Your delay hook might be something like below:

您的延迟挂钩可能如下所示:

FARPROC WINAPI delayHook( unsigned dliNotify, PDelayLoadInfo pdli )
{
    switch( dliNotify )
    {
        case dliNotePreLoadLibrary:
            if( strcmp( pdli->szDll, "origional.dll" ) == 0 )
                return (FARPROC)LoadLibrary( "renamed.dll" );
            break;
        default:
            return NULL;
    }

    return NULL;
}

回答by wimh

Using the LIB tool (included with visual studio) you can generate a lib file from a def file. Asuming your dll source does not include a def file, you have to create one first. You can use dumpbin to assist you. For example: dumpbin /exports ws2_32.dll

使用 LIB 工具(包含在 Visual Studio 中),您可以从 def 文件生成一个 lib 文件。假设您的 dll 源不包含 def 文件,您必须先创建一个。您可以使用 dumpbin 来帮助您。例如:dumpbin /exports ws2_32.dll

In the output you see the names of the functions exported. Now create a def file like this:

在输出中,您会看到导出的函数的名称。现在创建一个像这样的 def 文件:

LIBRARY WS2_32
EXPORTS
    accept      @1
    bind        @2
    closesocket @3
    connect     @4

The @number is the ordinal in the dumpbin output

@number 是 dumpbin 输出中的序号

Use LIB /MACHINE:x86 /def:ws2_32.defto generete the lib file.

使用LIB /MACHINE:x86 /def:ws2_32.def到generete的lib文件。

Now you can easily modify the def file, and generate a new libfile each time you rename your dll.

现在您可以轻松修改 def 文件,并在每次重命名 dll 时生成一个新的 libfile。

you can verify the libfile using dumpbin: dumpbin /exports ws2_32.lib. You should get the same output as the original lib file.

您可以使用 dumpbin: 验证 libfile dumpbin /exports ws2_32.lib。您应该获得与原始 lib 文件相同的输出。

回答by wimh

Is your customer drunk? Of all the crazy requirements in all the world ...

你的客户喝醉了吗?在世界上所有疯狂的要求中......

Back in my glory days as a syphilitic madman midnight C++ programmer I used to add my DLLs to my .exe file as resources. Then at startup I'd unpack them and write them to the exe's directory. Your program can decide on the DLL filename at this point. Really go for the obfuscation thing - start with a random number, concatenate some Edward Lear poetry and xor it with your favourite German double-barrelled noun; should do for starters anyway. Then load the DLL using LoadLibrary().

回到我作为梅毒疯子午夜 C++ 程序员的辉煌时代,我曾经将我的 DLL 作为资源添加到我的 .exe 文件中。然后在启动时我会解压它们并将它们写入 exe 的目录。此时您的程序可以决定 DLL 文件名。真正去做混淆的事情——从一个随机数开始,连接一些 Edward Lear 的诗歌,然后用你最喜欢的德语双管名词异或;无论如何应该为初学者做。然后使用 LoadLibrary() 加载 DLL。

enum ukOverwrite {dontOverwriteAnything = 0, overwriteWhateverPresent = 1};
void unpackResource (ukOverwrite param1, int resourceID, const char* basePath,  
const char* endFilename)
{
  char* lpName = 0;
  lpName += resourceID;
  HRSRC MrResource = FindResource (0, lpName, "file");

  if (MrResource)
  {
    HGLOBAL loadedResource = LoadResource (0, MrResource);
    if (loadedResource)
    {
      void* lockedResource = LockResource (loadedResource);
      if (lockedResource)
      {
        DWORD size = SizeofResource (0, MrResource);
        if (size)
        {
          unsigned long creationDisposition = CREATE_NEW;
          if (param1 == overwriteWhateverPresent)
            creationDisposition = CREATE_ALWAYS;

          char filepath [MAX_PATH];
          strcpy (filepath, basePath);
          strcat (filepath, endFilename);
          HANDLE rabbit = CreateFile (filepath, GENERIC_WRITE, 0, 0,  
creationDisposition, 0, 0);
          if (rabbit != INVALID_HANDLE_VALUE)
          {
            DWORD numBytesWritten = 0;
            int wf = WriteFile (rabbit, lockedResource, size, &numBytesWritten,  
0);
            CloseHandle (rabbit);
          }
        }
      }
      FreeResource (loadedResource);
    }
  }
}

回答by Chris Berry

I created a little python script to rename native dlls properly. It generates a new lib file for you to use in project linking in MSVC.

我创建了一个小的 python 脚本来正确重命名本机 dll。它会生成一个新的 lib 文件,供您在 MSVC 中的项目链接中使用。

https://github.com/cmberryau/rename_dll/blob/master/rename_dll.py.

https://github.com/cmberryau/rename_dll/blob/master/rename_dll.py

You'll need to use the developer command prompt for it to work of course.

当然,您需要使用开发人员命令提示符才能使其正常工作。

回答by Woods

  1. Use LoadLibrary (Read new name from registry) is one option.
  2. You can rename your visual studio project to have a generalised name (which your customer has no objection).
  3. The DLL itself needs to be renamed. But the lib still carries the old name? Did you cross verify using DUMPBIN /ALL *.lib > file. grep for the old DLL name. Is it still there? Check *.def file in the project. Did you rename the LIBRARY "OLDNAME"
  1. 使用 LoadLibrary(从注册表中读取新名称)是一种选择。
  2. 您可以将 Visual Studio 项目重命名为通用名称(您的客户不反对)。
  3. DLL 本身需要重命名。但是 lib 仍然带有旧名称?您是否使用 DUMPBIN /ALL *.lib > 文件进行交叉验证。grep 获取旧的 DLL 名称。它还在吗?检查项目中的 *.def 文件。您是否将图书馆重命名为“OLDNAME”

Otherwise, there is no reason for the LIB to carry old DLL name.

否则,LIB 就没有理由携带旧的 DLL 名称。

回答by Mladen Prajdic

you'll have to use Assembly.Load and have the obfuscated assembly name saved in the app.config.

您必须使用 Assembly.Load 并将混淆的程序集名称保存在 app.config 中。

either that or use the same approach that plug-ins use. have a class in your assembly implement an interface that you search for from your app in every assembly in a certain directory. if found loat it. you'll of course have to not obfuscate the Interface name.

或者使用插件使用的相同方法。在您的程序集中有一个类实现一个接口,您可以在特定目录中的每个程序集中从您的应用程序中搜索该接口。如果找到它。您当然不必混淆接口名称。