我可以在NSIS中使用LoadLibrary加载多个dll吗?

时间:2018-10-22 09:48:48

标签: nsis

作为项目的一部分,我在NSIS脚本中使用LoadLibrary加载了多个dll。因为其他dll是主dll的引用。 之后,如何使用GetProcAddress调用函数?因为我已经加载了多个DLL。

下面是我的代码段:

    !include LogicLib.nsh

    Section
    SetOutPath $InstDir
    File drvutil.dll
    System::Call 'KERNEL32::LoadLibrary(t "$InstDir\drvutil.dll")p.r8 ?e'
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\UPSControls.dll")p.r8 ?e'
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\UPSDevice.dll")p.r8 ?e'
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\pdcdll.dll")p.r8 ?e'
    Pop $7
    ${If} $8 P<> 0
        MessageBox MB_OK 'Successfully loaded "$InstDir\drvutil.dll" @ $8'
        System::Call 'KERNEL32::GetProcAddress(pr8, m "IsUPSPresent")p.r9 ?e'
        Pop $7
        ${If} $9 P<> 0
            MessageBox MB_OK 'Successfully found "IsUPSPresent" @ $9'
        ${Else}
            MessageBox MB_ICONSTOP 'Unable to find "IsUPSPresent", error $7'
        ${EndIf}
        System::Call 'KERNEL32::FreeLibrary(pr8)'
    ${Else}
        MessageBox MB_ICONSTOP 'Unable to load "$InstDir\drvutil.dll", error $7'
    ${EndIf}

运行此脚本时,它正在成功加载DLL。但是它没有加载功能。您能帮我解决问题吗?

1 个答案:

答案 0 :(得分:2)

  

运行此脚本时,它正在成功加载DLL。

您正在检查发布的示例中的HMODULE错误!您只是在检查pdcdll.dll是否正确加载,而不是要检查的.DLL。

理想情况下,使用系统插件时,您应该对Win32有一定的经验。

LoadLibrary将为您加载依赖的.DLL,在大多数情况下,您无需手动进行此操作。一个潜在的问题是NSIS activates some extra hardening protections避免加载hijacking-.DLL,这可能会阻止.DLL加载其依赖项。

在这里,我将为您提供一个完整的示例,该示例手动加载每个.DLL,但您不应正常执行此操作,只需加载所需的.DLL,然后让Windows为您解决其余的问题。

!include LogicLib.nsh

Section
SetOutPath $InstDir
File drvutil.dll
File UPSControls.dll
File UPSDevice.dll
File pdcdll.dll

System::Call 'KERNEL32::AddDllDirectory(w "$InstDir")' ; Tell Windows we trust all .DLLs in this directory

System::Call 'KERNEL32::LoadLibrary(t "$InstDir\pdcdll.dll")p.r8'
${IfThen} $8 P= 0 ${|} MessageBox MB_ICONSTOP "DEBUG: Failed to load pdcdll.dll" ${|}
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\UPSDevice.dll")p.r8'
${IfThen} $8 P= 0 ${|} MessageBox MB_ICONSTOP "DEBUG: Failed to load UPSDevice.dll" ${|}
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\UPSControls.dll")p.r8'
${IfThen} $8 P= 0 ${|} MessageBox MB_ICONSTOP "DEBUG: Failed to load UPSControls.dll" ${|}

System::Call 'KERNEL32::LoadLibrary(t "$InstDir\drvutil.dll")p.r8 ?e'
Pop $7 ; Get ?e result
${IfThen} $8 P= 0 ${|} MessageBox MB_ICONSTOP "Failed to load drvutil.dll, error $7" ${|}
${If} $8 P<> 0
  System::Call 'KERNEL32::GetProcAddress(pr8, m "IsUPSPresent")p.r9 ?e'
  Pop $7 ; Get ?e result
  ${IfThen} $9 P= 0 ${|} MessageBox MB_ICONSTOP "Failed to find the exported function, error $7. Inspect the .DLL with Dependency Walker to make sure the function is exported with the correct un-decorated name!" ${|}
${EndIf}

SectionEnd

如果收到“无法加载drvutil.dll”消息,则需要查看.DLLs依赖项等。

如果收到“无法找到导出的函数”消息,则您没有exported the function correctly。函数名称不应为decoratedDependency Walker将为您显示导出的函数名称。如果您无法删除修饰,则可以将修饰的名称直接传递给GetProcAddress,但是请记住,如果您使用64位编译或更改为,则名称可能不相同。另一个编译器供应商。

它应该像这样:

Dependency Walker