Backdooring PE Files

James Patrick
7 min readSep 19, 2023

--

A Trojan is designed to fool the end user. It can be software mimicking the real program, running malware under the hood, or a real program modified by the attacker in order to run the malware side by side. There are typically three ways to backdoor PE files.

- Code Cave
- New Section
- Extending Section

Code cave is a space inside of a PE file, usually in the text section, and this space is not occupied by any other data or code. The only downside to this is you would only have a few hundred bytes for your malware.

If you need more space you can add a new section to your victim program and set the size however you want. The downside is this section needs to be set as executable which could be flagged by AV engines.

Extending a section allow you to pick a section, usually the last one, and increase its size so it can hold your additional code.

These can also be combined. You can use code cave in a text section for small shellcode which will then load code from your “added” section or even the resource section, which lowers the probability of being flagged.

For this example we with concentrate on a Code Cave and modifying a PE so our shell code get executed while still running the original code.

The target for this example will be putty.exe:

We will open putty in a debugger and verify the entry point:

Let’s scroll down to find some empty space for our Code Cave:

Setting a break point here for reference and so we can easily find it, and document the address:

Going back to the entry point we need to create a jump to the address of our Code Cave where we will place our shell code and jump back to the entry point. For the jump we will need to overwrite several instructions, so we will copy some of the initial code and save it to Notepad:

We will right-click the entry point and choose assemble:

Entering `jmp 0x0045C961`which is our Code Cave address:

Hitting Enter on that jump will take us to our Code Cave:

We could copy our shellcode here, but since it will change the state of the machine — registers, instruction pointers, and other values on the stack — we should save the state of all the registers and flags onto the stack with two instructions. We will use “pushad” which will push all the values of the registers:

And “pushfd” for flags:

Now we select the remaining open space by highlighting the first and last address by holding shift:

Here I will be using Hex from calc32.hex, select all:

Back to the debugger we right-click the selected, choose binary and edit:

And paste the Hex:

This is our shellcode:

To test we will right-click and choose “patches”:

Select all:

Patch the file, naming it something like Putty2.exe:

Then open the new putty in the Debugger and hit enter on the entry point to land on our jump, and set another break point:

Let’s hit run — and run again from our BP and hopefully our shellcode runs:

Success. But putty has exited! We could search to find the exit code which would be tedious. Let’s try to find the exit *call* and skip or override it. For now we will set breakpoints on all the calls in our code:

We will run it, it first lands on our entry point:

Run again and it lands on our Cave:

We will see after this jump it launches our shellcode (calc):

We will add a comment here “calc launched”:

We will run again to see if the program exits:

It doesn’t. We have one more *call* left, which should cause it to exit:

And it does.

So now we have to get rid of this. We can jump out of it and get back to the original putty call which we have saved:

We will choose an empty address in our Cave and copy it:

Right-click the “push 0” and choose “Assemble” and add the jump:

Now we have to restore the original context of the CPU. If you remember we saved the state previously with pushad and pushfd:

We will right-click the jump destination and assemble:

Finally we have to restore these two instructions:

Let’s clean it up and copy the bytes:

Then select some space and choose Binary — Edit:

And Control-V paste the copied Hex:

Restored:

The last task we need to perform is to jump to the below putty.exe instruction:

We will copy the address (00454AD7) and right-click the next line — assemble:

Add our jump:

Then hit enter and see if we jump back:

And we do:

Now we can right-click anywhere and select *patches*. Make sure it all is selected and save as Putty3.exe (or whatever):

Launch Putty3.exe, we get putty and our calc shellcode!

--

--