Last active
January 22, 2024 16:49
-
-
Save foxoman/af83d383bc4fef267c3d25aa5f8f81ff to your computer and use it in GitHub Desktop.
Using native code/shellcode and assembly language with Nim
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ---------------------------------- | |
# Shellcode Execution Utility in Nim | |
# ---------------------------------- | |
# This Nim script is designed to execute a predefined shellcode, | |
# a small piece of low-level code used for various purposes. | |
# In this specific case, the shellcode is a function that performs | |
# hashing of a string. | |
# | |
# The script takes a hardcoded string "Fergo", loads the shellcode | |
# into memory, and then executes the shellcode using this string | |
# as the input. The shellcode function returns the hash of the | |
# input string as a 32-bit integer. | |
# The script then prints the hashed result in hexadecimal format. | |
# | |
# The shellcode loaded into memory using the VirtualAlloc function, | |
# which is a part of the Windows API. After the execution, the memory | |
# is freed using the VirtualFree function to prevent memory leaks. | |
# | |
# Please note: | |
# This script serves as an example of how to execute shellcode in Nim. | |
# Be aware that executing arbitrary shellcode can pose security risks. | |
# | |
# Author: Sultan Al Isaiee @foxoman | |
# Date: 11/07/2023 | |
# Translation of C# Code: https://www.fergonez.net/post/shellcode-csharp | |
# We're using two modules: `winim` provides Windows API bindings, and | |
# `strformat` allows for Python-like string formatting. | |
import winim/lean | |
import strformat | |
# This is our shellcode. In computing, shellcode is a small piece | |
# of code used as the payload in the exploitation of a software | |
# vulnerability. | |
#[ | |
section .text | |
global _start | |
_start: | |
mov edx, 0x811c9dc5 | |
mov ebx, 0xf0b | |
mov esi, 0xc033c0be | |
xor edx, 0x93d069 | |
mov eax, 0x10001 | |
mov al, BYTE [ecx] | |
dec eax | |
inc ecx | |
dec eax | |
inc eax | |
dec eax | |
test al, al | |
jnz _start | |
mov eax, edx | |
ret | |
]# | |
# It's often written in machine code. Here it is represented as an array | |
# of bytes. | |
const shellcode: array[30, byte] = [ | |
byte 0xBA, 0xC5, 0x9D, 0x1C, 0x81, 0xEB, 0x0B, 0x0F, 0xBE, 0xC0, | |
0x33, 0xC2, 0x69, 0xD0, 0x93, 0x01, 0x00, 0x01, 0x8A, 0x01, 0x48, | |
0xFF, 0xC1, 0x84, 0xC0, 0x75, 0xEC, 0x8B, 0xC2, 0xC3 | |
] | |
# We allocate memory in our program to store the shellcode. `VirtualAlloc` | |
# is a Windows API function that reserves, commits, or changes the state | |
# of a region of pages in the virtual address space of the calling process | |
# (our program in this case). | |
let buffer = VirtualAlloc(NULL, | |
shellcode.len(), | |
MEM_COMMIT, | |
PAGE_EXECUTE_READWRITE) | |
# We check if memory allocation was successful. | |
# VirtualAlloc returns NULL when it fails to allocate memory. | |
# If that happens, we print an error message and exit the program. | |
if buffer == NULL: | |
quit("[Error] Unable to allocate memory for shellcode. The program will exit.") | |
# We copy the shellcode into the memory we just allocated. | |
copyMem(buffer, addr shellcode, shellcode.len()) | |
# We prepare the string that we're going to pass to the shellcode function. | |
let stringArray = "Fergo\0" # For Safety will use Null Terminated String | |
# We declare a type for a function that takes a single cstring | |
# (a string in C language) argument and returns a uint32 | |
# (32-bit unsigned integer). | |
type HashPrototype = proc(s: cstring): uint32 {.stdcall.} | |
# We cast the shellcode address to a HashPrototype function pointer. | |
# In simple terms, we're saying, "Treat the code in this memory | |
# address as a function that matches our HashPrototype type." | |
let MyHashingFunction = cast[HashPrototype](buffer) | |
# We call the shellcode function, passing it our string. | |
# It returns the result of hashing our string, according to the code | |
# in the shellcode. | |
let hashedResult = MyHashingFunction(stringArray.cstring) | |
# We print the result in hexadecimal form. | |
echo(fmt"[*] Here is hashed result in hex: {hashedResult:0X}") | |
# Finally, we free the memory we allocated earlier. | |
# This is good practice because it prevents memory leaks—situations | |
# where a program uses more and more memory over time, which can | |
# eventually cause the program to slow down or crash. | |
discard VirtualFree(buffer, 0, MEM_RELEASE) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment