/// <summary> /// Takes either an array or list of strings containing assembly instructions, a MachineType of I386 or x64, /// an instance of the ERC_Core object and returns the associated opcodes. /// </summary> /// <param name="instructions">The instructions to be assemble=d</param> /// <param name="machineType">a ERC.MachineType of either I386 or x64</param> /// <returns>Returns an ERC_Result byte array containing the assembled instructions</returns> public static ErcResult <byte[]> AssembleOpcodes(List <string> instructions, MachineType machineType) { ErcResult <byte[]> result = new ErcResult <byte[]>(new ErcCore()); List <string> mnemonics = new List <string>(); if (machineType == MachineType.I386) { mnemonics.Add("use32"); } else if (machineType == MachineType.x64) { mnemonics.Add("use64"); } for (int i = 0; i < instructions.Count; i++) { mnemonics.Add(instructions[i]); } var asm = new Assembler(); try { result.ReturnValue = asm.Assemble(mnemonics); asm.Dispose(); } catch (Exception e) { result.Error = e; result.LogEvent(); asm.Dispose(); return(result); } return(result); }
/// <summary> /// Takes a string of characters and returns the location of the first character in a pattern created by Pattern_Create. /// </summary> /// <param name="pattern">The pattern to be searched for.</param> /// <param name="core">An ErcCore object</param> /// <param name="extended">(Optional) bool specifying whether the extended character set should be used</param> /// <returns>Returns an ErcResult int containing the offset of the supplied pattern within the generated pattern</returns> public static ErcResult <int> PatternOffset(string pattern, ErcCore core, bool extended = false) { string digits = "0123456789"; string patternFull; if (extended == true) { digits += ": ,.;+=-_!&()#@'({})[]%"; patternFull = File.ReadAllText(core.PatternExtendedPath); } else { patternFull = File.ReadAllText(core.PatternStandardPath); } ErcResult <int> result = new ErcResult <int>(core); if (pattern.Length < 3) { result.Error = new ERCException("User Input Error: Pattern length must be 3 characters or longer."); result.LogEvent(); return(result); } if (patternFull.Contains(pattern)) { result.ReturnValue = patternFull.IndexOf(pattern); return(result); } result.Error = new ERCException("Error: Pattern not found."); result.ReturnValue = -1; return(result); }
internal ErcResult <string> PopulateTEB() { ErcResult <string> returnString = new ErcResult <string>(ThreadCore); var retInt = ErcCore.ZwQueryInformationThread(ThreadHandle, 0, ref ThreadBasicInfo, Marshal.SizeOf(typeof(ThreadBasicInformation)), IntPtr.Zero); if (retInt != 0) { Console.WriteLine("NTSTATUS Error was thrown: " + retInt); returnString.Error = new ERCException("NTSTATUS Error was thrown: " + retInt); return(returnString); } byte[] tebBytes; int ret = 0; if (X64 == MachineType.x64) { tebBytes = new byte[0x16A0]; ErcCore.ReadProcessMemory(ThreadProcess.ProcessHandle, ThreadBasicInfo.TebBaseAdress, tebBytes, 0x16A0, out ret); } else { tebBytes = new byte[3888]; ErcCore.ReadProcessMemory(ThreadProcess.ProcessHandle, ThreadBasicInfo.TebBaseAdress, tebBytes, 3888, out ret); } if (ret == 0) { ERCException e = new ERCException("System error: An error occured when executing ReadProcessMemory\n Process Handle = 0x" + ThreadProcess.ProcessHandle.ToString("X") + " TEB Base Address = 0x" + ThreadBasicInfo.TebBaseAdress.ToString("X") + " Return value = " + ret); returnString.Error = e; return(returnString); } if (X64 == MachineType.x64) { PopulateTEBStruct64(tebBytes); } else { PopulateTEBStruct32(tebBytes); } var bSehChain = BuildSehChain(); if (bSehChain.Error != null) { returnString.Error = bSehChain.Error; return(returnString); } return(returnString); }
/// <summary> /// Disassembles opcodes into the associated instructions. Takes a byte array containing opcodes, a MachineType of I386 or x64, /// an instance of the ERC_Core object and returns an ERC_Result containing associated instructions. /// </summary> /// <param name="opcodes">A byte array containing opcodes to be disassembled</param> /// <param name="machineType">a ERC.MachineType of either I386 or x64</param> /// <returns>Returns an ERC_Result containing associated instructions.</returns> public static ErcResult <string> Disassemble(byte[] opcodes, MachineType machineType) { ErcResult <string> result = new ErcResult <string>(new ErcCore()); SharpDisasm.Disassembler.Translator.IncludeAddress = true; SharpDisasm.Disassembler.Translator.IncludeBinary = true; SharpDisasm.Disassembler disasm; SharpDisasm.ArchitectureMode mode; try { if (machineType == MachineType.I386) { mode = SharpDisasm.ArchitectureMode.x86_32; } else if (machineType == MachineType.x64) { mode = SharpDisasm.ArchitectureMode.x86_64; } else { throw new ERCException("User input error: Machine Type is invalid, must be ERC.MachineType.x86_64 or ERC.MachineType.x86_32"); } } catch (ERCException e) { result.Error = e; result.LogEvent(); return(result); } try { disasm = new SharpDisasm.Disassembler( HexStringToByteArray(BitConverter.ToString(opcodes).Replace("-", "")), mode, 0, true); } catch (Exception e) { result.Error = e; result.LogEvent(e); return(result); } foreach (var insn in disasm.Disassemble()) { var mne = insn.ToString().Split(new string[] { " " }, StringSplitOptions.None); result.ReturnValue += mne[mne.Length - 1].Trim() + Environment.NewLine; } return(result); }
/// <summary> /// Lists all HeapIDs associated with a process. /// </summary> /// <returns>Returns an ErcResult<List<ulong>>"</returns> public ErcResult <List <ulong> > HeapIDs() { ErcResult <List <ulong> > result = new ErcResult <List <ulong> >(HeapProcess); result.ReturnValue = new List <ulong>(); foreach (HEAPLIST32 hl in HeapLists) { result.ReturnValue.Add((ulong)hl.th32HeapID); } if (result.ReturnValue.Count == 0) { result.Error = new ERCException("Error: No heap ids found associated with this process."); } return(result); }
/// <summary> /// Takes a string of characters and returns the location of the first character in a pattern created by Pattern_Create. /// </summary> /// <param name="pattern">The pattern to be searched for.</param> /// <param name="core">An ErcCore object</param> /// <param name="extended">(Optional) bool specifying whether the extended character set should be used</param> /// <returns>Returns an ErcResult int containing the offset of the supplied pattern within the generated pattern</returns> public static ErcResult <string> PatternOffset(string pattern, ErcCore core, bool extended = false) { //create string with reversed version of pattern to be searched for. char[] reversedChars = pattern.ToCharArray(); Array.Reverse(reversedChars); string reversed = new string(reversedChars); //Create pattern to search within. Either extended or normal. string digits = "0123456789"; string patternFull; if (extended == true) { digits += ": ,.;+=-_!&()#@'*^[]%$?"; patternFull = File.ReadAllText(core.PatternExtendedPath); } else { patternFull = File.ReadAllText(core.PatternStandardPath); } ErcResult <string> result = new ErcResult <string>(core); if (pattern.Length < 3) { result.Error = new ERCException("User Input Error: Pattern length must be 3 characters or longer."); result.LogEvent(); return(result); } if (patternFull.Contains(pattern)) { result.ReturnValue = "Value found at postiont " + patternFull.IndexOf(pattern).ToString() + " in pattern."; return(result); } else if (patternFull.Contains(reversed)) { result.ReturnValue = "Value found reversed at postiont " + patternFull.IndexOf(reversed).ToString() + " in pattern."; return(result); } result.Error = new ERCException("Error: Value not found."); result.ReturnValue = "Value not found in pattern."; return(result); }
internal ThreadInfo(ProcessThread thread, ErcCore core, ProcessInfo process) { ThreadID = thread.Id; ThreadCurrent = thread; ThreadCore = core; ThreadProcess = process; if (process.ProcessMachineType == MachineType.x64) { X64 = MachineType.x64; } else if (process.ProcessMachineType == MachineType.I386) { X64 = MachineType.I386; } try { ThreadHandle = ErcCore.OpenThread(ThreadAccess.All_ACCESS, false, (uint)thread.Id); if (ThreadHandle == null) { ThreadFailed = true; throw new ERCException(new Win32Exception(Marshal.GetLastWin32Error()).Message); } } catch (ERCException e) { ErcResult <Exception> exceptionThrower = new ErcResult <Exception>(ThreadCore) { Error = e }; exceptionThrower.LogEvent(); } var errorCheck = PopulateTEB(); //This needs to be revisited. if (errorCheck.Error != null && errorCheck.Error.Message != "Error: No SEH chain has been generated yet. An SEH chain will not be generated until a crash occurs.") { throw errorCheck.Error; } }
/// <summary> /// Searches for a string of bytes within a specific module. Takes a byte array to be searched for. /// </summary> /// <param name="searchBytes">A byte array to be searched for</param> /// <returns>Returns ERC_Result of pointers to the search term</returns> public ErcResult <List <IntPtr> > SearchModule(byte[] searchBytes) { ErcResult <List <IntPtr> > results = new ErcResult <List <IntPtr> >(ModuleCore); List <IntPtr> ptrs = new List <IntPtr>(); IntPtr baseAddress = ModuleBase; byte[] buffer = new byte[ModuleSize]; int bytesread = 0; ErcCore.ReadProcessMemory(ModuleProcess.Handle, ModuleBase, buffer, buffer.Length, out bytesread); List <int> positions = SearchBytePattern(searchBytes, buffer); for (int i = 0; i < positions.Count; i++) { ptrs.Add((IntPtr)(positions[i] + (long)ModuleBase)); } results.ReturnValue = ptrs; return(results); }
internal ThreadInfo(ProcessThread thread, ErcCore core, ProcessInfo process) { ThreadID = thread.Id; ThreadCurrent = thread; ThreadCore = core; ThreadProcess = process; if (process.ProcessMachineType == MachineType.x64) { X64 = MachineType.x64; } else if (process.ProcessMachineType == MachineType.I386) { X64 = MachineType.I386; } try { ThreadHandle = ErcCore.OpenThread(ThreadAccess.All_ACCESS, false, (uint)thread.Id); if (ThreadHandle == null) { ThreadFailed = true; throw new ERCException(new Win32Exception(Marshal.GetLastWin32Error()).Message); } } catch (ERCException e) { ErcResult <Exception> exceptionThrower = new ErcResult <Exception>(ThreadCore) { Error = e }; exceptionThrower.LogEvent(); } PopulateTEB(); }
/// <summary> /// Searches heap entries for a specified pattern. Returns pointers to all instances of the pattern. If heapID and startAddress are both supplied heapID takes precedence. /// </summary> /// <param name="searchBytes">byte array containing the pattern to search for</param> /// <param name="heapID">ID of the heap to be searched(Optional)</param> /// <param name="hexStartAddress">Start address of the heap entry to be searched in hexadecimal(Optional)</param> /// <returns>Returns an ERCResult of IntPtr containing pointers to all instances of the pattern found.</returns> public ErcResult <List <Tuple <IntPtr, IntPtr, IntPtr> > > SearchHeap(byte[] searchBytes, ulong heapID = 0, string hexStartAddress = "") { ErcResult <List <Tuple <IntPtr, IntPtr, IntPtr> > > result = new ErcResult <List <Tuple <IntPtr, IntPtr, IntPtr> > >(HeapProcess); result.ReturnValue = new List <Tuple <IntPtr, IntPtr, IntPtr> >(); if (hexStartAddress.Contains("0x") || hexStartAddress.Contains("0x") || hexStartAddress.Contains("x") || hexStartAddress.Contains("X")) { hexStartAddress = hexStartAddress.Replace("0x", ""); hexStartAddress = hexStartAddress.Replace("0X", ""); hexStartAddress = hexStartAddress.Replace("X", ""); hexStartAddress = hexStartAddress.Replace("x", ""); } IntPtr startAddress = IntPtr.Zero; IntPtr HeapID = IntPtr.Zero; if (heapID != 0) { HeapID = (IntPtr)heapID; } if (HeapProcess.ProcessMachineType == MachineType.I386) { try { startAddress = (IntPtr)Convert.ToInt32(hexStartAddress, 16); } catch { } } else { try { startAddress = (IntPtr)Convert.ToInt64(hexStartAddress, 16); } catch { } } if (searchBytes.Length < 3) { result.Error = new ERCException("Search pattern not long enough. Minimum length is 3 bytes"); result.ReturnValue = null; return(result); } if (heapID != 0) { foreach (HEAPENTRY32 he in HeapEntries) { if (he.th32HeapID == HeapID) { byte[] bytes = HeapProcess.DumpMemoryRegion(he.dwAddress, (int)he.dwBlockSize).ReturnValue; int maxFirstCharSlot = bytes.Length - searchBytes.Length + 1; for (int i = 0; i < maxFirstCharSlot; i++) { if (bytes[i] != searchBytes[0]) { continue; } for (int j = searchBytes.Length - 1; j >= 1; j--) { if (bytes[i + j] != searchBytes[j]) { break; } if (j == 1) { Tuple <IntPtr, IntPtr, IntPtr> element = new Tuple <IntPtr, IntPtr, IntPtr>(he.dwAddress + i, he.th32HeapID, he.dwAddress); result.ReturnValue.Add(element); } } } } } } else if (startAddress != IntPtr.Zero) { foreach (HEAPENTRY32 he in HeapEntries) { if (he.dwAddress == startAddress) { byte[] bytes = HeapProcess.DumpMemoryRegion((IntPtr)startAddress, (int)he.dwBlockSize).ReturnValue; int maxFirstCharSlot = bytes.Length - searchBytes.Length + 1; for (int i = 0; i < maxFirstCharSlot; i++) { if (bytes[i] != searchBytes[0]) { continue; } for (int j = searchBytes.Length - 1; j >= 1; j--) { if (bytes[i + j] != searchBytes[j]) { break; } if (j == 1) { Tuple <IntPtr, IntPtr, IntPtr> element = new Tuple <IntPtr, IntPtr, IntPtr>(he.dwAddress + i, he.th32HeapID, he.dwAddress); result.ReturnValue.Add(element); } } } } } } else { foreach (HEAPENTRY32 he in HeapEntries) { byte[] bytes = HeapProcess.DumpMemoryRegion(he.dwAddress, (int)he.dwBlockSize).ReturnValue; int maxFirstCharSlot = bytes.Length - searchBytes.Length + 1; for (int i = 0; i < maxFirstCharSlot; i++) { if (bytes[i] != searchBytes[0]) { continue; } for (int j = searchBytes.Length - 1; j >= 1; j--) { if (bytes[i + j] != searchBytes[j]) { break; } if (j == 1) { Tuple <IntPtr, IntPtr, IntPtr> element = new Tuple <IntPtr, IntPtr, IntPtr>(he.dwAddress + i, he.th32HeapID, he.dwAddress); result.ReturnValue.Add(element); } } } } } return(result); }
/// <summary> /// Returns a collections of stats related to the heap of the current process object. If both heapID and startAddress are specified heapID takes precedence. /// </summary> /// <param name="extended">display an extended set of </param> /// <param name="heapID">The ID of the heap to display stats for. (optional)</param> /// <param name="hexStartAddress">The start address of the specific heap block to display stats for in hexadecimal. (optional)</param> /// <returns>returns a List<string> object</returns> public ErcResult <List <string> > HeapStatistics(bool extended = false, ulong heapID = 0, string hexStartAddress = "") { ErcResult <List <string> > result = new ErcResult <List <string> >(HeapProcess); if (hexStartAddress.Contains("0x") || hexStartAddress.Contains("0x") || hexStartAddress.Contains("x") || hexStartAddress.Contains("X")) { hexStartAddress = hexStartAddress.Replace("0x", ""); hexStartAddress = hexStartAddress.Replace("0X", ""); hexStartAddress = hexStartAddress.Replace("X", ""); hexStartAddress = hexStartAddress.Replace("x", ""); } ulong startAddress = 0; if (HeapProcess.ProcessMachineType == MachineType.I386) { try { startAddress = (uint)Convert.ToInt32(hexStartAddress, 16); } catch { } } else { try { startAddress = (ulong)Convert.ToInt64(hexStartAddress, 16); } catch { } } List <string> heapStats = new List <string>(); heapStats.Add("ProcessID = " + HeapProcess.ProcessID + Environment.NewLine); heapStats.Add("Number of heaps = " + HeapLists.Count + Environment.NewLine); if (heapID != 0) { heapStats.Add(" Heap ID = " + heapID + Environment.NewLine); } int count = 0; foreach (HEAPLIST32 hl in HeapLists) { count++; int heapEnts = 0; if (heapID == 0 && startAddress == 0) { heapStats.Add(" Heap " + count + " ID = " + hl.th32HeapID + Environment.NewLine); } foreach (HEAPENTRY32 he in HeapEntries) { if (heapID != 0) { if (he.th32HeapID == (IntPtr)heapID && hl.th32HeapID == (IntPtr)heapID) { if (HeapProcess.ProcessMachineType == MachineType.I386) { heapStats.Add(" Heap Start Address = 0x" + he.dwAddress.ToString("X8") + Environment.NewLine); heapStats.Add(" Heap Entry size = " + he.dwBlockSize.ToString() + Environment.NewLine); switch (he.dwFlags) { case 1: heapStats.Add(" Heap flags = LF32_FIXED" + Environment.NewLine); break; case 2: heapStats.Add(" Heap flags = LF32_FREE" + Environment.NewLine); break; case 4: heapStats.Add(" Heap flags = LF32_MOVEABLE" + Environment.NewLine); break; default: break; } } else { heapStats.Add(" Heap Start Address = " + he.dwAddress.ToString("X16") + Environment.NewLine); heapStats.Add(" Heap Entry size = " + he.dwBlockSize.ToString() + Environment.NewLine); switch (he.dwFlags) { case 1: heapStats.Add(" Heap flags = LF32_FIXED" + Environment.NewLine); break; case 2: heapStats.Add(" Heap flags = LF32_FREE" + Environment.NewLine); break; case 4: heapStats.Add(" Heap flags = LF32_MOVEABLE" + Environment.NewLine); break; default: break; } } heapEnts++; } } else if (startAddress != 0) { if (he.dwAddress == (IntPtr)startAddress) { if (HeapProcess.ProcessMachineType == MachineType.I386) { heapStats.Add(" Heap ID = " + hl.th32HeapID + Environment.NewLine); heapStats.Add(" Heap Start Address = " + he.dwAddress.ToString("X8") + Environment.NewLine); heapStats.Add(" Heap Entry size = " + he.dwBlockSize.ToString() + Environment.NewLine); switch (he.dwFlags) { case 1: heapStats.Add(" Heap flags = LF32_FIXED" + Environment.NewLine); result.ReturnValue = heapStats; return(result); case 2: heapStats.Add(" Heap flags = LF32_FREE" + Environment.NewLine); result.ReturnValue = heapStats; return(result); case 4: heapStats.Add(" Heap flags = LF32_MOVEABLE" + Environment.NewLine); result.ReturnValue = heapStats; return(result); default: break; } } else { heapStats.Add(" Heap ID = " + hl.th32HeapID + Environment.NewLine); heapStats.Add(" Heap Start Address = " + he.dwAddress.ToString("X16") + Environment.NewLine); heapStats.Add(" Heap Entry size = " + he.dwBlockSize.ToString() + Environment.NewLine); switch (he.dwFlags) { case 1: heapStats.Add(" Heap flags = LF32_FIXED" + Environment.NewLine); result.ReturnValue = heapStats; return(result); case 2: heapStats.Add(" Heap flags = LF32_FREE" + Environment.NewLine); result.ReturnValue = heapStats; return(result); case 4: heapStats.Add(" Heap flags = LF32_MOVEABLE" + Environment.NewLine); result.ReturnValue = heapStats; return(result); default: break; } } } } else if (he.th32HeapID == hl.th32HeapID) { if (extended == true) { if (HeapProcess.ProcessMachineType == MachineType.I386) { heapStats.Add(" Heap Start Address = " + he.dwAddress.ToString("X8") + Environment.NewLine); heapStats.Add(" Heap Entry size = " + he.dwBlockSize.ToString() + Environment.NewLine); switch (he.dwFlags) { case 1: heapStats.Add(" Heap flags = LF32_FIXED" + Environment.NewLine); break; case 2: heapStats.Add(" Heap flags = LF32_FREE" + Environment.NewLine); break; case 4: heapStats.Add(" Heap flags = LF32_MOVEABLE" + Environment.NewLine); break; default: break; } } else { heapStats.Add(" Heap Start Address = " + he.dwAddress.ToString("X16") + Environment.NewLine); heapStats.Add(" Heap Entry size = " + he.dwBlockSize.ToString() + Environment.NewLine); switch (he.dwFlags) { case 1: heapStats.Add(" Heap flags = LF32_FIXED" + Environment.NewLine); break; case 2: heapStats.Add(" Heap flags = LF32_FREE" + Environment.NewLine); break; case 4: heapStats.Add(" Heap flags = LF32_MOVEABLE" + Environment.NewLine); break; default: break; } } } heapEnts++; } } if (heapID != 0 || startAddress != 0) { if ((IntPtr)heapID == hl.th32HeapID) { heapStats.Add(" Total number of entries in heap: " + heapEnts + Environment.NewLine); } } else { heapStats.Add(" Total number of entries in heap: " + heapEnts + Environment.NewLine); } } result.ReturnValue = heapStats; return(result); }
/// <summary> /// Gets the register values of a thread and populates the CONTEXT structs. Should only be used on a suspended thread, results on an active thread are unreliable. /// </summary> /// <returns>Returns an ErcResult, the return value can be ignored, the object should only be checked for error values</returns> public ErcResult <string> Get_Context() { ErcResult <string> result = new ErcResult <string>(ThreadCore); if (X64 == MachineType.x64) { Context64 = new CONTEXT64(); Context64.ContextFlags = CONTEXT_FLAGS.CONTEXT_ALL; try { bool returnVar = ErcCore.GetThreadContext64(ThreadHandle, ref Context64); if (returnVar == false) { throw new ERCException("Win32 Exception encountered when attempting to get thread context: " + new Win32Exception(Marshal.GetLastWin32Error()).Message); } } catch (ERCException e) { result.Error = e; result.LogEvent(); return(result); } catch (Exception e) { result.Error = e; result.LogEvent(e); } } else if (Environment.Is64BitOperatingSystem == true && X64 != MachineType.x64) { Context32 = new CONTEXT32(); Context32.ContextFlags = CONTEXT_FLAGS.CONTEXT_ALL; try { bool returnVar = ErcCore.Wow64GetThreadContext(ThreadHandle, ref Context32); if (returnVar == false) { throw new ERCException("Win32 Exception encountered when attempting to get thread context: " + new Win32Exception(Marshal.GetLastWin32Error()).Message); } } catch (ERCException e) { result.Error = e; result.LogEvent(); return(result); } catch (Exception e) { result.Error = e; result.LogEvent(e); } } else { Context32 = new CONTEXT32(); Context32.ContextFlags = CONTEXT_FLAGS.CONTEXT_ALL; try { bool returnVar = ErcCore.GetThreadContext32(ThreadHandle, ref Context32); if (returnVar == false) { throw new ERCException("Win32 Exception encountered when attempting to get thread context: " + new Win32Exception(Marshal.GetLastWin32Error()).Message); } } catch (ERCException e) { result.Error = e; result.LogEvent(); return(result); } catch (Exception e) { result.Error = e; result.LogEvent(e); } } return(result); }
/// <summary> /// Constructor for the ModuleInfo object. Takes (string)modules filepath (IntPtr)module handle (Process)Process from which the module is loaded /// </summary> /// <param name="module">Filepath of the module</param> /// <param name="ptr">Handle to the module</param> /// <param name="process">Process where the module is loaded</param> /// <param name="core">An ErcCore object</param> internal unsafe ModuleInfo(string module, IntPtr ptr, Process process, ErcCore core) { try { ModuleCore = core; ModuleProcess = process; ModuleName = FileVersionInfo.GetVersionInfo(module).InternalName; ModulePath = FileVersionInfo.GetVersionInfo(module).FileName; ModuleBase = ptr; FileInfo fileInfo = new FileInfo(ModulePath); FileStream file = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read); PopulateHeaderStructs(file); if (!string.IsNullOrEmpty(FileVersionInfo.GetVersionInfo(module).FileVersion)) { ModuleVersion = FileVersionInfo.GetVersionInfo(module).FileVersion.Split(' ')[0]; } else { ModuleVersion = ""; } ModuleProduct = FileVersionInfo.GetVersionInfo(module).ProductName; if (ModuleMachineType == MachineType.I386) { ModuleEntry = (IntPtr)ImageOptionalHeader32.AddressOfEntryPoint; ModuleSize = (int)ImageOptionalHeader32.SizeOfImage; ModuleImageBase = (IntPtr)ImageOptionalHeader32.ImageBase; byte[] dllByte = BitConverter.GetBytes(ImageOptionalHeader32.DllCharacteristics); BitArray bits = new BitArray(dllByte); for (int i = 0; i < bits.Count; i++) { if (bits[i] == true && i == 6) { ModuleASLR = true; } else { ModuleASLR = false; } if (bits[i] == true && i == 8) { ModuleNXCompat = true; } else { ModuleNXCompat = false; } } if (ModuleMachineType == MachineType.I386) { PopulateConfigStruct(); if (ImageConfigDir32.SEHandlerCount == 0 && ImageConfigDir32.SEHandlerTable == 0) { ModuleSafeSEH = false; } else { ModuleSafeSEH = true; } } else { ModuleSafeSEH = true; } } else if (ModuleMachineType == MachineType.x64) { ModuleEntry = (IntPtr)ImageOptionalHeader64.AddressOfEntryPoint; ModuleSize = (int)ImageOptionalHeader64.SizeOfImage; ModuleImageBase = (IntPtr)ImageOptionalHeader64.ImageBase; byte[] dllByte = BitConverter.GetBytes(ImageOptionalHeader64.DllCharacteristics); BitArray bits = new BitArray(dllByte); for (int i = 0; i < bits.Count; i++) { if (bits[i] == true && i == 6) { ModuleASLR = true; } else if (bits[i] == false && i == 6) { ModuleASLR = false; } if (bits[i] == true && i == 8) { ModuleNXCompat = true; } else if (bits[i] == false && i == 8) { ModuleNXCompat = false; } } PopulateConfigStruct(); if (ImageConfigDir64.SEHandlerCount == 0 && ImageConfigDir64.SEHandlerTable == 0) { ModuleSafeSEH = false; } else { ModuleSafeSEH = true; } } else { ModuleFailed = true; throw new ERCException("Unsupported machine type: " + ModuleMachineType.ToString()); } if (ModuleProduct == "Microsoft® Windows® Operating System") { ModuleOsDll = true; } else { ModuleOsDll = false; } if (ModuleImageBase != ptr) { ModuleRebase = true; } else { ModuleRebase = false; } } catch (Exception e) { ErcResult <Exception> ExceptionLogger = new ErcResult <Exception>(ModuleCore); ExceptionLogger.Error = e; ExceptionLogger.LogEvent(); ModuleFailed = true; } }
/// <summary> /// Constructor for the ModuleInfo object. Takes (string)modules filepath (IntPtr)module handle (Process)Process from which the module is loaded /// </summary> /// <param name="module">Filepath of the module</param> /// <param name="ptr">Handle to the module</param> /// <param name="process">Process where the module is loaded</param> /// <param name="core">An ErcCore object</param> internal unsafe ModuleInfo(string module, IntPtr ptr, Process process, ErcCore core) { try { ModuleCore = core; ModuleProcess = process; ModuleName = FileVersionInfo.GetVersionInfo(module).InternalName; ModulePath = FileVersionInfo.GetVersionInfo(module).FileName; ModuleBase = ptr; FileInfo fileInfo = new FileInfo(ModulePath); FileStream file = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read); PopulateHeaderStructs(file); if (!string.IsNullOrEmpty(FileVersionInfo.GetVersionInfo(module).FileVersion)) { ModuleVersion = FileVersionInfo.GetVersionInfo(module).FileVersion.Split(' ')[0]; } else { ModuleVersion = ""; } ModuleProduct = FileVersionInfo.GetVersionInfo(module).ProductName; if (ModuleMachineType == MachineType.I386) { ModuleEntry = (IntPtr)ImageOptionalHeader32.AddressOfEntryPoint; ModuleSize = (int)ImageOptionalHeader32.SizeOfImage; ModuleImageBase = (IntPtr)ImageOptionalHeader32.ImageBase; byte[] dllByte = BitConverter.GetBytes(ImageOptionalHeader32.DllCharacteristics); BitArray bits = new BitArray(dllByte); for (int i = 0; i < bits.Count; i++) { if (bits[i] == true && i == 6) { ModuleASLR = true; } else { ModuleASLR = false; } if (bits[i] == true && i == 8) { ModuleNXCompat = true; } else { ModuleNXCompat = false; } } if (ModuleMachineType == MachineType.I386) { PopulateConfigStruct(); if (ImageConfigDir32.SEHandlerCount == 0 && ImageConfigDir32.SEHandlerTable == 0) { ModuleSafeSEH = false; } else { ModuleSafeSEH = true; } } else { ModuleSafeSEH = true; } } else if (ModuleMachineType == MachineType.x64) { ModuleEntry = (IntPtr)ImageOptionalHeader64.AddressOfEntryPoint; ModuleSize = (int)ImageOptionalHeader64.SizeOfImage; ModuleImageBase = (IntPtr)ImageOptionalHeader64.ImageBase; byte[] dllByte = BitConverter.GetBytes(ImageOptionalHeader64.DllCharacteristics); BitArray bits = new BitArray(dllByte); for (int i = 0; i < bits.Count; i++) { if (bits[i] == true && i == 6) { ModuleASLR = true; } else if (bits[i] == false && i == 6) { ModuleASLR = false; } if (bits[i] == true && i == 8) { ModuleNXCompat = true; } else if (bits[i] == false && i == 8) { ModuleNXCompat = false; } } PopulateConfigStruct(); if (ImageConfigDir64.SEHandlerCount == 0 && ImageConfigDir64.SEHandlerTable == 0) { ModuleSafeSEH = false; } else { ModuleSafeSEH = true; } } else { ModuleFailed = true; throw new ERCException("Unsupported machine type: " + ModuleMachineType.ToString()); } if (ModuleProduct == "Microsoft® Windows® Operating System") { ModuleOsDll = true; } else { ModuleOsDll = false; } if (ModuleImageBase != ptr) { ModuleRebase = true; } else { ModuleRebase = false; } long MaxAddress = 0x7fffffff; long address = (long)ModuleBase; if (!ProcessInfo.Is64Bit(process)) { List <ERC.Structures.MEMORY_BASIC_INFORMATION32> ProcessMemoryBasicInfo32 = new List <ERC.Structures.MEMORY_BASIC_INFORMATION32>(); long oldAddress = 0; do { ERC.Structures.MEMORY_BASIC_INFORMATION32 m; int result = ErcCore.VirtualQueryEx32(ModuleProcess.Handle, (IntPtr)address, out m, (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION32))); if (address == (long)m.BaseAddress + (long)m.RegionSize) { break; } address = (long)m.BaseAddress + (long)m.RegionSize; if (oldAddress > address) { address = long.MaxValue; } oldAddress = address; ModuleProtection = m.AllocationProtect; } while (address <= MaxAddress); } else { List <ERC.Structures.MEMORY_BASIC_INFORMATION64> ProcessMemoryBasicInfo64 = new List <ERC.Structures.MEMORY_BASIC_INFORMATION64>(); long oldAddress = 0; do { ERC.Structures.MEMORY_BASIC_INFORMATION64 m; int result = ErcCore.VirtualQueryEx64(ModuleProcess.Handle, (IntPtr)address, out m, (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION64))); if (address == (long)m.BaseAddress + (long)m.RegionSize) { break; } address = (long)m.BaseAddress + (long)m.RegionSize; if (oldAddress > address) { address = long.MaxValue; } oldAddress = address; ModuleProtection = m.AllocationProtect; } while (address <= MaxAddress); } } catch (Exception e) { ErcResult <Exception> ExceptionLogger = new ErcResult <Exception>(ModuleCore); ExceptionLogger.Error = e; ExceptionLogger.LogEvent(); ModuleFailed = true; } }
/// <summary> /// Takes a string of characters and returns the location of the first character in a pattern created by Pattern_Create. /// </summary> /// <param name="pattern">The pattern to be searched for.</param> /// <param name="core">An ErcCore object</param> /// <param name="extended">(Optional) bool specifying whether the extended character set should be used</param> /// <returns>Returns an ErcResult int containing the offset of the supplied pattern within the generated pattern</returns> public static ErcResult <string> PatternOffset(string pattern, ErcCore core, bool extended = false) { //create string with reversed version of pattern to be searched for. char[] reversedChars = pattern.ToCharArray(); Array.Reverse(reversedChars); string reversed = new string(reversedChars); //Create pattern to search within. Either extended or normal. string digits = "0123456789"; string patternFull; if (extended == true) { digits += ": ,.;+=-_!&()#@'*^[]%$?"; patternFull = File.ReadAllText(core.PatternExtendedPath); } else { patternFull = File.ReadAllText(core.PatternStandardPath); } ErcResult <string> result = new ErcResult <string>(core); if (pattern.Length < 3) { result.Error = new ERCException("User Input Error: Pattern length must be 3 characters or longer."); result.LogEvent(); return(result); } if (patternFull.Contains(pattern)) { result.ReturnValue = "Value found at postiont " + patternFull.IndexOf(pattern).ToString() + " in pattern."; return(result); } else if (patternFull.Contains(reversed)) { result.ReturnValue = "Value found reversed at postiont " + patternFull.IndexOf(reversed).ToString() + " in pattern."; return(result); } bool validHexString = true; foreach (char c in pattern) { if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) { validHexString = false; } } if (validHexString == true) { byte[] patternBytes = ERC.Utilities.Convert.HexToBytes(pattern); byte[] patternBytesReversed = ERC.Utilities.Convert.HexToBytes(reversed); byte[] patternFullBytes = Encoding.ASCII.GetBytes(patternFull); string hexString = BitConverter.ToString(patternBytes).Replace("-", ""); string hexStringReversed = BitConverter.ToString(patternBytesReversed).Replace("-", ""); string hexPatternFull = BitConverter.ToString(patternFullBytes).Replace("-", ""); if (hexPatternFull.Contains(hexString)) { result.ReturnValue = "Value found at postiont " + (hexPatternFull.IndexOf(hexString) / 2).ToString() + " in pattern."; return(result); } else if (hexPatternFull.Contains(hexStringReversed)) { result.ReturnValue = "Value found reversed at postiont " + (hexPatternFull.IndexOf(hexStringReversed) / 2).ToString() + " in pattern."; return(result); } } result.Error = new ERCException("Error: Value not found."); result.ReturnValue = "Value not found in pattern."; return(result); }
/// <summary> /// Creates a string of non repeating characters. /// </summary> /// <param name="length">The length of the pattern to be created as integer</param> /// <param name="core">An ErcCore object</param> /// <param name="extended">(Optional) bool specifying whether the extended character set should be used</param> /// <returns>Returns an ErcResult string containing the generated pattern</returns> public static ErcResult <string> PatternCreate(int length, ErcCore core, bool extended = false) { string digits = "0123456789"; ErcResult <string> result = new ErcResult <string>(core); if (extended == true) { digits += ": ,.;+=-_!&()#@'*^[]%$?"; if (length > 66923) { result.Error = new ERCException("User input error: Pattern length must be less that 66923"); result.LogEvent(); return(result); } } else { if (length > 20277) { result.Error = new ERCException("User input error: Pattern length must be less that 20277. Add the extended flag to create larger strings."); result.LogEvent(); return(result); } } result.ReturnValue = ""; if (length < 1) { result.Error = new ERCException("User Input Error: Pattern length must be greate than 0."); result.LogEvent(); return(result); } for (int i = 0; i < uppercase.Length; i++) { for (int j = 0; j < lowercase.Length; j++) { for (int k = 0; k < digits.Length; k++) { char pos1 = uppercase[i]; char pos2 = lowercase[j]; char pos3 = digits[k]; if (result.ReturnValue.Length > length) { result.Error = new ERCException("Procedural Error: Pattern string has exceeded the length supplied"); result.ReturnValue = ""; return(result); } if (result.ReturnValue.Length == length) { return(result); } if (result.ReturnValue.Length < length - 2) { result.ReturnValue += pos1; result.ReturnValue += pos2; result.ReturnValue += pos3; if (result.ReturnValue.Length == length) { return(result); } } else if (result.ReturnValue.Length < length - 1) { result.ReturnValue += pos1; result.ReturnValue += pos2; if (result.ReturnValue.Length == length) { return(result); } } else if (result.ReturnValue.Length < length) { result.ReturnValue += pos1; if (result.ReturnValue.Length == length) { return(result); } } } } } result.Error = new ERCException("An unknown error has occured. Function exited incorrectly. Function: ERC.Pattern_Tools.Pattern_Create"); result.LogEvent(); return(result); }
internal ErcResult <List <Tuple <byte[], byte[]> > > BuildSehChain() { ErcResult <List <Tuple <byte[], byte[]> > > sehList = new ErcResult <List <Tuple <byte[], byte[]> > >(ThreadCore); sehList.ReturnValue = new List <Tuple <byte[], byte[]> >(); if (Teb.Equals(default(TEB))) { sehList.Error = new Exception("Error: TEB structure for this thread has not yet been populated. Call PopulateTEB first"); return(sehList); } if (Teb.CurrentSehFrame == IntPtr.Zero) { sehList.Error = new Exception("Error: No SEH chain has been generated yet. An SEH chain will not be generated until a crash occurs."); return(sehList); } byte[] sehEntry; byte[] sehFinal; int arraySize = 0; if (X64 == MachineType.x64) { arraySize = 8; sehEntry = new byte[arraySize]; sehFinal = new byte[arraySize]; sehEntry = BitConverter.GetBytes((long)Teb.CurrentSehFrame); } else { arraySize = 4; sehEntry = new byte[arraySize]; sehFinal = new byte[arraySize]; sehEntry = BitConverter.GetBytes((int)Teb.CurrentSehFrame); } for (int i = 0; i < sehFinal.Length; i++) { sehFinal[i] = 0xFF; } byte[] prevSEH = new byte[] { 0xFF }; string pattern_standard = File.ReadAllText(ThreadCore.PatternStandardPath); string pattern_extended = File.ReadAllText(ThreadCore.PatternExtendedPath); while (!sehEntry.SequenceEqual(sehFinal)) { byte[] reversedSehEntry = new byte[arraySize]; byte[] nSeh = new byte[arraySize]; byte[] sehHolder = new byte[arraySize * 2]; int ret = 0; if (X64 == MachineType.x64) { ret = ErcCore.ReadProcessMemory(ThreadProcess.ProcessHandle, (IntPtr)BitConverter.ToInt64(sehEntry, 0), sehHolder, arraySize * 2, out int retInt); Array.Copy(sehHolder, 0, sehEntry, 0, arraySize); Array.Copy(sehHolder, arraySize, nSeh, 0, arraySize); } else { ret = ErcCore.ReadProcessMemory(ThreadProcess.ProcessHandle, (IntPtr)BitConverter.ToInt32(sehEntry, 0), sehHolder, arraySize * 2, out int retInt); Array.Copy(sehHolder, 0, sehEntry, 0, arraySize); Array.Copy(sehHolder, arraySize, nSeh, 0, arraySize); } if (ret != 0 && ret != 1) { ERCException e = new ERCException("System error: An error occured when executing ReadProcessMemory\n Process Handle = 0x" + ThreadProcess.ProcessHandle.ToString("X") + " TEB Current Seh = 0x" + Teb.CurrentSehFrame.ToString("X") + " Return value = " + ret + Environment.NewLine + "Win32Exception: " + new Win32Exception(Marshal.GetLastWin32Error()).Message); sehList.Error = e; sehList.LogEvent(); return(sehList); } Array.Reverse(nSeh); for (int i = 0; i < sehEntry.Length; i++) { reversedSehEntry[i] = sehEntry[i]; } Array.Reverse(reversedSehEntry, 0, reversedSehEntry.Length); if (prevSEH.SequenceEqual(reversedSehEntry)) { sehEntry = new byte[sehFinal.Length]; Array.Copy(sehFinal, 0, sehEntry, 0, sehFinal.Length); } else if (!sehEntry.SequenceEqual(sehFinal) && !sehList.ReturnValue.Any(e => e.Item1.SequenceEqual(reversedSehEntry))) { Tuple <byte[], byte[]> tuple = new Tuple <byte[], byte[]>(reversedSehEntry, nSeh); sehList.ReturnValue.Add(tuple); } if (pattern_standard.Contains(Encoding.Unicode.GetString(reversedSehEntry)) || pattern_extended.Contains(Encoding.Unicode.GetString(reversedSehEntry))) { sehEntry = new byte[sehFinal.Length]; Array.Copy(sehFinal, 0, sehEntry, 0, sehFinal.Length); } if (pattern_standard.Contains(Encoding.ASCII.GetString(reversedSehEntry)) || pattern_extended.Contains(Encoding.ASCII.GetString(reversedSehEntry))) { sehEntry = new byte[sehFinal.Length]; Array.Copy(sehFinal, 0, sehEntry, 0, sehFinal.Length); } if (pattern_standard.Contains(Encoding.UTF32.GetString(reversedSehEntry)) || pattern_extended.Contains(Encoding.UTF32.GetString(reversedSehEntry))) { sehEntry = new byte[sehFinal.Length]; Array.Copy(sehFinal, 0, sehEntry, 0, sehFinal.Length); } if (pattern_standard.Contains(Encoding.UTF7.GetString(reversedSehEntry)) || pattern_extended.Contains(Encoding.UTF7.GetString(reversedSehEntry))) { sehEntry = new byte[sehFinal.Length]; Array.Copy(sehFinal, 0, sehEntry, 0, sehFinal.Length); } if (pattern_standard.Contains(Encoding.UTF8.GetString(reversedSehEntry)) || pattern_extended.Contains(Encoding.UTF8.GetString(reversedSehEntry))) { sehEntry = new byte[sehFinal.Length]; Array.Copy(sehFinal, 0, sehEntry, 0, sehFinal.Length); } prevSEH = new byte[reversedSehEntry.Length]; Array.Copy(reversedSehEntry, 0, prevSEH, 0, reversedSehEntry.Length); } SehChain = new List <Tuple <byte[], byte[]> >(sehList.ReturnValue); return(sehList); }