Domanda

Stavo pensando di provare la mia mano a qualche compilataion JIT (solo per il gusto di apprendimento) e sarebbe bello avere il lavoro multi-piattaforma da quando corro tutti i principali tre a casa (Windows, OS X, Linux) . Con questo in mente, voglio sapere se c'è qualche modo per uscire di utilizzare le funzioni virtuali finestre di memoria per allocare la memoria con i permessi di esecuzione. Sarebbe piacevole da usare solo malloc o nuovo e puntare il processore ad un tale blocco.

Qualche consiglio?

È stato utile?

Soluzione

Una possibilità è quella di renderlo un requisito che le installazioni di Windows in esecuzione il programma di essere sia configurato per DEP AlwaysOff (cattiva idea) o DEP OptOut (migliore idea).

Questo può essere configurato (sotto WinXp SP2 + e Win2k3 SP1 + almeno), modificando il file boot.ini di avere l'impostazione:

/noexecute=OptOut

e quindi configurare il programma individuale di opt-out, scegliendo (sotto XP):

Start button
    Control Panel
        System
            Advanced tab
                Performance Settings button
                    Data Execution Prevention tab

Questo dovrebbe consentire di eseguire codice da all'interno del programma che si crea al volo in blocchi malloc().

Tenete a mente che questo rende il programma più suscettibili agli attacchi che DEP è stato lo scopo di prevenire.

Sembra che questo è possibile anche in Windows 2008 con il comando:

bcdedit.exe /set {current} nx OptOut

Ma, ad essere onesti, se si desidera solo per ridurre al minimo il codice dipendente dalla piattaforma, che è facile da fare semplicemente isolando il codice in una singola funzione, qualcosa come:

void *MallocWithoutDep(size_t sz) {
    #if defined _IS_WINDOWS
        return VirtualMalloc(sz, OPT_DEP_OFF); // or whatever
    #elif defined IS_LINUX
        // Do linuxy thing
    #elif defined IS_MACOS
        // Do something almost certainly inexplicable
    #endif
}

Se mettete tutte le vostre piattaforme funzioni dipendenti nelle proprie file, il resto del codice è automaticamente indipendente dalla piattaforma.

Altri suggerimenti

DEP è appena svolta fuori permesso di esecuzione da ogni pagina non il codice della memoria. Il codice di applicazione viene caricata nella memoria che ha permesso di esecuzione; e ci sono molte squadre investigative comuni, che funziona in Windows / Linux / MacOSX, anche quando DEP è attivo. Questo è perché c'è un modo per allocare dinamicamente la memoria con i permessi necessari insieme.

Di solito, malloc pianura non deve essere usato, perché le autorizzazioni sono per-pagina. Allineamento della memoria malloced di pagine è ancora possibile al prezzo di un certo overhead. Se non si utilizza malloc, un po 'di gestione della memoria personalizzati (solo per codice eseguibile). gestione personalizzato è un modo comune di fare JIT.

C'è una soluzione dal progetto Chromium, che utilizza JIT per JavaScript V8 VM e che è cross-platform. Per essere cross-platform, la funzione necessaria è implementata in diversi file e sono selezionati in fase di compilazione.

Linux: (cromo src / V8 / src / platform-linux.cc) bandiera è PROT_EXEC di mmap ()

.
void* OS::Allocate(const size_t requested,
                   size_t* allocated,
                   bool is_executable) {
  const size_t msize = RoundUp(requested, AllocateAlignment());
  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
  void* addr = OS::GetRandomMmapAddr();
  void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  if (mbase == MAP_FAILED) {
    /** handle error */
    return NULL;
  }
  *allocated = msize;
  UpdateAllocatedSpaceLimits(mbase, msize);
  return mbase;
}

Win32 (src / V8 / src / platform-win32.cc): bandiera è PAGE_EXECUTE_READWRITE di VirtualAlloc

void* OS::Allocate(const size_t requested,
                   size_t* allocated,
                   bool is_executable) {
  // The address range used to randomize RWX allocations in OS::Allocate
  // Try not to map pages into the default range that windows loads DLLs
  // Use a multiple of 64k to prevent committing unused memory.
  // Note: This does not guarantee RWX regions will be within the
  // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
#ifdef V8_HOST_ARCH_64_BIT
  static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
  static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
#else
  static const intptr_t kAllocationRandomAddressMin = 0x04000000;
  static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
#endif

  // VirtualAlloc rounds allocated size to page size automatically.
  size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));
  intptr_t address = 0;

  // Windows XP SP2 allows Data Excution Prevention (DEP).
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;

  // For exectutable pages try and randomize the allocation address
  if (prot == PAGE_EXECUTE_READWRITE &&
      msize >= static_cast<size_t>(Page::kPageSize)) {
    address = (V8::RandomPrivate(Isolate::Current()) << kPageSizeBits)
      | kAllocationRandomAddressMin;
    address &= kAllocationRandomAddressMax;
  }

  LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address),
                              msize,
                              MEM_COMMIT | MEM_RESERVE,
                              prot);
  if (mbase == NULL && address != 0)
    mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);

  if (mbase == NULL) {
    LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed"));
    return NULL;
  }

  ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment()));

  *allocated = msize;
  UpdateAllocatedSpaceLimits(mbase, static_cast<int>(msize));
  return mbase;
}

MacOS (src / V8 / src / platform-macos.cc): bandiera è PROT_EXEC di mmap, proprio come Linux o altri POSIX

.
void* OS::Allocate(const size_t requested,
                   size_t* allocated,
                   bool is_executable) {
  const size_t msize = RoundUp(requested, getpagesize());
  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
  void* mbase = mmap(OS::GetRandomMmapAddr(),
                     msize,
                     prot,
                     MAP_PRIVATE | MAP_ANON,
                     kMmapFd,
                     kMmapFdOffset);
  if (mbase == MAP_FAILED) {
    LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
    return NULL;
  }
  *allocated = msize;
  UpdateAllocatedSpaceLimits(mbase, msize);
  return mbase;
}

E voglio anche notare, in questo modo bcdedit.exe-come deve essere utilizzato solo per molto vecchi programmi, che crea nuovo codice eseguibile nella memoria, ma non imposta un immobile Exec in questa pagina. Per i programmi più recenti, come Firefox o Chrome / Chromium, o qualsiasi JIT moderna, DEP dovrebbe essere attivo, e JIT gestirà i permessi di memoria in maniera a grana fine.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top