hasherezade / libpeconv

A library to load, manipulate, dump PE files. See also: https://github.com/hasherezade/libpeconv_tpl
https://hasherezade.github.io/libpeconv
BSD 2-Clause "Simplified" License
1.09k stars 177 forks source link

Process hiving - stripped relocs. #43

Open illnyang opened 2 years ago

illnyang commented 2 years ago

I found a rather peculiar edge case, which is not currently handled by libpeconv (and if it is, I am too dumb to figure it out). Consider following scenario:

Payload is an executable PE with stripped relocs, its imagebase is 0x400000. My loader accounts for this with an explicit section layout, like so:

Name     Start    End      R W X D Class
-------- -------- -------- - - - - -----
.payload 00401000 20401000 R W . . BSS   
.og_bss  20401000 20402000 R W . . BSS   
.og_text 20402000 20414000 R . X . CODE 
.og_data 20414000 20415000 R W . . DATA 

The loader maps EXE payload into the .payload section, patches what's needed and jumps to its OEP. This technique is called Process Hiving, I believe. I'm using it as an alternative to DLL load order hijacking method (aka proxy DLLs) in my game modding framework.

If payload is not reloc-stripped, the loader will relocate it into the .payload section anyway.

I do not call VirtualAlloc at all, VirtualProtect is used to set appropriate section flags before jumping to the OEP.

My long-term goal is to have per-game targeted Linux compat patches as well - stuff like replacing XInput/WndProc with SDL2, replacing d3d9 with dxvk, etc. It would be nice for libpeconv to support Linux as well. taviso/loadlibrary is Linux-only and it feels redundant to have two separate dependencies of identical nature.

Similar approach is used in the following projects

hasherezade commented 2 years ago

Hi @illnyang ! sorry for the late response, I am very busy nowadays. I am not sure if I understood correctly what exactly are you trying to achieve, so if you can provide some more context about your intentions that would be very helpful.

Is it that you have the full PE (the payload) mapped inside a section .payload of the loader? So, the layout of the loader is:

Name     Start    End      R W X D Class
-------- -------- -------- - - - - -----
.payload 00401000 20401000 R W . . BSS   -> this is where the whole new PE (payload) will be loaded
.og_bss  20401000 20402000 R W . . BSS   
.og_text 20402000 20414000 R . X . CODE 
.og_data 20414000 20415000 R W . . DATA 

You said that your problem is related with the relocations of the payload. What exactly is the thing that libpeconv doesn't do correctly? Is your intention NOT to have the payload relocated, even if the relocation table isn't stripped? If so, it is possible to achieve, although it isn't default.

Or maybe you mean that libpeconv's API does not allow you to load a PE into the memory area that you specified, but instead, it does the allocation by itself, and therefore you cannot make it load to a predefined section? For example, this is how the loading function is implemented at the moment:

/**
Loads full PE from the raw buffer in a way in which it can be directly executed: remaps to virual format, applies relocations, loads imports.
Allows for supplying custom function resolver.
*/
BYTE* load_pe_executable(BYTE* payload_raw, size_t r_size, OUT size_t &v_size, t_function_resolver* import_resolver=NULL);

more details and alternative versions of this API here

And in order to load it into a predefined section, the API should look like this:

size_t load_pe_executable(BYTE* payload_raw, size_t r_size, BYTE* out_buffer, size_t out_size, t_function_resolver* import_resolver=NULL);

Please let me know, and I will make the appropriate changes soon.


Regarding the Linux support, it is another, long topic, and I will consider it as a direction of future development.