如何使用 rundll32.exe 删除 Windows 中的文件?
How to delete a file in Windows using rundll32.exe for it?
我想它应该是这样的:
rundll32 kernel32.dll,DeleteFileA,test.txt
但这就是行不通。
我试过了:
rundll32 kernel32.dll,DeleteFileA test.txt
rundll32 "kernel32.dll,DeleteFileA test.txt"
文件保留。
当我从 PowerShell 尝试它时,当我拼错 DeleteFileA
时它会显示一条错误消息,因此它会在 kernel32.dll
中找到正确的条目。它只是不起作用可能是由于没有获取文件名参数。
为什么我需要它?我需要能够以管理员身份在常规用户上下文中 运行 的程序中删除文件。我绝对不希望整个应用程序成为 运行 作为管理员。只有确切的删除应该显示 UAC 确认。
这是在我的 C# 应用程序中工作的东西:
private static void DeleteAsAdmin(string target) {
Process.Start(new ProcessStartInfo { FileName = "cmd", Arguments = $"/C \"del /F /Q \"\"\"{target}\"\"\"\"", Verb = "RunAs", CreateNoWindow = true });
}
但是,无论如何它都会显示 window。一会儿,但它是可见的。这是因为我必须显式执行 cmd
才能使用 del
命令。
这就是为什么我想改用 rundll32
的原因。默认情况下,这将不创建 window。它公开了 FileDeleteA
方法。
我知道,我可以添加一个帮助程序可执行文件,它将以我的应用程序的管理员身份删除该文件,但这是一个非常丑陋的解决方案,甚至比调用 cmd
.
更丑陋
为什么我首先需要删除文件?为了安全。该文件包含一个敏感的程序配置,该配置被加密(使用 DPAPI)并移动到用户可访问的目录。为了额外的安全,需要删除位于“C:\Program Files”中的原始文件。如果用户取消 UAC 提示,那么,那将失败,但他们的敏感配置是纯文本的,这将是用户的错。
是的,我知道我可以通过 MSI 将文件放置在用户的目录中,但这对我也不利,因为它需要额外的配置步骤,我想避免。在使用完全默认的 MSI 安装程序安装后,该程序必须自行完成所有杂务。我可以这样离开,但似乎 rundll32
hack 只是在嘲笑我,而我离它只有一个特殊的角色 ;)
rundll32 需要一个非常具体的函数签名,it is not a generic "call any function" helper application。
要隐藏 cmd window,您可以尝试添加 WindowStyle = ProcessWindowStyle.Hidden
,但如果您已经拥有 C# 应用程序,何必费心呢?就叫自己去做任务吧。这至少会在 UAC 对话框中放入正确的 .exe。
即使你把这一切都搞定了,它仍然是错误的!如果您正在安装到 %ProgramFiles%,那么您正在为机器上的所有用户安装,并且一旦第二个用户运行您的应用程序,您的方案就会中断。任何写入用户配置文件的操作都必须在用户第一次运行您的程序时完成,而不是在安装阶段。您可以将模板文件从安装目录复制到用户配置文件,但不能删除模板。
如果您需要删除文件,您可以使用 IFileOperation
。示例代码:
#include <shobjidl_core.h>
// assume
// CoInitializeEx(0, COINIT_DISABLE_OLE1DDE|COINIT_APARTMENTTHREADED);
// already called
HRESULT DeleteFileElevated(PCWSTR lpFilename)
{
IShellItem* psi;
HRESULT hr = SHCreateItemFromParsingName(lpFilename, 0, IID_PPV_ARGS(&psi));
if (0 <= hr)
{
IFileOperation *pFileOp;
BIND_OPTS2 bo = { sizeof(bo) };
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
if (0 <= (hr = CoGetObject(L"Elevation:Administrator!new:{3ad05575-8857-4850-9277-11b85bdb8e09}", &bo, IID_PPV_ARGS(&pFileOp))))
{
0 <= (hr = pFileOp->SetOperationFlags(FOF_NOCONFIRMATION|
FOF_NOERRORUI|
FOF_FILESONLY|
FOFX_EARLYFAILURE|
FOFX_SHOWELEVATIONPROMPT)) &&
0 <= (hr = pFileOp->DeleteItem(psi, 0))
&&
0 <= (hr = pFileOp->PerformOperations());
pFileOp->Release();
}
psi->Release();
}
return hr;
}
我想它应该是这样的:
rundll32 kernel32.dll,DeleteFileA,test.txt
但这就是行不通。 我试过了:
rundll32 kernel32.dll,DeleteFileA test.txt
rundll32 "kernel32.dll,DeleteFileA test.txt"
文件保留。
当我从 PowerShell 尝试它时,当我拼错 DeleteFileA
时它会显示一条错误消息,因此它会在 kernel32.dll
中找到正确的条目。它只是不起作用可能是由于没有获取文件名参数。
为什么我需要它?我需要能够以管理员身份在常规用户上下文中 运行 的程序中删除文件。我绝对不希望整个应用程序成为 运行 作为管理员。只有确切的删除应该显示 UAC 确认。
这是在我的 C# 应用程序中工作的东西:
private static void DeleteAsAdmin(string target) {
Process.Start(new ProcessStartInfo { FileName = "cmd", Arguments = $"/C \"del /F /Q \"\"\"{target}\"\"\"\"", Verb = "RunAs", CreateNoWindow = true });
}
但是,无论如何它都会显示 window。一会儿,但它是可见的。这是因为我必须显式执行 cmd
才能使用 del
命令。
这就是为什么我想改用 rundll32
的原因。默认情况下,这将不创建 window。它公开了 FileDeleteA
方法。
我知道,我可以添加一个帮助程序可执行文件,它将以我的应用程序的管理员身份删除该文件,但这是一个非常丑陋的解决方案,甚至比调用 cmd
.
为什么我首先需要删除文件?为了安全。该文件包含一个敏感的程序配置,该配置被加密(使用 DPAPI)并移动到用户可访问的目录。为了额外的安全,需要删除位于“C:\Program Files”中的原始文件。如果用户取消 UAC 提示,那么,那将失败,但他们的敏感配置是纯文本的,这将是用户的错。
是的,我知道我可以通过 MSI 将文件放置在用户的目录中,但这对我也不利,因为它需要额外的配置步骤,我想避免。在使用完全默认的 MSI 安装程序安装后,该程序必须自行完成所有杂务。我可以这样离开,但似乎 rundll32
hack 只是在嘲笑我,而我离它只有一个特殊的角色 ;)
rundll32 需要一个非常具体的函数签名,it is not a generic "call any function" helper application。
要隐藏 cmd window,您可以尝试添加 WindowStyle = ProcessWindowStyle.Hidden
,但如果您已经拥有 C# 应用程序,何必费心呢?就叫自己去做任务吧。这至少会在 UAC 对话框中放入正确的 .exe。
即使你把这一切都搞定了,它仍然是错误的!如果您正在安装到 %ProgramFiles%,那么您正在为机器上的所有用户安装,并且一旦第二个用户运行您的应用程序,您的方案就会中断。任何写入用户配置文件的操作都必须在用户第一次运行您的程序时完成,而不是在安装阶段。您可以将模板文件从安装目录复制到用户配置文件,但不能删除模板。
如果您需要删除文件,您可以使用 IFileOperation
。示例代码:
#include <shobjidl_core.h>
// assume
// CoInitializeEx(0, COINIT_DISABLE_OLE1DDE|COINIT_APARTMENTTHREADED);
// already called
HRESULT DeleteFileElevated(PCWSTR lpFilename)
{
IShellItem* psi;
HRESULT hr = SHCreateItemFromParsingName(lpFilename, 0, IID_PPV_ARGS(&psi));
if (0 <= hr)
{
IFileOperation *pFileOp;
BIND_OPTS2 bo = { sizeof(bo) };
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
if (0 <= (hr = CoGetObject(L"Elevation:Administrator!new:{3ad05575-8857-4850-9277-11b85bdb8e09}", &bo, IID_PPV_ARGS(&pFileOp))))
{
0 <= (hr = pFileOp->SetOperationFlags(FOF_NOCONFIRMATION|
FOF_NOERRORUI|
FOF_FILESONLY|
FOFX_EARLYFAILURE|
FOFX_SHOWELEVATIONPROMPT)) &&
0 <= (hr = pFileOp->DeleteItem(psi, 0))
&&
0 <= (hr = pFileOp->PerformOperations());
pFileOp->Release();
}
psi->Release();
}
return hr;
}