Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

C 

Basic Framework for Writing Positionally Independent Shellcode in C

TL;DR: CShell Github Link

I'm just releasing this project that I had worked on about a year ago when I was interested in writing more complex shellcode payloads, but I was pretty much hitting the ceiling of my assembly language capabilities. For this reason, I thought it would be much easier to just simply write my payloads in something sane and readable like C. However, C compilers will create a binary file from object code that is complete with storage sections and symbols, but our shellcode payload should generally just contain executable instructions and nothing more.

When I was writing a fully positionally independent shellcode payload for Windows, I really enjoyed this article which essentially describes how to utilize C-compiled binaries to extract its own executable section. Utilizing customized shellcode should be in every hacker's repertoire, but it can definitely be tedious to learn, and especially difficult to master. Because Windows doesn't work on system calls, it parses the export table of standard libraries (that are consistently loaded into the same address space for various reasons) and uses them just like normal kernel functions. Linux, however, doesn't quite work the same way. Instead, it uses so-called "system calls" that each perform a specific function and are implemented by the kernel.

There are a few things to watch out for when writing positionally-independent C code:
  • No use of any functions in the standard library. This can definitely seem tedious, but it doesn't really take that long getting used to. Note: you CAN still use any type/struct/enum definition or PP macro that you wish.

  • Don't use string literals in function calls or in pointer assignments. This is just a feature of C compilers; they will place string literals in a separate section of the resulting binary. In order to prevent this, declare strings as arrays instead as this will store the characters on the stack.

  • NEVER use `goto`. EVER. Except in this case.




CShell Syscall Wrapper

There are two syscall wrappers that come packaged in with CShell: x86 and x64. These are for i386 and amd64 platforms respectively. These are the ONLY assembly portions of the entire project. Any other platforms that wish to be supported must provide a similar system-specific syscall wrapper. This wrapper is meant to accept a syscall number and up to 6 additional parameters (for x86 and x64 this is sufficient). In the nomenclature I have used (cshell1, cshell2, cshell[N]...) N determines the number of parameters.

32 Bit Assembly Syscall Wrapper
PHP Code

<?php 
.intel_syntax noprefix
.text
.globl cshell1, cshell2, cshell3, cshell4, cshell5, cshell6

cshell1
:
cshell2:
cshell3:
cshell4:
cshell5:
cshell6:
 
//; create a stack frame to preserve previous base pointer
 
push ebp
 mov ebp
, esp

 
//; move all possible arguments into gp registers
 
mov eax, [ebp+0x08]
 
mov ebx, [ebp+0x0c]
 
mov ecx, [ebp+0x10]
 
mov edx, [ebp+0x14]
 
mov esi, [ebp+0x18]
 
mov edi, [ebp+0x1c]

 
//; save current ebp
 
push ebp
 mov ebp
, [ebp+0x20]

 
//; kernel int
 
int 0x80

 
//; restore ebp and destroy the stack frame
 
pop ebp
 mov esp
, ebp
 pop ebp
 ret 

64 Bit Assembly Syscall Wrapper
PHP Code

<?php 
.intel_syntax noprefix
.text
.globl cshell1, cshell2, cshell3, cshell4, cshell5, cshell6

cshell1
:
cshell2:
cshell3:
cshell4:
cshell5:
cshell6:
 
//; create a stack frame
 
push rbp
 mov rbp
, rsp

 
//; move all parameters to set up a syscall
 
mov rax, rdi
 mov rdi
, rsi
 mov rsi
, rdx
 mov rdx
, rcx
 mov r10
, r8
 mov r8
,  r9
 mov r9
, [rbp + 0x10]

 
//; execute the syscall
 
syscall

 
//; destroy the stack frame
 
mov rsp, rbp
 pop rbp

 ret 

Syscall Headers
Each (supported) syscall is nothing more than a preprocessor definition to call the desired `cshell[N]` function (where N is the number of parameters) which also converts the provided arguments to a uniform type (unsigned long). There are so many syscalls that I haven't even looked at, but you can always call the cshell functions directly.

Header Wrapper (Click to View)

Writing a Payload

Writing the payload is similar to how you would go about writing a normal C program, but instead of using nice, portable, standard library functions, you must use system calls and implement your own versions of various functions. You are responsible for memory allocation, child process management, string parsing, etc... This really isn't so bad! I wrote a client that:
  • Forks child processes that perform the following:

  • Spawns a reverse TCP shell using the typical dup2/execve over a TCP socket method.

  • Connects to a public FTP server with a username and password and downloads the remote file `readme.txt` to the local file `/tmp/testing.txt`



Here's the source. (Click to View)

Once you compile it with the assembly shellcode wrapper that correctly suits your architecture (Makefile provided), the resulting binary will be a static executable ELF file. Using the provided `gettext.txt` shell script, or performing this manually, you can use the `objdump` to identify the starting and ending positions of the `.text` (executable) section of the binary. Simply extract that portion of the binary, and we have our executable shellcode!

The resulting payload isn't really tiny... it's just about 2KB (although most of it goes to implementing the tiny FTP client, so a raw TCP file transfer would't be nearly as big to implement). But it is shellcode, and it is full positionally independent. This can be injected into an arbitrary process, or used as-is to poison an ELF file, or be triggered from any number of attack vectors in the heap/stack. It relies on absolutely no knowledge of library locations or anything external.

As of right now it definitely works with the FTP server I tested with, but it wouldn't work on an unauthenticated FTP server. It isn't a fully features FTP client; that would be too bloated even for this monstrosity. Instead, it just implements exactly what is needed to connect to that server. The resulting file is saved in /tmp/, but could be easily tailored to save somewhere else. This could be an incredibly simple bootstrap to deploy a much more sophisticated bootstrap.
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
This is cool, I wonder how difficult it would be to extract the binaries of non-inlined PIC functions independently into byte arrays, create your own rudimentary ABI with intermediary shellcode snippet encryption/decryption routines in between calls, and create a simple metamorphic engine. Very unethical and no good use for this however and you should not spread this information
i saw the article few years ago
base on https://nickharbour.wordpress.com/2010/0...c-compiler
i wrote short code to extract and test the shellcode
[Image: bitcoin.png] Be Nice For Once 15hVUVz7xA4kazHdk2BuErENGCskVwjYXP
Nice example, I did use similar technique to extract my test shellcodes. (I suck at nasm and just to setup the compiler and the working env was too much, so I compiled my stuff in vs as C and dumped the .code)
Accepting freelancing jobs ! PM me for more info !
Be the [BRAND NAME REMOVED] king ..
This was pretty neat! Thank you for sharing. :)
(Oct 30, 2018 10:27 AM)HFDone Wrote:  i saw the article few years ago
base on https://nickharbour.wordpress.com/2010/0...c-compiler
i wrote short code to extract and test the shellcode

Yep, that article was amazing for me when I read it a few years ago. Immensely advanced my understanding of EXE and DLL format.

This is heavily inspired by that but is for Linux, not Windows. Unlike Windows, Linux calling convention doesn't rely on external standard libraries for just about ALL functionality in assembly... there's no reason to parse /proc/map entries in Linux for everything, you have a kernel interrupt which, when provided specific values, will call different functions in the standard library. This is basically reducing high level functions (multithreading, reverse shell, ftp file transfer, etc) to their system call counterparts so no external libraries are needed.


But that article is actually how I developed file-less malware called Sicarius. Stub was less than 500 bytes of shellcode and could easily be embedded in code caves of binaries. All functionality was written in C and the first stager transferred contained MemoryModule, and after that you can load literally any DLL you want, in memory, over a network, without adding an entry to the loaded DLLs. Nice piece of ass, that software.
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
That X64 code will crash (given the right environment) due to the boundary alignment required by SSE (a general protection fault will be generated if the stack pointer is not 16 byte aligned). Due to this alignment requirement compilers normally don't use stack frames, and reference directly from RSP. (Could be wrong about GCC about the no stack frames portion, depends on the convention used)


(Oct 29, 2018 08:37 PM)6577657534735 Wrote:  This is cool, I wonder how difficult it would be to extract the binaries of non-inlined PIC functions independently into byte arrays, create your own rudimentary ABI with intermediary shellcode snippet encryption/decryption routines in between calls, and create a simple metamorphic engine.  Very unethical and no good use for this however and you should not spread this information

That's not how metamorphic engines work.
First and foremost never rely on encryption/decryption for code obscurity, it's just a means for race conditions.

A metamorphic engine is a compiler by definition. Though its incentive isn't to optimize code, but to produce unique code that functions.
I know it's super simple but I've used this a dozen times for really simple C progs and it's actually been useful.
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials


Possibly Related Threads...
Thread / Author Replies Views Last Post
by CL1BFeb 4, 2026 04:24 AM 0 115 Feb 4, 2026 04:24 AM
Last Post: CL1B
[C#] by SmokyMay 4, 2024 07:40 AM 4 367 May 4, 2024 07:40 AM
Last Post: COCKBOT
[C#] by LuunaApr 24, 2022 06:10 AM 4 238 Apr 24, 2022 06:10 AM
Last Post: Luuna