/// <summary> /// Resolves the address of an address, pointer, or managed object. /// </summary> /// <returns>The base address of this object.</returns> protected override UInt64 ResolveAddress() { UInt64 pointer = Query.Default.ResolveModule(this.ModuleName); Boolean successReading = true; pointer = pointer.Add(this.ModuleOffset); if (this.PointerOffsets == null || this.PointerOffsets.Count() == 0) { return(pointer); } foreach (Int32 offset in this.PointerOffsets) { if (Processes.Default.IsOpenedProcess32Bit()) { pointer = Reader.Default.Read <Int32>(pointer, out successReading).ToUInt64(); } else { pointer = Reader.Default.Read <UInt64>(pointer, out successReading); } if (pointer == 0 || !successReading) { pointer = 0; break; } pointer = pointer.Add(offset); } return(pointer); }
public UInt64 EvaluatePointer(UInt64 address, IEnumerable <int> offsets) { UInt64 finalAddress = address; if (!offsets.IsNullOrEmpty()) { // Add and trace offsets foreach (Int32 offset in offsets.Take(offsets.Count() - 1)) { if (Processes.Default.IsOpenedProcess32Bit()) { finalAddress = this.Read <UInt32>(finalAddress.Add(offset), out _); } else { finalAddress = this.Read <UInt64>(finalAddress, out _).Add(offset); } } // The last offset is added, but not traced finalAddress = finalAddress.Add(offsets.Last()); } return(finalAddress); }
/// <summary> /// Resolves the address of an address, pointer, or managed object. /// </summary> /// <returns>The base address of this object.</returns> protected override UInt64 ResolveAddress() { UInt64 pointer = MemoryQueryer.Instance.ResolveModule(processSession?.OpenedProcess, this.ModuleName); pointer = pointer.Add(this.ModuleOffset); if (this.PointerOffsets == null || this.PointerOffsets.Count() == 0) { return(pointer); } foreach (Int32 offset in this.PointerOffsets) { bool successReading = false; if (processSession?.OpenedProcess?.Is32Bit() ?? false) { pointer = MemoryReader.Instance.Read <Int32>(processSession?.OpenedProcess, pointer, out successReading).ToUInt64(); } else { pointer = MemoryReader.Instance.Read <UInt64>(processSession?.OpenedProcess, pointer, out successReading); } if (pointer == 0 || !successReading) { return(0); } pointer = pointer.Add(offset); } return(pointer); }
/// <summary> /// Reserves a region of memory within the virtual address space of a specified process. /// </summary> /// <param name="processHandle">The handle to a process.</param> /// <param name="allocAddress">The rough address of where the allocation should take place.</param> /// <param name="size">The size of the region of memory to allocate, in bytes.</param> /// <param name="protectionFlags">The memory protection for the region of pages to be allocated.</param> /// <param name="allocationFlags">The type of memory allocation.</param> /// <returns>The base address of the allocated region</returns> public static UInt64 Allocate( IntPtr processHandle, UInt64 allocAddress, Int32 size, MemoryProtectionFlags protectionFlags = MemoryProtectionFlags.ExecuteReadWrite, MemoryAllocationFlags allocationFlags = MemoryAllocationFlags.Commit | MemoryAllocationFlags.Reserve) { if (allocAddress != 0) { /* A specific address has been given. We will modify it to support the following constraints: * - Aligned by 0x10000 / 65536 * - Pointing to an unallocated region of memory * - Within +/- 2GB (using 1GB for safety) of address space of the originally specified address, such as to always be in range of a far jump instruction * Note: A retry count has been put in place because VirtualAllocEx with an allocAddress specified may be invalid by the time we request the allocation. */ UInt64 result = 0; Int32 retryCount = 0; // Request all chunks of unallocated memory. These will be very large in a 64-bit process. IEnumerable <MemoryBasicInformation64> freeMemory = Memory.QueryUnallocatedMemory( processHandle, allocAddress.Subtract(Int32.MaxValue >> 1, wrapAround: false), allocAddress.Add(Int32.MaxValue >> 1, wrapAround: false)); // Convert to normalized regions IEnumerable <NormalizedRegion> regions = freeMemory.Select(x => new NormalizedRegion(x.BaseAddress.ToUInt64(), x.RegionSize.ToInt32())); // Chunk the large regions into smaller regions based on the allocation size (minimum size is the alloc alignment to prevent creating too many chunks) List <NormalizedRegion> subRegions = new List <NormalizedRegion>(); foreach (NormalizedRegion region in regions) { region.BaseAddress = region.BaseAddress.Subtract(region.BaseAddress.Mod(Memory.AllocAlignment), wrapAround: false); IEnumerable <NormalizedRegion> chunkedRegions = region.ChunkNormalizedRegion(Math.Max(size, Memory.AllocAlignment)).Take(128).Where(x => x.RegionSize >= size); subRegions.AddRange(chunkedRegions); } do { // Sample a random chunk and attempt to allocate the memory result = subRegions.ElementAt(StaticRandom.Next(0, subRegions.Count())).BaseAddress; result = NativeMethods.VirtualAllocEx(processHandle, result.ToIntPtr(), size, allocationFlags, protectionFlags).ToUInt64(); if (result != 0 || retryCount >= Memory.AllocateRetryCount) { break; } retryCount++; }while (result == 0); return(result); } else { // Allocate a memory page return(NativeMethods.VirtualAllocEx(processHandle, allocAddress.ToIntPtr(), size, allocationFlags, protectionFlags).ToUInt64()); } }
/// <summary> /// Determines the address that a code cave would need to return to, if one were to be created at the specified address. /// </summary> /// <param name="address">The address of the code cave.</param> /// <returns>The address to which the code cave will return upon completion.</returns> public UInt64 GetCaveExitAddress(UInt64 address) { this.PrintDebugTag(); Byte[] originalBytes = this.CollectOriginalBytes(address, MemoryCore.JumpSize); Int32 originalByteSize; if (originalBytes != null && originalBytes.Length < MemoryCore.JumpSize) { // Determine the size of the minimum number of instructions we will be overwriting originalByteSize = originalBytes.Length; } else { // Fall back if something goes wrong originalByteSize = MemoryCore.JumpSize; } address = address.Add(originalByteSize); return(address); }
/// <summary> /// Gets regions of memory allocated in the remote process based on provided parameters. /// </summary> /// <param name="requiredProtection">Protection flags required to be present.</param> /// <param name="excludedProtection">Protection flags that must not be present.</param> /// <param name="allowedTypes">Memory types that can be present.</param> /// <param name="startAddress">The start address of the query range.</param> /// <param name="endAddress">The end address of the query range.</param> /// <returns>A collection of pointers to virtual pages in the target process.</returns> public IEnumerable <NormalizedRegion> GetVirtualPages( Process process, MemoryProtectionEnum requiredProtection, MemoryProtectionEnum excludedProtection, MemoryTypeEnum allowedTypes, UInt64 startAddress, UInt64 endAddress) { MemoryProtectionFlags requiredFlags = 0; MemoryProtectionFlags excludedFlags = 0; if ((requiredProtection & MemoryProtectionEnum.Write) != 0) { requiredFlags |= MemoryProtectionFlags.ExecuteReadWrite; requiredFlags |= MemoryProtectionFlags.ReadWrite; } if ((requiredProtection & MemoryProtectionEnum.Execute) != 0) { requiredFlags |= MemoryProtectionFlags.Execute; requiredFlags |= MemoryProtectionFlags.ExecuteRead; requiredFlags |= MemoryProtectionFlags.ExecuteReadWrite; requiredFlags |= MemoryProtectionFlags.ExecuteWriteCopy; } if ((requiredProtection & MemoryProtectionEnum.CopyOnWrite) != 0) { requiredFlags |= MemoryProtectionFlags.WriteCopy; requiredFlags |= MemoryProtectionFlags.ExecuteWriteCopy; } if ((excludedProtection & MemoryProtectionEnum.Write) != 0) { excludedFlags |= MemoryProtectionFlags.ExecuteReadWrite; excludedFlags |= MemoryProtectionFlags.ReadWrite; } if ((excludedProtection & MemoryProtectionEnum.Execute) != 0) { excludedFlags |= MemoryProtectionFlags.Execute; excludedFlags |= MemoryProtectionFlags.ExecuteRead; excludedFlags |= MemoryProtectionFlags.ExecuteReadWrite; excludedFlags |= MemoryProtectionFlags.ExecuteWriteCopy; } if ((excludedProtection & MemoryProtectionEnum.CopyOnWrite) != 0) { excludedFlags |= MemoryProtectionFlags.WriteCopy; excludedFlags |= MemoryProtectionFlags.ExecuteWriteCopy; } IEnumerable <MemoryBasicInformation64> memoryInfo = WindowsMemoryQuery.VirtualPages(process == null ? IntPtr.Zero : process.Handle, startAddress, endAddress, requiredFlags, excludedFlags, allowedTypes); IList <NormalizedRegion> regions = new List <NormalizedRegion>(); foreach (MemoryBasicInformation64 next in memoryInfo) { if (next.RegionSize < ChunkSize) { regions.Add(new NormalizedRegion(next.BaseAddress.ToUInt64(), next.RegionSize.ToInt32())); } else { // This region requires chunking Int64 remaining = next.RegionSize; UInt64 currentBaseAddress = next.BaseAddress.ToUInt64(); while (remaining >= ChunkSize) { regions.Add(new NormalizedRegion(currentBaseAddress, ChunkSize)); remaining -= ChunkSize; currentBaseAddress = currentBaseAddress.Add(ChunkSize, wrapAround: false); } if (remaining > 0) { regions.Add(new NormalizedRegion(currentBaseAddress, remaining.ToInt32())); } } } return(regions); }
/// <summary> /// Retrieves information about a range of pages within the virtual address space of a specified process. /// </summary> /// <param name="processHandle">A handle to the process whose memory information is queried.</param> /// <param name="startAddress">A pointer to the starting address of the region of pages to be queried.</param> /// <param name="endAddress">A pointer to the ending address of the region of pages to be queried.</param> /// <param name="requiredProtection">Protection flags required to be present.</param> /// <param name="excludedProtection">Protection flags that must not be present.</param> /// <param name="allowedTypes">Memory types that can be present.</param> /// <returns> /// A collection of <see cref="MemoryBasicInformation64"/> structures containing info about all virtual pages in the target process. /// </returns> private static IEnumerable <MemoryBasicInformation64> VirtualPages( IntPtr processHandle, UInt64 startAddress, UInt64 endAddress, MemoryProtectionFlags requiredProtection, MemoryProtectionFlags excludedProtection, MemoryTypeEnum allowedTypes) { if (startAddress >= endAddress) { yield return(new MemoryBasicInformation64()); } Boolean wrappedAround = false; Int32 queryResult; // Enumerate the memory pages do { // Allocate the structure to store information of memory MemoryBasicInformation64 memoryInfo = new MemoryBasicInformation64(); if (!Environment.Is64BitProcess) { // 32 Bit struct is not the same MemoryBasicInformation32 memoryInfo32 = new MemoryBasicInformation32(); // Query the memory region (32 bit native method) queryResult = NativeMethods.VirtualQueryEx(processHandle, startAddress.ToIntPtr(), out memoryInfo32, Marshal.SizeOf(memoryInfo32)); // Copy from the 32 bit struct to the 64 bit struct memoryInfo.AllocationBase = memoryInfo32.AllocationBase; memoryInfo.AllocationProtect = memoryInfo32.AllocationProtect; memoryInfo.BaseAddress = memoryInfo32.BaseAddress; memoryInfo.Protect = memoryInfo32.Protect; memoryInfo.RegionSize = memoryInfo32.RegionSize; memoryInfo.State = memoryInfo32.State; memoryInfo.Type = memoryInfo32.Type; } else { // Query the memory region (64 bit native method) queryResult = NativeMethods.VirtualQueryEx(processHandle, startAddress.ToIntPtr(), out memoryInfo, Marshal.SizeOf(memoryInfo)); } // Increment the starting address with the size of the page UInt64 previousFrom = startAddress; startAddress = startAddress.Add(memoryInfo.RegionSize); if (previousFrom > startAddress) { wrappedAround = true; } // Ignore free memory. These are unallocated memory regions. if ((memoryInfo.State & MemoryStateFlags.Free) != 0) { continue; } // At least one readable memory flag is required if ((memoryInfo.Protect & MemoryProtectionFlags.ReadOnly) == 0 && (memoryInfo.Protect & MemoryProtectionFlags.ExecuteRead) == 0 && (memoryInfo.Protect & MemoryProtectionFlags.ExecuteReadWrite) == 0 && (memoryInfo.Protect & MemoryProtectionFlags.ReadWrite) == 0) { continue; } // Do not bother with this shit, this memory is not worth scanning if ((memoryInfo.Protect & MemoryProtectionFlags.ZeroAccess) != 0 || (memoryInfo.Protect & MemoryProtectionFlags.NoAccess) != 0 || (memoryInfo.Protect & MemoryProtectionFlags.Guard) != 0) { continue; } // Enforce allowed types switch (memoryInfo.Type) { case MemoryTypeFlags.None: if ((allowedTypes & MemoryTypeEnum.None) == 0) { continue; } break; case MemoryTypeFlags.Private: if ((allowedTypes & MemoryTypeEnum.Private) == 0) { continue; } break; case MemoryTypeFlags.Image: if ((allowedTypes & MemoryTypeEnum.Image) == 0) { continue; } break; case MemoryTypeFlags.Mapped: if ((allowedTypes & MemoryTypeEnum.Mapped) == 0) { continue; } break; } // Ensure at least one required protection flag is set if (requiredProtection != 0 && (memoryInfo.Protect & requiredProtection) == 0) { continue; } // Ensure no ignored protection flags are set if (excludedProtection != 0 && (memoryInfo.Protect & excludedProtection) != 0) { continue; } // Return the memory page yield return(memoryInfo); }while (startAddress < endAddress && queryResult != 0 && !wrappedAround); }
/// <summary> /// Retrieves information about a range of pages within the virtual address space of a specified process. /// </summary> /// <param name="processHandle">A handle to the process whose memory information is queried.</param> /// <param name="startAddress">A pointer to the starting address of the region of pages to be queried.</param> /// <param name="endAddress">A pointer to the ending address of the region of pages to be queried.</param> /// <returns> /// A collection of <see cref="MemoryBasicInformation64"/> structures containing info about all virtual pages in the target process. /// </returns> public static IEnumerable <MemoryBasicInformation64> QueryUnallocatedMemory( IntPtr processHandle, UInt64 startAddress, UInt64 endAddress) { if (startAddress >= endAddress) { yield return(new MemoryBasicInformation64()); } Boolean wrappedAround = false; Int32 queryResult; // Enumerate the memory pages do { // Allocate the structure to store information of memory MemoryBasicInformation64 memoryInfo = new MemoryBasicInformation64(); if (!Environment.Is64BitProcess) { // 32 Bit struct is not the same MemoryBasicInformation32 memoryInfo32 = new MemoryBasicInformation32(); // Query the memory region (32 bit native method) queryResult = NativeMethods.VirtualQueryEx(processHandle, startAddress.ToIntPtr(), out memoryInfo32, Marshal.SizeOf(memoryInfo32)); // Copy from the 32 bit struct to the 64 bit struct memoryInfo.AllocationBase = memoryInfo32.AllocationBase; memoryInfo.AllocationProtect = memoryInfo32.AllocationProtect; memoryInfo.BaseAddress = memoryInfo32.BaseAddress; memoryInfo.Protect = memoryInfo32.Protect; memoryInfo.RegionSize = memoryInfo32.RegionSize; memoryInfo.State = memoryInfo32.State; memoryInfo.Type = memoryInfo32.Type; } else { // Query the memory region (64 bit native method) queryResult = NativeMethods.VirtualQueryEx(processHandle, startAddress.ToIntPtr(), out memoryInfo, Marshal.SizeOf(memoryInfo)); } // Increment the starting address with the size of the page UInt64 previousFrom = startAddress; startAddress = startAddress.Add(memoryInfo.RegionSize); if (previousFrom > startAddress) { wrappedAround = true; } if ((memoryInfo.State & MemoryStateFlags.Free) != 0) { // Return the unallocated memory page yield return(memoryInfo); } else { // Ignore actual memory continue; } }while (startAddress < endAddress && queryResult != 0 && !wrappedAround); }