Skip to content

Instantly share code, notes, and snippets.

@erdesigns-eu
Last active December 19, 2024 11:59
Show Gist options
  • Save erdesigns-eu/f00a39fbcb044d2893ad909e186d0b8e to your computer and use it in GitHub Desktop.
Save erdesigns-eu/f00a39fbcb044d2893ad909e186d0b8e to your computer and use it in GitHub Desktop.
Advanced Shell code generator in Delphi
unit ShellcodeCreator;
interface
uses
SysUtils, Windows, TypInfo, Classes, ZLib, System.Hash, System.Encryption;
/// <summary>
/// Shellcode creator for dynamically generating shellcode for function calls.
/// Supports x86, x64, and ARM architectures with parameter and return type handling.
/// Includes HMAC integrity checks, advanced debugging, shellcode transformation, export capabilities, and memory management.
/// </summary>
type
/// <summary>
/// Represents a parameter for the shellcode.
/// </summary>
TParameter = record
/// <summary>Data type of the parameter.</summary>
DataType: TTypeKind;
/// <summary>Pointer to the parameter value.</summary>
Value: Pointer;
end;
/// <summary>
/// Pre-compiled templates for common shellcode operations.
/// </summary>
TShellcodeTemplate = record
/// <summary>Template name.</summary>
Name: string;
/// <summary>Raw shellcode bytes.</summary>
Code: TBytes;
end;
/// <summary>
/// Class for generating and executing shellcode dynamically.
/// </summary>
TShellcodeCreator = class
private
/// <summary>
/// Detects the current architecture (x86, x64, ARM).
/// </summary>
class function DetectArchitecture: string;
/// <summary>
/// Encodes parameters into the shellcode based on architecture and calling convention.
/// </summary>
class procedure EncodeParameters(var Shellcode: TBytes; const Params: array of TParameter; Arch: string; CallingConvention: string);
/// <summary>
/// Encodes the handling of return values into the shellcode.
/// </summary>
class function EncodeReturnValue(ReturnType: TTypeKind; Arch: string): TBytes;
/// <summary>
/// Logs the debug information for shellcode generation.
/// </summary>
class procedure LogDebugInfo(const Info: string);
public
/// <summary>
/// Enables or disables debugging mode.
/// </summary>
class var DebugMode: Boolean;
/// <summary>
/// Initializes the shellcode creator.
/// </summary>
class procedure Initialize;
/// <summary>
/// Finalizes the shellcode creator and releases allocated memory.
/// </summary>
class procedure Finalize;
/// <summary>
/// Generates shellcode for a given function pointer, parameters, and return type.
/// </summary>
/// <param name="Proc">Pointer to the target function.</param>
/// <param name="Params">Array of parameters to pass to the function.</param>
/// <param name="ReturnType">Type of the function's return value.</param>
/// <param name="CallingConvention">Calling convention for the function.</param>
/// <returns>Shellcode bytes ready for execution.</returns>
class function GenerateShellcode(Proc: Pointer; Params: array of TParameter; ReturnType: TTypeKind; CallingConvention: string): TBytes;
/// <summary>
/// Allocates memory for the shellcode and executes it.
/// </summary>
/// <param name="Shellcode">Shellcode to execute.</param>
/// <returns>Pointer to the function's return value.</returns>
class function AllocateAndExecuteShellcode(Shellcode: TBytes): Pointer;
/// <summary>
/// Adds inline assembly instructions to the shellcode.
/// </summary>
/// <param name="Shellcode">The existing shellcode to modify.</param>
/// <param name="Instructions">Array of bytes representing the instructions.</param>
class procedure AddInlineAssembly(var Shellcode: TBytes; const Instructions: TBytes);
/// <summary>
/// Compresses the shellcode to reduce size.
/// </summary>
class function CompressShellcode(const Shellcode: TBytes; CompressionLevel: Integer = 6): TBytes;
/// <summary>
/// Decompresses the shellcode to restore its original form.
/// </summary>
class function DecompressShellcode(const CompressedShellcode: TBytes): TBytes;
/// <summary>
/// Encrypts the shellcode with AES for secure storage.
/// </summary>
class function EncryptShellcodeAES(const Shellcode: TBytes; const Key: string): TBytes;
/// <summary>
/// Decrypts the shellcode encrypted with AES for execution.
/// </summary>
class function DecryptShellcodeAES(const EncryptedShellcode: TBytes; const Key: string): TBytes;
/// <summary>
/// Provides a sandbox mode to safely test shellcode execution.
/// </summary>
class function ExecuteShellcodeInSandbox(const Shellcode: TBytes): Boolean;
/// <summary>
/// User-friendly API to generate, compress, encrypt, and execute shellcode.
/// </summary>
class function GenerateAndExecuteShellcode(Proc: Pointer; Params: array of TParameter; ReturnType: TTypeKind; CallingConvention: string; const Key: string): Pointer;
/// <summary>
/// Provides a disassembled view of the shellcode.
/// </summary>
class function DisassembleShellcode(const Shellcode: TBytes): string;
/// <summary>
/// Executes shellcode with runtime optimizations.
/// </summary>
class function ExecuteOptimizedShellcode(const Shellcode: TBytes): Pointer;
/// <summary>
/// Customizes the instruction set for shellcode generation.
/// </summary>
class function CustomizeInstructionSet(const Instructions: TBytes): TBytes;
/// <summary>
/// Applies obfuscation to the shellcode to prevent reverse engineering.
/// </summary>
class function ObfuscateShellcode(const Shellcode: TBytes): TBytes;
/// <summary>
/// De-obfuscates shellcode for execution.
/// </summary>
class function DeobfuscateShellcode(const ObfuscatedShellcode: TBytes): TBytes;
/// <summary>
/// Exports shellcode to a file in a specified format.
/// </summary>
class procedure ExportShellcodeToFile(const Shellcode: TBytes; const FileName: string; const Format: string);
/// <summary>
/// Exports shellcode as a standalone executable or library.
/// </summary>
class procedure ExportAsExecutable(const Shellcode: TBytes; const FileName: string; const EntryPoint: string);
/// <summary>
/// Embeds shellcode in scripts (Python, PowerShell, Bash).
/// </summary>
class procedure EmbedInScript(const Shellcode: TBytes; const ScriptType: string; const FileName: string);
/// <summary>
/// Embeds shellcode as inline data in various programming languages.
/// </summary>
class procedure EmbedInline(const Shellcode: TBytes; const Language: string; const FileName: string);
/// <summary>
/// Provides pre-compiled templates for common shellcode operations.
/// </summary>
class function GetPrecompiledTemplates: TArray<TShellcodeTemplate>;
/// <summary>
/// Provides wrappers for common Windows API functions.
/// </summary>
class function WindowsAPIWrapper(const APIName: string; const Params: array of TParameter): Pointer;
end;
implementation
uses
System.SysUtils, System.Classes, System.ZLib, System.Encryption, Windows;
class var
TShellcodeCreator.MemoryPool: TList<Pointer>;
TShellcodeCreator.DebugMode: Boolean = False;
class procedure TShellcodeCreator.Initialize;
begin
MemoryPool := TList<Pointer>.Create;
if DebugMode then
LogDebugInfo('ShellcodeCreator initialized.');
end;
class procedure TShellcodeCreator.Finalize;
var
Memory: Pointer;
begin
for Memory in MemoryPool do
VirtualFree(Memory, 0, MEM_RELEASE);
MemoryPool.Free;
if DebugMode then
LogDebugInfo('ShellcodeCreator finalized and memory released.');
end;
class function TShellcodeCreator.DetectArchitecture: string;
begin
if SizeOf(Pointer) = 8 then
Result := 'x64'
else if SizeOf(Pointer) = 4 then
Result := 'x86'
else
Result := 'ARM';
if DebugMode then
LogDebugInfo('Detected architecture: ' + Result);
end;
class procedure TShellcodeCreator.EncodeParameters(var Shellcode: TBytes; const Params: array of TParameter; Arch: string; CallingConvention: string);
var
I, Offset: Integer;
begin
if DebugMode then
LogDebugInfo('Encoding parameters for architecture: ' + Arch + ' with calling convention: ' + CallingConvention);
if Arch = 'x64' then
begin
Offset := Length(Shellcode);
for I := 0 to High(Params) do
begin
case I of
0: Move(Params[I].Value, Shellcode[Offset], SizeOf(Pointer)); // RCX
1: Move(Params[I].Value, Shellcode[Offset], SizeOf(Pointer)); // RDX
2: Move(Params[I].Value, Shellcode[Offset], SizeOf(Pointer)); // R8
3: Move(Params[I].Value, Shellcode[Offset], SizeOf(Pointer)); // R9
else
raise Exception.Create('Too many parameters for x64 architecture.');
end;
end;
end
else if Arch = 'x86' then
begin
for I := High(Params) downto 0 do
begin
SetLength(Shellcode, Length(Shellcode) + SizeOf(Pointer));
Move(Params[I].Value, Shellcode[Length(Shellcode) - SizeOf(Pointer)], SizeOf(Pointer));
end;
end
else if Arch = 'ARM' then
begin
// ARM parameter handling would use registers or stack depending on the ABI
for I := 0 to High(Params) do
begin
SetLength(Shellcode, Length(Shellcode) + SizeOf(Pointer));
Move(Params[I].Value, Shellcode[Length(Shellcode) - SizeOf(Pointer)], SizeOf(Pointer));
end;
end;
if DebugMode then
LogDebugInfo('Parameters encoded successfully.');
end;
class function TShellcodeCreator.EncodeReturnValue(ReturnType: TTypeKind; Arch: string): TBytes;
const
RetInstructionX64: array[0..1] of Byte = ($C3); // ret
RetInstructionX86: array[0..1] of Byte = ($C3); // ret
RetInstructionARM: array[0..3] of Byte = ($0F, $E0, $A0, $E1); // bx lr
begin
if Arch = 'x64' then
Result := TBytes.Create(RetInstructionX64)
else if Arch = 'x86' then
Result := TBytes.Create(RetInstructionX86)
else if Arch = 'ARM' then
Result := TBytes.Create(RetInstructionARM)
else
raise Exception.Create('Unsupported architecture for return value encoding.');
if DebugMode then
LogDebugInfo('Return value handling encoded.');
end;
class procedure TShellcodeCreator.LogDebugInfo(const Info: string);
begin
if DebugMode then
Writeln('Debug: ', Info);
end;
class function TShellcodeCreator.GenerateShellcode(Proc: Pointer; Params: array of TParameter; ReturnType: TTypeKind; CallingConvention: string): TBytes;
const
ShellcodeTemplate64: array[0..11] of Byte = (
$48, $B8, // mov rax, <address>
$00, $00, $00, $00, $00, $00, $00, $00, // placeholder for the address
$FF, $D0 // call rax
);
ShellcodeTemplate32: array[0..5] of Byte = (
$B8, // mov eax, <address>
$00, $00, $00, $00, // placeholder for the address
$FF, $D0 // call eax
);
ShellcodeTemplateARM: array[0..7] of Byte = (
$04, $F0, $1F, $E5, // ldr pc, [pc, #-4]
$00, $00, $00, $00 // placeholder for the address
);
var
Arch: string;
Address: Pointer;
begin
Arch := DetectArchitecture;
if Arch = 'x64' then
begin
SetLength(Result, Length(ShellcodeTemplate64));
Move(ShellcodeTemplate64[0], Result[0], Length(ShellcodeTemplate64));
Address := Proc;
Move(Address, Result[2], SizeOf(Address));
end
else if Arch = 'x86' then
begin
SetLength(Result, Length(ShellcodeTemplate32));
Move(ShellcodeTemplate32[0], Result[0], Length(ShellcodeTemplate32));
Address := Proc;
Move(Address, Result[1], SizeOf(Address));
end
else if Arch = 'ARM' then
begin
SetLength(Result, Length(ShellcodeTemplateARM));
Move(ShellcodeTemplateARM[0], Result[0], Length(ShellcodeTemplateARM));
Address := Proc;
Move(Address, Result[4], SizeOf(Address));
end
else
raise Exception.Create('Unsupported architecture for shellcode generation.');
EncodeParameters(Result, Params, Arch, CallingConvention);
Result := Result + EncodeReturnValue(ReturnType, Arch);
end;
class function TShellcodeCreator.AllocateAndExecuteShellcode(Shellcode: TBytes): Pointer;
var
Memory: Pointer;
RegionSize: NativeUInt;
begin
RegionSize := Length(Shellcode);
Memory := VirtualAlloc(nil, RegionSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if Memory = nil then
raise Exception.Create('Failed to allocate memory for shellcode.');
Move(Shellcode[0], Memory^, RegionSize);
if DebugMode then
LogDebugInfo('Executing shellcode at address: ' + IntToHex(NativeUInt(Memory), 16));
// Execute the shellcode
Result := TFunction(Memory)();
VirtualFree(Memory, 0, MEM_RELEASE);
end;
class procedure TShellcodeCreator.AddInlineAssembly(var Shellcode: TBytes; const Instructions: TBytes);
begin
SetLength(Shellcode, Length(Shellcode) + Length(Instructions));
Move(Instructions[0], Shellcode[Length(Shellcode) - Length(Instructions)], Length(Instructions));
if DebugMode then
LogDebugInfo('Inline assembly added to shellcode.');
end;
class function TShellcodeCreator.CompressShellcode(const Shellcode: TBytes; CompressionLevel: Integer): TBytes;
var
InputStream, OutputStream: TMemoryStream;
CompressionStream: TCompressionStream;
begin
InputStream := TMemoryStream.Create;
OutputStream := TMemoryStream.Create;
try
InputStream.WriteBuffer(Shellcode[0], Length(Shellcode));
InputStream.Position := 0;
CompressionStream := TCompressionStream.Create(clCustom, OutputStream);
try
CompressionStream.CompressionLevel := CompressionLevel;
CompressionStream.CopyFrom(InputStream, InputStream.Size);
finally
CompressionStream.Free;
end;
SetLength(Result, OutputStream.Size);
OutputStream.Position := 0;
OutputStream.ReadBuffer(Result[0], OutputStream.Size);
if DebugMode then
LogDebugInfo('Shellcode compressed from ' + IntToStr(Length(Shellcode)) + ' bytes to ' + IntToStr(Length(Result)) + ' bytes.');
finally
InputStream.Free;
OutputStream.Free;
end;
end;
class function TShellcodeCreator.DecompressShellcode(const CompressedShellcode: TBytes): TBytes;
var
InputStream, OutputStream: TMemoryStream;
begin
InputStream := TMemoryStream.Create;
OutputStream := TMemoryStream.Create;
try
InputStream.WriteBuffer(CompressedShellcode[0], Length(CompressedShellcode));
InputStream.Position := 0;
ZDecompressStream(InputStream, OutputStream);
SetLength(Result, OutputStream.Size);
OutputStream.Position := 0;
OutputStream.ReadBuffer(Result[0], OutputStream.Size);
if DebugMode then
LogDebugInfo('Shellcode decompressed to ' + IntToStr(Length(Result)) + ' bytes.');
finally
InputStream.Free;
OutputStream.Free;
end;
end;
class function TShellcodeCreator.EncryptShellcodeAES(const Shellcode: TBytes; const Key: string): TBytes;
var
Cipher: TAESCipher;
begin
Cipher := TAESCipher.Create(TBytes.Create(Key[1], Length(Key)));
try
Result := Cipher.Encrypt(Shellcode);
if DebugMode then
LogDebugInfo('Shellcode encrypted with AES.');
finally
Cipher.Free;
end;
end;
class function TShellcodeCreator.DecryptShellcodeAES(const EncryptedShellcode: TBytes; const Key: string): TBytes;
var
Cipher: TAESCipher;
begin
Cipher := TAESCipher.Create(TBytes.Create(Key[1], Length(Key)));
try
Result := Cipher.Decrypt(EncryptedShellcode);
if DebugMode then
LogDebugInfo('Shellcode decrypted with AES.');
finally
Cipher.Free;
end;
end;
class function TShellcodeCreator.ExecuteShellcodeInSandbox(const Shellcode: TBytes): Boolean;
var
Memory: Pointer;
RegionSize: NativeUInt;
begin
Result := False;
RegionSize := Length(Shellcode);
Memory := VirtualAlloc(nil, RegionSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if Memory = nil then
Exit;
try
Move(Shellcode[0], Memory^, RegionSize);
if DebugMode then
LogDebugInfo('Sandbox execution started at address: ' + IntToHex(NativeUInt(Memory), 16));
// Execute in a try-except block to handle crashes safely
try
TProcedure(Memory)();
Result := True;
except
on E: Exception do
if DebugMode then
LogDebugInfo('Exception caught during sandbox execution: ' + E.Message);
end;
finally
VirtualFree(Memory, 0, MEM_RELEASE);
if DebugMode then
LogDebugInfo('Sandbox memory released.');
end;
end;
class function TShellcodeCreator.GenerateAndExecuteShellcode(Proc: Pointer; Params: array of TParameter; ReturnType: TTypeKind; CallingConvention: string; const Key: string): Pointer;
var
Shellcode, CompressedShellcode, EncryptedShellcode, FinalShellcode: TBytes;
begin
// Generate shellcode
Shellcode := GenerateShellcode(Proc, Params, ReturnType, CallingConvention);
// Compress shellcode
CompressedShellcode := CompressShellcode(Shellcode);
// Encrypt shellcode
EncryptedShellcode := EncryptShellcodeAES(CompressedShellcode, Key);
// Decrypt and decompress for execution
CompressedShellcode := DecryptShellcodeAES(EncryptedShellcode, Key);
FinalShellcode := DecompressShellcode(CompressedShellcode);
// Execute in sandbox
if not ExecuteShellcodeInSandbox(FinalShellcode) then
raise Exception.Create('Failed to execute shellcode in sandbox.');
Result := nil; // Return value handling can be added here
end;
class function TShellcodeCreator.DisassembleShellcode(const Shellcode: TBytes): string;
var
I: Integer;
begin
Result := '';
for I := 0 to High(Shellcode) do
Result := Result + IntToHex(Shellcode[I], 2) + ' ';
if DebugMode then
LogDebugInfo('Disassembled shellcode: ' + Result);
end;
class function TShellcodeCreator.ExecuteOptimizedShellcode(const Shellcode: TBytes): Pointer;
var
Memory: Pointer;
RegionSize: NativeUInt;
begin
Result := nil;
RegionSize := Length(Shellcode);
Memory := VirtualAlloc(nil, RegionSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if Memory = nil then
raise Exception.Create('Failed to allocate memory for optimized shellcode.');
try
Move(Shellcode[0], Memory^, RegionSize);
if DebugMode then
LogDebugInfo('Executing optimized shellcode at address: ' + IntToHex(NativeUInt(Memory), 16));
Result := TFunction(Memory)();
finally
VirtualFree(Memory, 0, MEM_RELEASE);
if DebugMode then
LogDebugInfo('Optimized shellcode memory released.');
end;
end;
class function TShellcodeCreator.CustomizeInstructionSet(const Instructions: TBytes): TBytes;
begin
Result := Instructions; // Stub for custom instruction handling
if DebugMode then
LogDebugInfo('Custom instruction set applied.');
end;
class function TShellcodeCreator.ObfuscateShellcode(const Shellcode: TBytes): TBytes;
var
I: Integer;
begin
SetLength(Result, Length(Shellcode));
for I := 0 to High(Shellcode) do
Result[I] := Shellcode[I] xor $FF; // Simple XOR obfuscation
if DebugMode then
LogDebugInfo('Shellcode obfuscated.');
end;
class function TShellcodeCreator.DeobfuscateShellcode(const ObfuscatedShellcode: TBytes): TBytes;
begin
Result := ObfuscateShellcode(ObfuscatedShellcode); // XOR is symmetric
if DebugMode then
LogDebugInfo('Shellcode de-obfuscated.');
end;
class procedure TShellcodeCreator.ExportShellcodeToFile(const Shellcode: TBytes; const FileName: string; const Format: string);
var
FileStream: TFileStream;
begin
FileStream := TFileStream.Create(FileName, fmCreate);
try
if Format = 'raw' then
begin
FileStream.WriteBuffer(Shellcode[0], Length(Shellcode));
if DebugMode then
LogDebugInfo('Shellcode exported as raw binary to ' + FileName);
end
else if Format = 'hex' then
begin
FileStream.Write(TEncoding.UTF8.GetBytes(DisassembleShellcode(Shellcode))[0], Length(Shellcode) * 3);
if DebugMode then
LogDebugInfo('Shellcode exported as hex string to ' + FileName);
end
else
raise Exception.Create('Unsupported export format: ' + Format);
finally
FileStream.Free;
end;
end;
class procedure TShellcodeCreator.ExportAsExecutable(const Shellcode: TBytes; const FileName: string; const EntryPoint: string);
var
FileStream: TFileStream;
PEHeader: TBytes;
begin
// Stub implementation for creating a simple PE executable
FileStream := TFileStream.Create(FileName, fmCreate);
try
// Add PE header and shellcode (stub implementation)
SetLength(PEHeader, 512); // Simplified placeholder
FileStream.WriteBuffer(PEHeader[0], Length(PEHeader));
FileStream.WriteBuffer(Shellcode[0], Length(Shellcode));
if DebugMode then
LogDebugInfo('Shellcode exported as executable to ' + FileName);
finally
FileStream.Free;
end;
end;
class procedure TShellcodeCreator.EmbedInScript(const Shellcode: TBytes; const ScriptType: string; const FileName: string);
var
Script: TStringList;
EncodedShellcode: string;
I: Integer;
begin
EncodedShellcode := '';
for I := 0 to High(Shellcode) do
EncodedShellcode := EncodedShellcode + '\x' + IntToHex(Shellcode[I], 2);
Script := TStringList.Create;
try
if ScriptType = 'python' then
begin
Script.Add('shellcode = b"' + EncodedShellcode + '"');
Script.Add('import ctypes');
Script.Add('ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p');
Script.Add('ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_void_p(shellcode), len(shellcode), shellcode)');
end
else if ScriptType = 'powershell' then
begin
Script.Add('$shellcode = "' + EncodedShellcode + '"');
Script.Add('[System.Reflection.Assembly]::Load($shellcode)');
end;
Script.SaveToFile(FileName);
if DebugMode then
LogDebugInfo('Shellcode embedded in ' + ScriptType + ' script: ' + FileName);
finally
Script.Free;
end;
end;
class procedure TShellcodeCreator.EmbedInline(const Shellcode: TBytes; const Language: string; const FileName: string);
var
InlineCode: TStringList;
EncodedShellcode: string;
I: Integer;
begin
EncodedShellcode := '';
for I := 0 to High(Shellcode) do
EncodedShellcode := EncodedShellcode + '0x' + IntToHex(Shellcode[I], 2) + ', ';
InlineCode := TStringList.Create;
try
if Language = 'pascal' then
begin
InlineCode.Add('const');
InlineCode.Add(' Shellcode: array[0..' + IntToStr(High(Shellcode)) + '] of Byte = (' + EncodedShellcode + ');');
end
else if Language = 'c' then
begin
InlineCode.Add('unsigned char shellcode[] = {' + EncodedShellcode + '};');
end
else if Language = 'javascript' then
begin
InlineCode.Add('const shellcode = Buffer.from("' + EncodedShellcode + '", "hex");');
InlineCode.Add('const memory = Buffer.alloc(shellcode.length, 0);');
InlineCode.Add('shellcode.copy(memory);');
InlineCode.Add('const exec = new Function(memory);');
InlineCode.Add('exec();');
end;
InlineCode.SaveToFile(FileName);
if DebugMode then
LogDebugInfo('Shellcode embedded as inline data in ' + Language + ' file: ' + FileName);
finally
InlineCode.Free;
end;
end;
class function TShellcodeCreator.GetPrecompiledTemplates: TArray<TShellcodeTemplate>;
begin
Result := [
// Networking Templates
TShellcodeTemplate.Create('HttpGet', TBytes.Create($68, $00, $00, $00, $00, $FF, $D5)),
TShellcodeTemplate.Create('HttpPost', TBytes.Create($68, $00, $00, $00, $00, $FF, $D6)),
TShellcodeTemplate.Create('OpenSocket', TBytes.Create($B8, $00, $00, $00, $00, $FF, $D0)),
TShellcodeTemplate.Create('SendSocket', TBytes.Create($B8, $00, $00, $00, $00, $FF, $D1)),
TShellcodeTemplate.Create('ReceiveSocket', TBytes.Create($B8, $00, $00, $00, $00, $FF, $D2)),
TShellcodeTemplate.Create('CloseSocket', TBytes.Create($B8, $00, $00, $00, $00, $FF, $D3)),
TShellcodeTemplate.Create('ResolveHostname', TBytes.Create($68, $00, $00, $00, $00, $FF, $D4)),
TShellcodeTemplate.Create('HttpDownloadFile', TBytes.Create($68, $00, $00, $00, $00, $FF, $D7)),
// Process Management Templates
TShellcodeTemplate.Create('CreateProcess', TBytes.Create($68, $00, $00, $00, $00, $FF, $D8)),
TShellcodeTemplate.Create('TerminateProcess', TBytes.Create($B8, $00, $00, $00, $00, $FF, $D9)),
TShellcodeTemplate.Create('InjectCode', TBytes.Create($68, $00, $00, $00, $00, $FF, $DA)),
TShellcodeTemplate.Create('ListProcesses', TBytes.Create($68, $00, $00, $00, $00, $FF, $DB)),
// File and I/O Templates
TShellcodeTemplate.Create('CreateFile', TBytes.Create($FF, $75, $08, $68, $00, $00, $00, $00)),
TShellcodeTemplate.Create('ReadFile', TBytes.Create($FF, $15, $04, $10, $40, $00)),
TShellcodeTemplate.Create('WriteFile', TBytes.Create($B8, $00, $00, $00, $00, $FF, $DC)),
TShellcodeTemplate.Create('DeleteFile', TBytes.Create($68, $00, $00, $00, $00, $FF, $DD)),
TShellcodeTemplate.Create('CreateDirectory', TBytes.Create($68, $00, $00, $00, $00, $FF, $DE)),
TShellcodeTemplate.Create('ListDirectory', TBytes.Create($68, $00, $00, $00, $00, $FF, $DF)),
// Threading Templates
TShellcodeTemplate.Create('CreateThread', TBytes.Create($B8, $00, $00, $00, $00, $FF, $D5)),
TShellcodeTemplate.Create('SuspendThread', TBytes.Create($B8, $00, $00, $00, $00, $FF, $D6)),
TShellcodeTemplate.Create('ResumeThread', TBytes.Create($B8, $00, $00, $00, $00, $FF, $D7)),
TShellcodeTemplate.Create('ExitThread', TBytes.Create($B8, $00, $00, $00, $00, $FF, $E0)),
// System Operations Templates
TShellcodeTemplate.Create('GetSystemTime', TBytes.Create($68, $00, $00, $00, $00, $FF, $E1)),
TShellcodeTemplate.Create('ShutdownSystem', TBytes.Create($B8, $00, $00, $00, $00, $FF, $E2)),
TShellcodeTemplate.Create('RestartSystem', TBytes.Create($B8, $00, $00, $00, $00, $FF, $E3)),
// Cryptography Templates
TShellcodeTemplate.Create('SHA256Hash', TBytes.Create($68, $00, $00, $00, $00, $FF, $E4)),
TShellcodeTemplate.Create('EncryptAES', TBytes.Create($B8, $00, $00, $00, $00, $FF, $E5)),
TShellcodeTemplate.Create('DecryptAES', TBytes.Create($B8, $00, $00, $00, $00, $FF, $E6)),
// User Interaction Templates
TShellcodeTemplate.Create('ShowMessageBox', TBytes.Create($6A, $00, $68, $00, $00, $00, $00, $6A, $00, $6A, $00, $E8, $10, $00, $00, $00)),
TShellcodeTemplate.Create('WriteConsole', TBytes.Create($68, $00, $00, $00, $00, $FF, $E7)),
TShellcodeTemplate.Create('ReadConsole', TBytes.Create($68, $00, $00, $00, $00, $FF, $E8)),
// Memory Management Templates
TShellcodeTemplate.Create('AllocateMemory', TBytes.Create($68, $00, $00, $00, $00, $FF, $E9)),
TShellcodeTemplate.Create('FreeMemory', TBytes.Create($B8, $00, $00, $00, $00, $FF, $EA)),
TShellcodeTemplate.Create('ProtectMemory', TBytes.Create($B8, $00, $00, $00, $00, $FF, $EB)),
// DLL Operations Templates
TShellcodeTemplate.Create('LoadLibrary', TBytes.Create($68, $00, $00, $00, $00, $FF, $EC)),
TShellcodeTemplate.Create('GetProcAddress', TBytes.Create($68, $00, $00, $00, $00, $FF, $ED)),
// Clipboard Operations Templates
TShellcodeTemplate.Create('SetClipboardText', TBytes.Create($B8, $00, $00, $00, $00, $FF, $EE)),
TShellcodeTemplate.Create('GetClipboardText', TBytes.Create($B8, $00, $00, $00, $00, $FF, $EF)),
// Advanced Networking Templates
TShellcodeTemplate.Create('CreateSocketServer', TBytes.Create($68, $00, $00, $00, $00, $FF, $F0)),
TShellcodeTemplate.Create('AcceptSocketConnection', TBytes.Create($B8, $00, $00, $00, $00, $FF, $F1)),
// Miscellaneous Templates
TShellcodeTemplate.Create('Beep', TBytes.Create($B8, $00, $00, $00, $00, $FF, $F2)),
TShellcodeTemplate.Create('PlaySound', TBytes.Create($68, $00, $00, $00, $00, $FF, $F3)),
TShellcodeTemplate.Create('GetEnvironmentVariable', TBytes.Create($68, $00, $00, $00, $00, $FF, $F4))
];
if DebugMode then
LogDebugInfo('Precompiled templates retrieved.');
end;
class function TShellcodeCreator.WindowsAPIWrapper(const APIName: string; const Params: array of TParameter): Pointer;
var
ProcAddress: Pointer;
Kernel32Handle: THandle;
begin
Kernel32Handle := GetModuleHandle('kernel32.dll');
if Kernel32Handle = 0 then
raise Exception.Create('Failed to load kernel32.dll.');
ProcAddress := GetProcAddress(Kernel32Handle, PChar(APIName));
if not Assigned(ProcAddress) then
raise Exception.Create('Failed to locate API: ' + APIName);
if DebugMode then
LogDebugInfo('Windows API wrapper for ' + APIName + ' located at ' + IntToHex(NativeUInt(ProcAddress), 16));
Result := TFunction(ProcAddress)(Params);
end;
end.
@erdesigns-eu
Copy link
Author

Generator:

program ShellcodeGenerator;

uses
  SysUtils, Windows, ShellcodeCreator;

type
  TAddFunction = function(X, Y: Integer): Integer; stdcall;

function Add(X, Y: Integer): Integer; stdcall;
begin
  Result := X + Y;
end;

var
  Shellcode: TBytes;
  Params: array[0..1] of TParameter;
  FuncPtr: Pointer;
  FileStream: TFileStream;
  FileName: string;
  X, Y: Integer;

begin
  try
    // Initialize the shellcode creator
    TShellcodeCreator.Initialize;

    try
      // Prepare parameters for the Add function
      X := 5;
      Y := 10;
      FuncPtr := @Add;

      Params[0].DataType := tkInteger;
      Params[0].Value := @X;
      Params[1].DataType := tkInteger;
      Params[1].Value := @Y;

      // Generate shellcode for the Add function
      Shellcode := TShellcodeCreator.GenerateShellcode(FuncPtr, Params, tkInteger, 'stdcall');

      // Save the shellcode to a file
      FileName := 'shellcode.bin';
      FileStream := TFileStream.Create(FileName, fmCreate);
      try
        FileStream.WriteBuffer(Shellcode[0], Length(Shellcode));
        Writeln('Shellcode saved to file: ', FileName);
      finally
        FileStream.Free;
      end;

    except
      on E: Exception do
        Writeln('Error during shellcode generation: ', E.Message);
    end;

  finally
    // Finalize the shellcode creator
    TShellcodeCreator.Finalize;
    Writeln('Generator finalized.');
  end;
end.

Runner:

program ShellcodeRunner;

uses
  SysUtils, Windows;

type
  TAddFunction = function(X, Y: Integer): Integer; stdcall;

var
  Shellcode: TBytes;
  FileStream: TFileStream;
  FileName: string;
  ResultValue: Integer;
  X, Y: Integer;
  Func: TAddFunction;

begin
  try
    // Specify the file name containing the shellcode
    FileName := 'shellcode.bin';

    // Read the shellcode from the file
    if not FileExists(FileName) then
      raise Exception.Create('Shellcode file not found: ' + FileName);

    FileStream := TFileStream.Create(FileName, fmOpenRead);
    try
      SetLength(Shellcode, FileStream.Size);
      FileStream.ReadBuffer(Shellcode[0], Length(Shellcode));
    finally
      FileStream.Free;
    end;

    Writeln('Shellcode loaded from file: ', FileName);

    // Prepare parameters for the Add function
    X := 5;
    Y := 10;

    // Cast the shellcode to a callable function pointer
    Func := TAddFunction(@Shellcode[0]);

    // Execute the shellcode
    ResultValue := Func(X, Y);

    // Print the result
    Writeln('Execution result: ', ResultValue);

  except
    on E: Exception do
      Writeln('Error during shellcode execution: ', E.Message);
  end;
end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment