Well, i want to learn about hooking, but it seems that the tutorials found on the internet won't run.
What i want to do is a jump hook, in C++.
Here's the code :
void DoHook(DWORD* Address, DWORD* Hook, DWORD pid){
HANDLE Server = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ , false, pid );
Address = (DWORD*)Address + 0x18;
DWORD OldProt;
DWORD HookOffset = (DWORD*)Hook-(DWORD*)Address-5;
std::wcout << "Hook on address" << std::hex << Address<< std::endl;
std::wcout << "Hook offset is " << std::hex << HookOffset << std::endl;
if ( ! VirtualProtectEx(Server, (LPVOID) Address, 40,PAGE_EXECUTE_READWRITE, &OldProt) ) {
ErrorExit(L"VirtualProtectEx");
};
char* CharPointer = (char*) Address;
BYTE newdata[5]={0xE9};
BYTE x;
int i = 1;
while ( HookOffset > 0 ) {
x = HookOffset & 0xff;
newdata[5-i] = x;
i++;
HookOffset >>= 8;
}
std::wcout << "Bytes " <<newdata[0] << " " << newdata[1] << " " << newdata[2] << " " << newdata[3] << " " << newdata[4] << std::endl;
DWORD newdatasize = sizeof(newdata);
if ( ! WriteProcessMemory(Server,Address,(LPCVOID*)newdata,newdatasize,NULL) ) {
ErrorExit(L"WriteProcessMemory");
}
// VirtualProtect((void*) Address, 40, 0x40, &OldProt);
return;
}
Here's some output text :
Process ID is 2764 // PID of the app that's being hooked
Function address is 00A81190 // this is the function i'm doing the jump to
Entry point is 00080000 // for the app that's being hooked
Hook on address 00080060 // for the app that's being hooked
Hook offset is 28048e // HookAddress - FunctionAddress - 5
Bytes e9 0 28 4 8e // this is the jump i'm planning to do
Press any key to continue . . .
However, the application doesn't update.
You must run your program as administrator to have correct permissions to write to process memory. Here is my x86 detour function which I have tested and used many times
bool Detour32(char* src, char* dst, const intptr_t len)
{
if (len < 5) return false;
DWORD curProtection;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);
intptr_t relativeAddress = (intptr_t)(dst - (intptr_t)src) - 5;
*src = (char)'\xE9';
*(intptr_t*)((intptr_t)src + 1) = relativeAddress;
VirtualProtect(src, len, curProtection, &curProtection);
return true;
}
src is the address you want to place the hook, dst is the address where you want to jump to. len is the number of bytes you are going to destroy with your jmp. The jmp is 5 bytes so if you're destroying instructions which are more than 5 bytes, you need copy more than 5 of the "stolen bytes" into your destination to ensure they get executed.
Related
The below code can correctly read Registry values from various different keys, however whenever I try to read a value from a key under Winlogon it will either come up as "not found" or it will return a completely wrong value. The code is ran as admin, and compiled with Visual Studio 2017.
HKEY registryHandle = NULL;
int registryResult = NULL;
DWORD dataType;
TCHAR dataBuffer[1024] = {};
DWORD bufferSize = sizeof(dataBuffer);
registryResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_QUERY_VALUE, ®istryHandle);
if (registryResult != ERROR_SUCCESS) {
std::cout << "Error: " << registryResult << std::endl;
return false;
}
registryResult = RegQueryValueEx(registryHandle, L"LastUsedUsername", NULL, NULL, (LPBYTE)dataBuffer, &bufferSize);
if (registryResult != ERROR_SUCCESS) {
std::cout << "Error2: " << registryResult << std::endl;
return false;
}
std::cout << "Data Size: " << bufferSize << std::endl;
for (int i = 0; i < 256; i++) {
if (dataBuffer[i] == NULL) { break; }
std::cout << (char)dataBuffer[i];
}
std::cin.get();
RegCloseKey(registryHandle);
Registry value that I'm trying to read:
Below refers to Remy's suggested solution.
RegQueryValueEx Returns a buffer size of 4 with an output of 18754 17236 0 52428
You are clearly calling the Unicode version of the Registry functions, so you should be using WCHAR instead of TCHAR for your data buffer.
And you should not be truncating the characters to char at all. Use std::wcout instead of std::cout for printing out Unicode strings. And use the returned bufferSize to know how many WCHARs were actually output. Your printing loop is ignoring the bufferSize completely, so it is possible that you are actually printing out random garbage that RegQueryValueEx() did not actually intend for you to use (hence why lpcbData parameter is an in/out parameter, so you know how many bytes are actually valid).
You are also leaking the opened HKEY handle if RegQueryValueEx() fails.
Try something more like this instead:
HKEY registryHandle;
int registryResult;
registryResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_QUERY_VALUE, ®istryHandle);
if (registryResult != ERROR_SUCCESS) {
std::cout << "Error: " << registryResult << std::endl;
return false;
}
WCHAR dataBuffer[1024];
DWORD bufferSize = sizeof(dataBuffer);
// TODO: consider using RegGetValueW() instead, which is safer
// when it comes to reading string values from the Registry...
registryResult = RegQueryValueExW(registryHandle, L"LastUsedUsername", NULL, NULL, (LPBYTE)dataBuffer, &bufferSize);
RegCloseKey(registryHandle);
if (registryResult != ERROR_SUCCESS) {
std::cout << "Error2: " << registryResult << std::endl;
return false;
}
DWORD len = bufferSize / sizeof(WCHAR);
if ((len > 0) && (dataBuffer[len-1] == L'\0')) {
--len;
}
std::cout << "Data Byte Size: " << bufferSize << std::endl;
std::cout << "Data Character Length: " << len << std::endl;
std::wcout.write(dataBuffer, len);
std::cin.get();
return true;
That being said, on my machine, there is no LastUsedUsername value in the Winlogon key you are accessing, so getting a "not found" error is a very likely possibility. But you definately need to handle
I've successfully injected a .dll into an .exe and need to access a value through multi level pointers.
This is a working example that's getting the correct value:
#include <Windows.h>
#include <iostream>
#include <vector>
#include <TlHelp32.h>
#include <tchar.h>
using namespace std;
DWORD dwGetModuleBaseAddress(TCHAR *lpszModuleName, DWORD pID)
{
DWORD dwBaseAddress = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pID);
MODULEENTRY32 moduleEntry32 = { 0 };
moduleEntry32.dwSize = sizeof(MODULEENTRY32);
if (Module32First(hSnapshot, &moduleEntry32))
{
do {
if (_tcscmp(moduleEntry32.szModule, lpszModuleName) == 0)
{
dwBaseAddress = (DWORD)moduleEntry32.modBaseAddr;
break;
}
} while (Module32Next(hSnapshot, &moduleEntry32));
}
CloseHandle(hSnapshot);
return dwBaseAddress;
}
int main()
{
DWORD pID;
DWORD off1, off2, off3, off4, off5;
DWORD baseAddress;
DWORD xAddress;
int newX;
int currentX;
char moduleName[] = "TibiaInjected2.exe";
HWND hGameWindow;
HANDLE pHandle;
// Getting handles
hGameWindow = FindWindowA(NULL, "Tibia - 127.0.0.1:7171");
GetWindowThreadProcessId(hGameWindow, &pID);
pHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
// Getting base address
DWORD clientBase = dwGetModuleBaseAddress(_T(moduleName), pID);
ReadProcessMemory(pHandle, (LPCVOID)(clientBase + 0x0031D0CC), &baseAddress, sizeof(baseAddress), NULL);
cout << "Base address: " << hex << baseAddress << endl;
ReadProcessMemory(pHandle, (LPCVOID)(baseAddress + 0x4), &off1, sizeof(off1), NULL);
cout << "Offset 1: " << hex << off1 << endl;
ReadProcessMemory(pHandle, (LPCVOID)(off1 + 0x4), &off2, sizeof(off2), NULL);
cout << "Offset 2: " << hex << off2 << endl;
ReadProcessMemory(pHandle, (LPCVOID)(off2 + 0xA0), &off3, sizeof(off3), NULL);
cout << "Offset 3: " << hex << off3 << endl;
ReadProcessMemory(pHandle, (LPCVOID)(off3 + 0x100), &off4, sizeof(off4), NULL);
cout << "Offset 4: " << hex << off4 << endl;
ReadProcessMemory(pHandle, (LPCVOID)(off4 + 0x14), &off5, sizeof(off5), NULL);
cout << "Offset 5: " << hex << off5 << endl;
cin.get();
}
I'd rather use my statically injected DLL and from what I've heard I can replace the whole dwGetModuleBaseAddress with GetModuleHandle(NULL) since it's from within the injected DLL. I also don't need to open any process. But if I don't do all that, what to replace the ReadProcessMemory with?
ReadProcessMemory(pHandle, (LPCVOID)(clientBase + 0x0031D0CC), &baseAddress, sizeof(baseAddress), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(baseAddress + 0x4), &off1, sizeof(off1), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(off1 + 0x4), &off2, sizeof(off2), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(off2 + 0xA0), &off3, sizeof(off3), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(off3 + 0x100), &off4, sizeof(off4), NULL);
ReadProcessMemory(pHandle, (LPCVOID)(off4 + 0x14), &off5, sizeof(off5), NULL);
I've managed to access value from static addresses directly by doing:
int* exampleValue = *(int*)0x12345678;
But can't figure out how to do the same with pointers and offset.
Yes you can use GetModuleHandle(NULL); to get the handle to the main .exe module or replace NULL with a string that matches the DLL name.
You can use this function that loops through the offsets, de-referencing and adding offsets at each level:
uintptr_t FindDMAAddy(uintptr_t ptr, std::vector<unsigned int> offsets)
{
uintptr_t addr = ptr;
for (unsigned int i = 0; i < offsets.size() ; ++i)
{
addr = *(uintptr_t*)addr;
addr += offsets[i];
}
return addr;
}
uintptr_t ammoAddr = FindDMAAddy(dynamicPtrBaseAddr, { 0x374, 0x14, 0x0 });
//or
int * ammoAddr = (int*)FindDMAAddy(dynamicPtrBaseAddr, { 0x374, 0x14, 0x0 });
You could also do some crazy thing like:
int * ammo = (int*)((*(uintptr_t*)((*(uintptr_t*)(dynamicPtrBaseAddr)) +0x374)) + 0x14);
But it's more confusing and annoying than it's worth.
This worked for me (could be put in a loop like the other answer did):
DWORD base = *(DWORD*)(clientBase + 0x0031D0CC);
DWORD offsets[] = { 0x4, 0x4, 0xA0, 0x100, 0x14 };
DWORD off1 = *(DWORD*)(base + offsets[0]);
DWORD off2 = *(DWORD*)(off1 + offsets[1]);
DWORD off3 = *(DWORD*)(off2 + offsets[2]);
DWORD off4 = *(DWORD*)(off3 + offsets[3]);
DWORD off5 = *(DWORD*)(off4 + offsets[4]);
cout << "Value: " << off5 << endl;
Background:
I'm trying to write a C++ application that can scan for and attempt to restore deleted files from a WinPE environment, mostly as a learning exercise. This app utilizes the FMAPI library (fmapi.dll), which is a scarcely-documented library that only works in a WinPE environment (does not work in a full Windows OS). I've been using the ScanRestorableFiles example released by MS (available here) as a starting point.
Now, I've done a LOT of digging and have found next to nothing when it comes to FMAPI documentation - just the sample noted above and some basic MSDN docs here. The MSDN pages provide the definitions for the API functions and a few extra notes on a couple of the functions that provide a hint or two, but that's it. So I thought I'd come here in hopes of finding some assistance.
Also please note, as far as development languages go, C++ is not my strong point - I would consider myself novice at best.
Now to the issue at hand:
My app is able to successfully load the library, create the file restore context and scan for restorable files. However, once I try to call the RestoreFile() function on one of the restorable items that was returned by the ScanRestorableFiles() call, I get an Invalid Handle error. The "restored file" ends up being a 0-byte file (it does get created successfully in the proper place) with no data in it.
Interestingly, even after returning the Invalid Handle error code, my app holds a handle open on the file until the file restore context is closed (I know this because if I try to read the restored file immediately after attempting to restore it, I get a "file is in use by another process" error).
Posted below is the entire code for my app (its just a single source file, not counting headers and such) - since this seems to be a rarely-used API, I feel like I should post the whole thing to add context to each function call (and also because I'm not quite sure exactly what may or may not be relevant to the issue I'm having).
Code:
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>
#include <stdlib.h>
#define SCAN_PATH L"\\"
//
//Define the needed FMAPI structures as documented in FMAPI
//
#define FILE_RESTORE_MAJOR_VERSION_2 0x0002
#define FILE_RESTORE_MINOR_VERSION_2 0x0000
#define FILE_RESTORE_VERSION_2 ((FILE_RESTORE_MAJOR_VERSION_2 << 16) | FILE_RESTORE_MINOR_VERSION_2)
using namespace std;
//External API function declarations
//We don't have an import library or
//header for the FMAPI functions, so
//we must dynamically link to them at
//runtime.
typedef PVOID PFILE_RESTORE_CONTEXT;
typedef enum {
ContextFlagVolume = 0x00000001,
ContextFlagDisk = 0x00000002,
FlagScanRemovedFiles = 0x00000004,
FlagScanRegularFiles = 0x00000008,
FlagScanIncludeRemovedDirectories = 0x00000010
} RESTORE_CONTEXT_FLAGS;
typedef enum {
FileRestoreProgressInfo = 100,
FileRestoreFinished = 101
} FILE_RESTORE_PACKET_TYPE, *PFILE_RESTORE_PACKET_TYPE;
typedef BOOL (WINAPI *FuncCreateFileRestoreContext) (
_In_ PCWSTR Volume,
_In_ RESTORE_CONTEXT_FLAGS Flags,
_In_ LONGLONG StartSector,
_In_ LONGLONG BootSector,
_In_ DWORD Version,
_Out_ PFILE_RESTORE_CONTEXT* Context
);
typedef BOOL (WINAPI *FuncCloseFileRestoreContext) (
_In_ PFILE_RESTORE_CONTEXT Context
);
typedef struct _RESTORABLE_FILE_INFO
{
ULONG Size;
DWORD Version;
ULONGLONG FileSize;
FILETIME CreationTime;
FILETIME LastAccessTime;
FILETIME LastWriteTime;
DWORD Attributes;
BOOL IsRemoved;
LONGLONG ClustersUsedByFile;
LONGLONG ClustersCurrentlyInUse;
ULONG RestoreDataOffset;
WCHAR FileName[1]; // Single-element array indicates a variable-length structure
} RESTORABLE_FILE_INFO, *PRESTORABLE_FILE_INFO;
typedef struct _FILE_RESTORE_PROGRESS_INFORMATION {
LONGLONG TotalFileSize;
LONGLONG TotalBytesCompleted;
LONGLONG StreamSize;
LONGLONG StreamBytesCompleted;
PVOID ClbkArg;
} FILE_RESTORE_PROGRESS_INFORMATION, *PFILE_RESTORE_PROGRESS_INFORMATION;
typedef struct _FILE_RESTORE_FINISHED_INFORMATION {
BOOL Success;
ULONG FinalResult;
PVOID ClbkArg;
} FILE_RESTORE_FINISHED_INFORMATION, *PFILE_RESTORE_FINISHED_INFORMATION;
typedef BOOL (WINAPI *FuncScanRestorableFiles) (
_In_ PFILE_RESTORE_CONTEXT Context,
_In_ PCWSTR Path,
_In_ ULONG FileInfoSize,
_Out_bytecap_(FileInfoSize) PRESTORABLE_FILE_INFO FileInfo,
_Out_ PULONG FileInfoUsed
);
typedef BOOLEAN (*FILE_RESTORE_CALLBACK) (
_In_ FILE_RESTORE_PACKET_TYPE PacketType,
_In_ ULONG PacketLength,
_In_ PVOID PacketData
);
typedef BOOL (WINAPI *FuncRestoreFile) (
_In_ PFILE_RESTORE_CONTEXT Context,
_In_ PRESTORABLE_FILE_INFO RestorableFile,
_In_ PCWSTR DstFile,
_In_opt_ FILE_RESTORE_CALLBACK Callback,
_In_opt_ PVOID ClbkArg
);
HMODULE hLib;
wchar_t VOLUME[255];
BOOLEAN FuncRestoreCallback(_In_ FILE_RESTORE_PACKET_TYPE pType, _In_ ULONG pLength, _In_ PVOID pData)
{
// This is the callback that is passed to RestoreFile(), which
// returns data about the status of an attempted restoration.
if (pType == FileRestoreProgressInfo)
{
wcout << L"FILE RESTORE PROGRESS INFO:" << L"\n";
wprintf(L"Length of status data: %lu\n", pLength);
wcout << L"Location of data: " << pData << L"\n";
PFILE_RESTORE_PROGRESS_INFORMATION restoreProgressInfo = static_cast<PFILE_RESTORE_PROGRESS_INFORMATION>(pData);
wprintf(L"Total file size: %lld\n", restoreProgressInfo->TotalFileSize);
wprintf(L"Total bytes completed: %lld\n", restoreProgressInfo->TotalBytesCompleted);
wprintf(L"Stream size: %lld\n", restoreProgressInfo->StreamSize);
wprintf(L"Stream bytes completed: %lld\n", restoreProgressInfo->StreamBytesCompleted);
//wcout << L"Callback arg data: " << restoreProgressInfo->ClbkArg << L"\n";
wprintf(L"Callback arg: %p\n", restoreProgressInfo->ClbkArg);
}
else if (pType == FileRestoreFinished)
{
wcout << L"FILE RESTORE FINISHED INFO:" << L"\n";
wprintf(L"Length of status data: %lu\n", pLength);
wcout << L"Location of data: " << pData << L"\n";
// Obtain the struct
PFILE_RESTORE_FINISHED_INFORMATION restoreFinishedInfo = static_cast<PFILE_RESTORE_FINISHED_INFORMATION>(pData);
// Try to read some data from it
wprintf(L"Success data: %d\n", restoreFinishedInfo->Success);
wprintf(L"Final result data: %lu\n", restoreFinishedInfo->FinalResult);
wprintf(L"Callback arg: %p\n", restoreFinishedInfo->ClbkArg);
}
return TRUE;
}
void Scan(_In_ PFILE_RESTORE_CONTEXT context, _In_ LPCWSTR path)
{
// This is the main function that scans the files
// Dynamically link to the needed FMAPI functions
FuncScanRestorableFiles ScanRestorableFiles;
ScanRestorableFiles = reinterpret_cast<FuncScanRestorableFiles>( GetProcAddress( hLib, "ScanRestorableFiles" ) );
ULONG neededBufferSize = 0;
BOOL success = TRUE;
RESTORABLE_FILE_INFO tempFileInfo;
// Call ScanRestorableFiles the first time with a size of 0 to get the required buffer size
if ( ! ScanRestorableFiles(context, path, 0, &tempFileInfo, &neededBufferSize) )
{
wprintf(L"Failed to retrieve required buffer size, Error: #%u\n", GetLastError());
return;
}
// Create the buffer needed to hold restoration information
BYTE *buffer = new BYTE[neededBufferSize];
wcout << L"Initial buffer size is: " << neededBufferSize << L"\n";
// Loops until an error occurs or no more files found
while (success)
{
// Cast the byte buffer pointer into a structure pointer
PRESTORABLE_FILE_INFO fileInfo = reinterpret_cast<PRESTORABLE_FILE_INFO>(buffer);
#pragma warning( push )
#pragma warning( disable : 6386 ) /* warning is ignored since fileInfo grows in size by design */
success = ScanRestorableFiles(context, path, neededBufferSize, fileInfo, &neededBufferSize);
#pragma warning( pop )
wcout << L"Current buffer size is: " << neededBufferSize << L"\n";
if (success)
{
wcout << L"Call returned success! Required buffer size from latest call is " << neededBufferSize <<
L" bytes." L"\n";
if (fileInfo->IsRemoved)
{
// Found restorable file
wprintf(L"Restorable file found: %s\n", fileInfo->FileName);
// Echo size of char array containing file name
wcout << L"Restorable file name size: " <<
(sizeof(fileInfo->FileName) / sizeof(fileInfo->FileName[0])) << L"\n";
// Echo RESTORABLE_FILE_INFO structure info to console
wcout << L"Restorable file info structure memory address: " << fileInfo << L"\n";
wcout << L"Restorable file info structure size (returned via RESTORABLE_FILE_INFO): " << fileInfo->Size << L"\n";
wcout << L"Restorable file info structure size (returned via sizeof()): " << sizeof(*fileInfo) << L"\n";
// Echo restorable file (FMAPI) version to console
wcout << L"Restorable file version: " << fileInfo->Version << L"\n";
// Retrieve creation, write and access times for the file
// Define temp FILETIME, SYSTEMTIME and TIME_ZONE_INFORMATION
// structure vars
// All of these types and functions are defined in windows.h
FILETIME tmpFT;
SYSTEMTIME tmpST;
TIME_ZONE_INFORMATION tmpTZI;
// Initialize empty char arrays
wchar_t szLocalDate[255] = {0}, szLocalTime[255] = {0};
// Get local time zone info
SetTimeZoneInformation(&tmpTZI);
// Get file creation time
FileTimeToLocalFileTime(&(fileInfo->CreationTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file created: " << szLocalDate << " " << szLocalTime << L"\n";
// Clear array for re-use
fill(begin(szLocalDate), end(szLocalDate), 0);
// Get last write time
FileTimeToLocalFileTime(&(fileInfo->LastWriteTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file last written: " << szLocalDate << " " << szLocalTime << L"\n";
// Clear array for re-use
fill(begin(szLocalDate), end(szLocalDate), 0);
// Get last access time
FileTimeToLocalFileTime(&(fileInfo->LastAccessTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file last accessed: " << szLocalDate << " " << szLocalTime << L"\n";
// Output the rest of the file info
wcout << L"Restorable file attributes: " << fileInfo->Attributes << L"\n";
wcout << L"Restorable file size: " << fileInfo->FileSize << L"\n";
wcout << L"Restorable file ClustersUsedByFile: " << fileInfo->ClustersUsedByFile << L"\n";
wcout << L"Restorable file ClustersCurrentlyInUse: " << fileInfo->ClustersCurrentlyInUse << L"\n";
wcout << L"Restorable file RestoreDataOffset: " << fileInfo->RestoreDataOffset << L"\n";
// Attempt to restore the file
wstring tmpStr;
getline(wcin, tmpStr);
// Convert input to uppercase
for (wstring::size_type i = 0; i < tmpStr.size(); i++)
{
towupper(tmpStr[i]);
}
wcout << L"tmpStr is: " << tmpStr << L"\n";
if (tmpStr == L"RESTORE")
{
// Attempt to restore the file
wcout << L"Attempting to restore file " << fileInfo->FileName << L"..." << L"\n";
FuncRestoreFile RestoreFile;
//RestoreFile = (FuncRestoreFile)GetProcAddress( hLib, "RestoreFile" );
RestoreFile = reinterpret_cast<FuncRestoreFile>(GetProcAddress(hLib, "RestoreFile"));
wcout << L"RestoreFile address: " << RestoreFile << L"\n";
BOOL tmpRetVal = false;
PCWSTR restoredFileName = L"X:\\testfile.txt";
wcout << L"New file name: " << restoredFileName << L"\n";
PVOID cbArg = NULL;
tmpRetVal = RestoreFile(context, fileInfo, restoredFileName, &FuncRestoreCallback, cbArg);
wcout << L"Return value: " << tmpRetVal << L" ; cbArg: " << cbArg << L"\n";
if (tmpRetVal == 0)
{
wcout << L"Error was: " << GetLastError() << L"\n";
}
}
else if (tmpStr == L"CLOSE")
{
// Abort the scanning process and close the file restore context
wcout << L"Aborting scan and closing file restore context..." << L"\n";
success = false;
}
}
}
else
{
DWORD err = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == err)
{
wcout << L"Insufficient buffer size! Current size is " << sizeof(buffer) << L" bytes; " <<
L" required size is " << neededBufferSize << L" bytes. Resizing..." << L"\n";
delete [] buffer;
buffer = new BYTE[neededBufferSize];
success = true;
}
else if (ERROR_NO_MORE_FILES == err)
{
wprintf(L"Scanning Complete.\n");
success = false;
}
else
{
wprintf(L"ScanRestorableFiles, Error #%u.\n", err);
}
}
}
delete [] buffer;
buffer = NULL;
}
//
// Program entry point
//
void __cdecl wmain(int argc, wchar_t *argv[])
{
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
// Load the FMAPI DLL
hLib = ::LoadLibraryEx(L"fmapi.dll", NULL, NULL);
if ( !hLib )
{
wprintf(L"Could not load fmapi.dll. Error #%u.\n", GetLastError());
return;
}
// Dynamically link to the needed FMAPI functions
FuncCreateFileRestoreContext CreateFileRestoreContext;
CreateFileRestoreContext = reinterpret_cast<FuncCreateFileRestoreContext>( GetProcAddress( hLib, "CreateFileRestoreContext" ) );
FuncCloseFileRestoreContext CloseFileRestoreContext;
CloseFileRestoreContext = reinterpret_cast<FuncCloseFileRestoreContext>( GetProcAddress( hLib, "CloseFileRestoreContext" ) );
// Set the flags value for which kind of items we want to scan for
RESTORE_CONTEXT_FLAGS flags;
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
switch (argc)
{
case 2:
{
if (wcslen(argv[1]) < (sizeof(VOLUME) / sizeof(VOLUME[0]))) // ensure that argv[1] is not >255 chars long
{
wcscpy_s(VOLUME, argv[1]);
}
else
{
wcscpy_s(VOLUME, 255, argv[1]);
}
wcout << L"Volume set to: " << VOLUME << L"\n";
wcout << L"Defaulting to VOLUME search type; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
break;
}
case 3:
{
if (wcslen(argv[1]) < (sizeof(VOLUME) / sizeof(VOLUME[0]))) // ensure that argv[1] is not >255 chars long
{
wcscpy_s(VOLUME, argv[1]);
}
else // if it is, only copy the first 255 chars
{
wcscpy_s(VOLUME, 255, argv[1]);
}
int len;
// Get length of second argument passed by the user
len = wcslen(argv[2]);
// Allocate new wchar_t array big enough to hold it
wchar_t *tmpArg = new (nothrow) wchar_t[len + 1];
// Ensure that the memory was allocated successfully
if (tmpArg == nullptr)
{
// Error allocating memory - bail out
wcout << L"Error allocating memory! Bailing out..." << L"\n";
return;
}
// Copy the argument string from argv to tmpArg
wcscpy_s(tmpArg, len + 1, argv[2]);
// Convert to uppercase
_wcsupr_s(tmpArg, len + 1);
// Check whether VOLUME or DISK search type was specified and set flags accordingly
if (wcscmp(tmpArg, L"VOLUME") == 0)
{
wcout << L"Volume set to: " << VOLUME << L"\n";
if (wcschr(VOLUME, L':') != NULL)
{
wcout << L"VOLUME search type specified; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
}
else
{
wcout << L"VOLUME search type specified, but the volume identifier given doesn't appear " <<
L"to be a valid mounted volume! Please check your arguments and try again." << L"\n";
delete [] tmpArg;
return;
}
}
else if (wcscmp(tmpArg, L"DISK") == 0)
{
wcout << L"Disk set to: " << VOLUME << L"\n";
if (wcschr(VOLUME, L':') == NULL)
{
wcout << L"DISK search type specified; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagDisk | FlagScanRemovedFiles);
}
else
{
wcout << L"DISK search type specified, but the disk identifier given doesn't appear " <<
L"to be a valid physical disk! Please check your arguments and try again." << L"\n";
delete [] tmpArg;
return;
}
}
else
{
wcout << L"UNKNOWN search type specified! Defaulting to VOLUME; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
}
delete [] tmpArg;
break;
}
default:
{
// Set the default volume to scan here
wcscpy_s(VOLUME, L"\\\\.\\D:");
wcout << L"No arguments specified! Defaulting to VOLUME search of \\\\.\\D:" << L"\n";
break;
}
}
// Create the FileRestoreContext
PFILE_RESTORE_CONTEXT context = NULL;
if ( ! CreateFileRestoreContext(VOLUME, flags, 0, 0, FILE_RESTORE_VERSION_2, &context) )
{
DWORD err = GetLastError();
wprintf(L"Failed to Create FileRestoreContext, Error #%u.\n", err);
return;
}
else
{
wcout << L"Success! File restore context created! Value of context is: " << context << L"\n";
}
// Find restorable files starting at the given directory
Scan(context, SCAN_PATH);
// Close the context
if (context)
{
CloseFileRestoreContext(context);
context = NULL;
}
}
Please note this is still a very rudimentary app in its beginning stages. It basically begins a scan, defaulting (if no args are given) to scanning the D:\ drive and attempting to restore a deleted file to X:\testfile.txt. For those that may not be familiar with WinPE, X: is the system drive in a WinPE environment, and D: is usually the letter assigned to the OS drive of the machine that is booted to PE while in the PE environment, depending on the setup, with C: being the system reserved partition.
For each restorable file found, it pauses, and if the user enters the text "RESTORE" and hits ENTER, it will attempt to restore the file (this takes place around line 247). The callback function that indicates status for the restoration returns error code 6 (via FinalResult), as does GetLastError().
Any help on this is very much appreciated!
I am able to create a shared memory object, as well as open it using the guide from MSDN.
The first process creates it and keeps it open.
The second process inputs a string.
Then the first process will attempt to recover that string and display it, however I can't seem to get anything. It's always empty although it seems like the writing part is set up correctly.
I write a string to memory like this:
int MemoryMapper::Write(const std::string& data) {
m_pBuffer = (LPCTSTR)MapViewOfFile(m_OpenHandle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);
if (m_pBuffer == NULL)
{
std::cerr << m_DebugErrorTitle << "Write(): " << MM_ERROR_MAPPING_FAILED << " {" << GetLastError() << "}" << std::endl;
Close();
return 0;
}
const char* cdata = _CharFromString(data);
int size = (lstrlen(cdata) * sizeof(const char*));
CopyMemory((PVOID)m_pBuffer, cdata, size);
m_WrittenSize += size;
if (m_Debug > 1) { std::cout << m_DebugTitle << "Wrote " << size << " bytes." << std::endl; }
return size;
}
Then I read it like so:
int MemoryMapper::Read(std::string& data) {
m_pBuffer = (LPCTSTR) MapViewOfFile(m_OpenHandle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);
if (m_pBuffer == NULL)
{
std::cerr << m_DebugErrorTitle << "Read(" << m_MemoryName << "): " << MM_ERROR_MAPPING_FAILED << " {" << GetLastError() << "}" << std::endl;
Close();
return 0;
}
MessageBox(NULL, m_pBuffer, TEXT("TEST MESSAGE"), MB_OK);
int size = (lstrlen(m_pBuffer) * sizeof(const char*));
UnmapViewOfFile(m_pBuffer);
return size;
}
m_pBuffer is a LPCTSTR and m_BufferSize is 1024.
The name speficied for the object is the same on both ends. I've already made sure the creation and opening/closing part works.
The second process writes '8312.000000,8312.000000', a total of 92 bytes according to the code.
The reader's buffer is empty.
What am I doing wrong?
I've tried various data types, char, const char, string, tchar - same result.
8312.000000,8312.000000 is 23 characters in length.
std::string::c_str() returns a null-terminated char* pointer. lstrlen() returns the number of characters up to but not including the null terminator.
Write() is multiplying the string length by sizeof(const char*), which is 4 in a 32-bit process (8 in a 64-bit process). Write() is exceeding the bounds of data and attempting to copy 23 * 4 = 92 bytes into m_pBuffer. cdata is guaranteed to point at a buffer containing 24 bytes max (23 characters + 1 null terminator), so Write() is reaching into surrounding memory. That is undefined behavior, and anything could happen. In your case, you probably just ended up copying extra garbage into m_pBuffer. Write() could have easily crashed instead.
In fact, if data has more than 256 characters, Write() WOULD crash, because it would be trying to copy 257+ * 4 > 1024 bytes into m_pBuffer - more than MapViewOfFile() mapped access for.
You should be multiplying the string length by sizeof(std::string::value_type) instead, which is sizeof(char), which is always 1 (so you could just omit the multiplication).
Read() has the same sizeof() mistake, but it is also making the assumption that m_pBuffer is always null-terminated when calling lstrlen() and MessageBox(), but Write() does not guarantee that a null terminator is always present.
With that said, try something more like this instead:
int MemoryMapper::Write(const std::string& data)
{
// include the null terminator if there is room...
DWORD size = std::min(data.size() + 1, m_BufferSize);
char *pBuffer = (char*) MapViewOfFile(m_OpenHandle, FILE_MAP_WRITE, 0, 0, size);
if (!pBuffer)
{
DWORD errCode = GetLastError();
std::cerr << m_DebugErrorTitle << "Write(): " << MM_ERROR_MAPPING_FAILED << " {" << errCode << "}" << std::endl;
Close();
return 0;
}
CopyMemory(pBuffer, data.c_str(), size);
UnmapViewOfFile(pBuffer);
m_WrittenSize += size;
if (m_Debug > 1) {
std::cout << m_DebugTitle << "Wrote " << size << " bytes." << std::endl;
}
return size;
}
int MemoryMapper::Read(std::string& data)
{
char *pBuffer = (char*) MapViewOfFile(m_OpenHandle, FILE_MAP_READ, 0, 0, m_BufferSize);
if (!pBuffer)
{
DWORD errCode = GetLastError();
std::cerr << m_DebugErrorTitle << "Read(" << m_MemoryName << "): " << MM_ERROR_MAPPING_FAILED << " {" << errCode << "}" << std::endl;
Close();
return 0;
}
// check for a null terminator, but don't exceed the buffer...
char *terminator = std::find(pBuffer, pBuffer + m_BufferSize, '\0');
std::size_t len = std::distance(pBuffer, terminator);
data.assign(pBuffer, len);
UnmapViewOfFile(pBuffer);
MessageBoxA(NULL, data.c_str(), "TEST MESSAGE", MB_OK);
// include the null terminator if it was read...
return std::min(len + 1, m_BufferSize);
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
There are probably several post that explain my problem in several ways... But I have been searching in google and stackoverflow searchbox and I didn't found anything. So here I go.
I want to Write in a Process Memory a String Changing it in c++, but I don't even know clearly how it work so..
I have this pointer:
Image of the pointer
Please, can someone help me doing it?
I've tried it but it's not working..
#include <windows.h>
#include <iostream>
int main() {
HWND hWnd = FindWindow(0, "WindowName");
if (hWnd == 0) {
std::cout << "Cannot find window." << std::endl;
}
DWORD pId;
GetWindowThreadProcessId(hWnd, &pId);
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
DWORD baseAddress = 0x009B03D0;
DWORD offset = 0xA7;
DWORD ptrAddress;
char *newString = "newvalue";
ReadProcessMemory(hProc, (void*)baseAddress, &ptrAddress, sizeof(DWORD), 0);
WriteProcessMemory(hProc, (void*)(ptrAddress + offset), newString, strlen(newString), 0);
std::cout << "Done. " << &ptrAddress << std::endl;
std::getchar();
}
I should get the pointer and jumpt to the last one because I only have one offset.. But I'm not getting the correct one..
Edit:
Here is my new code, it works until the WriteProcessMemory function.. What can be wrong?
CODE THAT ACTUALLY WORKS:
int main()
{
unsigned long Pointer; /* to hold the final value */
unsigned long temp; /* hold the temp values */
unsigned long address = 0x009B03D0;
unsigned long offset = 0xA7;
unsigned long newString = 0;
DWORD pid;
HWND hwnd;
hwnd = FindWindow(0, TEXT("NewWindow"));
if (!hwnd)
{
cout << "No!\n";
cin.get();
}
else
{
GetWindowThreadProcessId(hwnd, &pid);
HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
if (!phandle)
{
cout << "None!\n";
cin.get();
}
else
{
while (1)
{
ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(address), &temp, sizeof(temp), 0);
Pointer = temp + offset;
//Good
ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(Pointer), &newString, 16, 0);
cout << reinterpret_cast<LPVOID>(Pointer) << " en " << newString;
Sleep(1000);
}
return 0;
}
}
}
CODE THAT NOT WORK:
int main()
{
unsigned int Pointer; /* to hold the final value */
unsigned int temp; /* hold the temp values */
unsigned int address = 0x009B03D0;
unsigned int offset = 0xA7;
unsigned int newString = 1768060259;
DWORD pid;
HWND hwnd;
hwnd = FindWindow(0, TEXT("NewWindow"));
if (!hwnd)
{
cout << "NO\n";
cin.get();
}
else
{
GetWindowThreadProcessId(hwnd, &pid);
HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
if (!phandle)
{
cout << "NONE\n";
cin.get();
}
else
{
while (1)
{
ReadProcessMemory(phandle, reinterpret_cast<LPVOID>(address), &temp, sizeof(temp), 0);
Pointer = temp + offset;
//Good
if (!WriteProcessMemory(phandle, reinterpret_cast<LPVOID>(Pointer), &newString, sizeof(newString), 0))
std::cerr << "Couldn't write process memory:" << GetLastError() << std::endl;
cout << reinterpret_cast<LPVOID>(Pointer) << " en " << newString;
Sleep(1000);
}
return 0;
}
}
}
Each process has its own memory and address space. So ReadProcessMemory() and WriteProcessMemory() use an intermediary buffer to do their job of accessing memory of another process.
Unfortunately, there are issues with your ReadProcessMemory() call:
you don't initialise ptrAddress to point to a buffer
you pass the address of ptrAddress and not its value that should point to a valid buffer
you pass 0 (i.e. a nullptr) instead of passing the address of the zie variable that should contain the number of bytes that could be read.
Note also that you manage the address in the target process using a DWORD for a LPCVOID. The first is always 32 bits, while the latter depend on your compiling options (32 bit code or 64 bit code).
You should also verify the error code in case of failure. It is almost certain taht special priviledges are required to read/write in distinct processes.
Here an adjusted code, with some diagnosis messages to help you further.
HWND hWnd = FindWindow(0, TEXT("WindowName") );
if (hWnd == 0) {
std::cerr << "Cannot find window." << std::endl;
}
else {
DWORD pId;
GetWindowThreadProcessId(hWnd, &pId);
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
if (hProc) {
char *newString = "newvalue";
size_t sz = strlen(newString) + 1;
LPVOID baseAddress = (LPVOID)0x009B03D0;
DWORD offset = 0xA7;
LPVOID ptrAddress = new char[sz];
SIZE_T bytes_read = 0, bytes_written=0;
if (ReadProcessMemory(hProc, baseAddress, ptrAddress, sz, &bytes_read) || GetLastError()== ERROR_PARTIAL_COPY) {
if (bytes_read == 0)
std::cerr << "Houston, we have a problem..." << std::endl;
if(!WriteProcessMemory(hProc, baseAddress, (LPCVOID)newString, sz, &bytes_written))
std::cerr << "Couldn't write process memory:" << GetLastError() << std::endl;
std::cout << "Done. " << bytes_read <<" bytes read and "<<bytes_written<<" bytes written"<< std::endl;
}
else {
std::cerr<< "Couldn't read process memory:" << GetLastError() << std::endl;
}
delete[] ptrAddress;
}
else {
std::cerr << "Couldn't open process " << pId << ": " << GetLastError() << std::endl;
}
}
std::getchar();