Writing windows debugger, Read/WriteProcessMemory vs file mapping - debugging

I wonder what is the "correct" way for the debugger to read debuggee's memory. Since debugger provides the ability to view and alter debuggee's memory, the user can modify the code. The code section is frequently read by the debugger to produce disassembly, also we should be able to detect jump to the middle of instruction and disassemble again.
While ReadProcessMemory and WriteProcessMemory seem appropriate for reading and writing data, I think it will be easier to use file mapping for code, so debugger will be able to work with code as if it was in its own address space. Also, we need to insert imported/exported function names in our disassembly output, to achieve this we need to walk image import/export directory (file mapping is more convenient here).
There is one problem though. MapViewOfFileEx(..., ImageBase) will fail, since ImageBase is used by Windows (it is a start of unnamed SEC_IMAGE section created by loader). We have the option to use MapViewOfFile and copy image, however, if an executable is large (like 100Mb Nvidia Driver) it will rob debuggee out of some heap.
//--------------------------------------------------------------------------
// debugger
//--------------------------------------------------------------------------
struct MY_PROCESS_INFORMATION
{
HANDLE hProcess;
DWORD dwProcessId;
};
struct FILEMAP_INFORMATION
{
HANDLE hFileMap;
void* MapAddr;
};
struct INJECT_INFORMATION
{
HMODULE hModule;
BOOL Success;
};
struct MODULE_INFORMATION
{
ptrdiff_t BaseDelta;
void* AddressOfEntryPoint;
};
BOOL DbgLoad(HANDLE hProcess, char* DllName, INJECT_INFORMATION* InjectInfo)
{
BOOL Loaded;
size_t Size;
void* pAlloc;
HMODULE hModule;
HANDLE hNewThread;
LPTHREAD_START_ROUTINE Start;
HANDLE hEvent;
if (InjectInfo)
{
hEvent = CreateEventA(NULL, FALSE, FALSE, "dbg_event");
if (!hEvent) return FALSE;
}
Loaded = FALSE;
hModule = GetModuleHandleA("kernel32.dll");
if (hModule)
{
Start = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
if (Start)
{
Size = strlen(DllName) + sizeof(char);
pAlloc = VirtualAllocEx(hProcess, NULL, Size, MEM_COMMIT, PAGE_READWRITE);
if (pAlloc)
{
if (WriteProcessMemory(hProcess, pAlloc, DllName, Size, NULL))
{
hNewThread = CreateRemoteThread(hProcess, NULL, 0, Start, pAlloc, 0, NULL);
if (hNewThread)
{
if (InjectInfo)
{
if (!WaitForSingleObject(hEvent, INFINITE)) InjectInfo->Success = TRUE;
else InjectInfo->Success = FALSE;
if (!WaitForSingleObject(hNewThread, INFINITE))
{
#ifdef _WIN32
if (GetExitCodeThread(hNewThread, (DWORD*)&hModule))
{
if (hModule)
{
InjectInfo->hModule = hModule;
Loaded = TRUE;
}
}
#else
//...
#endif
}
}
else
{
if (!WaitForSingleObject(hNewThread, INFINITE)) Loaded = TRUE;
}
CloseHandle(hNewThread);
}
}
if (InjectInfo) VirtualFreeEx(hProcess, pAlloc, 0, MEM_DECOMMIT);
}
}
}
if (InjectInfo) CloseHandle(hEvent);
return Loaded;
}
BOOL DbgMap(MY_PROCESS_INFORMATION* ProcessInfo, FILEMAP_INFORMATION* FileMapInfo)
{
HANDLE hFileMap;
void* MapAddr;
INJECT_INFORMATION InjectInfo;
if (DbgLoad(ProcessInfo->hProcess, "D:\\Data\\New\\DllMap\\Debug\\DllMap.dll", &InjectInfo))
{
if (InjectInfo.Success)
{
hFileMap = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, "file_map");
if (hFileMap)
{
MapAddr = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (MapAddr)
{
FileMapInfo->hFileMap = hFileMap;
FileMapInfo->MapAddr = MapAddr;
return TRUE;
}
CloseHandle(hFileMap);
}
}
// unload...
}
return FALSE;
}
BOOL DbgGetModuleInfo(FILEMAP_INFORMATION* FileMapInfo, MY_PROCESS_INFORMATION* ProcessInfo, MODULE_INFORMATION* ModuleInfo)
{
BYTE* ImageBase;
BYTE* __ImageBase;
ptrdiff_t BaseDelta;
BYTE* AddressOfEntryPoint;
ImageBase = (BYTE*)FileMapInfo->MapAddr;
assert(((PIMAGE_DOS_HEADER)ImageBase)->e_magic == IMAGE_DOS_SIGNATURE);
AddressOfEntryPoint = ImageBase + GetImageEntryRVA(ImageBase);
// BaseDelta:
// 1) determine whether we have 32bit or 64bit image (using ImageBase)
// 2) NtQueryInformationProcess to get PEB
// 3) use PEB32 or PEB64 (depends on 1st step) to get __ImageBase
// 4) BaseDelta = ImageBase - __ImageBase
// parse imports and exports (using ImageBase)...
return TRUE;
}
//--------------------------------------------------------------------------
// DllMap
//--------------------------------------------------------------------------
HANDLE g_hFileMap;
void* g_MapAddr;
DWORD GetImageSize(void* Image)
{
PIMAGE_NT_HEADERS header;
header = (PIMAGE_NT_HEADERS)((BYTE*)Image + ((PIMAGE_DOS_HEADER)Image)->e_lfanew);
return header->OptionalHeader.SizeOfImage;
}
void* HModuleToAddr(HMODULE hModule)
{
return (void*)((size_t)hModule & ~(HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE));
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
HANDLE hEvent;
HMODULE hExe;
void* ImageBase;
DWORD ImageSize;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hEvent = OpenEventA(EVENT_MODIFY_STATE, FALSE, "dbg_event");
if (hEvent)
{
hExe = GetModuleHandleA(NULL);
if (hExe)
{
ImageBase = HModuleToAddr(hExe);
ImageSize = GetImageSize(ImageBase);
g_hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ImageSize, "file_map");
if (g_hFileMap)
{
g_MapAddr = MapViewOfFile(g_hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (g_MapAddr)
{
memcpy(g_MapAddr, ImageBase, ImageSize);
SetEvent(hEvent);
}
}
}
CloseHandle(hEvent);
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
if (!lpReserved) // FreeLibrary
{
if (g_hFileMap)
{
if (g_MapAddr)
{
UnmapViewOfFile(g_MapAddr);
g_MapAddr = 0;
}
CloseHandle(g_hFileMap);
g_hFileMap = 0;
}
}
break;
}
return TRUE;
}
Then we do this:
if (DbgMap(&ProcessInfo, &FileMapInfo))
{
if (DbgAttach(&ProcessInfo))
{
if (DbgGetModuleInfo(&FileMapInfo, &ProcessInfo, &ModuleInfo))
{
// Good
}
}
}
Note that when we create debuggee process we create it in suspended state without debugging flags (otherwise we would be unable to run LoadLibrary thread to perform file mapping). After we have created or opened debuggee process and performed mapping we attach with the debugger (in case we have created debuggee process we also need to call ResumeThread on its main thread).
I never wrote debugger before. So my question is whether we should use file mapping or ReadProcessMemory/WriteProcessMemory (for data, code, imports, exports, etc)? Is my approach reasonable or it is nonsense? Thanks.

Related

win32: improve performance of disk write

In order to write to HD at max. performance I'm using overlapped I/O.
It works.
Upon acquiring 4MB of data (from sensor) I'm writing it to disk.
Then, upon getting the next 4MB I first ask if the previous writing completed.
How can I know what is the optimal block size (4MB ?) that is best for my disk ?
// AsyncFile.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "AsyncFile.h"
/****************************************************************************/
CAsyncFile::CAsyncFile()
{
}
/****************************************************************************/
CAsyncFile::~CAsyncFile()
{
}
/****************************************************************************/
int CAsyncFile::OpenFile(char *pcFileName,
bool bAsync, // Whether async read/write is required
bool bWrite) // True is file is used for writing to
{
DWORD dwAsyncMask = bAsync ? (FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING) : 0;
DWORD dwCreation = bWrite ? CREATE_ALWAYS : OPEN_EXISTING;
DWORD dwAccess = bWrite ? GENERIC_WRITE : GENERIC_READ;
DWORD dwShareMode = bWrite ? FILE_SHARE_READ : FILE_SHARE_WRITE;
if (strlen(pcFileName) < sizeof(m_cFileName))
strcpy_s(m_cFileName, 256, pcFileName);
else
m_cFileName[0] = 0; // NULL (error - file name is too long)
// Calling openFile() sets a valid value to the file handle
m_hFileHandle = INVALID_HANDLE_VALUE;
// Auto reset (manual reset=false), init state = false, no name
m_hIoCompleted = CreateEvent(NULL, FALSE, FALSE, NULL);
// Init OVERLAPPED structure, for async read
m_tOverlapped.Offset = 0;
m_tOverlapped.OffsetHigh = 0;
m_tOverlapped.hEvent = m_hIoCompleted;
m_Event = m_tOverlapped.hEvent;
if (m_hFileHandle != INVALID_HANDLE_VALUE)
{
// File is already openned; check open mode
if ((bAsync == m_bAsync) && (bWrite == m_bWrite))
return (ASYNCFILE_OK);
// File is already openned, but in other mode; Should close file
// before using it again
return ASYNCFILE_FILE_IS_NOT_IN_WRITE_MODE;
}
m_hFileHandle =
CreateFile((LPCTSTR)m_cFileName,
dwAccess, // Open for read or write
dwShareMode, //
NULL, // No SECURITY_ATTRBUTES
dwCreation, // Open exisiting file (if read) \ create new (if write)
dwAsyncMask, // For asynchronous operations, for maximum asynchronous performence
0);
if (m_hFileHandle == INVALID_HANDLE_VALUE)
{
DWORD dwError = GetLastError();
return ASYNCFILE_FAILED_TO_OPEN_FILE;
}
//In case file opened for reading, get its size
if (bWrite == false)
{
GetFileSizeEx(m_hFileHandle, &m_FileSize);
}
// Save open mode
m_bAsync = bAsync;
m_bWrite = bWrite;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::CloseFile()
{
//BOOL Status;
if (!CloseHandle(m_hFileHandle))
return ASYNCFILE_FAILED_TO_CLOSE_FILE;
if (!CloseHandle(m_hIoCompleted))
return ASYNCFILE_FAILED_TO_CLOSE_FILE;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::StartAsyncRead(void* pBuffer,
DWORD dwReadSize,
bool* pbEof)
{
*pbEof = false; // By default, EOF is false
int iError;
if (m_hFileHandle == INVALID_HANDLE_VALUE)
return (false);
if (!ReadFile(m_hFileHandle,
pBuffer,
dwReadSize,
NULL, // actual bytes read is not valid now
&m_tOverlapped))
{
if ((iError = GetLastError()) == ERROR_HANDLE_EOF)
{
*pbEof = true;
return ASYNCFILE_OK;
}
else if (!(m_bAsync && (iError == ERROR_IO_PENDING)))
{
return ASYNCFILE_START_READ_FAILED;
}
}
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::WaitAsyncOperationEnd(DWORD* pdwActualBytesTransferred)
{
if (m_hFileHandle == INVALID_HANDLE_VALUE)
return ASYNCFILE_WAIT_FOR_COMPLETION_FAILED;
// Wait for read operation to complete
if (!GetOverlappedResult(m_hFileHandle,
&m_tOverlapped,
pdwActualBytesTransferred,
true))
return ASYNCFILE_WAIT_FOR_COMPLETION_FAILED;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::StartAsyncWrite(void* pSrcBuf,
DWORD dwSize) // In bytes
{
int iError;
if (!WriteFile(m_hFileHandle,
pSrcBuf,
dwSize,
NULL, // actual bytes written is not valid now
&m_tOverlapped))
{
iError = GetLastError();
if (iError != ERROR_IO_PENDING)
return ASYNCFILE_START_WRITE_FAILED;
}
return ASYNCFILE_OK;
}
/****************************************************************************/
void CAsyncFile::SetFilePosition(UINT64 Position)
{
m_tOverlapped.Offset = Position & 0xFFFFFFFF;
m_tOverlapped.OffsetHigh = Position >> 32;
}
/****************************************************************************/
UINT64 CAsyncFile::GetFilePosition()
{
UINT64 Position;
Position = (m_tOverlapped.Offset) | ((UINT64)m_tOverlapped.OffsetHigh << 32);
return (Position);
}
/****************************************************************************/
UINT64 CAsyncFile::GetFileSize()
{
return (m_FileSize.QuadPart);
}
Well it depends on the average size of your files as well. If your file sizes are constantly ranging near 7 to 8 MB, then there would be some benefit in increasing the buffer size to 8192KB. How old is the drive? How often have you used it, many other factors come into play. We are able to learn more about this topic from an excellent piece of software called FastCopy. Hope this helps.

Creating MFC dialog to let the user choose file path

As title says, I am trying to create MFC dialog-based app to let the user select the file destination folder.
I am doing this by using CMFCShellTreeCtrl. However, somehow there is only one root item which is Desktop. I would like to see all items like My Computer, C drive etc.
Could you please tell me what's wrong and how do I fix it. Thanks.
Edit: Sorry I forgot to post my code. (Very simple dialog for browsing)
// BrowseDlg.cpp : implementation file
//
#include "stdafx.h"
#include "MFC Grab to FTP.h"
#include "BrowseDlg.h"
#include "afxdialogex.h"
// CBrowseDlg dialog
IMPLEMENT_DYNAMIC(CBrowseDlg, CDialog)
CBrowseDlg::CBrowseDlg(CWnd* pParent /*=NULL*/)
: CDialog(CBrowseDlg::IDD, pParent)
{
}
CBrowseDlg::~CBrowseDlg()
{
}
void CBrowseDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PATH, m_PathTree);
}
BEGIN_MESSAGE_MAP(CBrowseDlg, CDialog)
ON_NOTIFY(TVN_SELCHANGED, IDC_PATH, &CBrowseDlg::OnTvnSelchangedMfcshelltree1)
ON_BN_CLICKED(IDOK, &CBrowseDlg::OnBnClickedOk)
END_MESSAGE_MAP()
// CBrowseDlg message handlers
BOOL CBrowseDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
m_PathTree.Expand(m_PathTree.GetRootItem(),TVE_EXPAND);
return TRUE; // return TRUE unless you set the focus to a control
}
void CBrowseDlg::OnTvnSelchangedMfcshelltree1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}
void CBrowseDlg::OnBnClickedOk()
{
m_PathTree.GetItemPath(path,m_PathTree.GetSelectedItem());
// TODO: Add your control notification handler code here
CDialog::OnOK();
}
//
#pragma once
#include "afxshelltreectrl.h"
// CBrowseDlg dialog
// header file
class CBrowseDlg : public CDialog
{
DECLARE_DYNAMIC(CBrowseDlg)
public:
CBrowseDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CBrowseDlg();
// Dialog Data
enum { IDD = IDD_BROWSER };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnTvnSelchangedMfcshelltree1(NMHDR *pNMHDR, LRESULT *pResult);
CString path;
CMFCShellTreeCtrl m_PathTree;
afx_msg void OnBnClickedOk();
virtual BOOL OnInitDialog();
};
The problem is that CShellManager in not initialized. You have to do it manually. To initialize it you need to call CWinAppEx::InitShellManager() in OnInitInstance() of your CWinApp-derived class.
There is an alternative to using CMFCShellTreeCtrl, if you just want to pick a folder: IFileDialog.
This is my code for a select folder dialog (rather complicated, because I still want to support Windows XP using XFolderDialog):
HINSTANCE hEasyCTXP_DLL = NULL;
// Select Folder Dialog -- uses either CXFolderDialog or IFileDialog
// to open a folder picker dialog depending on OS version
// returns "" if Cancel was pressed or something else went wrong
// Note: This is just multi-byte code and not yet unicode compatible!
BOOL SelectFolder(LPSTR sFolder, LPCTSTR sTitle = "Choose Folder")
{
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (GetVersionEx((OSVERSIONINFO *)&osvi) && osvi.dwMajorVersion >= 6) // Vista or higher?
{
if (!(hEasyCTXP_DLL = LoadLibrary("XPHelper.dll")))
{
AfxMessageBox("Error opening Select Folder dialog. XPHelper.dll may not be installed properly.");
return FALSE;
}
else
{
BOOL (__cdecl *pSelectFolder)(LPSTR, LPCTSTR);
pSelectFolder = (BOOL (__cdecl *)(LPSTR, LPCTSTR))GetProcAddress(hEasyCTXP_DLL, "SelectFolder");
if (pSelectFolder)
{
return (*pSelectFolder)(sFolder, sTitle);
}
else
{
AfxMessageBox("Error opening Select Folder dialog. (SelectFolder() function entry point not found.)");
return FALSE;
}
}
}
else // XP
{
CXFolderDialog dlg(sFolder);
dlg.SetTitle(sTitle);
if (dlg.DoModal() == IDOK)
{
CString csPath = dlg.GetPath();
strcpy(sFolder, (LPCTSTR)csPath);
return TRUE;
}
else
return FALSE;
}
}
Here comes the function I provide in XPHelper.dll. This dll is delay loaded only, if Vista or later OS is used, so the main program won't fail because of missing dependencies in Windows XP:
// sFolder should be at least MAX_FILE in size!
extern "C" BOOL SelectFolder(LPSTR sFolder, LPCTSTR sTitle)
{
BOOL bRet = TRUE;
IFileDialog *pfd;
LPWSTR pwstrPath;
HRESULT hr;
if (SUCCEEDED(hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
{
DWORD dwOptions;
hr = pfd->GetOptions(&dwOptions);
if (SUCCEEDED(hr))
hr = pfd->SetOptions(dwOptions | FOS_PICKFOLDERS); // put IFileDialog in folder mode
if (SUCCEEDED(hr))
{
WCHAR wcTitle[MAX_PATH+1];
if (MultiByteToWideChar(CP_ACP, 0, sTitle, (int)min(strlen(sTitle), MAX_PATH), wcTitle, sizeof(MAX_PATH + 1)))
{
wcTitle[min(strlen(sTitle), MAX_PATH)] = '\0';
pfd->SetTitle(wcTitle); // Set dialog title
}
char *cp = sFolder;
WCHAR wcDefaultPath[MAX_PATH+1];
IShellItem *psi;
if (MultiByteToWideChar(CP_ACP, 0, cp, (int)strlen(cp), wcDefaultPath, MAX_PATH + 1))
{
wcDefaultPath[strlen(cp)] = '\0';
if (SUCCEEDED(::SHCreateItemFromParsingName(wcDefaultPath, NULL, IID_PPV_ARGS(&psi))))
{
hr = pfd->SetFileName(wcDefaultPath);
hr = pfd->SetFolder(psi);
psi->Release();
}
}
}
if (SUCCEEDED(hr))
hr = pfd->Show(AfxGetMainWnd()->GetSafeHwnd());
if (SUCCEEDED(hr))
{
IShellItem *psi;
if (SUCCEEDED(pfd->GetResult(&psi)))
{
if(SUCCEEDED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pwstrPath)))
{
int nSize = (int)wcslen(pwstrPath);
WideCharToMultiByte(CP_ACP, 0, pwstrPath, nSize, sFolder, MAX_PATH+1, NULL, NULL);
sFolder[nSize] = '\0';
::CoTaskMemFree(pwstrPath);
}
else
{
AfxMessageBox("IShellItem::GetDisplayName() failed.");
bRet = FALSE;
}
psi->Release();
}
else
{
AfxMessageBox("IFileDialog failed.");
bRet = FALSE;
}
}
pfd->Release();
}
if(!SUCCEEDED(hr))
bRet = FALSE;
return bRet;
}

When I load my filedisk driver, I got the ERROR_PROC_NOT_FOUND(127) error code

I want to develop an encrypt-virtual-disk based on the FileDisk-17 opensource project.
Here is my solution:
In IPR_MJ_READ, when the ZwReadFile returns, I use function 'DecryptData' to decrypt the data read by ZwReadFile.
In IPR_MJ_WRITE, before call ZwWriteFile, I use function 'EncryptData' to encrypt the data which will be written to the disk.
I put EncryptData & DecryptData functions in a single C source file.
The question is; when I loaded my driver, I get the ERROR_PROC_NOT_FOUND(127) error code
every time, even there are only one line in the EncryptData or DecryptData function.
Who can tell me what caused this and how to fix it?
filedisk.c
switch (io_stack->MajorFunction)
{
case IRP_MJ_READ:
system_buffer = (PUCHAR) MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
if (system_buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
buffer = (PUCHAR) ExAllocatePool(PagedPool, io_stack->Parameters.Read.Length);
if (buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
ZwReadFile(
device_extension->file_handle,
NULL,
NULL,
NULL,
&irp->IoStatus,
buffer,
io_stack->Parameters.Read.Length,
&io_stack->Parameters.Read.ByteOffset,
NULL
);
*if(bEncrypt)
{
cipher = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, irp->IoStatus.Information, 'TAG');
if(cipher)
{
**DecryptData**(buffer, cipher, irp->IoStatus.Information);
RtlCopyMemory(system_buffer, cipher, irp->IoStatus.Information);
ExFreePool(cipher);
}
else
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
}*
else
{
RtlCopyMemory(system_buffer, buffer, io_stack->Parameters.Read.Length);
ExFreePool(buffer);
}
crypto.c
VOID EncryptData(PUCHAR src, PUCHAR dst, ULONG length)
{
BF_LONG data[2];
BF_KEY key;
BF_set_key(&key, pCryptoInformation->CryptoKey, sizeof(pCryptoInformation->CryptoKey));
}
VOID DecryptData(PUCHAR src, PUCHAR dst, ULONG length)
{
BF_LONG data[2];
BF_KEY key;
BF_set_key(&key, pCryptoInformation->CryptoKey, sizeof(pCryptoInformation->CryptoKey));
}

Translating boost::thread->native_handle() to XP ThreadId

I've managed to get the Windows ThreadId out of the native_handle() from a boost::thread by using GetThreadId(HANDLE). Sadly that call is not available on Windows XP and after searching around I found the solution to offer als fallback support for XP by traversing all thread via Thread32First() and Thread32Next() functions of the WINAPI.
This does work somehow but my problem is I'm currently only able to identify the threads of my process... I don't now how to match the native_handle() / HANDLE from one side with the appropriate THREADENTRY32 from the loop traversal.
THREADENTRY32 te32;
//...
do {
if( te32.th32OwnerProcessID == GetCurrentProcessId() ) {
DWORD threadId = te32.th32ThreadID;
printf( "\n THREAD ID = 0x%08X", te32.th32ThreadID );
}
} while( Thread32Next(hThreadSnap, &te32 ) );
Can anyone help me with that? How do I convert a boost::thread->native_handle() to the ThreadId on WindowsXP?
Thank you very much!
Pass each thread ID in the loop to OpenThread() until you find a matching HANDLE. For example:
HANDLE hBoostThread = ...; // from boost::thread->native_handle()
DWORD dwBoostThreadID = 0;
THREADENTRY32 te32;
//...
do
{
if( te32.th32OwnerProcessID == GetCurrentProcessId() )
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
if (hThread != NULL)
{
if (hThread == hBoostThread)
{
CloseHandle(hThread);
dwBoostThreadID = te32.th32ThreadID;
break;
}
CloseHandle(hThread);
}
}
}
while( Thread32Next(hThreadSnap, &te32 ) );
For good measure, you can wrap this inside a function that you can call whenever GetThreadId() is not natively available so that your code does not need to know the difference, eg:
DWORD WINAPI MyGetThreadId(HANDLE Thread)
{
THREADENTRY32 te32;
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE)
return 0;
if (Thread32First(hThreadSnap, &te32))
{
do
{
HANDLE hOpenThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
if (hOpenThread != NULL)
{
if (hOpenThread == Thread)
{
CloseHandle(hOpenThread);
CloseHandle(hThreadSnap);
return te32.th32ThreadID;
}
CloseHandle(hOpenThread);
}
}
while( Thread32Next(hThreadSnap, &te32 ) );
}
CloseHandle(hThreadSnap);
return 0;
}
typedef DWORD (WINAPI *LPFN_GTID)(HANDLE);
LPFN_GTID lpGetThreadId = (LPFN_GTID) GetProcAddress(GetModuleHandle("kernel32"), "GetThreadId");
if (!lpGetThreadId)
lpGetThreadId = &MyGetThreadId;
DWORD dwThreadID = lpGetThreadId((HANDLE) boost::thread->native_handle());
With that said, a better option is to directly query the target thread itself for its own ID, instead of trying to hunt for it manually:
typedef long (WINAPI *LPFN_NTQIT)(HANDLE thread, int infoclass, void *buf, long size, long *used);
typedef struct _THREAD_BASIC_INFORMATION
{
ULONG ExitStatus;
void* TebBaseAddress;
ULONG UniqueProcessId;
ULONG UniqueThreadId;
ULONG AffinityMask;
ULONG BasePriority;
ULONG DiffProcessPriority;
} THREAD_BASIC_INFORMATION;
DWORD WINAPI MyGetThreadId(HANDLE Thread)
{
DWORD dwThreadId = 0;
HMODULE hLib = LoadLibrary("ntdll.dll");
if (hLib != NULL)
{
LPFN_NTQIT lpNtQueryInformationThread = (LPFN_NTQIT) GetProcAddress(hLib, "NtQueryInformationThread");
if (lpNtQueryInformationThread != NULL)
{
THREAD_BASIC_INFORMATION tbi = {0};
ULONG used = 0;
if (lpNtQueryInformationThread(Thread, 0, &tbi, sizeof(tbi), &used) == 0)
dwThreadId = tbi.UniqueThreadId;
}
FreeLibrary(hLib);
}
return dwThreadId;
}

How to fix service control buttons are disabled for custom service

I have a service that I start & it works fine (I verify it's running by looking at the EventLog messages it posts). For some reason though, services.msc shows the stop button greyed out & I can't figure out why.
static SERVICE_STATUS_HANDLE gServiceStatusHandle = NULL;
static DWORD WINAPI DaemonServiceHandler(DWORD control, DWORD eventType, LPVOID eventData, LPVOID context)
{
HANDLE stopEvent = reinterpret_cast<HANDLE>(context);
switch (control) {
case SERVICE_CONTROL_STOP:
ReportServiceStatus(SERVICE_STOP_PENDING, 100, 3000);
// notify main loop to stop
return NO_ERROR;
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
}
return ERROR_CALL_NOT_IMPLEMENTED;
}
void WINAPI DaemonMain(DWORD argc, LPWSTR *argv)
{
gServiceStatusHandle = RegisterServiceCtrlHandlerEx(WIN_UTF16(gServiceName), DaemonServiceHandler, NULL);
if (gServiceStatusHandle == NULL) {
ReportService(SERVICE_STOPPED);
return;
}
ReportService(SERVICE_RUNNING);
// do main loop
ReportService(SERVICE_STOPPED);
}
int tmain(int argc, tchar **argv)
{
const SERVICE_TABLE_ENTRYW DispatchTable[] =
{
{(L"MyService", DaemonMain},
{NULL, NULL}
};
if (!StartServiceCtrlDispatcherW(DispatchTable)) {
return 1;
}
return 0;
}
Bug in my ReportServiceStatus call.
I was setting dwControlsAccepted of the SERVICE_STATUS_HANDLE to 0 always instead of enabling SERVICE_ACCEPT_STOP when the current state to report wasn't SERVICE_START_PENDING.

Resources