How to patch EXE files

Leonid Khlebushchev
7 min readFeb 14, 2024

--

Introduction

Are you a penterster? Or maybe you are a hacker or just an extraordinary person who is interested in unusual topics? Or maybe you had a situation where you needed to insert some code inside an .exe or .dll file without recompiling? If something of sair is true then WELCOME!

WARNING: This article has no purpose to break the law. The tool which is reviewed here and this article are made only for education purposes.

Review

I want to present to you a tool for injecting custom bytecode into an .exe or .dll file (or usually it called a PE file). That tool has a name “PE-infector” (https://github.com/MastMind/PE-infector). The idea of injecting bytecode into another program is not something new, but when I needed to do that, I found out that Internet has no easy and usefull tool for implementing that (sometimes there were examples for demonstration purposes or tools that didn’t work properly). That’s why I wanted to make a similiar tool myself… And so I did.

Common properties of the PE-infector:

1. Bytecode injection inside a PE file (exe, dll, 32bit, 64bit)

2. An option of selecting the injection method (tool has several ways of injection)

3. Run injected bytecode within a separate thread

4. The tool is crossplatform: you can use it on Windows, Linux, Android or other compatible OS’ (you just need an installed gcc compiler)

How to use it

After downloading (https://github.com/MastMind/PE-infector) you should build it:

For Linux:
make

For Windows:
compile.bat

You will then have a new executable file PE-infector (or PE-infector.exe if you are using Windows). Let’s try to read help:

./PE-infector --help                                                          
Usage: ./PE-infector -i <input_file> -o <output_file> -s <raw_shellcode_file>
-d - show section info
-m - set infection method (available values: code, sect, resz)
-n - set new section name (for selected method: sect)
-t - execute shellcode within a separate thread (for 32bit and resize or new section methods only)

We can see here that for this tool we should set 3 necessary options: an input file, an output file and a raw shellcode file. The input file is obviously our target .exe or .dll which should be patched. The output file is a location for the patched file. It is obvious also. But what is a raw shellcode file? It is a file with your bytecode inside. The bytecode should have the same architecture as your target executable file (for example if your .exe has 64bit arch it means you have to use only 64bit bytecode). So you are to write the bytecode yourself or obtain it from another source (for example you can generate it with the metasploit framework which preinstalled in Kali Linux). Some theory about how Windows executables work.

What is a PE file

When you compile a program you will have an .exe or .dll file as a result. But what really is an .exe or .dll file? What is inside of it? Usually you’ll get an answer “Files contain a program in machine code view” and it is the right answer but only partly. Also those files contain special information for OS about what your program is and how to execute it. For example in .exe or .dll file you can read the information about architecture, required dll’s and their functions, DOS stub (for the compatibility with old DOS operation systems: this stub only reads “This program cannot be run in dos mode”) and so on. Actually we can say that .exe or .dll is a container for the compiled machine code and the format of this container is named PE (PE means Portable Executable format). Yes, .exe and .dll do not differ inside (they have the difference only in a single option: in the header and the import/export tables inside). We know that a machine code inside PE and bytecode are equialent terms and it means our tool gives us the ability to us to insert a new functionality without recompiling the program entitely.

In order to work with our tool properly we additionally need to know a couple of terms about PE: sections and an entry point. Section is a dedicated fragment of an .exe file where your program stores the data. It could be text constants, values and so on but we should know a very important fact for us that the section can hold a machine code also. When Windows is trying to open the program, it loads the sections into memory to special adresses in the virtual address space (it is just valid logical addresses where the data could be stored). How does Windows know about the beginning of the program? It knows it from a special entry point address in the PE header. The entry point address is always a logical address (non physical address which is an offset in the original file). Our tool does an easy job by the concept. It inserts external bytecode into a special section (or sections) and changes the entrypoint address to execute this (with resuming of the og program of course). We have only 3 ways to inject bytecode: inject it into the code section (the most popular method, because all modern PE have the only main code section, but it needs available space at the end of the section), inject it into a new premade section (it will work, but antimalware software will detect this stuff, because it was the most popular method in the past) and resizing the code section to the required size and injecting the bytecode there (the most safest method, but we can’t resize the code section over and over again). In the PE-infector all those ways are presented in -m option (“code” is a value for the first way, “sect” is for the new section method and “resz” for resizing the current code section):

-m - set infection method (available values: code, sect, resz)

Don’t worry. The tool calculates available space for your bytecode and informs if it is too small. I recommend using the “resz” method because it works for the most cases. Let’s try to use it on a real example.

Example

My roomate likes to play TES4 Oblivion. I want to prank him. I want to modify the main .exe file with the game to display a message with the text “Big brother is watching you” before starting the game. I could change the path in the link to another .exe but not in this case, because my roomate is a little bit paranoic and run the game directly via .exe file without any links. So I must patch the .exe. I copied Oblivion.exe file to my directory with the PE-infector and now I should generate bytecode for showing a message box. I use the metasploit framework for this:

msfvenom -p windows/messagebox TEXT="Big brother is watching you" -f raw > shellcode.raw

Very good. Now we have a target .exe file and raw bytecode. Now we can try to patch:

./PE-infector -i Oblivion.exe -o Oblivion_patched.exe -s shellcode.raw
That binary has 32bit arch
That is EXE file
EntryPoint: 0x0058787C
ImageBase: 0x00400000
File alignment: 0x00000200
size of shellcode: 282
original entry point 0x0098787C
injection new_entry_point 0x00627C3D
dll_characteristics 0x0000
Infection success!

We’ve got success. Such a lucky case to inject bytecode into a default code section (the use of the resize technique is necessary often very much). Very often you’ll have an error and it means you have to try the next command (it is a nobrainer with the resize option. It should work in most cases):

./PE-infector -i Oblivion.exe -o Oblivion_patched.exe -s shellcode.raw -m resz

Now we should replace the original .exe and check how it works.

Yes. We have a message but wait, why the game is not running after closing the window? What’s wrong? We don’t have the original code running because our shellcode has a small feature. It terminates the current process after it finishes (it is the default behavior for all kinds of shellcode generated via the metasploit). To fix that we have to use a little different command to generate shellcode:

msfvenom -p windows/messagebox TEXT="Big brother is watching you" EXITFUNC=none -f raw > shellcode.raw

And try to patch it again with the same command:

./PE-infector -i Oblivion.exe -o Oblivion_patched.exe -s shellcode.raw

Let’s test it:

The message is showing
The game is running after closing the message

Now it works as intented. But it has a little weird detail — the game will not be running until the user closes the message window. What if we want to run the game immidiately without user’s interactions? We can use -t option (-t means running the shellcode within a separate thread):

./PE-infector -i Oblivion.exe -o Oblivion_patched.exe -s shellcode.raw -t

Just try it and see the result.

Conclusion

Actually injecting a program into another program is not rocket science and could be implemented as a nobrainer tool (ok, almost nobrainer). On the page https://github.com/MastMind/PE-infector-GUI you can find a GUI wrapper for the PE-infector. But creating custom shellcode manually is a complicated topic and it deserves its own article. Have some nice hacking and Good Bye!

Update

The option -t (run shellcode within a separate thread) now works for x64 binaries too

--

--