int StackTraceResolverImpl<ObjectFileFormat::Windows>::resolve( StackTrace *stackTrace, bool demangle) // Given a specified stack trace object 'stackTrace' of stack trace frames // with only their 'address' fields valid, set as many other fields of the // frames as possible. The 'demangle' argument is ignored, demangling // always happens on Windows. Return 0 if successful and a non-zero value // otherwise. { typedef bsl::map<HMODULE, const char *> LibNameMap; bdlma::HeapBypassAllocator hbpAlloc; bslmt::QLockGuard guard(&DbghelpDllImpl_Windows::qLock()); DbghelpDllImpl_Windows::symSetOptions(SYMOPT_NO_PROMPTS | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS); // | SYMOPT_DEBUG); int numFrames = stackTrace->length(); LibNameMap libNameMap(&hbpAlloc); char *libNameBuf = (char *) hbpAlloc.allocate(MAX_PATH); enum { MAX_SYMBOL_BUF_NAME_LENGTH = 2000 }; #ifdef BSLS_PLATFORM_CPU_32_BIT enum { SIZEOF_SEGMENT = sizeof(SYMBOL_INFO) + MAX_SYMBOL_BUF_NAME_LENGTH * sizeof(TCHAR) }; SYMBOL_INFO *sym = (SYMBOL_INFO*) hbpAlloc.allocate(SIZEOF_SEGMENT); #else enum { SIZEOF_SEGMENT = sizeof(IMAGEHLP_SYMBOL64) + MAX_SYMBOL_BUF_NAME_LENGTH * sizeof(TCHAR) }; IMAGEHLP_SYMBOL64 *sym = (IMAGEHLP_SYMBOL64 *) hbpAlloc.allocate(SIZEOF_SEGMENT); #endif for (int i = 0; i < numFrames; ++i) { StackTraceFrame *frame = &(*stackTrace)[i]; DWORD64 address = (DWORD64) frame->address(); IMAGEHLP_LINE64 line; ZeroMemory(&line, sizeof(IMAGEHLP_LINE64)); line.SizeOfStruct = sizeof(line); DWORD offsetFromLine; int rc = DbghelpDllImpl_Windows::symGetLineFromAddr64(address, &offsetFromLine, &line); if (rc) { frame->setSourceFileName(line.FileName); frame->setLineNumber(line.LineNumber); } else { reportError("stack trace resolver error: symGetLineFromAddr64" " error code: "); } DWORD64 offsetFromSymbol = 0; ZeroMemory(sym, SIZEOF_SEGMENT); sym->SizeOfStruct = sizeof(*sym); #ifdef BSLS_PLATFORM_CPU_32_BIT sym->MaxNameLen = MAX_SYMBOL_BUF_NAME_LENGTH; rc = DbghelpDllImpl_Windows::symFromAddr(address, &offsetFromSymbol, sym); #else BSLMF_ASSERT(sizeof(void *) == 8); sym->MaxNameLength = MAX_SYMBOL_BUF_NAME_LENGTH; rc = DbghelpDllImpl_Windows::symGetSymFromAddr64(address, &offsetFromSymbol, sym); #endif if (rc) { // windows is always demangled ((TCHAR *) sym)[SIZEOF_SEGMENT - 1] = 0; frame->setMangledSymbolName(sym->Name); frame->setSymbolName(frame->mangledSymbolName()); frame->setOffsetFromSymbol((bsl::size_t) offsetFromSymbol); } else { #ifdef BSLS_PLATFORM_CPU_32_BIT reportError("stack trace resolver error: SymFromAddr" " error code: "); #else reportError("stack trace resolver error: SymGetSymFromAddr64" " error code: "); #endif } HMODULE hModule = NULL; MEMORY_BASIC_INFORMATION mbi; if (VirtualQuery((LPCVOID) address, &mbi, sizeof(mbi))) { hModule = (HMODULE)(mbi.AllocationBase); } LibNameMap::iterator it = libNameMap.find(hModule); if (libNameMap.end() != it) { // If the library name in the map is "", leave the library file // name in the frame null. if (*it->second) { frame->setLibraryFileName(it->second); } } else { rc = GetModuleFileNameA(hModule, libNameBuf, MAX_PATH); libNameBuf[MAX_PATH-1] = 0; if (!rc) { // Failed. Put a null lib name into the map so we won't waste // time looking up the same library again. Leave the // libraryFileName in the frame null. libNameMap[hModule] = bdlb::String::copy("", &hbpAlloc); } else { frame->setLibraryFileName(libNameBuf); libNameMap[hModule] = frame->libraryFileName().c_str(); } } } return 0; }
bool CSignatureFunction::getLibraryInfo(const void *libPtr, DynLibInfo &lib) { uintptr_t baseAddr; if (libPtr == NULL) { return false; } #ifdef _WIN32 MEMORY_BASIC_INFORMATION info; IMAGE_DOS_HEADER *dos; IMAGE_NT_HEADERS *pe; IMAGE_FILE_HEADER *file; IMAGE_OPTIONAL_HEADER *opt; if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION))) { return false; } baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase); // All this is for our insane sanity checks :o dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr); pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew); file = &pe->FileHeader; opt = &pe->OptionalHeader; // Check PE magic and signature if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { return false; } // Check architecture, which is 32-bit/x86 right now // Should change this for 64-bit if Valve gets their act together if (file->Machine != IMAGE_FILE_MACHINE_I386) { return false; } //For our purposes, this must be a dynamic library if ((file->Characteristics & IMAGE_FILE_DLL) == 0) { return false; } //Finally, we can do this lib.memorySize = opt->SizeOfImage; #else Dl_info info; Elf32_Ehdr *file; Elf32_Phdr *phdr; uint16_t phdrCount; if (!dladdr(libPtr, &info)) { return false; } if (!info.dli_fbase || !info.dli_fname) { return false; } // This is for our insane sanity checks :o baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase); file = reinterpret_cast<Elf32_Ehdr *>(baseAddr); // Check ELF magic if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) { return false; } // Check ELF version if (file->e_ident[EI_VERSION] != EV_CURRENT) { return false; } // Check ELF architecture, which is 32-bit/x86 right now // Should change this for 64-bit if Valve gets their act together if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB) { return false; } // For our purposes, this must be a dynamic library/shared object if (file->e_type != ET_DYN) { return false; } phdrCount = file->e_phnum; phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff); for (uint16_t i = 0; i < phdrCount; i++) { Elf32_Phdr &hdr = phdr[i]; // We only really care about the segment with executable code if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R)) { // From glibc, elf/dl-load.c: // c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1) // & ~(GLRO(dl_pagesize) - 1)); // // In glibc, the segment file size is aligned up to the nearest page size and // added to the virtual address of the segment. We just want the size here. lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz); break; } } #endif lib.baseAddress = reinterpret_cast<void *>(baseAddr); return true; }
/*******************MemHeap内存改写处理************************/ INT find_maps(ULONG addr, ULONG *start, ULONG *end) { #ifdef _OS_LINUX_ char mapFile[30]; char buf[120]; char attr[4]; FILE *fp; ULONG pid = vos_get_pid(); sprintf(mapFile, "/proc/%lu/maps", pid); if(NULL == (fp = fopen(mapFile, "r"))) return FALSE; while(NULL != fgets(buf, 120, fp)) { sscanf(buf, "%lx-%lx %s", start, end, attr); if((addr >= *start) && (addr < *end) && (attr[0] == 'r') && (attr[1] == 'w')) { fclose(fp); return TRUE; } else if(addr < *start)/* 位于空洞 */ break; else/* 下一个 */ continue; } fclose(fp); *start = (ULONG)NULL; *end = (ULONG)NULL; return FALSE; #endif #ifdef _OS_WINNT_ MEMORY_BASIC_INFORMATION info; BYTE *head, *tail; BYTE *page = (BYTE*)round_down(addr, PAGE_SIZE); *start = (ULONG)NULL; *end = (ULONG)NULL; if(0 == VirtualQuery(page, &info, sizeof(info))) return FALSE; if((info.Protect != PAGE_READWRITE) || (info.AllocationProtect != PAGE_READWRITE) || (info.State != MEM_COMMIT)) return FALSE; *end = (ULONG)(page + info.RegionSize); tail = (BYTE*)(info.AllocationBase); do { head = tail; VirtualQuery(head, &info, sizeof(info)); tail = head + info.RegionSize; }while(addr >= (ULONG)tail); *start = (ULONG)head; return TRUE; #endif }
/* ================== Sym_Init ================== */ void Sym_Init( long addr ) { TCHAR moduleName[MAX_STRING_CHARS]; MEMORY_BASIC_INFORMATION mbi; VirtualQuery( (void*)addr, &mbi, sizeof(mbi) ); GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) ); char *ext = moduleName + strlen( moduleName ); while( ext > moduleName && *ext != '.' ) { ext--; } if ( ext == moduleName ) { strcat( moduleName, ".map" ); } else { strcpy( ext, ".map" ); } module_t *module = (module_t *) malloc( sizeof( module_t ) ); module->name = (char *) malloc( strlen( moduleName ) + 1 ); strcpy( module->name, moduleName ); module->address = (int)mbi.AllocationBase; module->symbols = NULL; module->next = modules; modules = module; FILE *fp = fopen( moduleName, "rb" ); if ( fp == NULL ) { return; } int pos = ftell( fp ); fseek( fp, 0, SEEK_END ); int length = ftell( fp ); fseek( fp, pos, SEEK_SET ); char *text = (char *) malloc( length+1 ); fread( text, 1, length, fp ); text[length] = '\0'; fclose( fp ); const char *ptr = text; // skip up to " Address" on a new line while( *ptr != '\0' ) { SkipWhiteSpace( &ptr ); if ( idStr::Cmpn( ptr, "Address", 7 ) == 0 ) { SkipRestOfLine( &ptr ); break; } SkipRestOfLine( &ptr ); } int symbolAddress; int symbolLength; char symbolName[MAX_STRING_CHARS]; symbol_t *symbol; // parse symbols while( *ptr != '\0' ) { SkipWhiteSpace( &ptr ); ParseHexNumber( &ptr ); if ( *ptr == ':' ) { ptr++; } else { break; } ParseHexNumber( &ptr ); SkipWhiteSpace( &ptr ); // parse symbol name symbolLength = 0; while( *ptr != '\0' && *ptr != ' ' ) { symbolName[symbolLength++] = *ptr++; if ( symbolLength >= sizeof( symbolName ) - 1 ) { break; } } symbolName[symbolLength++] = '\0'; SkipWhiteSpace( &ptr ); // parse symbol address symbolAddress = ParseHexNumber( &ptr ); SkipRestOfLine( &ptr ); symbol = (symbol_t *) malloc( sizeof( symbol_t ) ); symbol->name = (char *) malloc( symbolLength ); strcpy( symbol->name, symbolName ); symbol->address = symbolAddress; symbol->next = module->symbols; module->symbols = symbol; } free( text ); }
// Check that the address is backed by a file, // get the binary's load address, // get the PE header, assuming there is one, // see if the last section has been tagged with "DYNINST_REWRITE" // get trap-table header from last binary section's end - label - size // sets allocBase to the binary's load address static struct trap_mapping_header *getStaticTrapMap(unsigned long addr, unsigned long *allocBase) { struct trap_mapping_header *header = NULL; char fileName[ERROR_STRING_LENGTH]; DWORD actualNameLen = 0; MEMORY_BASIC_INFORMATION memInfo; int numSections = 0; PIMAGE_NT_HEADERS peHdr = NULL; IMAGE_SECTION_HEADER curSecn; int sidx=0; char *str=NULL; //check that the address is backed by a file actualNameLen = GetMappedFileName(GetCurrentProcess(), (LPVOID)addr, fileName, ERROR_STRING_LENGTH); if (!actualNameLen) { fileName[0] = '\0'; goto done; // no file mapped at trap address } fileName[ERROR_STRING_LENGTH-1] = '\0'; // get the binary's load address, size if (!VirtualQuery((LPCVOID)addr, &memInfo, sizeof(memInfo)) || MEM_COMMIT != memInfo.State) { fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__,__LINE__); goto done; // shouldn't be possible given previous query, but hey } *allocBase = (unsigned long) memInfo.AllocationBase; rtdebug_printf("RTLIB: getStaticTrapMap addr=%lx meminfo.BaseAddress=%lx " "meminfo.AllocationBase = %lx, memInfo.RegionSize = %lx, " "%s[%d]\n", addr, memInfo.BaseAddress, memInfo.AllocationBase, memInfo.RegionSize, __FILE__,__LINE__); // get the PE header, assuming there is one peHdr = ImageNtHeader( memInfo.AllocationBase ); if (!peHdr) { fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__,__LINE__); goto done; // no pe header } // see if the last section has been tagged with "DYNINST_REWRITE" numSections = peHdr->FileHeader.NumberOfSections; curSecn = *(PIMAGE_SECTION_HEADER) (((unsigned char*)peHdr) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + peHdr->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_SECTION_HEADER)*(numSections-1)); //fprintf(stderr, "RTLIB: PE section header address = %lx\n", curSecn); //fprintf(stderr, "curSecn.chars = %lx %s[%d]\n",curSecn.Characteristics, __FILE__,__LINE__); if ((sizeof(void*) + 16) > curSecn.SizeOfRawData) { fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__,__LINE__); goto done; // last section is uninitialized, doesn't have trap table } //fprintf(stderr, "RTLIB %s[%d]\n", __FILE__,__LINE__); //fprintf(stderr, "RTLIB mi.ab =%lx cs.va =%lx cs.srd=%lx %s[%d]\n", memInfo.AllocationBase, curSecn.VirtualAddress, curSecn.SizeOfRawData, __FILE__,__LINE__); str = (char*)((long)memInfo.AllocationBase + curSecn.VirtualAddress + curSecn.SizeOfRawData - 16); if (0 != strncmp("DYNINST_REWRITE", str, 15)) { fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap found bad string [%s] at %lx %s[%d]\n", str, str, __FILE__,__LINE__); goto done; // doesn't have DYNINST_REWRITE label } // get trap-table header header = (struct trap_mapping_header*) ( (unsigned long)memInfo.AllocationBase + *((unsigned long*)(str - sizeof(void*))) ); done: if (header) { rtdebug_printf( "RTLIB: found trap map header at %lx: [%lx %lx]\n", (unsigned long) header, header->low_entry, header->high_entry); } else { rtdebug_printf( "ERROR: didn't find trap table\n"); } return header; }
/* * PrintStackdump * Prints the content of the stack into the logging buffer */ void ExceptionTracer::PrintStackdump() { // We need the ESP of the exception context to execute a stack dump, make sure we have access to it if ((context.ContextFlags & CONTEXT_CONTROL) == 0) return; static const auto align = sizeof_word; // Stack aligment static const auto max_words_in_line_magic = stackdump_words_per_line + 10; MEMORY_BASIC_INFORMATION mbi; #if !_M_X64 uintptr_t base, bottom, top = (uintptr_t)context.Esp; #else uintptr_t base, bottom, top = (uintptr_t)context.Rsp; #endif auto words_in_line = max_words_in_line_magic; // Finds the bottom of the stack from it's base pointer // Note: mbi will get overriden on this function auto GetStackBottom = [&mbi](uintptr_t base) { VirtualQuery((void*)base, &mbi, sizeof(mbi)); // Find uncommited region of the stack VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find guard page VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find commited region of the stack auto last = (uintptr_t)mbi.BaseAddress; return (base + (last - base) + mbi.RegionSize); // base + distanceToLastRegion + lastRegionSize }; // Prints an CPU word at the specified stack address auto PrintWord = [this, &words_in_line](uintptr_t addr) { if (words_in_line++ >= stackdump_words_per_line) { // Print new line only if it's not the first time we enter here (i.e. words_in_line has magical value) if (words_in_line != max_words_in_line_magic + 1) NewLine(); words_in_line = 1; Print("0x%p: ", addr); } Print(" %p", *(uint32_t*)addr); }; Print("Stack dump:"); EnterScope(); { // Makes sure the pointer at top (ESP) is valid and readable memory if (VirtualQuery((void*)(top), &mbi, sizeof(mbi)) && (mbi.State & MEM_COMMIT) && (mbi.Protect & (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_READONLY)) != 0) { base = (uintptr_t)mbi.AllocationBase; // Base of the stack (uncommited) bottom = GetStackBottom(base); // Bottom of the stack (commited) // Align the stack top (esp) in a 4 bytes boundary auto remainder = top % align; uintptr_t current = remainder ? top + (align - remainder) : top; // on x86 stack grows downward! (i.e. from bottom to base) for (int n = 0; n < stackdump_max_words && current < bottom; ++n, current += align) PrintWord(current); NewLine(); Print("base: 0x%p top: 0x%p bottom: 0x%p", base, top, bottom); NewLine(); } } LeaveScope(); }
THIS WILL NOT WORK ON WINCE 6.0 AND ABOVE #endif #endif #ifdef UNDER_CE // The WinCE version of getPrivateResidentPageCount must do some specific things to get // an accurate picture of private bytes due to how WinCE lays out memory for the process. // see http://msdn.microsoft.com/en-us/library/bb331824.aspx for a desccription of how the memory is laid out. // Note that we are running on Windows Mobile 6.0, but that is based on WinCE 5.0. // Basically, first we walk the memory for the process slot, from 0x10000 to 0x2000000. Then we walk the memory // in the large memory area (0x42000000 - 0x80000000), as this is where gcheap allocates memory from. size_t AVMPI_getPrivateResidentPageCount() { void *addr = (void*)(0x00010000); void *endAddr = (void*)(0x02000000); size_t bytes=0; MEMORY_BASIC_INFORMATION mib; while(true) { size_t ret = VirtualQuery(addr, &mib, sizeof(MEMORY_BASIC_INFORMATION)); if(ret == 0) break; if((mib.State & MEM_COMMIT)) if ((DWORD)mib.BaseAddress + mib.RegionSize > (DWORD)endAddr) bytes += (DWORD)endAddr - (DWORD)mib.BaseAddress; else bytes += mib.RegionSize; addr = (void*) ((intptr_t)mib.BaseAddress + mib.RegionSize); if (addr>=endAddr) break; } MMgc::GCHeap* heap = MMgc::GCHeap::GetGCHeap(); // We need to also walk the shared memory regions to make sure we // count the blocks we've allocated there MMgc::GCHeap::Region* curRegion = heap->lastRegion; if (curRegion) addr = curRegion->baseAddr; else addr = NULL; while (curRegion!=NULL) { addr = curRegion->baseAddr; if (addr < (void*)0x42000000) { // Not in the shared regions curRegion = curRegion->prev; continue; } while(true) { size_t ret = VirtualQuery(addr, &mib, sizeof(MEMORY_BASIC_INFORMATION)); if(ret == 0) break; if((mib.State & MEM_COMMIT)) // && (mib.Type & MEM_PRIVATE)) { if ((DWORD)mib.BaseAddress + mib.RegionSize > (DWORD)curRegion->reserveTop) bytes += (DWORD)curRegion->reserveTop - (DWORD)mib.BaseAddress; else bytes += mib.RegionSize; } addr = (void*) ((intptr_t)mib.BaseAddress + mib.RegionSize); if (addr>=curRegion->reserveTop) break; } curRegion = curRegion->prev; } return bytes / VMPI_getVMPageSize(); }
/*********************************************************************** * VxDCall_VMM */ static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context ) { switch ( LOWORD(service) ) { case 0x0011: /* RegOpenKey */ { HKEY hkey = (HKEY) stack32_pop( context ); LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context ); LPHKEY retkey = (LPHKEY)stack32_pop( context ); return RegOpenKeyA( hkey, lpszSubKey, retkey ); } case 0x0012: /* RegCreateKey */ { HKEY hkey = (HKEY) stack32_pop( context ); LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context ); LPHKEY retkey = (LPHKEY)stack32_pop( context ); return RegCreateKeyA( hkey, lpszSubKey, retkey ); } case 0x0013: /* RegCloseKey */ { HKEY hkey = (HKEY)stack32_pop( context ); return RegCloseKey( hkey ); } case 0x0014: /* RegDeleteKey */ { HKEY hkey = (HKEY) stack32_pop( context ); LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context ); return RegDeleteKeyA( hkey, lpszSubKey ); } case 0x0015: /* RegSetValue */ { HKEY hkey = (HKEY) stack32_pop( context ); LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context ); DWORD dwType = (DWORD) stack32_pop( context ); LPCSTR lpszData = (LPCSTR)stack32_pop( context ); DWORD cbData = (DWORD) stack32_pop( context ); return RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData ); } case 0x0016: /* RegDeleteValue */ { HKEY hkey = (HKEY) stack32_pop( context ); LPSTR lpszValue = (LPSTR)stack32_pop( context ); return RegDeleteValueA( hkey, lpszValue ); } case 0x0017: /* RegQueryValue */ { HKEY hkey = (HKEY) stack32_pop( context ); LPSTR lpszSubKey = (LPSTR) stack32_pop( context ); LPSTR lpszData = (LPSTR) stack32_pop( context ); LPDWORD lpcbData = (LPDWORD)stack32_pop( context ); return RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData ); } case 0x0018: /* RegEnumKey */ { HKEY hkey = (HKEY) stack32_pop( context ); DWORD iSubkey = (DWORD)stack32_pop( context ); LPSTR lpszName = (LPSTR)stack32_pop( context ); DWORD lpcchName = (DWORD)stack32_pop( context ); return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName ); } case 0x0019: /* RegEnumValue */ { HKEY hkey = (HKEY) stack32_pop( context ); DWORD iValue = (DWORD) stack32_pop( context ); LPSTR lpszValue = (LPSTR) stack32_pop( context ); LPDWORD lpcchValue = (LPDWORD)stack32_pop( context ); LPDWORD lpReserved = (LPDWORD)stack32_pop( context ); LPDWORD lpdwType = (LPDWORD)stack32_pop( context ); LPBYTE lpbData = (LPBYTE) stack32_pop( context ); LPDWORD lpcbData = (LPDWORD)stack32_pop( context ); return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpReserved, lpdwType, lpbData, lpcbData ); } case 0x001A: /* RegQueryValueEx */ { HKEY hkey = (HKEY) stack32_pop( context ); LPSTR lpszValue = (LPSTR) stack32_pop( context ); LPDWORD lpReserved = (LPDWORD)stack32_pop( context ); LPDWORD lpdwType = (LPDWORD)stack32_pop( context ); LPBYTE lpbData = (LPBYTE) stack32_pop( context ); LPDWORD lpcbData = (LPDWORD)stack32_pop( context ); return RegQueryValueExA( hkey, lpszValue, lpReserved, lpdwType, lpbData, lpcbData ); } case 0x001B: /* RegSetValueEx */ { HKEY hkey = (HKEY) stack32_pop( context ); LPSTR lpszValue = (LPSTR) stack32_pop( context ); DWORD dwReserved = (DWORD) stack32_pop( context ); DWORD dwType = (DWORD) stack32_pop( context ); LPBYTE lpbData = (LPBYTE)stack32_pop( context ); DWORD cbData = (DWORD) stack32_pop( context ); return RegSetValueExA( hkey, lpszValue, dwReserved, dwType, lpbData, cbData ); } case 0x001C: /* RegFlushKey */ { HKEY hkey = (HKEY)stack32_pop( context ); return RtlNtStatusToDosError (NtFlushKey (hkey)); } case 0x001D: /* RegQueryInfoKey */ { /* NOTE: This VxDCall takes only a subset of the parameters that the corresponding Win32 API call does. The implementation in Win95 ADVAPI32 sets all output parameters not mentioned here to zero. */ HKEY hkey = (HKEY) stack32_pop( context ); LPDWORD lpcSubKeys = (LPDWORD)stack32_pop( context ); LPDWORD lpcchMaxSubKey = (LPDWORD)stack32_pop( context ); LPDWORD lpcValues = (LPDWORD)stack32_pop( context ); LPDWORD lpcchMaxValueName = (LPDWORD)stack32_pop( context ); LPDWORD lpcchMaxValueData = (LPDWORD)stack32_pop( context ); return RegQueryInfoKeyA( hkey, NULL, NULL, NULL, lpcSubKeys, lpcchMaxSubKey, NULL, lpcValues, lpcchMaxValueName, lpcchMaxValueData, NULL, NULL ); } case 0x0021: /* RegLoadKey */ { HKEY hkey = (HKEY) stack32_pop( context ); LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context ); LPCSTR lpszFile = (LPCSTR)stack32_pop( context ); return RegLoadKeyA( hkey, lpszSubKey, lpszFile ); } case 0x0022: /* RegUnLoadKey */ { HKEY hkey = (HKEY) stack32_pop( context ); LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context ); FIXME ("(%p, %s): stub (should call NtUnloadKey)\n", (void *)hkey, lpszSubKey); return ERROR_SUCCESS; } case 0x0023: /* RegSaveKey */ { HKEY hkey = (HKEY) stack32_pop( context ); LPCSTR lpszFile = (LPCSTR)stack32_pop( context ); LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context ); return RegSaveKeyA( hkey, lpszFile, sa ); } #if 0 /* Functions are not yet implemented in misc/registry.c */ case 0x0024: /* RegRemapPreDefKey */ case 0x0026: /* RegQueryMultipleValues */ #endif case 0x0027: /* RegReplaceKey */ { HKEY hkey = (HKEY) stack32_pop( context ); LPCSTR lpszSubKey = (LPCSTR)stack32_pop( context ); LPCSTR lpszNewFile= (LPCSTR)stack32_pop( context ); LPCSTR lpszOldFile= (LPCSTR)stack32_pop( context ); FIXME ("(%p, %s, %s, %s): stub (should call NtReplaceKey)\n", (void *)hkey, lpszSubKey, lpszNewFile, lpszOldFile); return ERROR_SUCCESS; } case 0x0000: /* PageReserve */ { LPVOID address; LPVOID ret; DWORD psize = getpagesize(); ULONG page = (ULONG) stack32_pop( context ); ULONG npages = (ULONG) stack32_pop( context ); ULONG flags = (ULONG) stack32_pop( context ); TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n", page, npages, flags ); if ( page == PR_SYSTEM ) { ERR("Can't reserve ring 1 memory\n"); return -1; } /* FIXME: This has to be handled separately for the separate address-spaces we now have */ if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0; /* FIXME: Handle flags in some way */ address = (LPVOID )(page * psize); ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 ); TRACE("PageReserve: returning: %08lx\n", (DWORD )ret ); if ( ret == NULL ) return -1; else return (DWORD )ret; } case 0x0001: /* PageCommit */ { LPVOID address; LPVOID ret; DWORD virt_perm; DWORD psize = getpagesize(); ULONG page = (ULONG) stack32_pop( context ); ULONG npages = (ULONG) stack32_pop( context ); ULONG hpd = (ULONG) stack32_pop( context ); ULONG pagerdata = (ULONG) stack32_pop( context ); ULONG flags = (ULONG) stack32_pop( context ); TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: " "%08lx, flags: %08lx partial stub\n", page, npages, hpd, pagerdata, flags ); if ( flags & PC_USER ) if ( flags & PC_WRITEABLE ) virt_perm = PAGE_EXECUTE_READWRITE; else virt_perm = PAGE_EXECUTE_READ; else virt_perm = PAGE_NOACCESS; address = (LPVOID )(page * psize); ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm ); TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret ); return (DWORD )ret; } case 0x0002: /* PageDecommit */ { LPVOID address; BOOL ret; DWORD psize = getpagesize(); ULONG page = (ULONG) stack32_pop( context ); ULONG npages = (ULONG) stack32_pop( context ); ULONG flags = (ULONG) stack32_pop( context ); TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n", page, npages, flags ); address = (LPVOID )( page * psize ); ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT ); TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" ); return ret; } case 0x000d: /* PageModifyPermissions */ { DWORD pg_old_perm; DWORD pg_new_perm; DWORD virt_old_perm; DWORD virt_new_perm; MEMORY_BASIC_INFORMATION mbi; LPVOID address; DWORD psize = getpagesize(); ULONG page = stack32_pop ( context ); ULONG npages = stack32_pop ( context ); ULONG permand = stack32_pop ( context ); ULONG permor = stack32_pop ( context ); TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n", page, npages, permand, permor ); address = (LPVOID )( page * psize ); VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION )); virt_old_perm = mbi.Protect; switch ( virt_old_perm & mbi.Protect ) { case PAGE_READONLY: case PAGE_EXECUTE: case PAGE_EXECUTE_READ: pg_old_perm = PC_USER; break; case PAGE_READWRITE: case PAGE_WRITECOPY: case PAGE_EXECUTE_READWRITE: case PAGE_EXECUTE_WRITECOPY: pg_old_perm = PC_USER | PC_WRITEABLE; break; case PAGE_NOACCESS: default: pg_old_perm = 0; break; } pg_new_perm = pg_old_perm; pg_new_perm &= permand & ~PC_STATIC; pg_new_perm |= permor & ~PC_STATIC; virt_new_perm = ( virt_old_perm ) & ~0xff; if ( pg_new_perm & PC_USER ) { if ( pg_new_perm & PC_WRITEABLE ) virt_new_perm |= PAGE_EXECUTE_READWRITE; else virt_new_perm |= PAGE_EXECUTE_READ; } if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) { ERR("Can't change page permissions for %08lx\n", (DWORD )address ); return 0xffffffff; } TRACE("Returning: %08lx\n", pg_old_perm ); return pg_old_perm; } case 0x000a: /* PageFree */ { BOOL ret; LPVOID hmem = (LPVOID) stack32_pop( context ); DWORD flags = (DWORD ) stack32_pop( context ); TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n", (DWORD )hmem, flags ); ret = VirtualFree ( hmem, 0, MEM_RELEASE ); context->Eax = ret; TRACE("Returning: %d\n", ret ); return 0; } case 0x001e: /* GetDemandPageInfo */ { DWORD dinfo = (DWORD)stack32_pop( context ); DWORD flags = (DWORD)stack32_pop( context ); /* GetDemandPageInfo is supposed to fill out the struct at * "dinfo" with various low-level memory management information. * Apps are certainly not supposed to call this, although it's * demoed and documented by Pietrek on pages 441-443 of "Windows * 95 System Programming Secrets" if any program needs a real * implementation of this. */ FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags); return 0; } default: if (LOWORD(service) < N_VMM_SERVICE) FIXME( "Unimplemented service %s (%08lx)\n", VMM_Service_Name[LOWORD(service)], service); else FIXME( "Unknown service %08lx\n", service); break; } return 0xffffffff; /* FIXME */ }
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, PTSTR, int) { TCHAR szAppName[] = TEXT("MEM_RESET tester"); TCHAR szTestData[] = TEXT("Some text data"); // Commit a page of storage and modify its contents. PTSTR pszData = (PTSTR) VirtualAlloc(NULL, 1024, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); _tcscpy_s(pszData, 1024, szTestData); if (MessageBox(NULL, TEXT("Do you want to access this data later?"), szAppName, MB_YESNO) == IDNO) { // We want this page of storage to remain in our process but the // contents aren't important to us anymore. // Tell the system that the data is not modified. // Note: Because MEM_RESET destroys data, VirtualAlloc rounds // the base address and size parameters to their safest range. // Here is an example: // VirtualAlloc(pvData, 5000, MEM_RESET, PAGE_READWRITE) // resets 0 pages on CPUs where the page size is greater than 4 KB // and resets 1 page on CPUs with a 4 KB page. So that our call to // VirtualAlloc to reset memory below always succeeds, VirtualQuery // is called first to get the exact region size. MEMORY_BASIC_INFORMATION mbi; VirtualQuery(pszData, &mbi, sizeof(mbi)); VirtualAlloc(pszData, mbi.RegionSize, MEM_RESET, PAGE_READWRITE); } // Commit as much storage as there is physical RAM. MEMORYSTATUS mst; GlobalMemoryStatus(&mst); PVOID pvDummy = VirtualAlloc(NULL, mst.dwTotalPhys, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); // Touch all the pages in the dummy region so that any // modified pages in RAM are written to the paging file. if (pvDummy != NULL) ZeroMemory(pvDummy, mst.dwTotalPhys); // Compare our data page with what we originally wrote there. if (_tcscmp(pszData, szTestData) == 0) { // The data in the page matches what we originally put there. // ZeroMemory forced our page to be written to the paging file. MessageBox(NULL, TEXT("Modified data page was saved."), szAppName, MB_OK); } else { // The data in the page does NOT match what we originally put there // ZeroMemory didn't cause our page to be written to the paging file MessageBox(NULL, TEXT("Modified data page was NOT saved."), szAppName, MB_OK); } // Don't forget to release part of the address space. // Note that it is not mandatory here since the application is exiting. if (pvDummy != NULL) VirtualFree(pvDummy, 0, MEM_RELEASE); VirtualFree(pszData, 0, MEM_RELEASE); return(0); }
bool RedirectIAT( SDLLHook* DLLHook, PIMAGE_IMPORT_DESCRIPTOR pImportDesc, PVOID pBaseLoadAddr ) { PIMAGE_THUNK_DATA pIAT; // Ptr to import address table PIMAGE_THUNK_DATA pINT; // Ptr to import names table PIMAGE_THUNK_DATA pIteratingIAT; // Figure out which OS platform we're on OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx( &osvi ); // If no import names table, we can't redirect this, so bail if ( pImportDesc->OriginalFirstThunk == 0 ) return false; pIAT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->FirstThunk ); pINT = MakePtr( PIMAGE_THUNK_DATA, pBaseLoadAddr, pImportDesc->OriginalFirstThunk ); // Count how many entries there are in this IAT. Array is 0 terminated pIteratingIAT = pIAT; unsigned cFuncs = 0; while ( pIteratingIAT->u1.Function ) { cFuncs++; pIteratingIAT++; } if ( cFuncs == 0 ) // If no imported functions, we're done! return false; // These next few lines ensure that we'll be able to modify the IAT, // which is often in a read-only section in the EXE. DWORD flOldProtect, flNewProtect, flDontCare; MEMORY_BASIC_INFORMATION mbi; // Get the current protection attributes VirtualQuery( pIAT, &mbi, sizeof(mbi) ); // remove ReadOnly and ExecuteRead attributes, add on ReadWrite flag flNewProtect = mbi.Protect; flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ); flNewProtect |= (PAGE_READWRITE); if ( !VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flNewProtect, &flOldProtect) ) { return false; } // If the Default hook is enabled, build an array of redirection stubs in the processes memory. DLPD_IAT_STUB * pStubs = 0; if ( DLLHook->UseDefault ) { // Allocate memory for the redirection stubs. Make one extra stub at the // end to be a sentinel pStubs = new DLPD_IAT_STUB[ cFuncs + 1]; if ( !pStubs ) return false; } // Scan through the IAT, completing the stubs and redirecting the IAT // entries to point to the stubs pIteratingIAT = pIAT; while ( pIteratingIAT->u1.Function ) { void* HookFn = 0; // Set to either the SFunctionHook or pStubs. if ( !IMAGE_SNAP_BY_ORDINAL( pINT->u1.Ordinal ) ) // import by name { PIMAGE_IMPORT_BY_NAME pImportName = MakePtr( PIMAGE_IMPORT_BY_NAME, pBaseLoadAddr, pINT->u1.AddressOfData ); // Iterate through the hook functions, searching for this import. SFunctionHook* FHook = DLLHook->Functions; while ( FHook->Name ) { if ( lstrcmpi( FHook->Name, (char*)pImportName->Name ) == 0 ) { OutputDebugString( "Hooked function: " ); OutputDebugString( (char*)pImportName->Name ); OutputDebugString( "\n" ); // Save the old function in the SFunctionHook structure and get the new one. FHook->OrigFn = (void*)pIteratingIAT->u1.Function; HookFn = (PIMAGE_IMPORT_BY_NAME)FHook->HookFn; break; } FHook++; } // If the default function is enabled, store the name for the user. if ( DLLHook->UseDefault ) pStubs->pszNameOrOrdinal = (DWORD)&pImportName->Name; } else { // If the default function is enabled, store the ordinal for the user. if ( DLLHook->UseDefault ) pStubs->pszNameOrOrdinal = pINT->u1.Ordinal; } // If the default function is enabled, fill in the fields to the stub code. if ( DLLHook->UseDefault ) { pStubs->data_call = (DWORD)(PDWORD)DLLHook->DefaultFn - (DWORD)(PDWORD)&pStubs->instr_JMP; pStubs->data_JMP = *(PDWORD)pIteratingIAT - (DWORD)(PDWORD)&pStubs->count; // If it wasn't manually hooked, use the Stub function. if ( !HookFn ) HookFn = (void*)pStubs; } // Replace the IAT function pointer if we have a hook. if ( HookFn ) { // Cheez-o hack to see if what we're importing is code or data. // If it's code, we shouldn't be able to write to it if ( IsBadWritePtr( (PVOID)pIteratingIAT->u1.Function, 1 ) ) { pIteratingIAT->u1.Function = (DWORD)HookFn; } else if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) { // Special hack for Win9X, which builds stubs for imported // functions in system DLLs (Loaded above 2GB). These stubs are // writeable, so we have to explicitly check for this case if ( pIteratingIAT->u1.Function > (DWORD)0x80000000 ) pIteratingIAT->u1.Function = (DWORD)HookFn; } } if ( DLLHook->UseDefault ) pStubs++; // Advance to next stub pIteratingIAT++; // Advance to next IAT entry pINT++; // Advance to next INT entry } if ( DLLHook->UseDefault ) pStubs->pszNameOrOrdinal = 0; // Final stub is a sentinel // Put the page attributes back the way they were. VirtualProtect( pIAT, sizeof(PVOID) * cFuncs, flOldProtect, &flDontCare); return true; }
SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states) { if (m_IgnoreLevel) { m_IgnoreLevel--; return SMCResult_Continue; } if (m_CustomLevel) { m_CustomLevel--; m_CustomHandler->ReadSMC_LeavingSection(states); return SMCResult_Continue; } switch (m_ParseState) { case PSTATE_GAMES: { m_ParseState = PSTATE_NONE; break; } case PSTATE_GAMEDEFS: { m_ParseState = PSTATE_GAMES; break; } case PSTATE_GAMEDEFS_CLASSES: { m_MatchedClasses = false; m_ParseState = PSTATE_GAMEDEFS; break; } case PSTATE_GAMEDEFS_CLASSES_CLASS: { m_ParseState = PSTATE_GAMEDEFS_CLASSES; m_Class[0] = '\0'; break; } case PSTATE_GAMEDEFS_CUSTOM: { m_ParseState = PSTATE_GAMEDEFS; m_CustomHandler->ReadSMC_ParseEnd(false, false); break; } case PSTATE_GAMEDEFS_KEYS: { m_ParseState = m_MatchedClasses ? PSTATE_GAMEDEFS_CLASSES_CLASS : PSTATE_GAMEDEFS; break; } case PSTATE_GAMEDEFS_OFFSETS: { m_ParseState = m_MatchedClasses ? PSTATE_GAMEDEFS_CLASSES_CLASS : PSTATE_GAMEDEFS; break; } case PSTATE_GAMEDEFS_OFFSETS_OFFSET: { if (m_FoundOffset) { if (m_Class[0]) { auto ic = m_OffsetsByClass.findForAdd(m_Class); if (ic.found()) { ic->value->list.replace(m_Offset, TempType); } else if (m_OffsetsByClass.add(ic, m_Class)) { ic->value = new OffsetClass; ic->value->list.insert(m_Offset, TempType); } } else { m_Offsets.replace(m_Offset, TempType); } } m_ParseState = PSTATE_GAMEDEFS_OFFSETS; break; } case PSTATE_GAMEDEFS_SUPPORTED: { if (!m_ShouldBeReadingDefault) { m_IgnoreLevel = 1; m_ParseState = PSTATE_GAMES; } else { m_ParseState = PSTATE_GAMEDEFS; } break; } case PSTATE_GAMEDEFS_SIGNATURES: { m_ParseState = m_MatchedClasses ? PSTATE_GAMEDEFS_CLASSES_CLASS : PSTATE_GAMEDEFS; break; } case PSTATE_GAMEDEFS_SIGNATURES_SIG: { if (TempSig.library[0] == '\0') { strncopy(TempSig.library, "server", sizeof(TempSig.library)); } void *addressInBase = nullptr; if (strcmp(TempSig.library, "server") == 0) { addressInBase = reinterpret_cast<void*>(MDLL_Spawn); } else if (strcmp(TempSig.library, "engine") == 0) { addressInBase = reinterpret_cast<void*>(gpGlobals); } void *finalAddress = nullptr; if (!addressInBase) { AMXXLOG_Error("Unrecognized library \"%s\" (gameconf \"%s\")", TempSig.library, m_CurrentPath); } else if (TempSig.signature[0]) { if (TempSig.signature[0] == '@') { #if defined PLATFORM_WINDOWS MEMORY_BASIC_INFORMATION mem; if (VirtualQuery(addressInBase, &mem, sizeof(mem))) { finalAddress = g_MemUtils.ResolveSymbol(mem.AllocationBase, &TempSig.signature[1]); } else { AMXXLOG_Error("Unable to find library \"%s\" in memory (gameconf \"%s\")", TempSig.library, m_File); } #elif defined PLATFORM_POSIX Dl_info info; if (dladdr(addressInBase, &info) != 0) { void *handle = dlopen(info.dli_fname, RTLD_NOW); if (handle) { finalAddress = g_MemUtils.ResolveSymbol(handle, &TempSig.signature[1]); dlclose(handle); } else { AMXXLOG_Error("Unable to load library \"%s\" (gameconf \"%s\")", TempSig.library, m_File); } } else { AMXXLOG_Error("Unable to find library \"%s\" in memory (gameconf \"%s\")", TempSig.library, m_File); } #endif } if (!finalAddress) { finalAddress = g_MemUtils.DecodeAndFindPattern(addressInBase, TempSig.signature); } m_Sigs.replace(m_Offset, finalAddress); } m_ParseState = PSTATE_GAMEDEFS_SIGNATURES; break; } case PSTATE_GAMEDEFS_ADDRESSES: { m_ParseState = m_MatchedClasses ? PSTATE_GAMEDEFS_CLASSES_CLASS : PSTATE_GAMEDEFS; break; } case PSTATE_GAMEDEFS_ADDRESSES_ADDRESS: { m_ParseState = PSTATE_GAMEDEFS_ADDRESSES; if (m_Address[0] != '\0' && m_AddressSignature[0] != '\0') { AddressConf addrConf(m_AddressSignature, sizeof(m_AddressSignature), m_AddressReadCount, m_AddressRead); m_Addresses.replace(m_Address, addrConf); } break; } case PSTATE_GAMEDEFS_ADDRESSES_ADDRESS_READ: { m_ParseState = PSTATE_GAMEDEFS_ADDRESSES_ADDRESS; break; } } return SMCResult_Continue; }
SAMPGDK_EXPORT void *SAMPGDK_CALL sampgdk_get_plugin_handle(void *symbol) { MEMORY_BASIC_INFORMATION mbi; VirtualQuery(symbol, &mbi, sizeof(mbi)); return (void*)mbi.AllocationBase; }
// Entry point into the main exception handling routine. This routine is put into an except() // statment at the beginning of a thread and is called anytime that there is a program exception // The data is stored in a file called ErrorLog.txt in the data directory. // // data: pointer to the exception data // Message: Any message that should be printed out in the error log file // // returns: // int __cdecl RecordExceptionInfo(PEXCEPTION_POINTERS data, const char *Message) { static bool BeenHere = false; // Going recursive! That must mean this routine crashed! if (BeenHere) { return EXCEPTION_CONTINUE_SEARCH; } BeenHere = true; char ModuleName[MAX_PATH]; char FileName[MAX_PATH] = "Unknown"; // Create a filename to record the error information to. // Storing it in the executable directory works well. if (GetModuleFileName(0, ModuleName, sizeof(ModuleName)) <= 0) { ModuleName[0] = 0; } char *FilePart = GetFilePart(ModuleName); // Extract the file name portion and remove it's file extension. We'll // use that name shortly. lstrcpy(FileName, FilePart); char *lastperiod = strrchr(FileName, '.'); if (lastperiod) { lastperiod[0] = 0; } // Replace the executable filename with our error log file name. lstrcpy(FilePart, "errorlog.txt"); HANDLE LogFile = CreateFile(ModuleName, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0); if (LogFile == INVALID_HANDLE_VALUE) { OutputDebugString("Error creating exception report"); return EXCEPTION_CONTINUE_SEARCH; } // Append to the error log. SetFilePointer(LogFile, 0, 0, FILE_END); // Print out some blank lines to separate this error log from any previous ones. hprintf(LogFile, "\r\n\r\n\r\n\r\n"); PEXCEPTION_RECORD Exception = data->ExceptionRecord; PCONTEXT Context = data->ContextRecord; char CrashModulePathName[MAX_PATH]; char *CrashModuleFileName = "Unknown"; MEMORY_BASIC_INFORMATION MemInfo; // VirtualQuery can be used to get the allocation base associated with a // code address, which is the same as the ModuleHandle. This can be used // to get the filename of the module that the crash happened in. if (VirtualQuery((void*)Context->Eip, &MemInfo, sizeof(MemInfo)) && GetModuleFileName((HINSTANCE)MemInfo.AllocationBase, CrashModulePathName, sizeof(CrashModulePathName)) > 0) { CrashModuleFileName = GetFilePart(CrashModulePathName); } // Print out the beginning of the error log in a Win95 error window // compatible format. hprintf(LogFile, "%s caused %s in module %s at %04x:%08x.\r\n", FileName, GetExceptionDescription(Exception->ExceptionCode), CrashModuleFileName, Context->SegCs, Context->Eip); hprintf(LogFile, "Exception handler called in %s.\r\n", Message); RecordSystemInformation(LogFile); // If the exception was an access violation, print out some additional // information, to the error log and the debugger. if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION && Exception->NumberParameters >= 2) { char DebugMessage[1000]; const char* readwrite = "Read from"; if (Exception->ExceptionInformation[0]) { readwrite = "Write to"; } wsprintf(DebugMessage, "%s location %08x caused an access violation.\r\n", readwrite, Exception->ExceptionInformation[1]); #ifdef _DEBUG // The VisualC++ debugger doesn't actually tell you whether a read // or a write caused the access violation, nor does it tell what // address was being read or written. So I fixed that. OutputDebugString("Exception handler: "); OutputDebugString(DebugMessage); #endif hprintf(LogFile, "%s", DebugMessage); } // Print out the register values in a Win95 error window compatible format. hprintf(LogFile, "\r\n"); hprintf(LogFile, "Registers:\r\n"); hprintf(LogFile, "EAX=%08x CS=%04x EIP=%08x EFLGS=%08x\r\n", Context->Eax, Context->SegCs, Context->Eip, Context->EFlags); hprintf(LogFile, "EBX=%08x SS=%04x ESP=%08x EBP=%08x\r\n", Context->Ebx, Context->SegSs, Context->Esp, Context->Ebp); hprintf(LogFile, "ECX=%08x DS=%04x ESI=%08x FS=%04x\r\n", Context->Ecx, Context->SegDs, Context->Esi, Context->SegFs); hprintf(LogFile, "EDX=%08x ES=%04x EDI=%08x GS=%04x\r\n", Context->Edx, Context->SegEs, Context->Edi, Context->SegGs); hprintf(LogFile, "Bytes at CS:EIP:\r\n"); // Print out the bytes of code at the instruction pointer. Since the // crash may have been caused by an instruction pointer that was bad, // this code needs to be wrapped in an exception handler, in case there // is no memory to read. If the dereferencing of code[] fails, the // exception handler will print '??'. unsigned char *code = (unsigned char*)Context->Eip; for (int codebyte = 0; codebyte < NumCodeBytes; codebyte++) { #ifdef _MSC_VER __try { #endif hprintf(LogFile, "%02x ", code[codebyte]); #ifdef _MSC_VER } __except(EXCEPTION_EXECUTE_HANDLER) { hprintf(LogFile, "?? "); } #endif } #ifdef _MSC_VER // Time to print part or all of the stack to the error log. This allows // us to figure out the call stack, parameters, local variables, etc. hprintf(LogFile, "\r\n" "Stack dump:\r\n"); __try { // Esp contains the bottom of the stack, or at least the bottom of // the currently used area. DWORD* pStack = (DWORD *)Context->Esp; DWORD* pStackTop; __asm { // Load the top (highest address) of the stack from the // thread information block. It will be found there in // Win9x and Windows NT. mov eax, fs:[4] mov pStackTop, eax } if (pStackTop > pStack + MaxStackDump) { pStackTop = pStack + MaxStackDump; } int Count = 0; // Too many calls to WriteFile can take a long time, causing // confusing delays when programs crash. Therefore I implemented // simple buffering for the stack dumping code instead of calling // hprintf directly. char buffer[1000] = ""; const int safetyzone = 50; char* nearend = buffer + sizeof(buffer) - safetyzone; char* output = buffer; while (pStack + 1 <= pStackTop) { if ((Count % StackColumns) == 0) { output += wsprintf(output, "%08x: ", pStack); } char *Suffix = " "; if ((++Count % StackColumns) == 0 || pStack + 2 > pStackTop) { Suffix = "\r\n"; } output += wsprintf(output, "%08x%s", *pStack, Suffix); pStack++; // Check for when the buffer is almost full, and flush it to disk. if (output > nearend) { hprintf(LogFile, "%s", buffer); buffer[0] = 0; output = buffer; } } // Print out any final characters from the cache. hprintf(LogFile, "%s", buffer); } __except(EXCEPTION_EXECUTE_HANDLER) { hprintf(LogFile, "Exception encountered during stack dump.\r\n"); } #endif #ifndef NDEBUG if (safe_string[0]) hprintf(LogFile, "Last safe point: %s\r\n", safe_string); #endif RecordModuleList(LogFile); CloseHandle(LogFile); // Return the magic value which tells Win32 that this handler didn't // actually handle the exception - so that things will proceed as per // normal. return EXCEPTION_CONTINUE_SEARCH; }
bool CDetour::Detour(BYTE *&jmp, BYTE *&orig, const BYTE *&det, int iPatchType, int len) { DWORD dwBack = 0; int i = 0; BYTE *pPatchBuf = NULL; // Allocate space for the jump jmp = (BYTE*)malloc(len+5); // Force page protection flags to read|write MEMORY_BASIC_INFORMATION mbi; VirtualQuery( ( void* )orig, &mbi, sizeof( mbi ) ); VirtualProtect( mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect ); // Copy the overwritten opcodes at the original to the malloced space memcpy(jmp, orig, len); // Increment to the end of the opcodes at the malloced space jmp += len; // Place a jump back to the original at this point jmp[0] = 0xE9; *(DWORD*)(jmp+1) = (DWORD)(orig+len - jmp) - 5; // Generate a random opcode int iTmpRnd = (rand() * 0xFF) + rand(); BYTE bTmpRnd = (BYTE)iTmpRnd; // Place a jump at the original to the detour function pPatchBuf = new BYTE[len]; // Pad out the bytes with NOPs so we don't have ends of intructions memset(pPatchBuf, 0x90, len); // Write the opcodes to the buffer according to patch type switch(iPatchType) { case DETOUR_TYPE_JMP: pPatchBuf[0] = '\xE9'; *(DWORD*)&pPatchBuf[1] = (DWORD)(det - orig) - 5; break; case DETOUR_TYPE_PUSH_RET: pPatchBuf[0] = '\x68'; *(DWORD*)&pPatchBuf[1] = (DWORD)det; pPatchBuf[5] = '\xC3'; break; case DETOUR_TYPE_NOP_JMP: pPatchBuf[0] = '\x90'; pPatchBuf[1] = '\xE9'; *(DWORD*)&pPatchBuf[2] = (DWORD)(det - orig) - 6; break; case DETOUR_TYPE_NOP_NOP_JMP: pPatchBuf[0] = '\x90'; pPatchBuf[1] = '\x90'; pPatchBuf[2] = '\xE9'; *(DWORD*)&pPatchBuf[3] = (DWORD)(det - orig) - 7; break; case DETOUR_TYPE_STC_JC: pPatchBuf[0] = '\xF9'; pPatchBuf[1] = '\x0F'; pPatchBuf[2] = '\x82'; *(DWORD*)&pPatchBuf[3] = (DWORD)(det - orig) - 7; break; case DETOUR_TYPE_CLC_JNC: pPatchBuf[0] = '\xF8'; pPatchBuf[1] = '\x0F'; pPatchBuf[2] = '\x83'; *(DWORD*)&pPatchBuf[3] = (DWORD)(det - orig) - 7; break; case DETOUR_TYPE_OBS_ADD: pPatchBuf[0] = '\xB8'; //mov eax *(DWORD*)&pPatchBuf[1] = iTmpRnd; pPatchBuf[5] = '\x05'; //add eax *(int*)&pPatchBuf[6] = (DWORD)det - iTmpRnd; pPatchBuf[10] = '\xFF'; //jmp eax pPatchBuf[11] = '\xE0'; break; case DETOUR_TYPE_OBS_XOR: pPatchBuf[0] = '\x33'; //xor eax, eax pPatchBuf[1] = '\xC0'; pPatchBuf[2] = '\x2D'; //sub eax *(int*)&pPatchBuf[3] = (int)iTmpRnd; pPatchBuf[7] = '\x35'; //xor eax *(DWORD*)&pPatchBuf[8] = (DWORD)det ^ (-iTmpRnd); pPatchBuf[12] = '\xFF'; //jmp eax pPatchBuf[13] = '\xE0'; break; case DETOUR_TYPE_OBS_STACKADD: pPatchBuf[0] = '\x68'; //push *(DWORD*)&pPatchBuf[1] = (DWORD)iTmpRnd; pPatchBuf[5] = '\x81'; //xor dword ptr [esp] pPatchBuf[6] = '\x34'; pPatchBuf[7] = '\x24'; *(DWORD*)&pPatchBuf[8] = (DWORD)det ^ iTmpRnd; pPatchBuf[12] = '\xC3'; //ret break; case DETOUR_TYPE_OBS_ROR: while(!(bTmpRnd % 32)) bTmpRnd = (BYTE)rand(); __asm{ pushad mov cl, bTmpRnd mov eax, det rol eax, cl mov dword ptr det, eax popad } pPatchBuf[0] = '\x51'; //push ecx pPatchBuf[1] = '\xB1'; //mov cl, pPatchBuf[2] = bTmpRnd; pPatchBuf[3] = '\xB8'; //mov eax *(DWORD*)&pPatchBuf[4] = (DWORD)det; pPatchBuf[8] = '\xD3'; //ror eax, cl pPatchBuf[9] = '\xC8'; pPatchBuf[10] = '\x59'; //pop ecx pPatchBuf[11] = '\xFF'; //jmp eax pPatchBuf[12] = '\xE0'; break; case DETOUR_TYPE_OBS_ADDNOT: pPatchBuf[0] = '\xB8'; //mov eax *(DWORD*)&pPatchBuf[1] = iTmpRnd; pPatchBuf[5] = '\x05'; //add eax *(int*)&pPatchBuf[6] = (~(DWORD)det) - iTmpRnd; pPatchBuf[10] = '\xF7'; //not eax pPatchBuf[11] = '\xD0'; pPatchBuf[12] = '\xFF'; //jmp eax pPatchBuf[13] = '\xE0'; break; default: return false; } // Write the detour for(i=0; i<len; i++) orig[i] = pPatchBuf[i]; // Put the old page protection flags back VirtualProtect( mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &mbi.Protect ); FlushInstructionCache( GetCurrentProcess( ), orig, len ); return true; }
uintptr_t AVMPI_getThreadStackBase() { MEMORY_BASIC_INFORMATION __mib; VirtualQuery(&__mib, &__mib, sizeof(MEMORY_BASIC_INFORMATION)); return (uintptr_t)__mib.BaseAddress + __mib.RegionSize; }
void * mmap_realloc (void **var, size_t nbytes) { MEMORY_BASIC_INFORMATION memInfo, m2; void *old_ptr; if (*var == NULL) return mmap_alloc (var, nbytes); /* This case happens in init_buffer(). */ if (nbytes == 0) { mmap_free (var); return mmap_alloc (var, nbytes); } memset (&memInfo, 0, sizeof (memInfo)); if (VirtualQuery (*var, &memInfo, sizeof (memInfo)) == 0) DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError ())); /* We need to enlarge the block. */ if (memInfo.RegionSize < nbytes) { memset (&m2, 0, sizeof (m2)); if (VirtualQuery ((char *)*var + memInfo.RegionSize, &m2, sizeof(m2)) == 0) DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError ())); /* If there is enough room in the current reserved area, then commit more pages as needed. */ if (m2.State == MEM_RESERVE && m2.AllocationBase == memInfo.AllocationBase && nbytes <= memInfo.RegionSize + m2.RegionSize) { void *p; p = VirtualAlloc (*var, nbytes, MEM_COMMIT, PAGE_READWRITE); if (!p /* && GetLastError() != ERROR_NOT_ENOUGH_MEMORY */) { DebPrint (("realloc enlarge: VirtualAlloc (%p + %I64x, %I64x) error %ld\n", *var, (uint64_t)memInfo.RegionSize, (uint64_t)(nbytes - memInfo.RegionSize), GetLastError ())); DebPrint (("next region: %p %p %I64x %x\n", m2.BaseAddress, m2.AllocationBase, (uint64_t)m2.RegionSize, m2.AllocationProtect)); } else return *var; } /* Else we must actually enlarge the block by allocating a new one and copying previous contents from the old to the new one. */ old_ptr = *var; if (mmap_alloc (var, nbytes)) { CopyMemory (*var, old_ptr, memInfo.RegionSize); mmap_free (&old_ptr); return *var; } else { /* We failed to reallocate the buffer. */ *var = old_ptr; return NULL; } } /* If we are shrinking by more than one page... */ if (memInfo.RegionSize > nbytes + getpagesize()) { /* If we are shrinking a lot... */ if ((memInfo.RegionSize / 2) > nbytes) { /* Let's give some memory back to the system and release some pages. */ old_ptr = *var; if (mmap_alloc (var, nbytes)) { CopyMemory (*var, old_ptr, nbytes); mmap_free (&old_ptr); return *var; } else { /* In case we fail to shrink, try to go on with the old block. But that means there is a lot of memory pressure. We could also decommit pages. */ *var = old_ptr; return *var; } } /* We still can decommit pages. */ if (VirtualFree ((char *)*var + nbytes + get_page_size(), memInfo.RegionSize - nbytes - get_page_size(), MEM_DECOMMIT) == 0) DebPrint (("mmap_realloc: VirtualFree error %ld\n", GetLastError ())); return *var; } /* Not enlarging, not shrinking by more than one page. */ return *var; }
static bool mm_GetLibraryInfo(const void *libPtr, DynLibInfo &lib) { uintptr_t baseAddr; if (libPtr == NULL) { return false; } #ifdef _WIN32 MEMORY_BASIC_INFORMATION info; IMAGE_DOS_HEADER *dos; IMAGE_NT_HEADERS *pe; IMAGE_FILE_HEADER *file; IMAGE_OPTIONAL_HEADER *opt; if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION))) { return false; } baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase); /* All this is for our insane sanity checks :o */ dos = reinterpret_cast<IMAGE_DOS_HEADER *>(baseAddr); pe = reinterpret_cast<IMAGE_NT_HEADERS *>(baseAddr + dos->e_lfanew); file = &pe->FileHeader; opt = &pe->OptionalHeader; /* Check PE magic and signature */ if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { return false; } /* Check architecture, which is 32-bit/x86 right now * Should change this for 64-bit if Valve gets their act together */ if (file->Machine != IMAGE_FILE_MACHINE_I386) { return false; } /* For our purposes, this must be a dynamic library */ if ((file->Characteristics & IMAGE_FILE_DLL) == 0) { return false; } /* Finally, we can do this */ lib.memorySize = opt->SizeOfImage; #elif defined __linux__ Dl_info info; Elf32_Ehdr *file; Elf32_Phdr *phdr; uint16_t phdrCount; if (!dladdr(libPtr, &info)) { return false; } if (!info.dli_fbase || !info.dli_fname) { return false; } /* This is for our insane sanity checks :o */ baseAddr = reinterpret_cast<uintptr_t>(info.dli_fbase); file = reinterpret_cast<Elf32_Ehdr *>(baseAddr); /* Check ELF magic */ if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) { return false; } /* Check ELF version */ if (file->e_ident[EI_VERSION] != EV_CURRENT) { return false; } /* Check ELF architecture, which is 32-bit/x86 right now * Should change this for 64-bit if Valve gets their act together */ if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB) { return false; } /* For our purposes, this must be a dynamic library/shared object */ if (file->e_type != ET_DYN) { return false; } phdrCount = file->e_phnum; phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff); for (uint16_t i = 0; i < phdrCount; i++) { Elf32_Phdr &hdr = phdr[i]; /* We only really care about the segment with executable code */ if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X|PF_R)) { /* From glibc, elf/dl-load.c: * c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1) * & ~(GLRO(dl_pagesize) - 1)); * * In glibc, the segment file size is aligned up to the nearest page size and * added to the virtual address of the segment. We just want the size here. */ lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz); break; } } #elif defined __APPLE__ Dl_info info; struct mach_header *file; struct segment_command *seg; uint32_t cmd_count; if (!dladdr(libPtr, &info)) { return false; } if (!info.dli_fbase || !info.dli_fname) { return false; } /* This is for our insane sanity checks :o */ baseAddr = (uintptr_t)info.dli_fbase; file = (struct mach_header *)baseAddr; /* Check Mach-O magic */ if (file->magic != MH_MAGIC) { return false; } /* Check architecture (32-bit/x86) */ if (file->cputype != CPU_TYPE_I386 || file->cpusubtype != CPU_SUBTYPE_I386_ALL) { return false; } /* For our purposes, this must be a dynamic library */ if (file->filetype != MH_DYLIB) { return false; } cmd_count = file->ncmds; seg = (struct segment_command *)(baseAddr + sizeof(struct mach_header)); /* Add up memory sizes of mapped segments */ for (uint32_t i = 0; i < cmd_count; i++) { if (seg->cmd == LC_SEGMENT) { lib.memorySize += seg->vmsize; } seg = (struct segment_command *)((uintptr_t)seg + seg->cmdsize); } #endif lib.baseAddress = reinterpret_cast<void *>(baseAddr); return true; }
SIZE_T WINAPI VirtualQueryUnix(LPCVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer,SIZE_T dwLength) { #ifndef OS_UNIX_STRUCT return (SIZE_T)VirtualQuery(lpAddress,lpBuffer,dwLength); #else if(lpBuffer==NULL||lpBuffer->State!=MEM_FREE||dwLength<=0) { return (SIZE_T)VirtualQuery(lpAddress,lpBuffer,dwLength); } SIZE_T xy=VirtualQuery(lpAddress,lpBuffer,dwLength); if(xy==0) { return (SIZE_T)0; } SIZE_T ia = 40; if(lpBuffer->State!=MEM_FREE&&lpBuffer->RegionSize>0&&lpBuffer->RegionSize>(dwLength+(ia*2))) { if(lpBuffer->AllocationProtect==PAGE_READWRITE||lpBuffer->AllocationProtect==PAGE_EXECUTE_READWRITE) { SIZE_T ix=0; SIZE_T rs=lpBuffer->RegionSize; SIZE_T ixp=0; SIZE_T rsp=dwLength+(ia*2); char * lxx = (char*)lpBuffer->BaseAddress; BOOL allok=FALSE; for(ix=0; ix < rs; ix++) { if(ixp>=rsp) { allok=TRUE; break; } if(lxx[ix]==0) { ixp++; } else { ixp=0; } } //char * nb=(char*)&lxx[(ix-ixp)]; //SIZE_T nrs=old_basic.RegionSize; //memcpy((void*)&nb[64],(void*)lpBuffer,sizeof(MEMORY_BASIC_INFORMATION)); //memcpy((void*)&old_basic,(void*)lpBuffer,sizeof(MEMORY_BASIC_INFORMATION)); //old_basic.BaseAddress = (void*)&nb[128]; //old_basic.RegionSize = nrs; //memset((void*)lpBuffer,0,sizeof(MEMORY_BASIC_INFORMATION)); //memcpy((void*)lpBuffer,(void*)&old_basic,sizeof(MEMORY_BASIC_INFORMATION)); if(allok==TRUE) { lpBuffer->BaseAddress=(LPVOID)&lxx[((ix-ixp)+ia)]; } return xy; } else { return xy; } } else { return xy; } #endif return (SIZE_T)VirtualQuery(lpAddress,lpBuffer,dwLength); }
BOOL __stdcall HookOrdinalExport ( HMODULE hModule , LPCTSTR szImportMod , DWORD dwOrdinal , PROC pHookFunc , PROC * ppOrigAddr ) { // Assert the parameters. ASSERT ( NULL != hModule ) ; ASSERT ( FALSE == IsBadStringPtr ( szImportMod , MAX_PATH ) ) ; ASSERT ( 0 != dwOrdinal ) ; ASSERT ( FALSE == IsBadCodePtr ( pHookFunc ) ) ; // Perform the error checking for the parameters. if ( ( NULL == hModule ) || ( TRUE == IsBadStringPtr ( szImportMod , MAX_PATH ) ) || ( 0 == dwOrdinal ) || ( TRUE == IsBadCodePtr ( pHookFunc ) ) ) { SetLastErrorEx ( ERROR_INVALID_PARAMETER , SLE_ERROR ) ; return ( FALSE ) ; } if ( NULL != ppOrigAddr ) { ASSERT ( FALSE == IsBadWritePtr ( ppOrigAddr , sizeof ( PROC ) ) ) ; if ( TRUE == IsBadWritePtr ( ppOrigAddr , sizeof ( PROC ) ) ) { SetLastErrorEx ( ERROR_INVALID_PARAMETER , SLE_ERROR ) ; return ( FALSE ) ; } } // Get the specific import descriptor. PIMAGE_IMPORT_DESCRIPTOR pImportDesc = GetNamedImportDescriptor ( hModule , szImportMod ) ; if ( NULL == pImportDesc ) { // The requested module wasn't imported. Don't return an error. return ( TRUE ) ; } // Get the original thunk information for this DLL. I can't use // the thunk information stored in pImportDesc->FirstThunk // because the loader has already changed that array to fix up // all the imports. The original thunk gives me access to the // function names. PIMAGE_THUNK_DATA pOrigThunk = MakePtr ( PIMAGE_THUNK_DATA , hModule , pImportDesc->OriginalFirstThunk ) ; // Get the array that pImportDesc->FirstThunk points to because I'll // do the actual hooking there. PIMAGE_THUNK_DATA pRealThunk = MakePtr ( PIMAGE_THUNK_DATA , hModule , pImportDesc->FirstThunk ); // The flag is going to be set from the thunk, so make it // easier to look up. DWORD dwCompareOrdinal = IMAGE_ORDINAL_FLAG | dwOrdinal ; // Loop through and find the function to hook. while ( NULL != pOrigThunk->u1.Function ) { // Look only at functions that are imported by ordinal value, // not those that are imported by name. if ( IMAGE_ORDINAL_FLAG == ( pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG )) { // Did I find the function to hook? if ( dwCompareOrdinal == pOrigThunk->u1.Ordinal ) { // I found the function to hook. Now I need to change // the memory protection to writable before I overwrite // the function pointer. Note that I'm now writing into // the real thunk area! MEMORY_BASIC_INFORMATION mbi_thunk ; VirtualQuery ( pRealThunk , &mbi_thunk , sizeof ( MEMORY_BASIC_INFORMATION ) ) ; if ( FALSE == VirtualProtect ( mbi_thunk.BaseAddress , mbi_thunk.RegionSize , PAGE_READWRITE , &mbi_thunk.Protect )) { ASSERT ( !"VirtualProtect failed!" ) ; // There's nothing I can do but fail the function. SetLastErrorEx ( ERROR_INVALID_PARAMETER , SLE_ERROR ) ; return ( FALSE ) ; } // Save the original address if requested. if ( NULL != ppOrigAddr ) { *ppOrigAddr = (PROC)pRealThunk->u1.Function ; } // Microsoft has two different definitions of the // PIMAGE_THUNK_DATA fields as they are moving to // support Win64. The W2K RC2 Platform SDK is the // latest header, so I'll use that one and force the // Visual C++ 6 Service Pack 3 headers to deal with it. // Hook the function. DWORD * pTemp = (DWORD*)&pRealThunk->u1.Function ; *pTemp = (DWORD)(pHookFunc) ; DWORD dwOldProtect ; // Change the protection back to what it was before I // overwrote the function pointer. VERIFY ( VirtualProtect ( mbi_thunk.BaseAddress , mbi_thunk.RegionSize , mbi_thunk.Protect , &dwOldProtect ) ) ; // Life is good. SetLastError ( ERROR_SUCCESS ) ; return ( TRUE ) ; } } // Increment both tables. pOrigThunk++ ; pRealThunk++ ; } // Nothing was hooked. Technically, this isn't an error. It just // means that the module is imported but the function isn't. SetLastError ( ERROR_SUCCESS ) ; return ( FALSE ) ; }
bool CDetour::Detour ( BYTE * &jmp, BYTE * &orig, const BYTE * &det, int iPatchType, int len ) { DWORD dwBack = 0; int i = 0; BYTE *pPatchBuf = NULL; // Allocate space for the jump jmp = (BYTE *)malloc( len + 5 ); // Force page protection flags to read|write MEMORY_BASIC_INFORMATION mbi; VirtualQuery( (void *)orig, &mbi, sizeof(mbi) ); VirtualProtect( mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect ); // Copy the overwritten opcodes at the original to the malloced space memcpy( jmp, orig, len ); // Increment to the end of the opcodes at the malloced space jmp += len; // Place a jump back to the original at this point jmp[0] = 0xE9; *( DWORD * ) ( jmp + 1 ) = ( DWORD ) ( orig + len - jmp ) - 5; // Generate a random opcode int iTmpRnd = ( rand() * 0xFF ) + rand(); BYTE bTmpRnd = ( BYTE ) iTmpRnd; // Place a jump at the original to the detour function pPatchBuf = new BYTE[len]; // Pad out the bytes with NOPs so we don't have ends of intructions memset( pPatchBuf, 0x90, len ); // Write the opcodes to the buffer according to patch type switch ( iPatchType ) { case DETOUR_TYPE_JMP: pPatchBuf[0] = '\xE9'; *(DWORD *) &pPatchBuf[1] = ( DWORD ) ( det - orig ) - 5; break; case DETOUR_TYPE_PUSH_RET: pPatchBuf[0] = '\x68'; *(DWORD *) &pPatchBuf[1] = ( DWORD ) det; pPatchBuf[5] = '\xC3'; break; case DETOUR_TYPE_PUSH_FUNC: pPatchBuf[0] = '\x68'; *(DWORD *) &pPatchBuf[1] = ( DWORD ) det; break; case DETOUR_TYPE_CALL_FUNC: pPatchBuf[0] = '\xE8'; *(DWORD *) &pPatchBuf[1] = ( DWORD ) ( det - orig ) - 5; break; default: return false; } // Write the detour for ( i = 0; i < len; i++ ) orig[i] = pPatchBuf[i]; // Put the old page protection flags back VirtualProtect( mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &mbi.Protect ); FlushInstructionCache( GetCurrentProcess(), orig, len ); return true; }
static HMODULE ThisModule() { MEMORY_BASIC_INFORMATION info; return VirtualQuery(ThisModule, &info, sizeof(info)) ? (HMODULE) info.AllocationBase : nsnull; }
static int zend_shared_alloc_reattach(size_t requested_size, char **error_in) { int err; void *wanted_mapping_base; char *mmap_base_file = get_mmap_base_file(); FILE *fp = fopen(mmap_base_file, "r"); MEMORY_BASIC_INFORMATION info; if (!fp) { err = GetLastError(); zend_win_error_message(ACCEL_LOG_WARNING, mmap_base_file, err); zend_win_error_message(ACCEL_LOG_FATAL, "Unable to open base address file", err); *error_in="fopen"; return ALLOC_FAILURE; } if (!fscanf(fp, "%p", &wanted_mapping_base)) { err = GetLastError(); zend_win_error_message(ACCEL_LOG_FATAL, "Unable to read base address", err); *error_in="read mapping base"; fclose(fp); return ALLOC_FAILURE; } fclose(fp); /* Check if the requested address space is free */ if (VirtualQuery(wanted_mapping_base, &info, sizeof(info)) == 0 || info.State != MEM_FREE || info.RegionSize < requested_size) { #if ENABLE_FILE_CACHE_FALLBACK if (ZCG(accel_directives).file_cache && ZCG(accel_directives).file_cache_fallback) { size_t pre_size, wanted_mb_save; wanted_mb_save = (size_t)wanted_mapping_base; err = ERROR_INVALID_ADDRESS; zend_win_error_message(ACCEL_LOG_WARNING, "Base address marks unusable memory region (fall-back to file cache)", err); pre_size = ZEND_ALIGNED_SIZE(sizeof(zend_smm_shared_globals)) + ZEND_ALIGNED_SIZE(sizeof(zend_shared_segment)) + ZEND_ALIGNED_SIZE(sizeof(void *)) + ZEND_ALIGNED_SIZE(sizeof(int)); /* Map only part of SHM to have access opcache shared globals */ mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, pre_size + ZEND_ALIGNED_SIZE(sizeof(zend_accel_shared_globals)), NULL); if (mapping_base == NULL) { err = GetLastError(); zend_win_error_message(ACCEL_LOG_FATAL, "Unable to reattach to opcache shared globals", err); return ALLOC_FAILURE; } accel_shared_globals = (zend_accel_shared_globals *)((char *)((zend_smm_shared_globals *)mapping_base)->app_shared_globals + ((char *)mapping_base - (char *)wanted_mb_save)); /* Make this process to use file-cache only */ ZCG(accel_directives).file_cache_only = 1; return ALLOC_FALLBACK; } #endif err = ERROR_INVALID_ADDRESS; zend_win_error_message(ACCEL_LOG_FATAL, "Base address marks unusable memory region. Please setup opcache.file_cache and opcache.file_cache_fallback directives for more convenient Opcache usage", err); return ALLOC_FAILURE; } mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, wanted_mapping_base); if (mapping_base == NULL) { err = GetLastError(); if (err == ERROR_INVALID_ADDRESS) { zend_win_error_message(ACCEL_LOG_FATAL, "Unable to reattach to base address", err); return ALLOC_FAILURE; } return ALLOC_FAIL_MAPPING; } smm_shared_globals = (zend_smm_shared_globals *) mapping_base; return SUCCESSFULLY_REATTACHED; }
static PROC SetProcAddressA( __in HINSTANCE targetModule, __in LPCSTR lpLibFileName, __in LPCSTR lpProcName, __in PROC newFunction ) { HMODULE hModule = LoadLibraryA( lpLibFileName ); if(hModule == NULL) return NULL; // To do: call FreeLibrary(hModule) at the appropriate time. PROC pfnHookAPIAddr = GetProcAddress(hModule, lpProcName ); HINSTANCE hInstance = targetModule; ULONG ulSize; PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData( hInstance, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize ); while (pImportDesc->Name) { PSTR pszModName = (PSTR)((PBYTE) hInstance + pImportDesc->Name); if (_stricmp(pszModName, lpLibFileName) == 0) break; pImportDesc++; } PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE) hInstance + pImportDesc->FirstThunk); while (pThunk->u1.Function) { PROC* ppfn = (PROC*) &pThunk->u1.Function; BOOL bFound = (*ppfn == pfnHookAPIAddr); if (bFound) { MEMORY_BASIC_INFORMATION mbi; VirtualQuery( ppfn, &mbi, sizeof(MEMORY_BASIC_INFORMATION) ); VirtualProtect( mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect); *ppfn = *newFunction; DWORD dwOldProtect; VirtualProtect( mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect ); break; } pThunk++; } return pfnHookAPIAddr; }
LPVOID PreReservedVirtualAllocWrapper::AllocPages(LPVOID lpAddress, size_t pageCount, DWORD allocationType, DWORD protectFlags, bool isCustomHeapAllocation) { if (pageCount > AutoSystemInfo::MaxPageCount) { return nullptr; } size_t dwSize = pageCount * AutoSystemInfo::PageSize; AssertMsg(isCustomHeapAllocation, "PreReservation used for allocations other than CustomHeap?"); Assert(dwSize != 0); { AutoCriticalSection autocs(&this->cs); //Return nullptr, if no space to Reserve if (EnsurePreReservedRegionInternal() == nullptr) { PreReservedHeapTrace(_u("No space to pre-reserve memory with %d pages. Returning NULL\n"), PreReservedAllocationSegmentCount * AutoSystemInfo::Data.GetAllocationGranularityPageCount()); return nullptr; } char * addressToReserve = nullptr; uint freeSegmentsBVIndex = BVInvalidIndex; size_t requestedNumOfSegments = dwSize / (AutoSystemInfo::Data.GetAllocationGranularityPageSize()); Assert(requestedNumOfSegments <= MAXUINT32); if (lpAddress == nullptr) { Assert(requestedNumOfSegments != 0); AssertMsg(dwSize % AutoSystemInfo::Data.GetAllocationGranularityPageSize() == 0, "dwSize should be aligned with Allocation Granularity"); do { freeSegmentsBVIndex = freeSegments.GetNextBit(freeSegmentsBVIndex + 1); //Return nullptr, if we don't have free/decommit pages to allocate if ((freeSegments.Length() - freeSegmentsBVIndex < requestedNumOfSegments) || freeSegmentsBVIndex == BVInvalidIndex) { PreReservedHeapTrace(_u("No more space to commit in PreReserved Memory region.\n")); return nullptr; } } while (!freeSegments.TestRange(freeSegmentsBVIndex, static_cast<uint>(requestedNumOfSegments))); uint offset = freeSegmentsBVIndex * AutoSystemInfo::Data.GetAllocationGranularityPageSize(); addressToReserve = (char*) preReservedStartAddress + offset; //Check if the region is not already in MEM_COMMIT state. MEMORY_BASIC_INFORMATION memBasicInfo; size_t bytes = VirtualQuery(addressToReserve, &memBasicInfo, sizeof(memBasicInfo)); if (bytes == 0) { MemoryOperationLastError::RecordLastError(); } if (bytes == 0 || memBasicInfo.RegionSize < requestedNumOfSegments * AutoSystemInfo::Data.GetAllocationGranularityPageSize() || memBasicInfo.State == MEM_COMMIT) { CustomHeap_BadPageState_fatal_error((ULONG_PTR)this); } } else { //Check If the lpAddress is within the range of the preReserved Memory Region Assert(((char*) lpAddress) >= (char*) preReservedStartAddress || ((char*) lpAddress + dwSize) < GetPreReservedEndAddress()); addressToReserve = (char*) lpAddress; freeSegmentsBVIndex = (uint) ((addressToReserve - (char*) preReservedStartAddress) / AutoSystemInfo::Data.GetAllocationGranularityPageSize()); #if DBG uint numOfSegments = (uint)ceil((double)dwSize / (double)AutoSystemInfo::Data.GetAllocationGranularityPageSize()); Assert(numOfSegments != 0); Assert(freeSegmentsBVIndex + numOfSegments - 1 < freeSegments.Length()); Assert(!freeSegments.TestRange(freeSegmentsBVIndex, numOfSegments)); #endif } AssertMsg(freeSegmentsBVIndex < PreReservedAllocationSegmentCount, "Invalid BitVector index calculation?"); AssertMsg(dwSize % AutoSystemInfo::PageSize == 0, "COMMIT is managed at AutoSystemInfo::PageSize granularity"); char * allocatedAddress = nullptr; bool failedToProtectPages = false; if ((allocationType & MEM_COMMIT) != 0) { #if defined(ENABLE_JIT_CLAMP) AutoEnableDynamicCodeGen enableCodeGen; #endif #if defined(_CONTROL_FLOW_GUARD) if (AutoSystemInfo::Data.IsCFGEnabled()) { DWORD oldProtect = 0; DWORD allocProtectFlags = 0; if (AutoSystemInfo::Data.IsCFGEnabled()) { allocProtectFlags = PAGE_EXECUTE_RW_TARGETS_INVALID; } else { allocProtectFlags = PAGE_EXECUTE_READWRITE; } allocatedAddress = (char *)VirtualAlloc(addressToReserve, dwSize, MEM_COMMIT, allocProtectFlags); if (allocatedAddress != nullptr) { BOOL result = VirtualProtect(allocatedAddress, dwSize, protectFlags, &oldProtect); if (result == FALSE) { CustomHeap_BadPageState_fatal_error((ULONG_PTR)this); } AssertMsg(oldProtect == (PAGE_EXECUTE_READWRITE), "CFG Bitmap gets allocated and bits will be set to invalid only upon passing these flags."); } else { MemoryOperationLastError::RecordLastError(); } } else #endif { allocatedAddress = (char *)VirtualAlloc(addressToReserve, dwSize, MEM_COMMIT, protectFlags); if (allocatedAddress == nullptr) { MemoryOperationLastError::RecordLastError(); } } } else { // Just return the uncommitted address if we didn't ask to commit it. allocatedAddress = addressToReserve; } // Keep track of the committed pages within the preReserved Memory Region if (lpAddress == nullptr && allocatedAddress != nullptr) { Assert(allocatedAddress == addressToReserve); Assert(requestedNumOfSegments != 0); freeSegments.ClearRange(freeSegmentsBVIndex, static_cast<uint>(requestedNumOfSegments)); } PreReservedHeapTrace(_u("MEM_COMMIT: StartAddress: 0x%p of size: 0x%x * 0x%x bytes \n"), allocatedAddress, requestedNumOfSegments, AutoSystemInfo::Data.GetAllocationGranularityPageSize()); if (failedToProtectPages) { return nullptr; } return allocatedAddress; } }
/*! * @brief Prepare the session for use, including all the resources that are embedded. */ VOID python_prepare_session() { Py_IgnoreEnvironmentFlag = 1; Py_NoSiteFlag = 1; Py_Initialize(); PyEval_InitThreads(); PyObject* stdoutModule = Py_InitModule("meterpreter_stdout", meterpreter_stdout_hooks); if (stdoutModule != NULL && PySys_SetObject("stdout", stdoutModule) == 0) { dprintf("[PYTHON] Successfully set the stdout hook"); } else { dprintf("[PYTHON] Failed to set the stdout hook"); } PyObject* stderrModule = Py_InitModule("meterpreter_stderr", meterpreter_stderr_hooks); if (stderrModule != NULL && PySys_SetObject("stderr", stderrModule) == 0) { dprintf("[PYTHON] Successfully set the stderr hook"); } else { dprintf("[PYTHON] Failed to set the stderr hook"); } // with the output handlers sorted, we load the stuff from the compressed resource // which should give us all the stuff we need to be useful. initerrno(); initnt(); init_socket(); init_functools(); // have we loaded the core pointer already? if (coreLibPointer == NULL) { MEMORY_BASIC_INFORMATION mbi; if (!VirtualQuery((LPVOID)python_prepare_session, &mbi, sizeof(mbi))) { dprintf("[PYTHON] VirtualQuery failed: %d", GetLastError()); return; } HMODULE mod = (HMODULE)mbi.AllocationBase; dprintf("[PYTHON] Module handle: %p", (LPVOID)mod); HRSRC res = FindResource(mod, MAKEINTRESOURCEA(IDR_PYTHON_CORE), "BINARY"); if (res == NULL) { dprintf("[PYTHON] Unable to find resource: %d", GetLastError()); return; } HGLOBAL file = LoadResource(mod, res); if (file == NULL) { dprintf("[PYTHON] Unable to load core library resource: %d", GetLastError()); return; } // store these pointers for when we reset the session, saves us from // doing all of this nonsense again. coreLibPointer = (LPBYTE)LockResource(file); coreLibSize = *(LPDWORD)coreLibPointer; coreLibPointer += sizeof(DWORD); } dprintf("[PYTHON] coreLibPointer: %p, coreLibSize: %d", coreLibPointer, coreLibSize); if (coreLibPointer != NULL) { // Create a byte array with everything in it PyObject* libString = PyString_FromStringAndSize(coreLibPointer, coreLibSize); dprintf("[PYTHON] libString is %p", libString); // import zlib PyObject* zlibModStr = PyString_FromString("zlib"); dprintf("[PYTHON] zlibModStr: %p", zlibModStr); PyObject* zlibMod = PyImport_Import(zlibModStr); dprintf("[PYTHON] zlibMod: %p", zlibMod); // get a reference to the decompress function PyObject* zlibDecompress = PyObject_GetAttrString(zlibMod, "decompress"); dprintf("[PYTHON] zlibDecompress: %p", zlibDecompress); // prepare arguments for invocation PyObject* zlibDecompressArgs = PyTuple_Pack(1, libString); dprintf("[PYTHON] zlibDecompressArgs: %p", zlibDecompressArgs); // call zlib.decompress(libString) PyObject* zlibDecompressResult = PyObject_CallObject(zlibDecompress, zlibDecompressArgs); dprintf("[PYTHON] zlibDecompressResult: %p", zlibDecompressResult); //dprintf("[PYTHON] zlibDecompressResult type: %s", zlibDecompressResult->ob_type->tp_name); PCHAR byteArray = NULL; Py_ssize_t byteArrayLength = 0; PyString_AsStringAndSize(zlibDecompressResult, &byteArray, &byteArrayLength); dprintf("[PYTHON] bytes: %p %u", byteArray, byteArrayLength); PyObject* modData = PyMarshal_ReadObjectFromString(byteArray, byteArrayLength); dprintf("[PYTHON] modData: %p", modData); PyObject* mainMod = PyImport_AddModule("__main__"); PyObject* mainDict = PyModule_GetDict(mainMod); PyModule_AddObject(mainMod, "met_lib_data", modData); // TODO: double-check that we don't need to remove existing finders which might // hit the file system #ifdef DEBUGTRACE PyRun_SimpleString("eval(met_lib_data[0]);met_init(True)"); #else PyRun_SimpleString("eval(met_lib_data[0]);met_init(False)"); #endif // TODO: figure out which reference counts need to be reduce to avoid leaking. } // now load the baked-in modules PyErr_Clear(); for (InitFunc* f = &init_funcs[0]; f->func != NULL; f += 1) { dprintf("[PYTHON] Running %s", f->name); f->func(); if (PyErr_Occurred()) { #ifdef DEBUGTRACE PyErr_Print(); #endif dprintf("[PYTHON] %s errored", f->name); PyErr_Clear(); } } initialize_std_handlers(); binding_init(); }
/***************************************************************************** * vlc_exception_filter: handles unhandled exceptions, like segfaults *****************************************************************************/ LONG WINAPI vlc_exception_filter(struct _EXCEPTION_POINTERS *lpExceptionInfo) { if(IsDebuggerPresent()) { //If a debugger is present, pass the exception to the debugger //with EXCEPTION_CONTINUE_SEARCH return EXCEPTION_CONTINUE_SEARCH; } else { fprintf( stderr, "unhandled vlc exception\n" ); FILE * fd = _wfopen ( crashdump_path, L"w, ccs=UTF-8" ); if( !fd ) { fprintf( stderr, "\nerror while opening file" ); exit( 1 ); } OSVERSIONINFO osvi; ZeroMemory( &osvi, sizeof(OSVERSIONINFO) ); osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); GetVersionEx( &osvi ); fwprintf( fd, L"[version]\nOS=%d.%d.%d.%d.%ls\nVLC=" VERSION_MESSAGE, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, osvi.dwPlatformId, osvi.szCSDVersion); const CONTEXT *const pContext = (const CONTEXT *) lpExceptionInfo->ContextRecord; const EXCEPTION_RECORD *const pException = (const EXCEPTION_RECORD *) lpExceptionInfo->ExceptionRecord; /* No nested exceptions for now */ fwprintf( fd, L"\n\n[exceptions]\n%08x at %px", pException->ExceptionCode, pException->ExceptionAddress ); for( unsigned int i = 0; i < pException->NumberParameters; i++ ) fwprintf( fd, L" | %p", pException->ExceptionInformation[i] ); #ifdef _WIN64 fwprintf( fd, L"\n\n[context]\nRDI:%px\nRSI:%px\n" \ "RBX:%px\nRDX:%px\nRCX:%px\nRAX:%px\n" \ "RBP:%px\nRIP:%px\nRSP:%px\nR8:%px\n" \ "R9:%px\nR10:%px\nR11:%px\nR12:%px\n" \ "R13:%px\nR14:%px\nR15:%px\n", pContext->Rdi,pContext->Rsi,pContext->Rbx, pContext->Rdx,pContext->Rcx,pContext->Rax, pContext->Rbp,pContext->Rip,pContext->Rsp, pContext->R8,pContext->R9,pContext->R10, pContext->R11,pContext->R12,pContext->R13, pContext->R14,pContext->R15 ); #else fwprintf( fd, L"\n\n[context]\nEDI:%px\nESI:%px\n" \ "EBX:%px\nEDX:%px\nECX:%px\nEAX:%px\n" \ "EBP:%px\nEIP:%px\nESP:%px\n", pContext->Edi,pContext->Esi,pContext->Ebx, pContext->Edx,pContext->Ecx,pContext->Eax, pContext->Ebp,pContext->Eip,pContext->Esp ); #endif fwprintf( fd, L"\n[stacktrace]\n#EIP|base|module\n" ); #ifdef _WIN64 LPCVOID caller = (LPCVOID)pContext->Rip; LPVOID *pBase = (LPVOID*)pContext->Rbp; #else LPVOID *pBase = (LPVOID*)pContext->Ebp; LPCVOID caller = (LPCVOID)pContext->Eip; #endif for( unsigned frame = 0; frame <= 100; frame++ ) { MEMORY_BASIC_INFORMATION mbi; wchar_t module[ 256 ]; VirtualQuery( caller, &mbi, sizeof( mbi ) ) ; GetModuleFileName( mbi.AllocationBase, module, 256 ); fwprintf( fd, L"%p|%ls\n", caller, module ); if( IsBadReadPtr( pBase, 2 * sizeof( void* ) ) ) break; /*The last BP points to NULL!*/ caller = *(pBase + 1); if( !caller ) break; pBase = *pBase; if( !pBase ) break; } HANDLE hpid = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); if (hpid) { HMODULE mods[1024]; DWORD size; if (EnumProcessModules(hpid, mods, sizeof(mods), &size)) { fwprintf( fd, L"\n\n[modules]\n" ); for (unsigned int i = 0; i < size / sizeof(HMODULE); i++) { wchar_t module[ 256 ]; GetModuleFileName(mods[i], module, 256); fwprintf( fd, L"%p|%ls\n", mods[i], module); } } CloseHandle(hpid); } fclose( fd ); fflush( stderr ); exit( 1 ); } }
void CDynPatcher::Error(const char *File, const char *Func, int Line, bool IsCritical, char *Fmt, ...) { static char Buff[0x1000]; int len=0; len+=_snprintf(&Buff[len],sizeof(Buff)-len-1,"[CDynPatcher] %serror",IsCritical?"critical":""); if(File&&Func&&Line&&strlen(File)<MAX_PATH&&strlen(Func)<300) { len+=_snprintf(&Buff[len],sizeof(Buff)-len-1," at %s(%s:%i)",CSectionData::GetFileName(File),Func,Line); } len+=_snprintf(&Buff[len],sizeof(Buff)-len-1,":"); va_list marker; if(!Fmt) { len+=_snprintf(&Buff[len],sizeof(Buff)-len-1,"(NO DESCRIPTION)\r\n"); } else { va_start( marker, Fmt ); len+=_vsnprintf(&Buff[len],sizeof(Buff)-len-1, Fmt, marker ); } len+=_snprintf(&Buff[len],sizeof(Buff)-len-1,"\r\n"); printf("%s",Buff); if(IsCritical) { #ifdef WIN32 __asm{int 3}; if(!IsDebuggerPresent()) { exit(0); } #else exit(0); #endif } } void CDynPatcher::Message(const char *File, const char *Func, int Line, char *Fmt, ...) { static char Buff[0x1000]; int len=0; len+=_snprintf(&Buff[len],sizeof(Buff)-len-1,"[CDynPatcher]"); if(File&&Func&&Line&&strlen(File)<MAX_PATH&&strlen(Func)<300) { len+=_snprintf(&Buff[len],sizeof(Buff)-len-1," at %s(%s:%i)",CSectionData::GetFileName(File),Func,Line); } len+=_snprintf(&Buff[len],sizeof(Buff)-len-1,":"); va_list marker; if(!Fmt) { len+=_snprintf(&Buff[len],sizeof(Buff)-len-1,"(NO DESCRIPTION)\r\n"); } else { va_start( marker, Fmt ); len+=_vsnprintf(&Buff[len],sizeof(Buff)-len-1, Fmt, marker ); } len+=_snprintf(&Buff[len],sizeof(Buff)-len-1,"\r\n"); printf("%s",Buff); } bool CDynPatcher::Init(const char *LibName,bool ForceLoad) { if (!LibName) { szLibName = "<<===NO LIBRARY NAME===>>"; return false; } if(!LoadLib(LibName,ForceLoad)) { DynErr(false,"Unable to load \"%s\"",LibName); return false; } #ifdef WIN32 if(!ParseGenericDllData_PE()) { DynErr(false,"Failed to parse \"%s\"",szLibName); return false; } DynMsg("\"%s\" parsed",szLibName); #else FILE *fl = fopen(szLibName, "rb"); int LibSize; void* LibBuf; if (fl == NULL) { DynErr(false,"Failed to open '%s' for read\n", szLibName); return false; } fseek(fl, 0, SEEK_END); LibSize = ftell(fl); fseek(fl, 0, SEEK_SET); if (LibSize < 0) LibSize = 0; LibBuf = malloc(LibSize + 4); fread(LibBuf, 1, LibSize, fl); fclose(fl); if(!ParseGenericDllData_ELF(LibBuf, LibSize)) { DynErr(false,"Failed to parse \"%s\"",szLibName); return false; } #endif return true; } bool CDynPatcher::Init(const wchar_t *LibName, bool ForceLoad /*= false*/) { return 0; static char UTF8LibName[MAX_PATH]; //Q_UnicodeToUTF8(LibName, UTF8LibName, MAX_PATH-1); return Init(UTF8LibName, ForceLoad); } bool CDynPatcher::Init(void *FuncAddr) { char szTmpName[400]; sprintf(szTmpName, "Unk_load_by_func_addr_%p", FuncAddr); szLibName = new char[strlen(szTmpName) + 1]; strcpy(szLibName, szTmpName); bSelfLoaded = false; #ifdef _WIN32 MEMORY_BASIC_INFORMATION mem; VirtualQuery(FuncAddr, &mem, sizeof(mem)); szTmpName[0] = 0; GetModuleFileNameA(reinterpret_cast<HMODULE>(mem.AllocationBase ), szTmpName, sizeof(szTmpName) - 1); if (szTmpName[0] != 0) { delete[]szLibName; szLibName = new char[strlen(CSectionData::GetFileName(szTmpName)) + 1]; strcpy(szLibName, CSectionData::GetFileName(szTmpName)); } IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER*)mem.AllocationBase; IMAGE_NT_HEADERS *pe = (IMAGE_NT_HEADERS*)((unsigned long)dos + (unsigned long)dos->e_lfanew); if (pe->Signature == IMAGE_NT_SIGNATURE) { this->DllHandler = mem.AllocationBase; if (!ParseGenericDllData_PE()) { DynErr(false, "Failed to parse \"%s\"", szLibName); return false; } DynMsg("\"%s\" parsed",szLibName); } #else Dl_info info; if (dladdr(FuncAddr, &info) && info.dli_fbase &&info.dli_fname) { delete [] szLibName; szLibName = new char[strlen(info.dli_fname) + 1]; strcpy(szLibName, info.dli_fname); bool ParseOK=false; size_t LoadLibSize=0; DllBase = info.dli_fbase; LoadLibSize = (size_t)GetBaseLen(DllBase); DllHandler = dlopen(info.dli_fname, RTLD_NOW); dlclose(DllHandler); DynMsg("Found library \"%s\" at addr %p. Base=%p, size=%x, handler=%p",szLibName,FuncAddr,DllBase,LoadLibSize,DllHandler); FILE *fl = fopen(szLibName, "rb"); int LibSize; void* LibBuf; if (fl) { fseek(fl, 0, SEEK_END); LibSize = ftell(fl); fseek(fl, 0, SEEK_SET); DynMsg("Reading \"%s\" as file. Size=%x",szLibName,LibSize); if (LibSize < 0) LibSize = 0; LibBuf = malloc(LibSize + 4); fread(LibBuf, 1, LibSize, fl); fclose(fl); ParseOK=ParseGenericDllData_ELF(LibBuf, LibSize); free(LibBuf); } else { DynMsg("Unable to read \"%s\" as file. Trying to use information from Dl_info.",szLibName); ParseOK=ParseGenericDllData_ELF(DllBase, LoadLibSize); } if (!ParseOK) { DynErr(false, "Failed to parse \"%s\"", szLibName); return false; } } #endif else { DynErr(false, "Failed find library at %p",FuncAddr); return false; } return true; }
// Returns the HMODULE that contains the specified memory address static HMODULE ModuleFromAddress(PVOID pv) { MEMORY_BASIC_INFORMATION mbi; return((VirtualQuery(pv, &mbi, sizeof(mbi)) != 0) ? (HMODULE) mbi.AllocationBase : NULL); }
HMODULE WINAPI GetModuleHandleUni() { MEMORY_BASIC_INFORMATION mbi; VirtualQuery((LPCVOID)GetModuleHandleUni, &mbi, sizeof(mbi)); return (HMODULE)mbi.AllocationBase; }
static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget) { // We have to place trampolines within +/- 2GB of target. // The allocation code assumes that PDETOUR_TRAMPOLINE pLo = (PDETOUR_TRAMPOLINE) ((pbTarget > (PBYTE)0x7ff80000) ? pbTarget - 0x7ff80000 : (PBYTE)(ULONG_PTR)DETOUR_REGION_SIZE); PDETOUR_TRAMPOLINE pHi = (PDETOUR_TRAMPOLINE) ((pbTarget < (PBYTE)0xffffffff80000000) ? pbTarget + 0x7ff80000 : (PBYTE)0xfffffffffff80000); DETOUR_TRACE(("[%p..%p..%p]\n", pLo, pbTarget, pHi)); PDETOUR_TRAMPOLINE pTrampoline = NULL; // Insure that there is a default region. if (s_pRegion == NULL && s_pRegions != NULL) { s_pRegion = s_pRegions; } // First check the default region for an valid free block. if (s_pRegion != NULL && s_pRegion->pFree != NULL && s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { found_region: pTrampoline = s_pRegion->pFree; // do a last sanity check on region. if (pTrampoline < pLo || pTrampoline > pHi) { return NULL; } s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain; memset(pTrampoline, 0xcc, sizeof(*pTrampoline)); return pTrampoline; } // Then check the existing regions for a valid free block. for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) { if (s_pRegion != NULL && s_pRegion->pFree != NULL && s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { goto found_region; } } // We need to allocate a new region. // Round pbTarget down to 64K block. pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff); // First we search down (within the valid region) DETOUR_TRACE((" Looking for free region below %p:\n", pbTarget)); PBYTE pbTry; for (pbTry = pbTarget; pbTry > (PBYTE)pLo;) { MEMORY_BASIC_INFORMATION mbi; DETOUR_TRACE((" Try %p\n", pbTry)); if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 && pbTry <= (PBYTE)(ULONG_PTR)0x80000000) { // Skip region reserved for system DLLs. pbTry = (PBYTE)(ULONG_PTR)(0x70000000 - DETOUR_REGION_SIZE); } if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { break; } DETOUR_TRACE((" Try %p => %p..%p %6x\n", pbTry, mbi.BaseAddress, (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, mbi.State)); if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry, DETOUR_REGION_SIZE, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (s_pRegion != NULL) { alloced_region: s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE; s_pRegion->pFree = NULL; s_pRegion->pNext = s_pRegions; s_pRegions = s_pRegion; DETOUR_TRACE((" Allocated region %p..%p\n\n", s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1)); // Put everything but the first trampoline on the free list. PBYTE pFree = NULL; pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1; for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) { pTrampoline[i].pbRemain = pFree; pFree = (PBYTE)&pTrampoline[i]; } s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree; goto found_region; } else { DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError())); break; } } pbTry = (PBYTE)mbi.AllocationBase - DETOUR_REGION_SIZE; } DETOUR_TRACE((" Looking for free region above %p:\n", pbTarget)); for (pbTry = pbTarget; pbTry < (PBYTE)pHi;) { MEMORY_BASIC_INFORMATION mbi; if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 && pbTry <= (PBYTE)(ULONG_PTR)0x80000000) { // Skip region reserved for system DLLs. pbTry = (PBYTE)(ULONG_PTR)(0x80000000 + DETOUR_REGION_SIZE); } if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { break; } DETOUR_TRACE((" Try %p => %p..%p %6x\n", pbTry, mbi.BaseAddress, (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, mbi.State)); if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1); if (extra != 0) { // WinXP64 returns free areas that aren't REGION aligned to // 32-bit applications. ULONG_PTR adjust = DETOUR_REGION_SIZE - extra; mbi.RegionSize -= adjust; ((PBYTE&)mbi.BaseAddress) += adjust; DETOUR_TRACE(("--Try %p => %p..%p %6x\n", pbTry, mbi.BaseAddress, (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, mbi.State)); pbTry = (PBYTE)mbi.BaseAddress; } s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry, DETOUR_REGION_SIZE, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (s_pRegion != NULL) { goto alloced_region; } else { DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError())); } } pbTry = (PBYTE)mbi.BaseAddress + mbi.RegionSize; } DETOUR_TRACE(("Couldn't find available memory region!\n")); return NULL; }