static void* MapAlignedPagesSlow(size_t size, size_t alignment) { /* Overallocate and unmap the region's edges. */ size_t reqSize = size + alignment - pageSize; void* region = MapMemory(reqSize); if (!region) return nullptr; void* regionEnd = (void*)(uintptr_t(region) + reqSize); void* front; void* end; if (growthDirection <= 0) { size_t offset = OffsetFromAligned(regionEnd, alignment); end = (void*)(uintptr_t(regionEnd) - offset); front = (void*)(uintptr_t(end) - size); } else { size_t offset = OffsetFromAligned(region, alignment); front = (void*)(uintptr_t(region) + (offset ? alignment - offset : 0)); end = (void*)(uintptr_t(front) + size); } if (front != region) UnmapPages(region, uintptr_t(front) - uintptr_t(region)); if (end != regionEnd) UnmapPages(end, uintptr_t(regionEnd) - uintptr_t(end)); return front; }
/* * In a low memory or high fragmentation situation, alignable chunks of the * desired size may still be available, even if there are no more contiguous * free chunks that meet the |size + alignment - pageSize| requirement of * MapAlignedPagesSlow. In this case, try harder to find an alignable chunk * by temporarily holding onto the unaligned parts of each chunk until the * allocator gives us a chunk that either is, or can be aligned. */ static void* MapAlignedPagesLastDitch(size_t size, size_t alignment) { void* tempMaps[MaxLastDitchAttempts]; int attempt = 0; void* p = MapMemory(size); if (OffsetFromAligned(p, alignment) == 0) return p; for (; attempt < MaxLastDitchAttempts; ++attempt) { GetNewChunk(&p, tempMaps + attempt, size, alignment); if (OffsetFromAligned(p, alignment) == 0) { if (tempMaps[attempt]) UnmapPages(tempMaps[attempt], size); break; } if (!tempMaps[attempt]) break; /* Bail if GetNewChunk failed. */ } if (OffsetFromAligned(p, alignment)) { UnmapPages(p, size); p = nullptr; } while (--attempt >= 0) UnmapPages(tempMaps[attempt], size); return p; }
/*++ Routine Description: Opens and memory maps a file using Unix services. If BaseAddress is non zero the process will try and allocate the memory starting at BaseAddress. Arguments: FileName - The name of the file to open and map MapSize - The amount of the file to map in bytes CreationDisposition - The flags to pass to CreateFile(). Use to create new files for memory emulation, and exiting files for firmware volume emulation BaseAddress - The base address of the mapped file in the user address space. If passed in as NULL the a new memory region is used. If passed in as non NULL the request memory region is used for the mapping of the file into the process space. Length - The size of the mapped region in bytes Returns: EFI_SUCCESS - The file was opened and mapped. EFI_NOT_FOUND - FileName was not found in the current directory EFI_DEVICE_ERROR - An error occured attempting to map the opened file **/ EFI_STATUS MapFile ( IN CHAR8 *FileName, IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, OUT UINT64 *Length ) { int fd; VOID *res; UINTN FileSize; fd = open (FileName, O_RDWR); if (fd < 0) { return EFI_NOT_FOUND; } FileSize = lseek (fd, 0, SEEK_END); res = MapMemory (fd, FileSize, PROT_READ | PROT_EXEC, MAP_PRIVATE); close (fd); if (res == NULL) { perror ("MapFile() Failed"); return EFI_DEVICE_ERROR; } *Length = (UINT64) FileSize; *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res; return EFI_SUCCESS; }
void* MapAlignedPages(size_t size, size_t alignment) { MOZ_ASSERT(size >= alignment); MOZ_ASSERT(size % alignment == 0); MOZ_ASSERT(size % pageSize == 0); MOZ_ASSERT(alignment % allocGranularity == 0); void* p = MapMemory(size); /* Special case: If we want page alignment, no further work is needed. */ if (alignment == allocGranularity) return p; if (OffsetFromAligned(p, alignment) == 0) return p; void* retainedAddr; GetNewChunk(&p, &retainedAddr, size, alignment); if (retainedAddr) UnmapPages(retainedAddr, size); if (p) { if (OffsetFromAligned(p, alignment) == 0) return p; UnmapPages(p, size); } p = MapAlignedPagesSlow(size, alignment); if (!p) return MapAlignedPagesLastDitch(size, alignment); MOZ_ASSERT(OffsetFromAligned(p, alignment) == 0); return p; }
static void* MapAlignedPagesSlow(size_t size, size_t alignment) { /* * Windows requires that there be a 1:1 mapping between VM allocation * and deallocation operations. Therefore, take care here to acquire the * final result via one mapping operation. This means unmapping any * preliminary result that is not correctly aligned. */ void* p; do { /* * Over-allocate in order to map a memory region that is definitely * large enough, then deallocate and allocate again the correct size, * within the over-sized mapping. * * Since we're going to unmap the whole thing anyway, the first * mapping doesn't have to commit pages. */ size_t reserveSize = size + alignment - pageSize; p = MapMemory(reserveSize, MEM_RESERVE); if (!p) return nullptr; void* chunkStart = (void*)AlignBytes(uintptr_t(p), alignment); UnmapPages(p, reserveSize); p = MapMemoryAt(chunkStart, size, MEM_COMMIT | MEM_RESERVE); /* Failure here indicates a race with another thread, so try again. */ } while (!p); return p; }
/*++ Routine Description: This service is called from Index == 0 until it returns EFI_UNSUPPORTED. It allows discontinuous memory regions to be supported by the emulator. It uses gSystemMemory[] and gSystemMemoryCount that were created by parsing the host environment variable EFI_MEMORY_SIZE. The size comes from the varaible and the address comes from the call to UnixOpenFile. Arguments: Index - Which memory region to use MemoryBase - Return Base address of memory region MemorySize - Return size in bytes of the memory region Returns: EFI_SUCCESS - If memory region was mapped EFI_UNSUPPORTED - If Index is not supported **/ EFI_STATUS SecUnixPeiAutoScan ( IN UINTN Index, OUT EFI_PHYSICAL_ADDRESS *MemoryBase, OUT UINT64 *MemorySize ) { void *res; if (Index >= gSystemMemoryCount) { return EFI_UNSUPPORTED; } *MemoryBase = 0; res = MapMemory ( 0, gSystemMemory[Index].Size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS ); if (res == MAP_FAILED) { return EFI_DEVICE_ERROR; } *MemorySize = gSystemMemory[Index].Size; *MemoryBase = (UINTN)res; gSystemMemory[Index].Memory = *MemoryBase; return EFI_SUCCESS; }
bool GrVkBuffer::vkUpdateData(const GrVkGpu* gpu, const void* src, size_t srcSizeInBytes, bool* createdNewBuffer) { SkASSERT(!this->vkIsMapped()); VALIDATE(); if (srcSizeInBytes > fDesc.fSizeInBytes) { return false; } if (!fResource->unique()) { // in use by the command buffer, so we need to create a new one fResource->unref(gpu); fResource = Create(gpu, fDesc); if (createdNewBuffer) { *createdNewBuffer = true; } } void* mapPtr; VkResult err = VK_CALL(gpu, MapMemory(gpu->device(), alloc(), 0, srcSizeInBytes, 0, &mapPtr)); if (VK_SUCCESS != err) { return false; } memcpy(mapPtr, src, srcSizeInBytes); VK_CALL(gpu, UnmapMemory(gpu->device(), alloc())); return true; }
int main(int argc, char *argv[]) { HIJACK *hijack; FUNC *func; unsigned long addr; PLT *plts, *plt; if (argc != 2) usage(argv[0]); hijack = InitHijack(); ToggleFlag(hijack, F_DEBUG); ToggleFlag(hijack, F_DEBUG_VERBOSE); AssignPid(hijack, atoi(argv[1])); if (Attach(hijack) != ERROR_NONE) { fprintf(stderr, "[-] Couldn't attach!\n"); exit(EXIT_FAILURE); } if (LocateAllFunctions(hijack) != ERROR_NONE) { fprintf(stderr, "[-] Couldn't locate all functions!\n"); exit(EXIT_FAILURE); } if (LocateSystemCall(hijack) != ERROR_NONE) { fprintf(stderr, "[-] Couldn't locate system call!\n"); exit(EXIT_FAILURE); } addr = MapMemory(hijack, NULL, 8192, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_SHARED); if (GetErrorCode(hijack) != ERROR_NONE) { fprintf(stderr, "[-] %s\n", GetErrorString(hijack)); perror("ptrace"); } printf("[*] PLT/GOT @ 0x%016lx\n", hijack->pltgot); printf("[*] Baseaddr @ 0x%016lx\n", hijack->baseaddr); printf("[*] Syscall @ 0x%016lx\n", hijack->syscalladdr); printf("[*] addr @ 0x%016lx\n", addr); Detach(hijack); return 0; }
void* AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) { #define NEED_PAGE_ALIGNED 0 size_t pa_start; // Page aligned starting size_t pa_end; // Page aligned ending size_t pa_size; // Total page aligned size struct stat st; uint8_t* buf; // Make sure file exists and do sanity check for offset and size. if (fstat(fd, &st) < 0 || offset >= (size_t) st.st_size || length == 0 || length > (size_t) st.st_size - offset) return nullptr; // Check for minimal alignment requirement. #if NEED_PAGE_ALIGNED alignment = std::max(alignment, pageSize); #endif if (offset & (alignment - 1)) return nullptr; // Page aligned starting of the offset. pa_start = offset & ~(pageSize - 1); // Calculate page aligned ending by adding one page to the page aligned // starting of data end position(offset + length - 1). pa_end = ((offset + length - 1) & ~(pageSize - 1)) + pageSize; pa_size = pa_end - pa_start; // Ask for a continuous memory location. buf = (uint8_t*) MapMemory(pa_size); if (!buf) return nullptr; buf = (uint8_t*) MapMemoryAt(buf, pa_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, pa_start); if (!buf) return nullptr; // Reset the data before target file, which we don't need to see. memset(buf, 0, offset - pa_start); // Reset the data after target file, which we don't need to see. memset(buf + (offset - pa_start) + length, 0, pa_end - (offset + length)); return buf + (offset - pa_start); }
/* * mmap calls don't have to be matched with calls to munmap, so we can unmap * just the pages we don't need. However, as we don't know a priori if addresses * are handed out in increasing or decreasing order, we have to try both * directions (depending on the environment, one will always fail). */ static void GetNewChunk(void** aAddress, void** aRetainedAddr, size_t size, size_t alignment) { void* address = *aAddress; void* retainedAddr = nullptr; bool addrsGrowDown = growthDirection <= 0; int i = 0; for (; i < 2; ++i) { /* Try the direction indicated by growthDirection. */ if (addrsGrowDown) { size_t offset = OffsetFromAligned(address, alignment); void* head = (void*)((uintptr_t)address - offset); void* tail = (void*)((uintptr_t)head + size); if (MapMemoryAt(head, offset)) { UnmapPages(tail, offset); if (growthDirection >= -8) --growthDirection; address = head; break; } } else { size_t offset = alignment - OffsetFromAligned(address, alignment); void* head = (void*)((uintptr_t)address + offset); void* tail = (void*)((uintptr_t)address + size); if (MapMemoryAt(tail, offset)) { UnmapPages(address, offset); if (growthDirection <= 8) ++growthDirection; address = head; break; } } /* If we're confident in the growth direction, don't try the other. */ if (growthDirection < -8 || growthDirection > 8) break; /* If that failed, try the opposite direction. */ addrsGrowDown = !addrsGrowDown; } /* If our current chunk cannot be aligned, see if the next one is aligned. */ if (OffsetFromAligned(address, alignment)) { retainedAddr = address; address = MapMemory(size); } *aAddress = address; *aRetainedAddr = retainedAddr; }
void* GrVkBuffer::vkMap(const GrVkGpu* gpu) { VALIDATE(); SkASSERT(!this->vkIsMapped()); if (!fResource->unique()) { // in use by the command buffer, so we need to create a new one fResource->unref(gpu); fResource = Create(gpu, fDesc); } VkResult err = VK_CALL(gpu, MapMemory(gpu->device(), alloc(), 0, VK_WHOLE_SIZE, 0, &fMapPtr)); if (err) { fMapPtr = nullptr; } VALIDATE(); return fMapPtr; }
/* * On Windows, map and unmap calls must be matched, so we deallocate the * unaligned chunk, then reallocate the unaligned part to block off the * old address and force the allocator to give us a new one. */ static void GetNewChunk(void** aAddress, void** aRetainedAddr, size_t size, size_t alignment) { void* address = *aAddress; void* retainedAddr = nullptr; do { size_t retainedSize; size_t offset = OffsetFromAligned(address, alignment); if (!offset) break; UnmapPages(address, size); retainedSize = alignment - offset; retainedAddr = MapMemoryAt(address, retainedSize, MEM_RESERVE); address = MapMemory(size, MEM_COMMIT | MEM_RESERVE); /* If retainedAddr is null here, we raced with another thread. */ } while (!retainedAddr); *aAddress = address; *aRetainedAddr = retainedAddr; }
void GrVkBuffer::internalMap(GrVkGpu* gpu, size_t size, bool* createdNewBuffer) { VALIDATE(); SkASSERT(!this->vkIsMapped()); if (!fResource->unique()) { if (fDesc.fDynamic) { // in use by the command buffer, so we need to create a new one fResource->recycle(gpu); fResource = this->createResource(gpu, fDesc); if (createdNewBuffer) { *createdNewBuffer = true; } } else { SkASSERT(fMapPtr); this->addMemoryBarrier(gpu, buffer_type_to_access_flags(fDesc.fType), VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false); } } if (fDesc.fDynamic) { const GrVkAlloc& alloc = this->alloc(); VkResult err = VK_CALL(gpu, MapMemory(gpu->device(), alloc.fMemory, alloc.fOffset + fOffset, size, 0, &fMapPtr)); if (err) { fMapPtr = nullptr; } } else { if (!fMapPtr) { fMapPtr = new unsigned char[this->size()]; } } VALIDATE(); }
void* GrVkBuffer::vkMap(const GrVkGpu* gpu) { VALIDATE(); SkASSERT(!this->vkIsMapped()); if (!fResource->unique()) { // in use by the command buffer, so we need to create a new one fResource->unref(gpu); fResource = Create(gpu, fDesc); } if (fDesc.fDynamic) { const GrVkAlloc& alloc = this->alloc(); VkResult err = VK_CALL(gpu, MapMemory(gpu->device(), alloc.fMemory, alloc.fOffset + fOffset, fDesc.fSizeInBytes, 0, &fMapPtr)); if (err) { fMapPtr = nullptr; } } else { fMapPtr = new unsigned char[this->size()]; } VALIDATE(); return fMapPtr; }
int main ( IN int Argc, IN char **Argv, IN char **Envp ) /*++ Routine Description: Main entry point to SEC for Unix. This is a unix program Arguments: Argc - Number of command line arguments Argv - Array of command line argument strings Envp - Array of environmemt variable strings Returns: 0 - Normal exit 1 - Abnormal exit --*/ { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS InitialStackMemory; UINT64 InitialStackMemorySize; UINTN Index; UINTN Index1; UINTN Index2; UINTN PeiIndex; CHAR8 *FileName; BOOLEAN Done; VOID *PeiCoreFile; CHAR16 *MemorySizeStr; CHAR16 *FirmwareVolumesStr; UINTN *StackPointer; setbuf(stdout, 0); setbuf(stderr, 0); MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdUnixMemorySizeForSecMain); FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdUnixFirmwareVolume); printf ("\nEDK SEC Main UNIX Emulation Environment from edk2.sourceforge.net\n"); #ifdef __APPLE__ // // We can't use dlopen on OS X, so we need a scheme to get symboles into gdb // We need to create a temp file that contains gdb commands so we can load // symbols when we load every PE/COFF image. // Index = strlen (*Argv); gGdbWorkingFileName = malloc (Index + strlen(".gdb") + 1); strcpy (gGdbWorkingFileName, *Argv); strcat (gGdbWorkingFileName, ".gdb"); #endif // // Allocate space for gSystemMemory Array // gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1; gSystemMemory = calloc (gSystemMemoryCount, sizeof (UNIX_SYSTEM_MEMORY)); if (gSystemMemory == NULL) { printf ("ERROR : Can not allocate memory for system. Exiting.\n"); exit (1); } // // Allocate space for gSystemMemory Array // gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1; gFdInfo = calloc (gFdInfoCount, sizeof (UNIX_FD_INFO)); if (gFdInfo == NULL) { printf ("ERROR : Can not allocate memory for fd info. Exiting.\n"); exit (1); } // // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION) // printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdUnixBootMode)); // // Open up a 128K file to emulate temp memory for PEI. // on a real platform this would be SRAM, or using the cache as RAM. // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping // InitialStackMemorySize = STACK_SIZE; InitialStackMemory = (UINTN)MapMemory(0, (UINT32) InitialStackMemorySize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE); if (InitialStackMemory == 0) { printf ("ERROR : Can not open SecStack Exiting\n"); exit (1); } printf (" SEC passing in %u KB of temp RAM at 0x%08lx to PEI\n", (unsigned int)(InitialStackMemorySize / 1024), (unsigned long)InitialStackMemory); for (StackPointer = (UINTN*) (UINTN) InitialStackMemory; StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize); StackPointer ++) { *StackPointer = 0x5AA55AA5; } // // Open All the firmware volumes and remember the info in the gFdInfo global // FileName = (CHAR8 *)malloc (StrLen (FirmwareVolumesStr) + 1); if (FileName == NULL) { printf ("ERROR : Can not allocate memory for firmware volume string\n"); exit (1); } Index2 = 0; for (Done = FALSE, Index = 0, PeiIndex = 0, PeiCoreFile = NULL; FirmwareVolumesStr[Index2] != 0; Index++) { for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) FileName[Index1++] = FirmwareVolumesStr[Index2]; if (FirmwareVolumesStr[Index2] == '!') Index2++; FileName[Index1] = '\0'; // // Open the FD and remmeber where it got mapped into our processes address space // Status = MapFile ( FileName, &gFdInfo[Index].Address, &gFdInfo[Index].Size ); if (EFI_ERROR (Status)) { printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status); exit (1); } printf (" FD loaded from %s at 0x%08lx", FileName, (unsigned long)gFdInfo[Index].Address); if (PeiCoreFile == NULL) { // // Assume the beginning of the FD is an FV and look for the PEI Core. // Load the first one we find. // Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile); if (!EFI_ERROR (Status)) { PeiIndex = Index; printf (" contains SEC Core"); } } printf ("\n"); } // // Calculate memory regions and store the information in the gSystemMemory // global for later use. The autosizing code will use this data to // map this memory into the SEC process memory space. // Index1 = 0; Index = 0; while (1) { UINTN val = 0; // // Save the size of the memory. // while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') { val = val * 10 + MemorySizeStr[Index1] - '0'; Index1++; } gSystemMemory[Index++].Size = val * 0x100000; if (MemorySizeStr[Index1] == 0) break; Index1++; } printf ("\n"); // // Hand off to PEI Core // SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile); // // If we get here, then the PEI Core returned. This is an error as PEI should // always hand off to DXE. // printf ("ERROR : PEI Core returned\n"); exit (1); }
EFI_STATUS MapFile ( IN CHAR8 *FileName, IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, OUT UINT64 *Length ) /*++ Routine Description: Opens and memory maps a file using Unix services. If BaseAddress is non zero the process will try and allocate the memory starting at BaseAddress. Arguments: FileName - The name of the file to open and map MapSize - The amount of the file to map in bytes CreationDisposition - The flags to pass to CreateFile(). Use to create new files for memory emulation, and exiting files for firmware volume emulation BaseAddress - The base address of the mapped file in the user address space. If passed in as NULL the a new memory region is used. If passed in as non NULL the request memory region is used for the mapping of the file into the process space. Length - The size of the mapped region in bytes Returns: EFI_SUCCESS - The file was opened and mapped. EFI_NOT_FOUND - FileName was not found in the current directory EFI_DEVICE_ERROR - An error occured attempting to map the opened file --*/ { int fd; VOID *res; UINTN FileSize; fd = open (FileName, O_RDONLY); if (fd < 0) return EFI_NOT_FOUND; FileSize = lseek (fd, 0, SEEK_END); #if 0 if (IsMain) { /* Read entry address. */ lseek (fd, FileSize - 0x20, SEEK_SET); if (read (fd, &EntryAddress, 4) != 4) { close (fd); return EFI_DEVICE_ERROR; } } #endif res = MapMemory(fd, FileSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE); close (fd); if (res == MAP_FAILED) return EFI_DEVICE_ERROR; *Length = (UINT64) FileSize; *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res; return EFI_SUCCESS; }
int main(int argc, char *argv[]) { HIJACK *hijack; FUNC *funcs, *func; unsigned long shellcode_addr, filename_addr, dlopen_addr, dlsym_addr, funcname_addr, pltgot_addr; struct stat sb; char *shellcode, *p1; int fd; struct user_regs_struct *regs, *backup; if (argc != 5) usage(argv[0]); hijack = InitHijack(); ToggleFlag(hijack, F_DEBUG); ToggleFlag(hijack, F_DEBUG_VERBOSE); AssignPid(hijack, atoi(argv[1])); if (Attach(hijack) != ERROR_NONE) { fprintf(stderr, "[-] Couldn't attach!\n"); exit(EXIT_FAILURE); } backup = GetRegs(hijack); regs = malloc(sizeof(struct user_regs_struct)); stat(argv[2], &sb); shellcode = malloc(sb.st_size); fd = open(argv[2], O_RDONLY); read(fd, shellcode, sb.st_size); close(fd); LocateAllFunctions(hijack); funcs = FindFunctionInLibraryByName(hijack, "/lib/libdl.so.2", "dlopen"); if (!(funcs)) { fprintf(stderr, "[-] Couldn't locate dlopen!\n"); exit(EXIT_FAILURE); } dlopen_addr = funcs->vaddr; printf("dlopen_addr: 0x%08lx\n", dlopen_addr); funcs = FindFunctionInLibraryByName(hijack, "/lib/libdl.so.2", "dlsym"); if (!(funcs)) { fprintf(stderr, "[-] Couldn't locate dlsym!\n"); exit(EXIT_FAILURE); } dlsym_addr = funcs->vaddr; printf("dlsym_addr: 0x%08lx\n", dlsym_addr); memcpy(regs, backup, sizeof(struct user_regs_struct)); LocateSystemCall(hijack); filename_addr = MapMemory(hijack, (unsigned long)NULL, 4096,PROT_READ | PROT_EXEC | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE); memcpy(regs, backup, sizeof(struct user_regs_struct)); p1 = memmem(shellcode, sb.st_size, "\x22\x22\x22\x22", 4); memcpy(p1, &filename_addr, 4); funcname_addr = filename_addr + strlen(argv[3]) + 1; shellcode_addr = funcname_addr + strlen(argv[4]) + 1; printf("filename_addr: 0x%08lx\n", filename_addr); printf("shellcode_addr: 0x%08lx\n", shellcode_addr); printf("esp: 0x%08lx\n", regs->esp); printf("eip: 0x%08lx\n", regs->eip); p1 = memmem(shellcode, sb.st_size, "\x33\x33\x33\x33", 4); memcpy(p1, &dlopen_addr, 4); p1 = memmem(shellcode, sb.st_size, "\x44\x44\x44\x44", 4); memcpy(p1, &funcname_addr, 4); p1 = memmem(shellcode, sb.st_size, "\x55\x55\x55\x55", 4); memcpy(p1, &dlsym_addr, 4); funcs = FindAllFunctionsByName(hijack, argv[4], false); for (func = funcs; func != NULL; func = func->next) { if (!(func->name)) continue; pltgot_addr = FindFunctionInGot(hijack, hijack->pltgot, func->vaddr); if (pltgot_addr > 0) break; } printf("pltgot_addr: 0x%08lx\n", pltgot_addr); p1 = memmem(shellcode, sb.st_size, "\x66\x66\x66\x66", 4); memcpy(p1, &pltgot_addr, 4); WriteData(hijack, filename_addr, (unsigned char *)argv[3], strlen(argv[3])); WriteData(hijack, funcname_addr, (unsigned char *)argv[4], strlen(argv[4])); WriteData(hijack, shellcode_addr, (unsigned char *)shellcode, sb.st_size); regs->esp -= 4; SetRegs(hijack, regs); WriteData(hijack, regs->esp, &(regs->eip), 4); regs->eip = shellcode_addr; if (regs->orig_eax >= 0) { switch (regs->eax) { case -514: /* -ERESTARTNOHAND */ case -512: /* -ERESTARTSYS */ case -513: /* -ERESTARTNOINTR */ case -516: /* -ERESTART_RESTARTBLOCK */ regs->eip += 2; break; } } SetRegs(hijack, regs); Detach(hijack); return 0; }
/*++ Routine Description: Main entry point to SEC for Unix. This is a unix program Arguments: Argc - Number of command line arguments Argv - Array of command line argument strings Envp - Array of environment variable strings Returns: 0 - Normal exit 1 - Abnormal exit **/ int main ( IN int Argc, IN char **Argv, IN char **Envp ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS InitialStackMemory; UINT64 InitialStackMemorySize; UINTN Index; UINTN Index1; UINTN Index2; UINTN PeiIndex; CHAR8 *FileName; BOOLEAN Done; EFI_PEI_FILE_HANDLE FileHandle; VOID *SecFile; CHAR16 *MemorySizeStr; CHAR16 *FirmwareVolumesStr; UINTN *StackPointer; FILE *GdbTempFile; // // Xcode does not support sourcing gdb scripts directly, so the Xcode XML // has a break point script to source the GdbRun script. // SecGdbConfigBreak (); // // If dlopen doesn't work, then we build a gdb script to allow the // symbols to be loaded. // Index = strlen (*Argv); gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1); strcpy (gGdbWorkingFileName, *Argv); strcat (gGdbWorkingFileName, ".gdb"); // // Empty out the gdb symbols script file. // GdbTempFile = fopen (gGdbWorkingFileName, "w"); if (GdbTempFile != NULL) { fclose (GdbTempFile); } printf ("\nEDK II UNIX Host Emulation Environment from http://www.tianocore.org/edk2/\n"); setbuf (stdout, 0); setbuf (stderr, 0); MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize); FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume); // // PPIs pased into PEI_CORE // AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi); SecInitThunkProtocol (); // // Emulator Bus Driver Thunks // AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE); AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE); AddThunkProtocol (&gBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE); AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE); // // Emulator other Thunks // AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE); // EmuSecLibConstructor (); gPpiList = GetThunkPpiList (); // // Allocate space for gSystemMemory Array // gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1; gSystemMemory = AllocateZeroPool (gSystemMemoryCount * sizeof (EMU_SYSTEM_MEMORY)); if (gSystemMemory == NULL) { printf ("ERROR : Can not allocate memory for system. Exiting.\n"); exit (1); } // // Allocate space for gSystemMemory Array // gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1; gFdInfo = AllocateZeroPool (gFdInfoCount * sizeof (EMU_FD_INFO)); if (gFdInfo == NULL) { printf ("ERROR : Can not allocate memory for fd info. Exiting.\n"); exit (1); } printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode)); // // Open up a 128K file to emulate temp memory for SEC. // on a real platform this would be SRAM, or using the cache as RAM. // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping // InitialStackMemorySize = STACK_SIZE; InitialStackMemory = (UINTN)MapMemory ( 0, (UINT32) InitialStackMemorySize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE ); if (InitialStackMemory == 0) { printf ("ERROR : Can not open SecStack Exiting\n"); exit (1); } printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n", (unsigned int)(InitialStackMemorySize / 1024), (unsigned long)InitialStackMemory ); for (StackPointer = (UINTN*) (UINTN) InitialStackMemory; StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize); StackPointer ++) { *StackPointer = 0x5AA55AA5; } // // Open All the firmware volumes and remember the info in the gFdInfo global // FileName = (CHAR8 *) AllocatePool (StrLen (FirmwareVolumesStr) + 1); if (FileName == NULL) { printf ("ERROR : Can not allocate memory for firmware volume string\n"); exit (1); } Index2 = 0; for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL; FirmwareVolumesStr[Index2] != 0; Index++) { for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) { FileName[Index1++] = FirmwareVolumesStr[Index2]; } if (FirmwareVolumesStr[Index2] == '!') { Index2++; } FileName[Index1] = '\0'; if (Index == 0) { // Map FV Recovery Read Only and other areas Read/Write Status = MapFd0 ( FileName, &gFdInfo[0].Address, &gFdInfo[0].Size ); } else { // // Open the FD and remember where it got mapped into our processes address space // Maps Read Only // Status = MapFile ( FileName, &gFdInfo[Index].Address, &gFdInfo[Index].Size ); } if (EFI_ERROR (Status)) { printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status); exit (1); } printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address); if (SecFile == NULL) { // // Assume the beginning of the FD is an FV and look for the SEC Core. // Load the first one we find. // FileHandle = NULL; Status = PeiServicesFfsFindNextFile ( EFI_FV_FILETYPE_SECURITY_CORE, (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address, &FileHandle ); if (!EFI_ERROR (Status)) { Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile); if (!EFI_ERROR (Status)) { PeiIndex = Index; printf (" contains SEC Core"); } } } printf ("\n"); } if (SecFile == NULL) { printf ("ERROR : SEC not found!\n"); exit (1); } // // Calculate memory regions and store the information in the gSystemMemory // global for later use. The autosizing code will use this data to // map this memory into the SEC process memory space. // Index1 = 0; Index = 0; while (1) { UINTN val = 0; // // Save the size of the memory. // while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') { val = val * 10 + MemorySizeStr[Index1] - '0'; Index1++; } gSystemMemory[Index++].Size = val * 0x100000; if (MemorySizeStr[Index1] == 0) { break; } Index1++; } printf ("\n"); // // Hand off to SEC // SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile); // // If we get here, then the SEC Core returned. This is an error as SEC should // always hand off to PEI Core and then on to DXE Core. // printf ("ERROR : SEC returned\n"); exit (1); }