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;
}
Example #2
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;
}
Example #3
0
/*******************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
}
Example #4
0
/*
==================
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 );
}
Example #5
0
// 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();
}
Example #7
0
    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();
}
Example #8
0
/***********************************************************************
 *           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 */
}
Example #9
0
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);
}
Example #10
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;
}
Example #11
0
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;
}
Example #14
0
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;
}
Example #15
0
uintptr_t AVMPI_getThreadStackBase()
{
    MEMORY_BASIC_INFORMATION __mib;
    VirtualQuery(&__mib, &__mib, sizeof(MEMORY_BASIC_INFORMATION));
    return (uintptr_t)__mib.BaseAddress + __mib.RegionSize;
}
Example #16
0
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;
}
Example #17
0
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;
}
Example #18
0
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 ) ;
}
Example #20
0
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;
}
Example #22
0
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();
}
Example #26
0
File: winvlc.c Project: Geal/vlc
/*****************************************************************************
 * 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 );
    }
}
Example #27
0
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;
}
Example #28
0
// 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);
}
Example #29
0
HMODULE WINAPI GetModuleHandleUni()
{
	MEMORY_BASIC_INFORMATION mbi;
	VirtualQuery((LPCVOID)GetModuleHandleUni, &mbi, sizeof(mbi));
	return (HMODULE)mbi.AllocationBase;
}
Example #30
-1
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;
}