Home > Enterprise >  How to delete a file in Windows using rundll32.exe for it?
How to delete a file in Windows using rundll32.exe for it?

Time:11-07

I figured out it should go like this:

rundll32 kernel32.dll,DeleteFileA,test.txt

But it just doesn't work. I tried:

rundll32 kernel32.dll,DeleteFileA test.txt
rundll32 "kernel32.dll,DeleteFileA test.txt"

The file stays. When tried it from PowerShell it shows an error message when I misspell DeleteFileA so it finds the correct entry in kernel32.dll. It just doesn't work probably due to not getting the file name parameter.

Why do I need it? I need to be able to delete a file as an administrator in a program that is run in regular user context. I strictly do not want the entire app to be run as administrator. Only the exact one delete should show a UAC confirmation.

Here's something that works in my C# app:

private static void DeleteAsAdmin(string target) {
    Process.Start(new ProcessStartInfo { FileName = "cmd", Arguments = $"/C \"del /F /Q \"\"\"{target}\"\"\"\"", Verb = "RunAs", CreateNoWindow = true });
}

However, it shows a window anyway. For a while, but it's visible. It's because I have to explicitly execute cmd to be able to use the del command.

That's why I want to use rundll32 instead. This will create no window by default. And it has FileDeleteA method exposed.

I know, I could add a helper executable that would delete the file as admin for my app, but this is a very ugly solution, even uglier than calling cmd.

Why do I need to delete the file in the first place? For security. The file contains a sensitive program configuration that gets encrypted (with DPAPI) and moved to the user accessible directory. The original file, residing in "C:\Program Files" needs to be removed for extra safety. If the user cancels the UAC prompt, well, that will fail but it will be the user's fault that they have their sensitive config in plain text.

Yes, I know I could make the file placed in user's directory by the MSI, however this is also not good for me, because it would require an extra configuration step I'd like to avoid. The program must do all the chores itself after being installed with a totally default MSI installer. I can leave it like this, but it seems that rundll32 hack is just mocking me and I'm just one special character away from it ;)

CodePudding user response:

rundll32 requires a very specific function signature, it is not a generic "call any function" helper application.

To hide the cmd window you could try adding WindowStyle = ProcessWindowStyle.Hidden but why bother if you already have a C# app? Just call yourself to do the task. That at least puts the correct .exe in the UAC dialog.

Even if you get this all working it would still be wrong! If you are installing into %ProgramFiles% then you are installing for all users on the machine and your scheme breaks as soon as a 2nd user runs your app. Anything that writes to the users profile must be done the first time a user runs your program, not during the install phase. You can copy template files from your install directory to the users profile but you cannot delete the templates.

CodePudding user response:

if you need delete file you can use IFileOperation for this. example code:

#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;
}
  • Related