Im trying to make a tool for my end users that can create a MiniDump of my application if it hangs (i.e. external to the app). Im using the same code as the internal MiniDumper but with the handle and processid of the app but i keep getting error code 0xD0000024 when calling MiniDumpWriteDump. Any ideas?
void produceDump( const char* exe )
{
DWORD processId = 0;
HANDLE process = findProcess(exe, processId);
if (!process || processId == 0)
{
printf("Unable to find exe %s to produce dump.\n", exe);
return;
}
LONG retval = EXCEPTION_CONTINUE_SEARCH;
HWND hParent = NULL; // find a better value for your app
// firstly see if dbghelp.dll is around and has the function we need
// look next to the EXE first, as the one in System32 might be old
// (e.g. Windows 2000)
HMODULE hDll = NULL;
char szDbgHelpPath[_MAX_PATH];
if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
{
char *pSlash = _tcsrchr( szDbgHelpPath, '\\' );
if (pSlash)
{
_tcscpy( pSlash+1, "DBGHELP.DLL" );
hDll = ::LoadLibrary( szDbgHelpPath );
}
}
if (hDll==NULL)
{
// load any version we can
hDll = ::LoadLibrary( "DBGHELP.DLL" );
}
LPCTSTR szResult = NULL;
int err = 0;
if (hDll)
{
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
if (pDump)
{
char szDumpPath[_MAX_PATH];
char szScratch [_MAX_PATH];
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
char comAppPath[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA , NULL, SHGFP_TYPE_CURRENT, comAppPath );
//COMMONAPP_PATH
_snprintf(szDumpPath, _MAX_PATH, "%s\\DN", comAppPath);
CreateDirectory(szDumpPath, NULL);
_snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D", comAppPath);
CreateDirectory(szDumpPath, NULL);
_snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D\\dumps", comAppPath);
CreateDirectory(szDumpPath, NULL);
char fileName[_MAX_PATH];
_snprintf(fileName, _MAX_PATH, "%s_Dump_%04d%02d%02d_%02d%02d%02d.dmp", exe, timeinfo->tm_year+1900, timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec );
_snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D\\dumps\\%s", comAppPath, fileName);
// create the file
HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if (hFile!=INVALID_HANDLE_VALUE)
{
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
MiniDumpWithDataSegs |
MiniDumpWithHandleData |
//MiniDumpWithFullMemoryInfo |
//MiniDumpWithThreadInfo |
MiniDumpWithProcessThreadData |
MiniDumpWithUnloadedModules );
// write the dump
BOOL bOK = pDump( process, processId, hFile, mdt, NULL, NULL, &mci );
DWORD lastErr = GetLastError();
if (bOK)
{
printf("Crash dump saved to: %s\n", szDumpPath);
return;
}
else
{
_snprintf( szScratch, _MAX_PATH, "Failed to save dump file to '%s' (error %u)", szDumpPath, lastErr);
szResult = szScratch;
err = ERR_CANTSAVEFILE;
}
::CloseHandle(hFile);
}
else
{
_snprintf( szScratch, _MAX_PATH, "Failed to create dump file '%s' (error %u)", szDumpPath, GetLastError());
szResult = szScratch;
err = ERR_CANTMAKEFILE;
}
}
else
{
szResult = "DBGHELP.DLL too old";
err = ERR_DBGHELP_TOOLD;
}
}
else
{
szResult = "DBGHELP.DLL not found";
err = ERR_DBGHELP_NOTFOUND;
}
printf("Could not produce a crash dump of %s.\n\n[error: %u %s].\n", exe, err, szResult);
return;
}
this code works 100% when its internal to the process (i.e. with SetUnhandledExceptionFilter)
Are you opening the process with the necessary access rights? MiniDumpWriteDump() needs the process handle to be opened using PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights. When using GetCurrentProcess(), I think these are granted automatically, but when using OpenProcess() to open another process, you have to request these rights.
To do so, you might also have to enable SeDebugPrivilege, which would cause problems for users whose accounts don't have that privilege. But the documentation doesn't seem to be clear on whether SeDebugPrivilege is necessary for PROCESS_QUERY_INFORMATION and PROCESS_VM_READ rights specifically (as opposed to all process access rights), particularly when opening a process that is running as the same user account.
I see that you are explicitly casting MyMiniDumpCallback to be a PMINIDUMP_CALLBACK_INFORMATION type. That looks fishy, as if you had a compiler error that you were getting around because the types didn't match. That, and PMINIDUMP_CALLBACK_INFORMATION is a struct, not a function pointer.
The direct cast of function pointer to PMINIDUMP_CALLBACK_INFORMATION might be valid since the first parameter of that struct is the callback function. But again, it looks real fishy. Perhaps you misdeclared your callback function (like forgetting the CALLBACK/__stdcall modifier). Get your code to compile without casting those formal params first, then I'll be more inclined to help you.
Also, did you even check that your callback function is even getting called at all?
Related
Despite the fact that memory allocation/write, finding LoadLibraryA address and creating a remote thread return valid (not NULL) results, absolutely nothing happens after that (mainly, the DllMain of the loaded DLL doesn't seem to get called).
#define PROC_NAME L"TestConsole.exe"
#define DLL_NAME "TestLib.dll\0"
HANDLE GetProcessByName(const wchar_t* name);
int main()
{
const char dllName[] = DLL_NAME;
int dllNameSize = strlen(dllName) + 1;
HANDLE process = GetProcessByName(PROC_NAME);
LPVOID allocMem = VirtualAllocEx(process, NULL, dllNameSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(process, allocMem, dllName, dllNameSize, NULL);
// Just to make sure
char buff[20];
ReadProcessMemory(process, allocMem, buff, dllNameSize, NULL);
printf("Data: %s\n", buff);
LPVOID libraryAddress =
(LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
HANDLE remoteThread = CreateRemoteThread(process, NULL, NULL, (LPTHREAD_START_ROUTINE)libraryAddress, allocMem, NULL, NULL);
}
HANDLE GetProcessByName(const wchar_t* name)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (wcscmp(entry.szExeFile, name) == 0)
{
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ParentProcessID);
}
}
}
return NULL;
}
Things I know/checked:
The thread gets created and a valid (not null) handle is returned. Despite it nothing happens.
I'm pretty sure that it's not DLL's fault. It's extremely simple, simply prints to console when it gets loaded and it works correctly when used simply with CreateThread().
Injector, DLL and the app to which I'm injecting are all 64 bit. If I chose any other platform (for all 3) everything works the same except for CreateRemoteThread(), which now fails.
The entry.th32ParentProcessID is the identifier of the process that created this process (its parent process). which means you did inject into the parent process of the target process (explorer.exe in my test). You should use entry.th32ProcessID instead.
In addition, the open permission PROCESS_ALL_ACCESS used in OpenProcess is too large, you only need to use what the CreateRemoteThread document requires: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ
I am trying to create a simple C++ console app which dump the memory space of a given process (e.g. calc.exe) So I use MiniDumpWriteDump function
Here is the code :
DWORD procID = 1150;
char* procName = "calc.exe";
// opens the dump file
HANDLE hFile = CreateFile( "calc.dmp", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if(hFile)
{
// opens the process
HANDLE hProcToDump = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procID);
if(hProcToDump)
{
// dumps via the API
BOOL rv = MiniDumpWriteDump(hProcToDump, GetProcessId(hProcToDump), hFile, MiniDumpNormal, NULL, NULL, NULL);
HRESULT hr = GetLastError();
if( !rv )
printf("MiniDumpWriteDump failed.");
else
printf("Minidump OK!");
CloseHandle( hFile );
CloseHandle( hProcToDump );
}
}
But I get the error :
GetLastError() = hresult 0x8007012b Only part of a ReadProcessMemory or WriteProcessMemory request was completed
Why ?
Note : I am admin on Win 7 x64.
Thank you for your help.
Try this, which is similar to your example. Usage of MiniDumpWriteDump.
I have several processes that try to read and write the same file. I want each of them to lock the file so that only one of them accesses it at a time.
I tried this (edit: this is a complete test code this time):
#include "stdafx.h"
#include "Windows.h"
bool test()
{
const char* path = "test.txt";
HANDLE hFile = CreateFileA(path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("ERROR: Cannot open file %s\n", path);
return false;
}
// Lock the file
{
OVERLAPPED overlapped = {0};
BOOL res = LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, ~0, &overlapped);
if (!res)
{
printf("ERROR: Cannot lock file %s\n", path);
return false;
}
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (fileSize > 0)
{
char* content = new char[fileSize+1];
// Read the file
BOOL res = ReadFile(hFile, content, fileSize, NULL, NULL);
if (!res)
{
printf("ERROR: Cannot read file %s\n", path);
}
delete[] content;
}
const char* newContent = "bla";
int newContentSize = 3;
// Write the file
BOOL res = WriteFile(hFile, newContent, newContentSize, NULL, NULL);
if (!res)
{
//int err = GetLastError();
printf("ERROR: Cannot write to file\n");
}
// Unlock the file
{
OVERLAPPED overlapped = {0};
UnlockFileEx(hFile, 0, ~0, ~0, &overlapped);
}
CloseHandle(hFile);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool res = test();
return 0;
}
This works fine on my computer, which has Windows 8. But on my colleague's computer, which has Windows 7, it crashes. Specifically, the calls to ReadFile and WriteFile crash, always.
Note that it never enters the code paths with the error printfs. This code triggers no error except for a write at location 0x00000000 in ReadFile (when run on Windows 7).
We tried to also pass the overlapped struct to the ReadFile and WriteFile calls. It prevents the crash but the lock doesn't work anymore, the file is all scrambled (not with this test code, with the real code).
What am I doing wrong?
Looks like your problem is:
lpNumberOfBytesRead [out, optional] argument is null in your call.
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
Heres your problem :
You are missing a necessary struct-member and:
0 and ~0 and {0} are all bad code, constant expressions like these will always produce unepected results -- WINAPI doesnt work like libc, parameters are not always compared against constants, instead they are tested against/via macros and other preprocessor-definitions themselves so passing constant values or initializing WINAPI structs with constants will often lead to errors like these.
After years of experimenting i have found that there is only one surefire way of avoiding them, i will express it in corrected code :
OVERLAPPED overlapped;
overlapped.hEvent = CreateEvent( ........... ); // put valid parameters here!
UnlockFileEx(hFile, 0 /*"reserved"*/, ULONG_MAX, ULONG_MAX, &overlapped);
please read this carefully : http://msdn.microsoft.com/en-us/library/windows/desktop/aa365716%28v=vs.85%29.aspx
I`m trying to inject a DLL in a process and call a exported function in my DLL.
The DLL is injected alright with that code:
HANDLE Proc;
char buf[50] = { 0 };
LPVOID RemoteString, LoadLibAddy;
if (!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());
printf(buf);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
// Allocate space in the process for our DLL
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write the string name of our DLL in the memory allocated
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
// Load our DLL
HANDLE hThread = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
The module of my DLL is created OK, like you see in that image of Process Hacker (BootstrapDLL.exe):
My exported functions is ok too, like you see in the list of functions exported on Process Hacker (ImplantDotNetAssembly):
The problems, I think, happens on the offset calculation to get the address of the "ImplantDotNetAssembly", because everything above is alright and when I do the calculation I get the address of the "ImplantDotNetAssembly", but when I call CreateRemoteThread again to call it, the window "Has stopped working..." of the windows is showed and the process stoped. What`s happening?
Here is the code of the calculation of the offset:
DWORD_PTR hBootstrap = GetRemoteModuleHandle(ProcId, L"BootstrapDLL.exe");
DWORD_PTR offset = GetFunctionOffset(L"C:\\Users\\Acaz\\Documents\\Visual Studio 2013\\Projects\\Contoso\\Debug\\BootstrapDLL.exe", "ImplantDotNetAssembly");
DWORD_PTR fnImplant = hBootstrap + offset;
HANDLE hThread2 = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)fnImplant, NULL, 0, NULL);
Here are the functions GetRemoteModuleHandle and GetFunctionOffset:
DWORD_PTR GetFunctionOffset(const wstring& library, const char* functionName)
{
// load library into this process
HMODULE hLoaded = LoadLibrary(library.c_str());
// get address of function to invoke
void* lpInject = GetProcAddress(hLoaded, functionName);
// compute the distance between the base address and the function to invoke
DWORD_PTR offset = (DWORD_PTR)lpInject - (DWORD_PTR)hLoaded;
// unload library from this process
FreeLibrary(hLoaded);
// return the offset to the function
return offset;
}
DWORD_PTR GetRemoteModuleHandle(const int processId, const wchar_t* moduleName)
{
MODULEENTRY32 me32;
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
// get snapshot of all modules in the remote process
me32.dwSize = sizeof(MODULEENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId);
// can we start looking?
if (!Module32First(hSnapshot, &me32))
{
CloseHandle(hSnapshot);
return 0;
}
// enumerate all modules till we find the one we are looking for or until every one of them is checked
while (wcscmp(me32.szModule, moduleName) != 0 && Module32Next(hSnapshot, &me32));
// close the handle
CloseHandle(hSnapshot);
// check if module handle was found and return it
if (wcscmp(me32.szModule, moduleName) == 0)
return (DWORD_PTR)me32.modBaseAddr;
return 0;
}
If someone know what is happening, I'll be very grateful!
I cant`t even debug the "has stopped work.." error. When I clik in the DEBUG button on the window, the error throw again and everything stop.
Thank you.
NEVER inject managed assemblies. If for some reason you must inject code into another process, use native code with either NO C library or a STATIC C library.
I am want to find the type of drive for that i used DeviceIoControl function which is working. However when I use the same function in DLL it returns with ERROR_BAD_LENGTH error. Following is my code.
BOOL Globals::IsUsbDevice ( wchar_t letter)
{
wchar_t volumeAccessPath[] = L"\\\\.\\X:";
volumeAccessPath [4] = letter;
HANDLE deviceHandle= CreateFileW(
volumeAccessPath,
0, // no access to the Drive
FILE_SHARE_READ | // Share mode
FILE_SHARE_WRITE,
NULL, // Default Security attributes
OPEN_EXISTING, // Disposition
0, // file attributes
NULL); // do not Copy file attributes
if (deviceHandle == INVALID_HANDLE_VALUE) // cannot open the drive
{
CloseHandle (deviceHandle);
return (FALSE);
}
// Setup query
STORAGE_PROPERTY_QUERY Query;
memset (&Query, 0, sizeof (Query));
Query.PropertyId = StorageDeviceProperty;
Query.QueryType = PropertyStandardQuery;
// Issue query
DWORD bytes;
//STORAGE_DEVICE_DESCRIPTOR Devd;
STORAGE_BUS_TYPE busType = BusTypeUnknown;
char OutBuf[1024] = {0}; // good enough, usually about 100 bytes
PSTORAGE_DEVICE_DESCRIPTOR pDevDesc = (PSTORAGE_DEVICE_DESCRIPTOR)OutBuf;
pDevDesc->Size = sizeof(OutBuf);
if (DeviceIoControl (deviceHandle,
IOCTL_STORAGE_QUERY_PROPERTY,
&Query, sizeof(STORAGE_PROPERTY_QUERY),
pDevDesc, pDevDesc->Size,
&bytes,NULL))
{
busType = pDevDesc->BusType;
}
else
{
// Retrieve the system error message for the last-error code
..........
}
CloseHandle (deviceHandle);
return BusTypeUsb == busType;
}
I am executing my program as Administrator.
Any help would be greatly appreciated.