I am developing a win32 API hook program.
Accordingly to my understanding, when a program calls ReadFile for a particular file, the content of that file is copied to lpBuffer(see the definition below),
ReadFile definition:
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
Now, my target is to alter this lpBuffer and fill it with provided content by me!
I am using EasyHook to hook ReadFile. I am not familiar with LPVOID type. I was able to alter the content for GetCurrentDirectory using the following code.
string b = "C:\\my\\altered\\directory";
DWORD returnLength = b.length();
int i;
for (i = 0; i<b.length(); i++)
{
lpBuffer[i] = b[i];
}
lpBuffer[i++] = '\0';
GetCurrentDirectory definition:
DWORD GetCurrentDirectory(
DWORD nBufferLength,
LPTSTR lpBuffer
);
How to do similar value assignment for ReadFile (LPVOID lpBuffer)?
Here's the LPVOID typedef:
#define far
typedef void far *LPVOID;
The far macro is defined as nothing, I guess it's because of some historical reasons (baggage).
So you can almost directly treat the LPVOID as void*.
And now, suppose you have a std::vector<uint8_t> named FakeData, just:
if (nNumberOfBytesToRead < FakeData.size()) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
memcpy(lpBuffer, FakeData.data(), FakeData.size());
*lpNumberOfBytesRead = FakeData.size();
SetLastError(ERROR_SUCCESS);
return TRUE;
Related
Firstly, I want to hook CreateFile() and rewrite it. Then I want to recode the callstack of my new CreateFile() function. But when I use SymInitialize() to Initialize a handle, it falls into an endless loop. Through my debug, the reason is SymInitialize() invokes CreateFile(). So why does SymInitialize() involve CreateFile()? How to avoid this loop? Is there any alternative method to record callstack information to avoid this loop?
#include <windows.h>
#include <stdio.h>
#include "detours.h"
#include <fstream>
#include <io.h>
#pragma comment(lib, "detours.lib")
#include <DbgHelp.h> //SymInitialize
#pragma comment(lib,"dbghelp.lib")
#define STACK_INFO_LEN 200
struct stackInfo {
PDWORD hashValue; // hash value to identify same stack
char* szBriefInfo; // callstack info
};
stackInfo ShowTraceStack(char* szBriefInfo)
{
static const int MAX_STACK_FRAMES = 12;
void* pStack[MAX_STACK_FRAMES];
static char szStackInfo[STACK_INFO_LEN * MAX_STACK_FRAMES];
static char szFrameInfo[STACK_INFO_LEN];
HANDLE process = GetCurrentProcess(); // The handle used must be unique to avoid sharing a session with another component,
SymInitialize(process, NULL, TRUE);
PDWORD hashValue = (PDWORD)malloc(sizeof(DWORD)); // allow memory for hashVavlue, it will be rewrited in function CaptureStackBackTrace
WORD frames = CaptureStackBackTrace(0, MAX_STACK_FRAMES, pStack, hashValue);
//printf("hash value is: %ud \n", &hashValue);
if (szBriefInfo == NULL) {
strcpy_s(szStackInfo, "stack traceback:\n");
}
else {
strcpy_s(szStackInfo, szBriefInfo);
}
for (WORD i = 0; i < frames; ++i) {
DWORD64 address = (DWORD64)(pStack[i]);
DWORD64 displacementSym = 0;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD displacementLine = 0;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymFromAddr(process, address, &displacementSym, pSymbol) &&
SymGetLineFromAddr64(process, address, &displacementLine, &line))
{
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\t%s() at %s:%d(0x%x)\n",
pSymbol->Name, line.FileName, line.LineNumber, pSymbol->Address);
}
else
{
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\terror: %d\n", GetLastError());
}
strcat_s(szStackInfo, szFrameInfo);
}
stackInfo traceStackInfo;
traceStackInfo.hashValue = hashValue;
traceStackInfo.szBriefInfo = szStackInfo;
return traceStackInfo;
//printf("%s", szStackInfo);
}
HANDLE (*__stdcall oldCreateFile)(LPCWSTR,
DWORD,
DWORD,
LPSECURITY_ATTRIBUTES,
DWORD,
DWORD,
HANDLE) = CreateFileW;
HANDLE WINAPI newCreateFile(
_In_ LPCWSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
) {
ShowTraceStack((char*)"trace information.\n");
return oldCreateFile(
L".\\newFiles.txt", // L".\\NewFile.txt", // Filename
//lpFileName,
dwDesiredAccess, // Desired access
dwShareMode, // Share mode
lpSecurityAttributes, // Security attributes
dwCreationDisposition, // Creates a new file, only if it doesn't already exist
dwFlagsAndAttributes, // Flags and attributes
NULL);
}
void hook() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)oldCreateFile, newCreateFile);
DetourTransactionCommit();
}
void unhook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)oldCreateFile, newCreateFile);
DetourTransactionCommit();
}
void myProcess() {
HANDLE hFile = CreateFile(TEXT(".\\CreateFileDemo.txt"),
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
OutputDebugString(TEXT("CreateFile fail!\r\n"));
}
// write to file
const int BUFSIZE = 4096;
char chBuffer[BUFSIZE];
memcpy(chBuffer, "Test", 4);
DWORD dwWritenSize = 0;
BOOL bRet = WriteFile(hFile, chBuffer, 4, &dwWritenSize, NULL);
if (bRet) {
OutputDebugString(TEXT("WriteFile success!\r\n"));
}
}
int main(){
hook();
myProcess();
unhook();
}
The main problem is the call to SymInitialize where you pass through "TRUE" for fInvadeProcess parameter. This is causing it to SymLoadModuleEx to be called for each loaded module. This will cause a lot of file access to download / create / open PDB files for each loaded module. This is the reason for your infinite loop.
The "quick" fix for this sample is to move the call to SymInitialize into your main before the hook call as it only needs to be called once. This means all the PDB modules are loaded before the hooking / call to ShowTraceStack.
The other problems are:
dbghelp API is NOT thread safe - so this example will not work in a multi-threaded application
SymFromAddr may call CreateFile as well for the same reason to load a newly loaded module PDB information - so your hook not passing through the filename will cause PDB information to not work
If you are trying to make someone more useful I would:
Move SymInitialize to main before the hooking (called only once)
Only call CaptureStackBackTrace in the hook and queue the thread stack information to be processed at a later time
Create a separate thread the takes the CaptureStackBackTrace stack information output and convert it to a stack trace - this would is the only thread calling the dbghlp API making calls to dbghlp API thread safe
In your hook detect when being called from the dbghlp API usage thread and don't do the stack trace and don't modify the CreateFile parameters so you don't get into a infinite loop
I'm experimenting with loading functions from dlls during run-time on windows. I tried doing a program that would print it's own modules, based on this one: https://learn.microsoft.com/en-us/windows/win32/psapi/enumerating-all-modules-for-a-process.
I need two functions to do what i want: EnumProcessModules and GetModuleFileNameExA. I managed to get both of them from psapi.dll on runtime, however GetModuleFileNameExA just doesn't work like it should and I can't tell why
this is the functional script I have written:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <psapi.h>
typedef DWORD (__cdecl *EnumModules)(HANDLE hprocess, HMODULE *moduleHandles, DWORD cb, LPDWORD lpcNeeded);
typedef DWORD (__cdecl *GetModuleName)(HANDLE hprocess, HMODULE hmodule, LPSTR name, DWORD size);
void ErrorMessage(const char *message){
fprintf(stderr, message);
exit(EXIT_FAILURE);
}
int PrintModules( HANDLE pHandle )
{
HMODULE hMods[1024];
DWORD cbNeeded;
unsigned int i;
if (NULL == pHandle)
return EXIT_FAILURE;
// Loads the lib
HMODULE psapiLib = LoadLibrary("C:\\Windows\\SysWOW64\\psapi.dll");
if(! psapiLib) ErrorMessage("Error loading psapi.dll\n");
// Get the functions we need from the lib
EnumModules getModules = (EnumModules)GetProcAddress(psapiLib, "EnumProcessModules");
GetModuleName getModuleName = (GetModuleName)GetProcAddress(psapiLib, "GetModuleFileNameExA");
if(!getModules) ErrorMessage("Error finding EnumProcessModules from psapi.dll\n");
if(!getModuleName) ErrorMessage("Error finding GetModuleFileNameExA from psapi.dll\n");
// Get a list of all the modules in this process.
if( getModules(pHandle, hMods, sizeof(hMods), &cbNeeded))
{
for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
{
LPSTR szModName;
szModName = malloc(1024 * sizeof(LPSTR));
// Get the full path to the module's file.
// change GetModuleFileNameExA with getModuleName to see the error
if ( GetModuleFileNameExA( pHandle, hMods[i], szModName, 1024 * sizeof(char))){
// Print the module name and handle value.
printf(("\t%s (0x%08X)\n"), szModName, hMods[i] );
}
free(szModName);
}
}
return 0;
}
int main( void )
{
HANDLE myHandle = GetCurrentProcess();
PrintModules(myHandle);
CloseHandle(myHandle);
return 0;
}
If I change this part
if ( GetModuleFileNameExA( pHandle, hMods[i], szModName, 1024 * sizeof(char))){
// Print the module name and handle value.
printf(("\t%s (0x%08X)\n"), szModName, hMods[i] );
}
to this
if ( getModuleName( pHandle, hMods[i], szModName, 1024 * sizeof(char))){
// Print the module name and handle value.
printf(("\t%s (0x%08X)\n"), szModName, hMods[i] );
}
so it would use my function instead, taking the need to link the psapi.dll on load-time away, it just does't work. It will either segfault or not print anything. I have tried modiffing how i present the buffer, tried using widechar or Tchar but nothing seems to work.
This is the output I have with the functional script:
working script ouput
and this is the output i have with my function:
non functional script output
The funny part is that one of the functions, the getModules (which points to EnumProcessModules) worked perfectly fine! I just can't understand what's going on.
You should change this line of code
typedef DWORD (__cdecl *EnumModules)(HANDLE hprocess, HMODULE *moduleHandles, DWORD cb, LPDWORD lpcNeeded);
to this.
typedef DWORD(__stdcall* EnumModules)(HANDLE hprocess, HMODULE* moduleHandles, DWORD cb, LPDWORD lpcNeeded);
for more info you can reference this
I have an array of hWnds of buttons that I want to monitor for clicks. I also have an array of HWINEVENTHOOKs that I will use to monitor them. GetWindowThreadProcessID gives me an LPDWORD process ID, which is not accepted by SetWinEventHook. I am unclear on whether I am correctly using LPDWORDs in this example. Please could somebody point me in the right direction?
EDIT: Thank you to everyone who contributed, I have posted the corrected code below.
New Code:
int i = 0;
for (HWND hWnd : hWnds) {
DWORD processID = 0;
DWORD threadID = GetWindowThreadProcessId(hWnd, &processID);
hooks[i] = SetWinEventHook(EVENT_OBJECT_INVOKED, EVENT_OBJECT_INVOKED,
NULL,
WinEventProcCallback, processID, threadID, WINEVENT_OUTOFCONTEXT);
i++;
}
LPDWORD is just a typedef for DWORD* and when a Windows SDK function parameter is a "LPsomething" you generally need to pass a pointer to a "something" (except for the LP[C][W]STR string types).
DWORD processID;
DWORD threadID = GetWindowThreadProcessId(hWnd, &processID);
if (threadID)
{
// Do something with threadID and/or processID
}
The Windows SDK uses Systems Hungarian notation for the Desktop/Classic API.
i try to read the Registry in my NPAPI-Plugin:
bool ScriptablePluginObject::Invoke(NPObject* obj, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result) {
ScriptablePluginObject *thisObj = (ScriptablePluginObject*) obj;
char* name = npnfuncs->utf8fromidentifier(methodName);
LPCWSTR game_path = getRegKey(L"SOFTWARE\\World of RPG", L"Path");
MessageBox(NULL, game_path, L"Debugging", MB_TOPMOST);
/* ... */
}
LPCWSTR ScriptablePluginObject::getRegKey(LPCWSTR location, LPCWSTR name) {
HKEY hKey;
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
long registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, location, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
long entry = RegQueryValueEx(hKey, name, NULL, REG_NONE, folder, &dwSize);
if(registry != ERROR_SUCCESS) {
return L"Error1";
}
if(entry != ERROR_SUCCESS) {
return L"Error2";
}
RegCloseKey(hKey);
folder[dwSize / sizeof(folder[0])] = '\0';
return (LPCWSTR) folder;
}
But it's returned every call Error2. I've tried a lot of changes:
change the Path (with Start and/or Ending \\)
change parameters
I Want to get the Path of HKEY_LOCAL_MACHINE\SOFTWARE\World of RPG\Path:
Anyone can help me? What i'm doing wrong?
Here's the sample I mentioned in the comments above:
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, DWORD *pBufferSize );
int _tmain(int argc, _TCHAR* argv[])
{
const int BUFFER_SIZE = 1024;
WCHAR sBuffer[BUFFER_SIZE]; // 2048 bytes
DWORD nBufferSize = BUFFER_SIZE * sizeof ( WCHAR );
ZeroMemory ( sBuffer, nBufferSize );
LSTATUS nResult = ReadRegistry ( L"SOFTWARE\\7-Zip", L"Path64",
sBuffer, &nBufferSize );
// check nResult for ERROR_SUCCESS to know if the call succeeded or not
return 0;
}
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, LPDWORD pBufferSize )
{
HKEY hKey;
LSTATUS nResult = ::RegOpenKeyEx ( HKEY_LOCAL_MACHINE, sPath,
0, KEY_READ | KEY_WOW64_64KEY, &hKey );
if ( nResult == ERROR_SUCCESS )
{
nResult = ::RegQueryValueEx ( hKey, sKey, NULL, NULL,
(LPBYTE) pBuffer, pBufferSize );
RegCloseKey ( hKey );
}
return ( nResult );
}
Notice how the ReadRegistry function doesn't allocate memory - it takes a buffer and fills it with data. It's a lot easier to deal with memory if you always have the caller allocate memory. If the callee allocates memory, the caller may not know how memory was allocated and it may not know how to free it. (Of course, you can always assume the use of new and delete but things are simpler if only one side does this consistently. If the caller allocates memory, it'll know how to free it. The callee only needs to put data in the allocated space.
Also, notice how the return value of the API functions is checked before proceeding to the next call - this is important because this tells you if you got a useful registry handle back or not and whether you need to close it or not.
(This sample is really just C, not C++ but it still applies.)
In getRegKey(), your folder variable is a pointer, so sizeof(folder) is 4 (if compiling for 32bit) or 8 (if compiling for 64bit). Thus RegQueryValueEx() fails with an ERROR_MORE_DATA error code.
You are also using the wrong data type for the array. You need to use WCHAR instead of BYTE.
Change this:
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
To this:
LPWSTR folder = new WCHAR[MAX_PATH];
DWORD dwSize = sizeof(WCHAR) * MAX_PATH;
With that said, you are leaking the memory pointed to by folder, since you never delete[] it.
I am trying to call LsaICryptUnprotectData but I get error code 87 unsupported parameter. Has anyone been able to successfully call this function? would like to see an example function call
Here is how I am calling,
typedef int (WINAPI *LPFUN_LSAICRYPTUNPROTECTDATA)
(
LPBYTE encCredData,
DWORD encCredDataSize,
DWORD reserved1,
DWORD reserved2,
DWORD reserved3,
DWORD reserved4,
DWORD dwFlags,
DWORD reserved5,
LPBYTE *decCredData,
LPDWORD decCredDataSize
);
LPFUN_LSAICRYPTUNPROTECTDATA pLsaICryptUnprotectData = (LPFUN_LSAICRYPTUNPROTECTDATA) GetProcAddress (hLsasrv, "LsaICryptUnprotectData");
if(!pLsaICryptUnprotectData)
{return GetLastError();}
HANDLE credfile = NULL;
LPBYTE buffer = NULL;
LPBYTE pDecrypted = NULL;
DWORD dwSize = 0;
DWORD cbsize=0;
credfile = CreateFile(filename,GENERIC_READ,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,NULL);
dwSize = GetFileSize(credfile,NULL);
buffer=(LPBYTE)malloc(dwSize);
SetFilePointer(credfile,0,0,FILE_BEGIN);
DWORD credFileSize=0;
ReadFile(credfile,buffer,dwSize,&credFileSize,NULL)
if(!pLsaICryptUnprotectData( buffer, dwSize, 0,0,0,0, 0, 0, &pDecrypted, &cbsize) != NULL))
{
// do error handling
}
The LsalCryptUnprotectData function is undocumented, but from this example, you might try with similar parameters:
cbSize = 0;
pLsaICryptUnprotectData ( buffer, dwSize, 0,0,0,0, 0x20000041, 0,
&pDecrypted, &cbSize);