Unregistering and uninstalling a Context menu driver - c++

I am writing a software removal program, and want to uninstall a context menu driver. Just unregistering the driver while Windows File Explorer is open fails when trying to unregister the dll. Closing file explorer first and then running the program does not always work either.
Here is the unregister code I am using now:
HINSTANCE hLib = LoadLibraryW(szDllPath);
if (hLib == NULL)
{
DWORD dwErrorCode = GetLastError();
szError.Format(_T("\nWindows could not load library %s due to %s"),szDllName,getLastWinError(dwErrorCode));
return false;
}
typedef HRESULT (CALLBACK *HCRET)(void);
HCRET lpfnDllRegisterServer;
// Find the entry point
lpfnDllRegisterServer = (HCRET)GetProcAddress(hLib, "DllUnregisterServer");
if (lpfnDllRegisterServer == NULL)
{
szError = NEWLINE;
szError = ERR_PROCEDURE_ADDRESS;
return false;
}
// Call the function by function pointer..
if (FAILED((*lpfnDllRegisterServer)()))
{
szError.Format(_T("\nWindows could not unregister context menu driver %s!"),szDllName);
return false;
}
FreeLibrary(hLib);
What is the best way to go about this? It seems that even if the dll is unregistered by just deleting the relevant registry keys, File Explorer still will not let go of it.

Related

detours vs MinHook for DLL injection

I have succefully hooked a gog game (DRM free) with this code:
bool WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
static HMODULE libogg_ori = nullptr;
int FFBInitDelayInMillliseconds;
char* DLLFileName;
std::string DLLFile = "libogg_ori.dll";
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
// Load dll
// Initialize config File
Local_InitConfigComplete = Init_Config();
// Delay for timer that initialize the Force Feedback
FFBInitDelayInMillliseconds = Config.FFBDelayBeforeInit * 1000;
DLLFileName = R"(libogg_ori.dll)";
if (FS::File_Exist(DLLFileName))
{
LF::Log_Update("File DLL exit");
// Load the System DLL
d3d9dll = LoadLibraryA(DLLFileName);
if (d3d9dll == NULL)
LF::Log_Update("Load DLL error");
}
else
{
LF::Log_Update("File DLL not exist");
}
// Initilize Detour
if (Local_InitConfigComplete)
Local_InitConfigComplete = Init_Detour();
break;
case DLL_PROCESS_DETACH:
// Close the DLL
LF::Log_Update("Closing session ...");
LF::Log_Update("Release hook in progress ...");
// unhook
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
// this will hook the sound function
DetourDetach(&(LPVOID&)AddressOfHookSoundFunction, &HookSoundFileSub);
// this will hook the damage function (if present in configuration)
if (AddressOfHookDamageFunction>0)
DetourDetach(&(LPVOID&)AddressOfHookDamageFunction, &HookDamageSub);
if (DetourTransactionCommit() == NO_ERROR)
LF::Log_Update(LOG_FLAG_DONE);
else
LF::Log_Update(LOG_FLAG_ERROR, "Warning Hooking not relased.");
LF::Log_Update("Session closed.");
break;
}
return true;
}
bool Init_Detour()
{
// Initialize Detours
// we will find the function/s to hook with IDA pro.
try
{
LF::Log_Update("Initialize Hooking ...");
AddressOfHookSoundFunction = std::strtoul(Config.GameFileSoundOffsetPos.c_str() ,NULL,16); // BattleZoneRedux 0x43AA30
if (Config.GameFileDamageOffsetPos.size() > 1)
AddressOfHookDamageFunction = std::strtoul(Config.GameFileDamageOffsetPos.c_str(), NULL, 16); // BattleZoneRedux 0x49B430
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
// this will hook the sound function
DetourAttach(&(LPVOID&)AddressOfHookSoundFunction, &HookSoundFileSub);
// If is present a offset for hook the damage
if (AddressOfHookDamageFunction!=0)
DetourAttach(&(LPVOID&)AddressOfHookDamageFunction, &HookDamageSub);
if (DetourTransactionCommit() == NO_ERROR)
{
LF::Log_Update(LOG_FLAG_DONE);
return true;
}
else
{
LF::Log_Update(LOG_FLAG_ERROR, "Hooking not initilizing.");
return false;
}
}
catch (const std::exception&)
{
LF::Log_Update(LOG_FLAG_ERROR, "Error while initialize Detour.");
return false;
}
}
to do it I have found a custom version of libogg.dll and d3d9.dll (DLL injection). Both work perfectly.
But when I used the some code to another GOG game with DRM free, to inject it with libogg.dll the game crash always on this row:
DetourDetach(&(LPVOID&)AddressOfHookSoundFunction, &HookSoundFileSub);
In all my test with the game that work, never crash in this row even if AddressOfHookSoundFunction is relative to a non-existent address.
In short independently by AddressOfHookSoundFunction and HookSoundFileSub that second game crash always.
Here the difference between the two games:
The first was made in 2017 and the second was made in 2018 by the some software house.
If I disassambly with IDA the first game I see always sub_xxxxxx , but in the second game sometimes I see the real name of the functions and not the address. So I suppose it was done by a more recent visual c++ version, and for this reason it may not work.
On many forums the people suggest to use MinHook becouse is better than detours, but I don't known why and if this is true for all cases.
Can someone have the some experience in situations like this ?
If the solution is use minhook, can someone help me to re-write this code:
AddressOfHookSoundFunction = std::strtoul(Config.GameFileSoundOffsetPos.c_str() ,NULL,16); // BattleZoneRedux 0x43AA30
if (Config.GameFileDamageOffsetPos.size() > 1)
AddressOfHookDamageFunction = std::strtoul(Config.GameFileDamageOffsetPos.c_str(), NULL, 16); // BattleZoneRedux 0x49B430
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
// this will hook the sound function
DetourAttach(&(LPVOID&)AddressOfHookSoundFunction, &HookSoundFileSub);
// If is present a offset for hook the damage
if (AddressOfHookDamageFunction!=0)
DetourAttach(&(LPVOID&)AddressOfHookDamageFunction, &HookDamageSub);
if (DetourTransactionCommit() == NO_ERROR)
{
LF::Log_Update(LOG_FLAG_DONE);
return true;
}
else
{
LF::Log_Update(LOG_FLAG_ERROR, "Hooking not initilizing.");
return false;
}
with MinHook ?
Thank you !

How Could I Get the Window Title from Its Process Name?

This is my code to check if the process name existed or not:
bool isRunning (LPCSTR processname)
{
HANDLE Snapshot;
Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(Snapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 ProcessEntry;
BOOL Succeed;
ProcessEntry.dwSize = sizeof(PROCESSENTRY32);
Succeed = Process32First(Snapshot, &ProcessEntry);
while(Succeed)
{
if(lstrcmp(ProcessEntry.szExeFile,processname) == 0)
{
return true;
}
Succeed = Process32Next(Snapshot, &ProcessEntry);
}
CloseHandle(Snapshot);
}
}
How could I use it or edit it to get the window title from its process name (for example "notepad.exe")?
If it existed the program would return text like "New text document - Notepad"
This is actually addressed in Microsoft's description of CreateToolhelp32Snapshot.
It says "You can use the QueryFullProcessImageName function to retrieve the full name of an executable image for both 32- and 64-bit processes from a 32-bit process."
You'll basically need to iterate through checking your HANDLEs with QueryFullProcessImageName.

CreateToolhelp32Snapshot: INVALID_HANDLE_VALUE (ERROR_PARTIAL_COPY)

This code is running in a 64-bit application. The target application is 32-bit.
Every time I run this code, CreateToolhelp32Snapshot() returns INVALID_HANDLE_VALUE and then GetLastError() returns ERROR_PARTIAL_COPY. So it skips the loop and returns false.
BOOL HookInjector::InjectIntoProcess(DWORD pID)
{
//Get Handle to Remote Process
HANDLE Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
....
//Check to see if 64-bit or 32-bit application
IsWow64Process(Proc, &isWow64);
size_t szCurProc = sizeof(void*); //returns 8
if (isWow64)
{
__debugbreak();
//Get list of all Modules associated with the Process
HANDLE hProc32Module;
do {
hProc32Module = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32, pID);
}
while ((hProc32Module == INVALID_HANDLE_VALUE) && (GetLastError() == ERROR_BAD_LENGTH));
if (hProc32Module == INVALID_HANDLE_VALUE) {
__debugbreak();
DWORD err = GetLastError(); //just to see the error code which is 0x12b
return false;
}
//Find the module for Kernel.dll and get the base address of it
MODULEENTRY32 entryModule;
entryModule.dwSize = sizeof(MODULEENTRY32);
BOOL isGetModuleSuccess = Module32First(hProc32Module, &entryModule);
DWORD errEndofList = GetLastError();
BOOL isSuccessful = false;
while (errEndofList != ERROR_NO_MORE_FILES && isGetModuleSuccess)
{
if (_tcscmp(entryModule.szModule, KERNEL32_DLL)){
isSuccessful = true;
break;
}
isGetModuleSuccess = Module32Next(hProc32Module, &entryModule);
errEndofList = GetLastError();
}
if (!isSuccessful)
{
__debugbreak();
CloseHandle(hProc32Module);
return false;
}
//Get handle for Kernel.dll module
hKernel32 = entryModule.hModule;
CloseHandle(hProc32Module);
}
else
{
....
According to the documentation, CreateToolhelp32Snapshot() only fails with ERROR_PARTIAL_COPY when CreateToolhelp32Snapshot() is called by a 32bit process trying to access a 64bit process:
If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).
Make sure your app really is compiled for 64bit to begin with. TH32CS_SNAPMODULE32 only makes sense to use when CreateToolhelp32Snapshot() is being called in a 64bit process:
TH32CS_SNAPMODULE32
0x00000010
Includes all 32-bit modules of the process specified in th32ProcessID in the snapshot when called from a 64-bit process.
You are also not taking into account that GetLastError() is only updated when API functions fail, unless documented otherwise. Your loops are assuming that GetLastError() is updated after every API call, that is simply not true.
Try something more like this instead:
BOOL HookInjector::InjectIntoProcess(DWORD pID)
{
//Get Handle to Remote Process
HANDLE Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
....
DWORD dwFlag;
#ifdef _WIN64
//Check if Remote Process is a 32-bit application
BOOL isWow64 = FALSE;
IsWow64Process(Proc, &isWow64);
if (!isWow64) return false;
// TH32CS_SNAPMODULE32 includes 32bit modules when used by a 64bit process...
dwFlag = TH32CS_SNAPMODULE32;
#else
// TH32CS_SNAPMODULE includes 32bit modules when used by a 32bit process...
dwFlag = TH32CS_SNAPMODULE;
#endif
__debugbreak();
//Get list of all Modules associated with the Process
HANDLE hProc32Module;
do {
hProc32Module = CreateToolhelp32Snapshot(dwFlag, pID);
}
while ((hProc32Module == INVALID_HANDLE_VALUE) && (GetLastError() == ERROR_BAD_LENGTH));
if (hProc32Module == INVALID_HANDLE_VALUE) {
__debugbreak();
return false;
}
//Find the module for Kernel.dll and get the base address of it
hKernel32 = NULL;
MODULEENTRY32 entryModule = {0};
entryModule.dwSize = sizeof(MODULEENTRY32);
BOOL isGetModuleSuccess = Module32First(hProc32Module, &entryModule);
while (isGetModuleSuccess) {
if (_tcscmp(entryModule.szModule, KERNEL32_DLL)) {
hKernel32 = entryModule.hModule;
break;
}
isGetModuleSuccess = Module32Next(hProc32Module, &entryModule);
}
if (!hKernel32) {
__debugbreak();
CloseHandle(hProc32Module);
return false;
}
CloseHandle(hProc32Module);
....
}
According to the documentation, CreateToolhelp32Snapshot() only fails with ERROR_PARTIAL_COPY when CreateToolhelp32Snapshot() is called by a 32bit process trying to access a 64bit process:
If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).
This is plain wrong as you could have deduced from the excerpt you posted. Where does it say it ONLY fails with ERROR_PARTIAL_COPY (299) when the caller is 32bit trying to access 64bit? It doesn't.
If the documentation would be complete, which it is not, then you would be right to assume that the stated behaviour is the only way to generate an ERROR_PARTIAL_COPY error code. Sadly the documentation is not complete.
For example if you start a process with the CREATE_SUSPENDED flag the CreateToolhelp32Snapshot API will set the error code to ERROR_PARTIAL_COPY when queried for modules regardless of the bitness of the host or target application. The reason it fails is because the DLLs aren't loaded until after the main thread is resumed and therefore the PebLdr pointer in the PEB structure is NULL.
Basically anything which prevents read of process memory (missing address in PEB, unmapped segment, etc.) can cause ERROR_PARTIAL_COPY as its description states:
ERROR_PARTIAL_COPY 299 (0x12B)
Only part of a ReadProcessMemory or WriteProcessMemory request was completed.

Windows Event Viewer holds a lock on my EXE file

I'm curious about something. I'm developing a Windows service and log all the diagnostic events into the Windows Event Log. So when the service is running I open the Event Viewer (from Administrative tools) to view the results of my service's operation.
This works great except for the moment when I need to uninstall my program (again, for the testing purposes.) For some weird reason the Event Viewer holds a lock on the .exe image file for my service so the uninstaller fails to delete it with the error code ERROR_SHARING_VIOLATION:
The process cannot access the file because it is being used by another process.
This happens only on Vista and later OS and seems not to be an issue on XP.
Any idea how to make Event Viewer release the file lock? (I'm asking about programmatic approach. I can obviously close it manually, but that's not what I'm after.)
I released the lock this way:
Start -> Services
Locate Windows Event Log
Right click -> Restart
There's a less known feature introduced in Vista called Restart Manager that can help you release file locks via a user-mode code. Since you tagged it as C++, based on this article here's a small code sample to do that:
#include <RestartManager.h>
#pragma comment(lib ,"Rstrtmgr.lib")
BOOL ReleaseFileLock(LPCTSTR pFilePath)
{
BOOL bResult = FALSE;
DWORD dwSession;
WCHAR szSessionKey[CCH_RM_SESSION_KEY+1] = { 0 };
DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey);
if (dwError == ERROR_SUCCESS)
{
dwError = RmRegisterResources(dwSession, 1, &pFilePath,
0, NULL, 0, NULL);
if (dwError == ERROR_SUCCESS)
{
UINT nProcInfoNeeded = 0;
UINT nProcInfo = 0;
RM_PROCESS_INFO rgpi[1];
DWORD dwReason;
dwError = RmGetList(dwSession, &nProcInfoNeeded,
&nProcInfo, rgpi, &dwReason);
if (dwError == ERROR_SUCCESS ||
dwError == ERROR_MORE_DATA)
{
if(nProcInfoNeeded > 0)
{
//If current process does not have enough privileges to close one of
//the "offending" processes, you'll get ERROR_FAIL_NOACTION_REBOOT
dwError = RmShutdown(dwSession, RmForceShutdown, NULL);
if (dwError == ERROR_SUCCESS)
{
bResult = TRUE;
}
}
else
bResult = TRUE;
}
}
}
RmEndSession(dwSession);
SetLastError(dwError);
return bResult;
}
I just met same problem. The DLL was locked by svchost.exe process (Windows Audio, DHCP Client, Windows Event Log, TCP/IP NetBIOS Helper, Security Center, Task Scheduler)
Solution: close Event Viewer! :)

Advanced Installer serial validation DLL

I am working on an installer project in Advanced Installer 10.2. I found out that I can use a DLL for serial validation then I found this resource on their website.
I succeeded in building that DLL, here is my code:
// SerialValidationLib.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "SerialValidationLib.h"
#include <Msi.h>
#include <MsiQuery.h>
#include <MsiDefs.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
UINT __stdcall ValidateSerial_Sample(MSIHANDLE hInstall)
{
TCHAR szPidKey[256];
DWORD dwLen = sizeof(szPidKey)/sizeof(szPidKey[0]);
//retrive the text entered by the user
UINT res = MsiGetProperty(hInstall, _T("PIDKEY"), szPidKey, &dwLen);
if(res != ERROR_SUCCESS)
{
//fail the installation
return 1;
}
bool snIsValid = false;
//validate the text from szPidKey according to your algorithm
//put the result in snIsValid
TCHAR * serialValid;
if(snIsValid)
serialValid = _T("TRUE");
else
{
//eventually say something to the user
MessageBox(0, _T("Serial invalid!"), _T("Message"), MB_ICONSTOP);
serialValid = _T("FALSE");
}
res = MsiSetProperty(hInstall, _T("SERIAL_VALIDATION"), serialValid);
if(res != ERROR_SUCCESS)
{
return 1;
}
//the validation succeeded - even the serial is wrong
//if the SERIAL_VALIDATION was set to FALSE the installation
//will not continue
return 0;
}
I also imported it to Advanced Installer, look here:
But when I run the installer, and try to proceed with the installation, after serial insertion point, I get this error message:
Where is my mistake? Does anybody know a good tutorial about this? I searched on the internet, but nothing helps me...
You could have two problems:
either you have typed the method name instead of picking it from the combo loaded by Advanced Installer. In this case the installer fails to call the method from the DLL, as it cannot find it.
or, there is a problem with your code, in which case you need to debug it, as you would do with a normal custom action, attaching from VS (add a mesagebox with a breakpoint after it).