Reputation: 1811
I have been trying to read all memory addresses within a process range only, (see question: C++ read memory addresses within process range only). I succeeded with reading from memory and it seems like I received the correct baseaddress
for the process. The problem I was having was to find specific values which I assumed the program would have.
For example if I played a game and had the score 500, I wanted to find 500 in the memory. I stepped through all the addresses but could not find the value. So I decided to read my own program (which is 64-bit) and set a value to 500, print its address and manually search and see if I found it.
int number = 500;
std::cout << &number;
For some reason the address it was written to was out of bounds of the process range.
I calculate the address range with:
uintptr_t moduleBase = GetModuleBaseAddress(procId, L"x.exe");
uintptr_t moduleSize = GetModuleSize(procId, L"x.exe");
// Set base and last address and print them for user
uintptr_t dynamicPtrBaseAddr = moduleBase;
uintptr_t dynamicPtrLastAddr = (moduleBase + moduleSize);
Methods used:
uintptr_t GetModuleSize(DWORD procId, const wchar_t* modName) {
uintptr_t modBaseSize = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | 0x10, procId);
if(hSnap != INVALID_HANDLE_VALUE) {
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if(Module32First(hSnap, &modEntry)) {
do {
if(!_wcsicmp(modEntry.szModule, modName)) {
modBaseSize = (uintptr_t)modEntry.modBaseSize;
break;
}
} while(Module32Next(hSnap, &modEntry));
}
}
CloseHandle(hSnap);
return modBaseSize;
}
and
uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName) {
uintptr_t modBaseAddr = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | 0x10, procId);
if(hSnap != INVALID_HANDLE_VALUE) {
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if(Module32First(hSnap, &modEntry)) {
do {
if(!_wcsicmp(modEntry.szModule, modName)) {
modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
break;
}
} while(Module32Next(hSnap, &modEntry));
}
}
CloseHandle(hSnap);
return modBaseAddr;
}
Since the value of number
is written out of bounds I assume that GetModuleSize
, might be incorrect.
Last address for me is: 0x4F4628
,
std::cout << &number;
gives me 0x6DFDD4
My questions are:
&number
. Is this because modulesize gives me a 32-bit range or is this giving me addresses out of bounds for the process?I compile with: g++ main.cpp -o x -lpsapi -DUNICODE -m64
, and had to add libgcc_s_seh-1.dll
to my path in order to run my program.
My entire project on github: https://github.com/Darclander/memory-reading
(Not sure if it is better for me to post the entire code on here).
Upvotes: 1
Views: 1533
Reputation: 7170
As @para said, the module is a image of PE file.
The variable you want to read is stored on the current thread stack, you will need to get the base address and limit address of the stack, with NtQueryInformationThread
#include <windows.h>
#include <iostream>
#include <winternl.h>
#include <tlhelp32.h>
#pragma warning(disable : 4996)
using namespace std;
typedef enum _mTHREADINFOCLASS {
ThreadBasicInformation = 0
} mTHREADINFOCLASS;
typedef struct _mTEB {
NT_TIB Tib;
PVOID EnvironmentPointer;
CLIENT_ID Cid;
PVOID ActiveRpcInfo;
PVOID ThreadLocalStoragePointer;
PPEB Peb;
ULONG LastErrorValue;
ULONG CountOfOwnedCriticalSections;
PVOID CsrClientThread;
PVOID Win32ThreadInfo;
ULONG Win32ClientInfo[0x1F];
PVOID WOW32Reserved;
ULONG CurrentLocale;
ULONG FpSoftwareStatusRegister;
PVOID SystemReserved1[0x36];
PVOID Spare1;
ULONG ExceptionCode;
ULONG SpareBytes1[0x28];
PVOID SystemReserved2[0xA];
ULONG GdiRgn;
ULONG GdiPen;
ULONG GdiBrush;
CLIENT_ID RealClientId;
PVOID GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PVOID GdiThreadLocaleInfo;
PVOID UserReserved[5];
PVOID GlDispatchTable[0x118];
ULONG GlReserved1[0x1A];
PVOID GlReserved2;
PVOID GlSectionInfo;
PVOID GlSection;
PVOID GlTable;
PVOID GlCurrentRC;
PVOID GlContext;
NTSTATUS LastStatusValue;
UNICODE_STRING StaticUnicodeString;
WCHAR StaticUnicodeBuffer[0x105];
PVOID DeallocationStack;
PVOID TlsSlots[0x40];
LIST_ENTRY TlsLinks;
PVOID Vdm;
PVOID ReservedForNtRpc;
PVOID DbgSsReserved[0x2];
ULONG HardErrorDisabled;
PVOID Instrumentation[0x10];
PVOID WinSockData;
ULONG GdiBatchCount;
ULONG Spare2;
ULONG Spare3;
ULONG Spare4;
PVOID ReservedForOle;
ULONG WaitingOnLoaderLock;
PVOID StackCommit;
PVOID StackCommitMax;
PVOID StackReserved;
} mTEB;
typedef NTSTATUS (WINAPI *fpNtQueryInformationThread)(
IN HANDLE ThreadHandle,
IN mTHREADINFOCLASS ThreadInformationClass,
OUT PVOID ThreadInformation,
IN ULONG ThreadInformationLength,
OUT PULONG ReturnLength
);
typedef struct _THREAD_BASIC_INFORMATION {
NTSTATUS ExitStatus;
mTEB* TebBaseAddress;
CLIENT_ID ClientId;
KAFFINITY AffinityMask;
KPRIORITY Priority;
KPRIORITY BasePriority;
} THREAD_BASIC_INFORMATION, * PTHREAD_BASIC_INFORMATION;
void fun()
{
return;
}
int main()
{
DWORD pid = 21112;//process id
DWORD tid = 5512;//thread id
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
if (hProcess == NULL)
{
int error = GetLastError();
cout << "OpenProcess error: " << error << endl;
}
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS,false, tid);
if (hThread == NULL)
{
int error = GetLastError();
cout << "OpenThread error: " << error << endl;
}
HMODULE h = LoadLibrary(L"ntdll.dll");
fpNtQueryInformationThread NtQueryInformationThread = (fpNtQueryInformationThread)GetProcAddress(h,"NtQueryInformationThread");
THREAD_BASIC_INFORMATION info = { 0 };
NTSTATUS ret = NtQueryInformationThread(hThread, ThreadBasicInformation, &info, sizeof(THREAD_BASIC_INFORMATION), NULL);
NT_TIB tib = { 0 };
if (!ReadProcessMemory(hProcess, info.TebBaseAddress, &tib, sizeof(NT_TIB), nullptr))
{
int error = GetLastError();
cout << "ReadProcessMemory error: " << error << endl;
}
cout << tib.StackLimit << " to " << tib.StackBase << endl;
return 0;
}
Process module sample:
#include <windows.h>
#include <iostream>
int main()
{
int number = 500;
std::cout << &number << std::endl;
std::cout << "Pid = " << GetCurrentProcessId() << std::endl;
std::cout << "Tid = " << GetCurrentThreadId() << std::endl;
getchar();
return 0;
}
Result:
If you do not know the specific thread ID, you can refer to this document to Traversing the Thread List
(Note: NtQueryInformationThread
may be altered or unavailable in future versions of Windows. )
Upvotes: 2
Reputation:
A "module" in WIN32 terms is an executable image file. This image contains things like code, static variables, stack unwind tables and more. The value you are attempting to read is a local variable and thus will be allocated on the stack. The stack is not part of the image, so you won't find it there.
What you need to do is find the address and size of the stack. See How can I locate a process' global and stack areas in Win32? on how to do that.
You probably also want to read the heap in addition to the stack, you can find all open heaps by using GetProcessHeaps and get the addresses/sizes with HeapSummary.
Upvotes: 2