/// <summary> /// Helper function for implementing memset. Could be more efficient if we /// could P/Invoke or call some otherwise native code to do this. /// </summary> private static IntPtr MemSet(IntPtr dest, byte value, IntPtr length) { IntPtr end = dest.Add(length.ToInt32()); for (IntPtr cur = dest; cur != end; cur = new IntPtr(cur.ToInt64() + 1)) { Marshal.WriteByte(cur, value); } return dest; }
internal static PyType GetPyType(IntPtr po, bool derived) { if (!_initialized) InitializeStructures(); if (po == IntPtr.Zero) return PyType.Invalid; PyType type; var pyType = Marshal.ReadIntPtr(po.Add(4)); if (!_types.TryGetValue(pyType, out type)) { type = GetPyType(pyType, true); _types.Add(pyType, type); return type; } if (derived) { var s = type.ToString(); type = (PyType) Enum.Parse(typeof (PyType), "Derived" + s); } return type; }
public BonfireStates GetBonfireState(BonfireFlags bonfire) { IntPtr pointer = (IntPtr)0x137E204; pointer = (IntPtr)MemoryTools.ReadInt(handle, pointer); pointer = (IntPtr)MemoryTools.ReadInt(handle, IntPtr.Add(pointer, 0xB48)); pointer = (IntPtr)MemoryTools.ReadInt(handle, IntPtr.Add(pointer, 0x24)); pointer = (IntPtr)MemoryTools.ReadInt(handle, pointer); IntPtr bonfirePointer = (IntPtr)MemoryTools.ReadInt(handle, IntPtr.Add(pointer, 0x8)); while (bonfirePointer != IntPtr.Zero) { int bonfireId = MemoryTools.ReadInt(handle, IntPtr.Add(bonfirePointer, 0x4)); if (bonfireId == (int)bonfire) { int bonfireState = MemoryTools.ReadInt(handle, IntPtr.Add(bonfirePointer, 0x8)); return((BonfireStates)bonfireState); } pointer = (IntPtr)MemoryTools.ReadInt(handle, pointer); bonfirePointer = (IntPtr)MemoryTools.ReadInt(handle, IntPtr.Add(pointer, 0x8)); } return(BonfireStates.Undiscovered); }
internal static void CopyUnmanagedMemory(IntPtr srcPtr, int srcOffset, IntPtr dstPtr, int dstOffset, int count) { srcPtr = srcPtr.Add<byte>( srcOffset ); dstPtr = dstPtr.Add<byte>( dstOffset ); memcpy(dstPtr, srcPtr, (UInt32)count ); }
/// <summary> /// Adds the specified integer to the module address supplied. /// </summary> /// <param name="addressToRebase">The address to rebase to the module address.</param> /// <param name="moduleAddress">The address of the module being rebased to.</param> /// <returns></returns> public static IntPtr Add(this int addressToRebase, IntPtr moduleAddress) => moduleAddress.Add(addressToRebase);
public override bool Unload(IntPtr hModule, IntPtr hProcess) { // Unloading a manually mapped file is fairly straightforward. There is no need to call FreeLibrary or anything // because the file was never actually injected using LoadLibrary and doesn't need to clear any PEB entries etc. // basically just call the Entry Point again with DLL_PROCESS_DETACH flag and not-null for the lpReserved parameter // and then VirtualFree the remote memory. ClearErrors(); if (hModule.IsNull()) throw new ArgumentNullException("hModule", "Invalid module handle"); if (hProcess.IsNull() || hProcess.Compare(-1)) throw new ArgumentException("Invalid process handle.", "hProcess"); IntPtr pStub = IntPtr.Zero; uint nBytes = 0; try { uint entry = FindEntryPoint(hProcess, hModule); if (entry != 0) { var stub = (byte[])DLLMAIN_STUB.Clone(); BitConverter.GetBytes(hModule.ToInt32()).CopyTo(stub, 0x0B); BitConverter.GetBytes((uint)0).CopyTo(stub, 0x06); BitConverter.GetBytes((uint)1000).CopyTo(stub, 0x01); pStub = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)DLLMAIN_STUB.Length, 0x1000 | 0x2000, 0x40); if (pStub.IsNull() || (!WinAPI.WriteProcessMemory(hProcess, pStub, stub, stub.Length, out nBytes) || nBytes != (uint)stub.Length)) throw new InvalidOperationException("Unable to write stub to the remote process."); IntPtr hStubThread = WinAPI.CreateRemoteThread(hProcess, 0, 0, pStub, (uint)hModule.Add(entry).ToInt32(), 0, 0); if (WinAPI.WaitForSingleObject(hStubThread, 5000) == 0x0L) { WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000); WinAPI.CloseHandle(hStubThread); return WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000); } return false; } else { return WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000); } } catch (Exception e) { SetLastError(e); return false; } }
private static void MapSections(PortableExecutable image, IntPtr hProcess, IntPtr pModule) { //very straightforward really. Just iterate through all the sections and map them to their desired virtual addresses in the remote process. //I'm not 100% sure about how well masking the section header characteristics and passing them off as memory protection constants goes. But //so far I haven't hit any issues. (i.e a section header with characteristics "IMAGE_SCN_TYPE_NO_PAD" will set "PAGE_WRITECOPY" memory protection. byte[] databuffer; uint n; foreach (var pSecHd in image.EnumSectionHeaders()) { databuffer = new byte[pSecHd.SizeOfRawData]; if (image.Read(pSecHd.PointerToRawData, SeekOrigin.Begin, databuffer)) { if ((pSecHd.Characteristics & 0x02000000) == 0) //can actually ignore this section (usually the reloc section) { WinAPI.WriteProcessMemory(hProcess, pModule.Add(pSecHd.VirtualAddress), databuffer, databuffer.Length, out n); WinAPI.VirtualProtectEx(hProcess, pModule.Add(pSecHd.VirtualAddress), pSecHd.SizeOfRawData, pSecHd.Characteristics & 0x00FFFFFF, out n); } } else { throw image.GetLastError(); } } }
/** * Find the entry point of a loaded module * based on its Base Address. Reverses the PE * structure to find the entry point */ private static uint FindEntryPoint(IntPtr hProcess, IntPtr hModule) { if (hProcess.IsNull() || hProcess.Compare(-1)) throw new ArgumentException("Invalid process handle.", "hProcess"); if (hModule.IsNull()) throw new ArgumentException("Invalid module handle.", "hModule"); byte[] bDosHeader = WinAPI.ReadRemoteMemory(hProcess, hModule, (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER))); if (bDosHeader != null) { ushort e_magic = BitConverter.ToUInt16(bDosHeader, 0); uint e_lfanew = BitConverter.ToUInt32(bDosHeader, 0x3C); if (e_magic == 23117) { byte[] bNtHeader = WinAPI.ReadRemoteMemory(hProcess, hModule.Add(e_lfanew), (uint)Marshal.SizeOf(typeof(IMAGE_NT_HEADER32))); if (bNtHeader != null && BitConverter.ToUInt32(bNtHeader, 0) == 17744) { IMAGE_NT_HEADER32 ntHd = default(IMAGE_NT_HEADER32); using (var buffer = new UnmanagedBuffer(256)) if (buffer.Translate<IMAGE_NT_HEADER32>(bNtHeader, out ntHd)) return ntHd.OptionalHeader.AddressOfEntryPoint; } } } return 0; }
public int GetGameTimeInMilliseconds() { IntPtr pointer = (IntPtr)MemoryTools.ReadInt(handle, (IntPtr)0x1378700); return(MemoryTools.ReadInt(handle, IntPtr.Add(pointer, 0x68))); }
public static string ReadRemoteString(IntPtr hProcess, IntPtr lpAddress, Encoding encoding = null) { if (encoding == null) encoding = Encoding.ASCII; var builder = new StringBuilder(); //easiest and cleanest way to build an unknown-length string. byte[] buffer = new byte[256]; uint nbytes = 0; int terminator = -1, index = 0; while (terminator < 0 && ReadProcessMemory(hProcess, lpAddress, buffer, buffer.Length, out nbytes) && nbytes > 0) { lpAddress = lpAddress.Add(nbytes); //advance where we're reading from. index = builder.Length; //micro-optimization for .IndexOf builder.Append(encoding.GetString(buffer, 0, (int)nbytes)); //append the data to the StringBuilder terminator = builder.ToString().IndexOf('\0', index); //check if there's a null-byte in the string yet (strings are null-terminated) } return builder.ToString().Substring(0, terminator); //return the data up til the null terminator. }
private static int SearchExports(IntPtr hProcess, IntPtr hModule, byte[] exports, string name) { uint cntExports = BitConverter.ToUInt32(exports, 0x18); //number of named exported functions uint ptrNameTable = BitConverter.ToUInt32(exports, 0x20); //pointer to the export name table int rva = -1; if (cntExports > 0 && ptrNameTable > 0) { byte[] rawPtrs = ReadRemoteMemory(hProcess, hModule.Add(ptrNameTable), cntExports << 2); //be lazy and read all the name pointers at once. if (rawPtrs != null) { //quickly convert that series of bytes into pointer values that make sense. uint[] namePtrs = new uint[cntExports]; for (int i = 0; i < namePtrs.Length; i++) namePtrs[i] = BitConverter.ToUInt32(rawPtrs, i << 2); //binary search, huzzah! Part of the PE specification is that all exported functions are ordered lexicographically in a PE file. int start = 0, end = namePtrs.Length - 1, middle = 0; string curvalue = string.Empty; //basically just search through all the exports looking for the specified function while (start >= 0 && start <= end && rva == -1) { middle = (start + end) / 2; curvalue = ReadRemoteString(hProcess, hModule.Add(namePtrs[middle])); if (curvalue.Equals(name)) rva = middle; else if (string.CompareOrdinal(curvalue, name) < 0) start = middle - 1; else end = middle + 1; } } } return rva; }
/* * This is my GetProcAddressEx function. Basically, it does exactly what GetProcAddress does, * but for a module in a remote process. It looks up the module, and from there parses the lexicographically * ordered export function table (commonly known as the EAT). It calculates based on ordinal offset. * However, if you find this method doesn't work for you for whatever reason (i rushed the binary search algorithm) * i've provided another GetProcAddressEx method below with the same parameters which basically just calls the 'official' * GetProcAddress function from within the remote process and captures the return. Up to you -Jason */ public static IntPtr GetProcAddressEx(IntPtr hProc, IntPtr hModule, object lpProcName) { IntPtr procAddress = IntPtr.Zero; byte[] pDosHd = ReadRemoteMemory(hProc, hModule, 0x40); //attempt to read the DOS header from memory if (pDosHd != null && BitConverter.ToUInt16(pDosHd, 0) == 0x5A4D) //compare the expected DOS "MZ" signature to whatever we just read { uint e_lfanew = BitConverter.ToUInt32(pDosHd, 0x3C); //read the e_lfanew number if (e_lfanew > 0) { byte[] pNtHd = ReadRemoteMemory(hProc, hModule.Add(e_lfanew), 0x108); //read the NT_HEADERS. if (pNtHd != null && BitConverter.ToUInt32(pNtHd, 0) == 0x4550) //check the NT_HEADERS signature (PE\0\0) { uint expDirPtr = BitConverter.ToUInt32(pNtHd, 0x78); //get the pointer to the export directory (first data directory) uint expDirSize = BitConverter.ToUInt32(pNtHd, 0x7C); if (expDirPtr > 0 && expDirSize > 0) //does this module even export functions? { byte[] pExpDir = ReadRemoteMemory(hProc, hModule.Add(expDirPtr), 0x28); //Read the export directory from the process uint pEat = BitConverter.ToUInt32(pExpDir, 0x1C); //pointer to the export address table uint pOrd = BitConverter.ToUInt32(pExpDir, 0x24); //pointer to the ordinal table. uint nFunc = BitConverter.ToUInt32(pExpDir, 0x14); int ord = -1; if (pEat > 0 && pOrd > 0) { if (lpProcName.GetType().Equals(typeof(string))) { int index = SearchExports(hProc, hModule, pExpDir, (string)lpProcName); //search the exported names table for the specified function if (index > -1) //check the function was found { byte[] bOrd = ReadRemoteMemory(hProc, hModule.Add(pOrd + (index << 1)), 0x2); //read the ordinal number for the function from the process ord = (int)(bOrd == null ? -1 : BitConverter.ToUInt16(bOrd, 0)); //get the ordinal number for this function } } else if (lpProcName.GetType().Equals(typeof(short)) || lpProcName.GetType().Equals(typeof(ushort))) { ord = int.Parse(lpProcName.ToString()); } if (ord > -1 && ord < nFunc) //just a final check to make sure we have a valid ordinal { //reference the Export Address Table to find the function address for our ordinal (don't forget to factor in the ordinal base) //Unlike zero-based indexing, the 'ordinal number' indexing starts at 1, so subtract 1 from the ordbase to get zero-based index byte[] addr = ReadRemoteMemory(hProc, hModule.Add(pEat + (ord << 2)), 0x4); if (addr != null) { uint pFunction = BitConverter.ToUInt32(addr, 0); if (pFunction >= expDirPtr && pFunction < (expDirPtr + expDirSize)) //forwarded. { string forward = ReadRemoteString(hProc, hModule.Add(pFunction)); if (!string.IsNullOrEmpty(forward) && forward.Contains(".")) procAddress = GetProcAddressEx(hProc, GetModuleHandleEx(hProc, forward.Split('.')[0]), forward.Split('.')[1]); } else { procAddress = hModule.Add(pFunction); } } } } } } } } return procAddress; }