Jump to content

Photo

RemoteModule and Structures.


  • Please log in to reply
3 replies to this topic

#1 master131 Posted 22 September 2013 - 04:04 AM

master131

    Soldier

  • Members
  • Pip
  • 3 posts

I came across BinarySharp today and its VERY impressive. It's like an all-in-one library for memory/process related operations and I'm amazed at how extensive it is.

 

I was interested in how the addresses of remote functions were being found and it seems that it attempts to call LoadLibrary on the target module instead of manually reading it remotely from the Portable Executable structure in memory. I did notice that you said that you were currently working on a "PE Format Analysis" feature which will probably allow this to happen without having to load the module but its just a suggestion if you didn't think of it.

 

I have written my own extensive portable executable class but I didn't add any abstraction for it to work with memory (only works with images on disk) so it'd be nice to see someone else's approach on it.

 

The following only applies when you decide to add both 32-bit and 64-bit support to your library (as far as I know it's 32-bit only right now).

 

Also, I've had a look at the ManagedTeb and ManagedPeb classes and it seems they're using Enums to obtain the field offsets. Due to the varying in sizes of the pointer type in 32-bit and 64-bit applications, wouldn't those offsets break? From looking at your enums, it seems like you've assumed that all pointer types are 4 bytes long. Also, in the TebStructure enum, you've called one of the fields "WoW64Reserved" when the correct name is actually "Wow32Reserved".

 

Another thing is that in WoW64 processes, there are actually 2 PEBs and 2 TEBs. One is the 32-bit version and the other one is the 64-bit version. The 64-bit TEB and PEB structure actually vary, that being the pointer sizes are different. Also, in the 64-bit PEB, the GdiHandleBuffer field only has 30 values as opposed to 34. If you require a detailed reference, you can look here.

 

Also, obtaining the PEB/TEB of another process is abit troublesome too. If you are a 64-bit process and wish to obtain the 32-bit PEB of a Wow64 process (which is the default one if you were that Wow64 process), you need to use ProcessWow64Information with NtQueryInformationProcess instead of ProcessBasicInformation otherwise it'll return the 64-bit PEB (use IsWow64Process along with a GetProcAddress check to determine if a process is running under WoW64). When using NtQueryInformationProcess with ProcessWow64Information, it takes a reference to a pointer-sized integer (aka, IntPtr) instead of a PROCESS_BASIC_INFORMATION structure and puts the address of the PEB in this pointer-sized integer.

[DllImport("ntdll.dll", SetLastError=true)]
public static extern int NtQueryInformationProcess(IntPtr hProcess, PROCESSINFOCLASS pic, ref IntPtr pbi, int cb, out int pSize);

 

If you are a 64-bit process and wish to obtain the 32-bit TEB of a Wow64 process, you use the same usual method of obtaining the TEB using NtQueryInformationThread (which in this case will return the 64-bit TEB) and then add 0x2000 because the 64-bit TEB always preceeds the 32-bit TEB by 2 pages (reference: here, check Side Notes, you can see the offset is hardcoded in Wow64cpu!CpuThreadInit).

 

Once you've made all the necessary fixes for 32-bit/64-bit TEB/PEB structures, you could easily add a feature that allows you to unlink/hide a module from the PEB. (example: here)

 

Another thing is the .NET Process suffers from a problem where if you are running as a 64-bit process and are trying to list the modules of a Wow64 process, it will only list the 64-bit modules (the target's main module, ntdll.dll, wow64.dll, wow64win.dll and wow64cpu.dll). The workaround is to use EnumProcessModulesEx with the LIST_MODULES_ALL filter flag (note that this function only exists in Vista and higher). Then you have you use the populated module handle array with the corresponding functions to obtain the module name, path, size, etc (GetModuleBaseName, GetModuleFileNameEx and GetModuleInformation respectively). The only problem with this is that you cannot create an instance of the ProcessModule class unless you use some hackery with Reflection and populate the internal ModuleInfo class and call the ProcessModule internal constructor.

 

Hope this helps. If you require me to explain me to explain anything, then let me know. :)


Edited by master131, 22 September 2013 - 06:27 AM.

  • Back to top
  • Report

#2 ZenLulz Posted 22 September 2013 - 03:32 PM

ZenLulz

    Lead Developer

  • Administrators
  • 67 posts
  • LocationSwitzerland

Hello Master131,

 

Thank you for your great feedback. I always appreciate to discuss about the future of my products.

 

To be exact, MemorySharp determines the function addresses using the function GetProcAddress if the requested module is already loaded within the application that executes the library. If this is not the case, the application loads the module using LoadLibrary, performs the function GetProcAddress, returns the address of the searched function (subtract the address of the function to the base address of the module if the module is loaded at a different location within the edited process), caches the address to avoid reloading the module for the same function and finally removes the module. It seems to be heavy operations but requires a minimum of function calls. Nevertheless, there can be a side effect if the module performs some actions in its DllMain function. This is why I don’t like this method. I can fix that by performing a remote call of the function GetProcAddress. Actually, this is not the case because the remote function calling feature was developed after the module part and I know these information can be gathered from the PE header. I will rewrite the function searching engine when I will implement the PE header reader. :)

 

Your post is here just at the right moment because I'm extending MemorySharp to be compatible with 64-bit applications!

 

I’m not really happy about the strong coupling between the library and the API Win32, because as you rightly stated, some API functions depend on the architecture of the process. So, I decided to add an abstraction layer to be able to call right API functions according the architecture of the edited process.

 

Here is a UML diagram that describes what I planned.

 

Attached File  Abstraction layer for 64-bit.png   24.67KB   1 downloads

 

I already began to implement it. My progress can be reviewed in the Development branch on Github if you are interested. I also spend some time to write a helper to determine the architecture of a process (here).

 

I was unaware that there are 2 PEB/TEB in a WOW64 process. I carefully read your post and want to thank you for your time to write this clear explanation. In my opinion, I will also add an abstraction layer for the PEB/TEB given that there are complex components and architecture dependent. I will look after of all these “so-funny” API Win32 functions. :D

 

I also didn’t know that a 64-bit .NET application couldn’t enumerate 32-bit modules for a WOW64 process (there is a nice read here)… Microsoft definitely makes our works harder. :P

After all, I don’t know if I will write a workaround for that. This will bypass the implementation of the modules of the .NET Framework and forces me to rewrite of the methods to collect data for a module. Instead, the developers can change the platform target of their applications to target 32-bit or 64-bit. Of course, if their goals were to edit modules with one binary, it won’t work. For the moment, I’m going to focus on 64-bit and features that are marked as “coming soon” on my list and after, if Microsoft didn’t change its logic, it can be the object of an improvement.

 

Again, thanks for your post !

 

Cheers,

ZenLulz


ZenLulz

  • Back to top
  • Report

#3 master131 Posted 22 September 2013 - 04:54 PM

master131

    Soldier

  • Members
  • Pip
  • 3 posts

I'm glad I could help. Also, just a tip, in your IsWoW64Process function, you should check that the function exists before calling it using GetProcAddress as suggested on MSDN, otherwise it'll throw an exception.

 

:D


Edited by master131, 22 September 2013 - 04:54 PM.

  • Back to top
  • Report

#4 ZenLulz Posted 22 September 2013 - 08:24 PM

ZenLulz

    Lead Developer

  • Administrators
  • 67 posts
  • LocationSwitzerland

Ah yeah, you are right. I'm going to add this check in the next push. ;)


ZenLulz

  • Back to top
  • Report




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users