Shellcode Development PDF
Shellcode Development PDF
development
HADESS [Link]
Introduction
Understanding Shellcode At its core, shellcode is a payload used in the exploitation of a
software vulnerability. It is the "shell" that hackers use to interact with the compromised
system. Unlike regular code, shellcode is written directly in machine language and is designed to
be injected into and executed by an exploited program. This low-level programming requires an
intimate understanding of system internals, memory management, and processor instruction
sets, making it a challenging yet rewarding endeavor.
The Evolution of Shellcode Historically, shellcode was simple and straightforward, primarily
used to spawn a shell on the target system, hence the name. However, as cybersecurity
defenses have evolved, so too has shellcode. Modern shellcode can perform a variety of
sophisticated tasks, from creating reverse connections to encrypting data for ransomware
attacks. This evolution reflects the ongoing cat-and-mouse game between attackers and
defenders in the digital world.
The Role of Assembly Language The development of effective shellcode is deeply rooted in the
use of assembly language. This low-level programming language offers direct control over
system resources, which is crucial for crafting concise and efficient shellcode. Mastery of
assembly language enables developers to write shellcode that can bypass security mechanisms,
exploit vulnerabilities, and execute payloads with minimal footprint.
Ethical Use and Research While shellcode is often associated with malicious activities, it also
plays a crucial role in ethical hacking and cybersecurity research. Security professionals use
shellcode to test and strengthen defenses, develop patches, and understand attack
methodologies. Ethical shellcode development is a key component in the arsenal of penetration
testers and security analysts, helping to safeguard systems against potential threats.
To be the vanguard of cybersecurity, Hadess envisions a world where digital assets are safeguarded from malicious actors. We strive to create a secure digital ecosystem, where
businesses and individuals can thrive with confidence, knowing that their data is protected. Through relentless innovation and unwavering dedication, we aim to establish Hadess as a
symbol of trust, resilience, and retribution in the fight against cyber threats.
Document info
HADESS
To be the vanguard of cybersecurity, Hadess envisions a world where digital assets are
safeguarded from malicious actors. We strive to create a secure digital ecosystem, where
businesses and individuals can thrive with confidence, knowing that their data is protected.
Through relentless innovation and unwavering dedication, we aim to establish Hadess as a
symbol of trust, resilience, and retribution in the fight against cyber threats.
At Hadess, our mission is twofold: to unleash the power of white hat hacking in punishing black
hat hackers and to fortify the digital defenses of our clients. We are committed to employing our
elite team of expert cybersecurity professionals to identify, neutralize, and bring to justice those
who seek to exploit vulnerabilities. Simultaneously, we provide comprehensive solutions and
services to protect our client's digital assets, ensuring their resilience against cyber attacks. With
an unwavering focus on integrity, innovation, and client satisfaction, we strive to be the guardian
of trust and security in the digital realm.
Security Researcher
Alex Nomad
Table of Content
Executive Summary
pe_to_shellcode
Unicorn project
msfvenom - nasm
DynamicCrawlingFunctioninPE(PortableExecutable)
ROP
Conclusion
Shellcode Development
[Link]
Executive Summary
1. pe_to_shellcode: The pe_to_shellcode project, developed 7. Rust and Python Shellcode Generator: These are tools
by Aleksandra Doniec and @hh86, focuses on converting PE developed in Rust and Python for generating shellcode. They
(Portable Executable) files into shellcode. This tool modifies typically involve assembling and linking assembly code into
the PE header, allowing the converted file to be injected and executable formats and then extracting the machine code to
executed like standard shellcode. It supports basic PE be used as shellcode.
structures like relocations, imports, and TLS callbacks.
However, it doesn't support more complex elements like 8. Writing 32-bit Shellcode in x86 Assembly: This involves the
exceptions, Delay Load Imports, and MUI files. The tool is development of shellcode specifically for 32-bit systems
designed for ease of use, where users can convert PEs using a using x86 assembly language. It requires an understanding of
simple command-line interface. the architecture and system internals to create effective and
compact shellcode.
2. Parsing Kernel32’s Export Table in x86 Assembly: This
process involves enumerating and extracting function 9. Dynamic Crawling Function in PE (Portable Executable):
addresses from the [Link]’s export table using x86 This function is part of shellcode development where the
assembly language. It's a crucial step in shellcode code dynamically crawls through the PE structure of a
development for Windows, as it allows the shellcode to loaded executable to locate specific data or functions. It's
dynamically locate essential system functions. essential for shellcode that needs to interact with or modify
the running executable.
3. Getting API Addresses in x86 Assembly: This technique
retrieves the addresses of API functions from the export 10. Understanding EATs in PE (Portable Executable): Export
table. It's done by matching function names against their Address Tables (EATs) in PE files are crucial for shellcode
hashed values and then extracting their addresses, a method developers as they provide information about the functions
commonly used in shellcode to avoid hardcoding addresses. exported by an executable or DLL. Understanding EATs is key
to developing shellcode that interacts with these functions.
4. File Mapping and Repairing the Import Table in x86: This
involves creating a memory-mapped file of an executable and 11. EATs in PE (Portable Executable): EATs are part of the PE
then repairing its import table. This process is essential for file format, listing the addresses of exported functions. They
ensuring that the loaded executable can correctly reference are essential for shellcode and exploit development, as they
external libraries and functions. allow for the dynamic resolution of function addresses at
runtime.
5. Unicorn Project: Developed by Dave Kennedy at
TrustedSec, the Unicorn project is a tool for creating
PowerShell-based injection attacks. It simplifies the process
of generating and using shellcode in various formats,
including HTA, macro, and DDE, and supports payloads like
Meterpreter.
Key Findings
User Account Control bypass techniques that allow malware to operate stealthily and resist detection and removal efforts.
The key findings highlight the innovative and diverse methods used by modern malware to evade security measures,
emphasizing the need for advanced and comprehensive security solutions to counter these threats.
pe_to_shellcode
Parsing Kernel32’s Export Table in x86 Assembly
Getting API Addresses in x86 Assembly
File Mapping and Repairing the Import Table in x86
Unicorn project
msfvenom - nasm
Rust and Python Shellcode Generator
Writing 32-bit Shellcode in x86 Assembly
Dynamic Crawling Function in PE (Portable Executable)
Understanding EATs in PE (Portable Executable)
EATs in PE (Portable Executable)
ROP
Shellcode Development
Abstract
This article explores the intricate and evolving world of shellcode development, a critical aspect of
cybersecurity that straddles the line between programming art and technical science. Shellcode,
essentially a set of machine code instructions designed to perform specific tasks when executed, plays a
pivotal role in both offensive and defensive cybersecurity strategies. The article begins by defining
shellcode and its primary functions in the context of software exploitation. It then traces the evolution of
shellcode from its origins as simple code for spawning system shells to its current state as a sophisticated
tool capable of performing complex and varied tasks.
A significant focus is placed on the role of assembly language in shellcode development, emphasizing its
importance in crafting efficient and effective payloads. The challenges inherent in shellcode development,
such as space limitations and the need for evasion techniques, are discussed, highlighting the creativity
and ingenuity required in this field. The article also addresses the ethical dimensions of shellcode,
underscoring its utility in ethical hacking and cybersecurity research for strengthening digital defenses.
Looking forward, the article speculates on the future trajectory of shellcode development, considering the
impact of emerging technologies and the evolving cybersecurity landscape. It concludes by reflecting on
the dual nature of shellcode as both a weapon in the hands of attackers and a shield in the arsenal of
defenders, underscoring its significance in the ongoing battle for cybersecurity.
[Link]
EATs in PE
Methods
Dynamic Crawling Function in PE
ROP
[Link]
Shellcode Development
01
Attacks
[Link] Shellcode Development
Shellcode
Shellcode is a set of instructions used as a payload in the exploitation of a software vulnerability. It is called "shellcode"
because it typically opens a command shell from which the attacker can control the compromised machine. However,
shellcode can perform a variety of operations, not just opening a shell.
Characteristics of Shellcode
Compact and Efficient: Shellcode is designed to be small and efficient to avoid detection and fit into small memory
spaces.
System-Level Access: It often aims to gain low-level system access, which can be used to bypass security mechanisms.
Written in Machine Code: Shellcode is usually written in machine code, the lowest-level programming language, because it
needs to interact directly with the operating system at a fundamental level.
Types of Shellcode
Local Shellcode: Executed on a user's machine to escalate privileges or gain access to restricted resources.
Remote Shellcode: Used in network-based attacks to gain control over a remote system.
Staged Shellcode: Delivered in parts, often used when there's a limitation on the size of the exploit.
Egg Hunters: Used when the shellcode is larger than the allowed space for the exploit. It searches for the rest of the code
in memory and executes it.
Payload Delivery: In the context of a cyber attack, shellcode is often the payload delivered by an exploit. Once the exploit
breaches the system's defenses, the shellcode is executed to perform malicious actions.
Reverse Engineering and Security Testing: Ethical hackers and security researchers use shellcode to test the security of
systems and applications.
[Link] Shellcode Development
Understanding EATs:
Function Exports: The EAT lists the addresses of functions that are exported by a DLL.
Lookup by Name or Ordinal: Functions can be looked up by name or ordinal number.
Dynamic Linking: The EAT is essential for dynamic linking, as it allows an executable to locate and call functions from a
DLL at runtime.
Overview of EAT in PE
DataDirectory Table:
Located in the Optional Header section of NT Headers in the PE [Link] various information records,
including pointers to different directories like Export Directory, Import Directory, Security Directory, and .NET Header.
Practical Example
Module Name: The EAT records the module name at compilation, which is used for integrity checks (e.g., [Link] vs.
[Link]).
Function Ordinals: Exported functions are assigned ordinals, which are used as identifiers. Internal functions without
ordinals are not affected by this.
NumberOfFunctions vs. NumberOfNames
Anonymous Functions: In C/C++, functions can be exported without a name, hence the need for two different
variables. Function calls can be made using ordinals instead of names.
Dependency Walker: Shows all dependent modules of a PE file and can display the EAT.
IDA Pro: A disassembler that can analyze the binary and show the EAT among other things.
Overview
Purpose: To find system module and function addresses dynamically, bypassing standard API calls.
Technique: Involves parsing the PE structure, particularly focusing on the EAT.
Usage: Common in shellcode for stealth and evasion, as it doesn't rely on standard API calls that can be monitored or
hooked.
Example: dynEatCall.c
This example demonstrates how to dynamically find the address of a function (like WinExec) in [Link] without using
GetProcAddress.
Main Function
The entry point is similar to ldrParser.c from a previous chapter.
Instead of GetProcAddress, a custom function GetFuncAddr is used to find the function address.
GetFuncAddr Function
Parsing the DLL Module Address:
The incoming dynamic DLL module address is parsed to find the EAT RVA in the Optional Header → DataDirectory
section.
Identifying Array Pointers:
Locate AddressOfFunctions, AddressOfNames, and AddressOfNameOrdinals in the EAT.
These arrays are used to find the correct address in dynamic memory.
Practical Example
Running dynEatCall:
Analyzes [Link] to export WinExec with an ordinal of 0x0601.
Successfully calls WinExec to launch the Calculator.
Confirmed by PE-bear tool analysis.
Important Notes
32-bit vs. 64-bit Environments:
In a 64-bit Windows environment, the path for [Link] should be C:\Windows\SysWoW64\[Link] (for 32-bit
compatibility) instead of C:\Windows\System32\[Link].
Windows uses WoW64 (Windows 32 on Windows 64) for backward compatibility with 32-bit applications.
section .text
global _start
_start:
; Assume the base address of [Link] is in EBX
; and the function name we are looking for is in ESI
This code is highly abstract and would need to be fleshed out with the specific details of the PE structure parsing and
array traversal logic.
Access IMAGE_DOS_HEADER:
Use the DLL base address to access the IMAGE_DOS_HEADER.Obtain e_lfanew at offset +0x3C to find the
IMAGE_NT_HEADERS.
Locate EAT:
Get the RVA of the EAT from IMAGE_NT_HEADERS + 0x78.
Trace AddressOfNames, AddressOfNameOrdinals, and AddressOfFunctions.
; NASM syntax
[SECTION .text]
global _start
_start:
xor eax, eax ; Clear the EAX register
push eax ; Push EAX to have a string terminator NULL byte
push 0x68732f2f ; Push //sh in reverse (little endian)
push 0x6e69622f ; Push /bin in reverse
mov ebx, esp ; Move the stack pointer to EBX, which now points to our string
push eax ; Push EAX (NULL) to the stack to terminate the array of pointers
push ebx ; Push the address of our command string
mov ecx, esp ; Move the stack pointer to ECX, which now points to our array of pointers
mov al, 0xb ; Syscall number for execve in Linux
int 0x80 ; Interrupt to invoke the kernel
section .text
global _start
_start:
; write(1, message, 13)
mov eax, 4 ; syscall number for sys_write
mov ebx, 1 ; file descriptor 1 is stdout
mov ecx, message ; message to write
mov edx, 13 ; number of bytes
int 0x80 ; call kernel
; exit(0)
mov eax, 1 ; syscall number for sys_exit
xor ebx, ebx ; exit code 0
int 0x80 ; call kernel
section .data
message db 'Hello, World!', 0xA
Important Note
32-bit vs. 64-bit: The process described is for 32-bit shellcode. For 64-bit, offsets and registers (like gs[0x60] for PEB) will
differ.
[Link] Shellcode Development
import subprocess
# Example usage
assembly_code = """
section .text
global _start
_start:
; Your assembly code here
"""
shellcode = generate_shellcode(assembly_code)
print(shellcode)
This script is a basic example and would need to be adapted for specific requirements, such as different architectures or
more complex shellcode generation.
use std::process::Command;
use std::fs::File;
use std::io::Write;
use std::error::Error;
Ok(String::from_utf8_lossy(&[Link]).to_string())
}
_start:
; Your assembly code here
";
Ok(())
}
[Link] Shellcode Development
Key Points
File Handling: Rust uses File::create and write! macro for file operations.
Command Execution: std::process::Command is used to run external commands like nasm, ld, and objdump.
Error Handling: Rust's error handling is done through the Result type, which either contains the result or an error.
String Handling: String::from_utf8_lossy is used to handle potential UTF-8 conversion issues.
Contents of reverse_tcp.nasm:
Contents of bind_tcp.nasm:
3. Windows MessageBox
Command to generate shellcode:
Contents of [Link]:
; Windows MessageBox
; Displays "Hello, World!"
; Generated Shellcode Here
Contents of [Link]:
5. Windows Exec
Command to generate shellcode:
Contents of [Link]:
; Windows Exec
; Executes [Link]
; Generated Shellcode Here
Notes:
Replace "Generated Shellcode Here" with the actual shellcode output from msfvenom.
The -f raw option in msfvenom generates the shellcode in raw format.
The -o option specifies the output file name.
The contents of the NASM files should be the raw shellcode bytes, formatted appropriately for NASM.
Ensure that the IP address and port numbers are appropriate for your environment and use case.
Be cautious while using and testing these shellcodes, especially on systems and networks where you do not have explicit
permission to do so.
Key Points
File Handling: Rust uses File::create and write! macro for file operations.
Command Execution: std::process::Command is used to run external commands like nasm, ld, and objdump.
Error Handling: Rust's error handling is done through the Result type, which either contains the result or an error.
String Handling: String::from_utf8_lossy is used to handle potential UTF-8 conversion issues.
"Unicorn" is a tool developed by Dave Kennedy and his team at TrustedSec, designed for shellcode development and
injection, particularly focusing on PowerShell-based attacks on Windows platforms. This tool simplifies the process of
creating complex attack vectors, making it easier for security professionals to test the resilience of systems against such
attacks.
Usage Examples:
HTA Payload:
parse_exports:
; esi points to API CRC table
; ebp is Kernel32 base address
; Code to parse export table and match function names with CRC values
; ...
; Copy PE headers
mov esi, [AddressOfPE] ; Source: Address of the PE file in memory
mov ecx, [SizeOfHeaders]
rep movsb ; Copy headers
The project by Aleksandra Doniec, pe_to_shellcode, provides a comprehensive implementation of these concepts. It's a
set of stubs written in x86 assembly language that can convert any EXE file into shellcode. This project demonstrates a
complete lightweight application loader, handling all the tasks mentioned above.
The primary goal of "pe_to_shellcode" is to simplify the process of generating PE files that can be injected with minimal
effort. This project draws inspiration from Stephen Fewer's ReflectiveDLLInjection but differs in a key aspect: it allows the
addition of a reflective loading stub post-compilation. Moreover, the PE file's header is modified so that the injected
buffer can be executed from the beginning, similar to a shellcode. The tool automatically locates the stub and proceeds to
load the full PE.
Supported Features:
Basic PE structures like relocations, imports, and TLS callbacks (the latter are called once before the Entry Point is
executed).
Limitations:
The tool does not support more complex PE features such as exceptions, Delay Load Imports, and MUI files. This
means that not every PE can be successfully converted into shellcode.
[Link] Shellcode Development
Use [Link] to convert a PE file: [Link] <path to your PE> [output path]. The output path is optional.
If the conversion is successful, the tool will indicate the location of the saved file, e.g., [+] Saved to file: test_file.[Link].
Use [Link] to run the output file and verify the conversion: [Link] <converted file>.
It's important to use the correct version of [Link] (32 or 64 bit) matching the bitness of the converted application.
#include <iostream>
#include <cstring>
return 0;
}
However, it's crucial to remember that with great power comes great
responsibility. The knowledge and skills associated with shellcode
development should be applied ethically, with a focus on improving
security, conducting responsible vulnerability research, and
developing robust defenses against malicious actors.
Website: Email
[Link] MARKETING@[Link]
To be the vanguard of cybersecurity, Hadess envisions a world where digital assets are safeguarded from malicious actors. We strive to create a secure digital ecosystem, where
businesses and individuals can thrive with confidence, knowing that their data is protected. Through relentless innovation and unwavering dedication, we aim to establish Hadess as a
symbol of trust, resilience, and retribution in the fight against cyber threats.