Building a Reverse Shell in Rust Using PEB Techniques

This post documents my exploration of implementing a reverse shell in Rust, starting from a standard API approach, and gradually shifting toward a stealthier variant that leverages manual parsing of the Process Environment Block (PEB). The goal is to reduce detection by Antivirus (AV) and Endpoint Detection and Response (EDR) engines.

Initial Implementation: Traditional API Call Chain

To begin, I created a basic reverse shell using the typical Windows API calls. The logic flow is straightforward and relies on functions exposed by common system libraries like Ws2_32.dll and kernel32.dll.

Reverse Shell Flow

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
WSASocket
inet_pton
connect
GetSystemDirectoryA
Initialize STARTUPINFOA
Set lpCommandLine
Initialize SECURITY_ATTRIBUTES
CreateProcessA
Finish
  • WSASocket / connect / inet_pton: Used to set up a TCP connection to the remote host.
  • GetSystemDirectoryA: Retrieves the system path, used to locate cmd.exe.
  • STARTUPINFOA / SECURITY_ATTRIBUTES / CreateProcessA: Used to spawn a new process (cmd.exe) with redirected input/output over the socket.

After compiling the shell, I submitted the resulting binary to VirusTotal. The community score was 28/72 — meaning 28 out of 72 AV/EDR engines flagged the executable as malicious. Most detections explicitly identified it as a reverse shell, which is expected due to the predictable API usage.

Image description


Improved Version: PEB-Based API Resolution

To evade static detection signatures, I rewrote the shell to resolve necessary APIs dynamically by walking the PEB instead of relying on the standard Windows API imports. This eliminates the need for a conventional import table and makes detection more difficult for AV engines relying on heuristic patterns or IAT analysis.

Revised Flow with Manual API Resolution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
WSAStartup (resolved from PEB)
WSASocket (resolved from PEB)
inet_pton (resolved from PEB)
connect (resolved from PEB)
GetSystemDirectoryA (resolved from PEB)
Initialize STARTUPINFOA
Set lpCommandLine
Initialize SECURITY_ATTRIBUTES
CreateProcessA (resolved from PEB)
Finish
  • All API addresses were resolved manually by parsing the export tables of kernel32.dll and Ws2_32.dll, accessed through the PEB.
  • No functions were declared in the import table, making the binary significantly harder to analyze via static disassembly or automated AV heuristics.

The resulting binary was again uploaded to VirusTotal. This time, the detection score dropped drastically to 2/72, with only Google and IKARUS flagging the file as suspicious. This demonstrates a significant improvement in stealthiness — achieved purely through API obfuscation and avoiding direct imports.

Image description

Today, I obtained a new VirusTotal scan result — this time, the detection score dropped to 11 out of 66.

Image description

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy