aboutsummaryrefslogtreecommitdiff
path: root/memscan.cc
diff options
context:
space:
mode:
Diffstat (limited to 'memscan.cc')
-rw-r--r--memscan.cc235
1 files changed, 235 insertions, 0 deletions
diff --git a/memscan.cc b/memscan.cc
new file mode 100644
index 0000000..674194a
--- /dev/null
+++ b/memscan.cc
@@ -0,0 +1,235 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+
+typedef uint8_t uint8;
+typedef uintptr_t uintptr;
+
+void PrintLastError(const char *Context){
+ DWORD ErrorCode = GetLastError();
+ char ErrorString[256];
+ DWORD Ret = FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ ErrorString, sizeof(ErrorString), NULL);
+ if(Ret == 0){
+ strcpy(ErrorString, "unknown error");
+ }
+ printf("%s | error(%d): %s\n", Context, ErrorCode, ErrorString);
+}
+
+void DebugPrintBuf(uintptr Address, const uint8 *Buffer, int Count){
+ const int BytesPerLine = 16;
+ int FullLines = Count / BytesPerLine;
+ int Remainder = Count % BytesPerLine;
+
+ for(int i = 0; i < FullLines; i += 1){
+ printf("%16llX | ", (Address + i * BytesPerLine));
+
+ for(int j = 0; j < BytesPerLine; j += 1){
+ if(j > 0) putchar(' ');
+ printf("%02X", Buffer[i * BytesPerLine + j]);
+ }
+
+ printf(" | ");
+
+ for(int j = 0; j < BytesPerLine; j += 1){
+ int ch = Buffer[i * BytesPerLine + j];
+ printf("%c", isprint(ch) ? ch : '.');
+ }
+
+ putchar('\n');
+ }
+
+ if(Remainder > 0){
+ printf("%16llX | ", (Address + FullLines * BytesPerLine));
+
+ for(int j = 0; j < BytesPerLine; j += 1){
+ if(j > 0) putchar(' ');
+ if(j < Remainder){
+ printf("%02X", Buffer[FullLines * BytesPerLine + j]);
+ }else{
+ printf(" ");
+ }
+ }
+
+ printf(" | ");
+
+ for(int j = 0; j < BytesPerLine; j += 1){
+ if(j < Remainder){
+ int ch = Buffer[FullLines * BytesPerLine + j];
+ printf("%c", isprint(ch) ? ch : '.');
+ }else{
+ printf(" ");
+ }
+ }
+
+ putchar('\n');
+ }
+}
+
+void DumpProcessMemory(HANDLE Process, uintptr BaseAddr, SIZE_T Size){
+ uintptr Addr = BaseAddr;
+ uintptr End = BaseAddr + Size;
+ while(Addr < End){
+ uint8 Buffer[32 * 1024];
+ SIZE_T BytesToRead = End - Addr;
+ if(BytesToRead > sizeof(Buffer)){
+ BytesToRead = sizeof(Buffer);
+ }
+
+ SIZE_T BytesRead;
+ if(!ReadProcessMemory(Process, (void*)Addr, Buffer, BytesToRead, &BytesRead)){
+ PrintLastError("DumpProcessMemory>ReadProcessMemory");
+ return;
+ }
+
+ DebugPrintBuf(Addr, Buffer, (int)BytesRead);
+ Addr += BytesRead;
+ }
+}
+
+int BufferFind(const uint8 *Buffer, int BufferSize, const uint8 *Data, int DataSize){
+ for(int i = 0; i < (BufferSize - DataSize); i += 1){
+ if(memcmp(Buffer + i, Data, DataSize) == 0){
+ return i;
+ }
+ }
+ return -1;
+}
+
+void ScanProcessMemory(HANDLE Process, uintptr BaseAddr, SIZE_T Size,
+ const uint8 *Data, SIZE_T DataSize, int ContextWindow){
+ uintptr Addr = BaseAddr;
+ uintptr End = BaseAddr + Size;
+ while(Addr < End){
+ uint8 Buffer[32 * 1024];
+ SIZE_T BytesToRead = End - Addr;
+ if(BytesToRead > sizeof(Buffer)){
+ BytesToRead = sizeof(Buffer);
+ }
+
+ SIZE_T BytesRead;
+ if(!ReadProcessMemory(Process, (void*)Addr, Buffer, BytesToRead, &BytesRead)){
+ PrintLastError("ScanProcessMemory>ReadProcessMemory");
+ return;
+ }
+
+ // TODO(fusion): This will work most of the time but is not the best way
+ // to scan for something because the data we're looking for may be split
+ // between reads, depending on the size of `Buffer`.
+ int Cursor = 0;
+ while(true){
+ int Offset = BufferFind(Buffer + Cursor, (int)BytesRead - Cursor, Data, (int)DataSize);
+ if(Offset == -1){
+ break;
+ }
+
+ Cursor += Offset;
+ int PrintStart = Cursor - ContextWindow;
+ int PrintEnd = Cursor + (int)DataSize + ContextWindow;
+
+ if(PrintStart < 0){
+ PrintStart = 0;
+ }
+
+ if(PrintEnd > (int)BytesRead){
+ PrintEnd = (int)BytesRead;
+ }
+
+ DebugPrintBuf(Addr + PrintStart, Buffer + PrintStart, PrintEnd - PrintStart);
+ Cursor += (int)DataSize;
+ }
+
+ Addr += BytesRead;
+ }
+}
+
+int main(int argc, char **argv){
+ uint8 Data[128];
+ int DataSize = 0;
+ int ContextWindow = 10;
+ for(int i = 1; i < argc; i += 1){
+ if(argv[i][0] == '-'){
+ if((i + 1) >= argc){
+ printf("missing \"%s\" value", argv[i]);
+ break;
+ }
+
+ if(strcmp(argv[i], "-c") == 0){
+ ContextWindow = atoi(argv[i + 1]);
+ }else if(strcmp(argv[i], "-byte") == 0){
+ int Num = atoi(argv[i + 1]);
+ Data[0] = (uint8)Num;
+ DataSize = 1;
+ }else if(strcmp(argv[i], "-le16") == 0){
+ int Num = atoi(argv[i + 1]);
+ Data[0] = (uint8)(Num >> 0);
+ Data[1] = (uint8)(Num >> 8);
+ DataSize = 2;
+ }else if(strcmp(argv[i], "-be16") == 0){
+ int Num = atoi(argv[i + 1]);
+ Data[0] = (uint8)(Num >> 8);
+ Data[1] = (uint8)(Num >> 0);
+ DataSize = 2;
+ }else if(strcmp(argv[i], "-le32") == 0){
+ int Num = atoi(argv[i + 1]);
+ Data[0] = (uint8)(Num >> 0);
+ Data[1] = (uint8)(Num >> 8);
+ Data[2] = (uint8)(Num >> 16);
+ Data[3] = (uint8)(Num >> 24);
+ DataSize = 4;
+ }else if(strcmp(argv[i], "-be32") == 0){
+ int Num = atoi(argv[i + 1]);
+ Data[0] = (uint8)(Num >> 24);
+ Data[1] = (uint8)(Num >> 16);
+ Data[2] = (uint8)(Num >> 8);
+ Data[3] = (uint8)(Num >> 0);
+ DataSize = 4;
+ }
+
+ i += 1;
+ }else{
+ DataSize = (int)strlen(argv[i]);
+ if(DataSize > (int)sizeof(Data)){
+ DataSize = (int)sizeof(Data);
+ }
+ memcpy(Data, argv[i], DataSize);
+ }
+ }
+
+ if(DataSize == 0){
+ printf("Invalid usage. See `memscan.cc`.\n");
+ return 1;
+ }
+
+ HWND Window = FindWindowA("TibiaClient", NULL);
+ if(Window == NULL){
+ PrintLastError("FindWindowA");
+ return -1;
+ }
+
+ DWORD ProcessID;
+ GetWindowThreadProcessId(Window, &ProcessID);
+
+ HANDLE Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessID);
+ if(Process == NULL){
+ PrintLastError("OpenProcess");
+ return -1;
+ }
+
+ uintptr BaseAddr = 0;
+ MEMORY_BASIC_INFORMATION Info;
+ while(VirtualQueryEx(Process, (void*)BaseAddr, &Info, sizeof(Info)) != 0){
+ if(Info.State & MEM_COMMIT && !(Info.Protect & PAGE_NOACCESS) && !(Info.Protect & PAGE_GUARD)){
+ ScanProcessMemory(Process, (uintptr)Info.BaseAddress, Info.RegionSize, Data, DataSize, ContextWindow);
+ }
+ BaseAddr = (uintptr)Info.BaseAddress + Info.RegionSize;
+ }
+ CloseHandle(Process);
+ return 0;
+}