Skip to content

Commit b3902c0

Browse files
committed
New features & improvements
1 parent 25ac2b0 commit b3902c0

File tree

11 files changed

+72
-25
lines changed

11 files changed

+72
-25
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
> [!WARNING]
44
> **Beta Testing Stage** – This repository is currently in beta. Expect bugs, incomplete features, and breaking changes. Use at your own risk.
55
6-
EPIC (*Extensible Position Independent Code*) – PIC shellcode development and building framework designed for developer experience, predictability, and modularity. *Write code, EPIC will take care of the rest!*
6+
EPIC (*Extensible Position Independent Code*) – PIC shellcode development and building toolkit designed for developer experience, predictability, and modularity. *Write code, EPIC will take care of the rest!*
77

88
![EPIC flow chart](_img/img-1.jpg)
99

@@ -43,7 +43,7 @@ epic init project/
4343

4444
# 3. Compile PIC code
4545
mkdir output/
46-
epic pic-compile project/ -o output/ -m hello
46+
epic pic-compile project/ -o output/
4747

4848
# 4. Link PIC code into standalone payload.bin
4949
epic pic-link output/ -o output/ -m hello
@@ -119,6 +119,7 @@ Compiles your project into a standard non-PIC executable (called a "monolith" in
119119
Flags:
120120

121121
- `-o / --output <path>` [required] - Output path for the monolith executable.
122+
- `--gcc <string>` – Specify additional flags for GCC compilation (e.g. `--gcc '-DDEBUG -DMAX_ITEMS=12'`)
122123

123124
### Global flags
124125

@@ -130,6 +131,7 @@ The following optional flags can be used with any command:
130131
- `--mingw-w64-objcopy <path>` – Specify path to MinGW-w64 objcopy.
131132
- `--no-banner` - Disable EPIC banner.
132133
- `--no-color` - Disable colored output.
134+
- `--version / -v` – Show EPIC version.
133135

134136
---
135137

@@ -365,7 +367,7 @@ To work around this, I use the MinGW-w64 toolchain (`gcc`) with a custom linker
365367
366368
### Do I have to manually align the stack before calling Windows API?
367369
368-
No, MinGW handles stack alignment automatically. However, you must mark every Windows API function with the `WINAPI` macro.
370+
No, MinGW handles stack alignment and required calling convention automatically. For x86_64 you can even omit the default `WINAPI` macro before the WinAPI function header. It’s harmless to include but not required for correctness.
369371
370372
### Why is the entry point called `__main_pic` and not simply `main()`?
371373

cmd/monolith.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"epic/cli"
55
"epic/ctx"
66
"epic/logic"
7+
"epic/utils"
78
"fmt"
89
"os"
910

@@ -12,6 +13,8 @@ import (
1213

1314
var mc logic.MonolithCompiler
1415

16+
var __mcGccFlags string
17+
1518
var monolithCmd = &cobra.Command{
1619
Use: "monolith <path>",
1720
Short: "Build monolithic executable from project",
@@ -20,6 +23,10 @@ var monolithCmd = &cobra.Command{
2023
PreRunE: func(cmd *cobra.Command, args []string) error {
2124
mc.ProjectPath = args[0]
2225

26+
if __mcGccFlags != "" {
27+
mc.GccFlags = utils.StringToSlice(__mcGccFlags, " ")
28+
}
29+
2330
if err := mc.ValidateProjectPath(); err != nil {
2431
return err
2532
}
@@ -54,6 +61,7 @@ func init() {
5461
rootCmd.AddCommand(monolithCmd)
5562

5663
monolithCmd.Flags().StringVarP(&mc.OutputPath, "output", "o", "", "output path for generated executable (required)")
64+
monolithCmd.Flags().StringVar(&__mcGccFlags, "gcc", "", "specify additional GCC flags")
5765

5866
// Mark required flags
5967
if err := monolithCmd.MarkFlagRequired("output"); err != nil {

cmd/root.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@ package cmd
33
import (
44
"epic/cli"
55
"epic/ctx"
6+
"fmt"
67
"os"
78

89
"github.com/spf13/cobra"
910
)
1011

12+
var __showVersion bool
13+
1114
var rootCmd = &cobra.Command{
1215
Use: "epic",
1316
Short: "EPIC (Extensible Position Independent Code)",
1417
Long: `EPIC is a CLI tool for automating modular PIC implant development and building process.`,
1518
Version: ctx.Version,
1619
PersistentPreRun: func(cmd *cobra.Command, args []string) {
20+
if __showVersion {
21+
fmt.Printf("EPIC %s\n", ctx.Version)
22+
os.Exit(0)
23+
}
24+
1725
if ctx.NoColor {
1826
cli.DisableColors()
1927
}
@@ -39,6 +47,7 @@ func init() {
3947
rootCmd.PersistentFlags().BoolVar(&ctx.Debug, "debug", false, "enable debug mode")
4048
rootCmd.PersistentFlags().BoolVar(&ctx.NoColor, "no-color", false, "disable colored output")
4149
rootCmd.PersistentFlags().BoolVar(&ctx.NoBanner, "no-banner", false, "disable EPIC banner")
50+
rootCmd.PersistentFlags().BoolVarP(&__showVersion, "version", "v", false, "show EPIC version")
4251
rootCmd.PersistentFlags().StringVar(&ctx.MingwGccPath, "mingw-w64-gcc", "", "path to MinGW-w64 GCC")
4352
rootCmd.PersistentFlags().StringVar(&ctx.MingwLdPath, "mingw-w64-ld", "", "path to MinGW-w64 ld")
4453
rootCmd.PersistentFlags().StringVar(&ctx.MingwObjcopyPath, "mingw-w64-objcopy", "", "path to MinGW-w64 objcopy")

ctx/ctx.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ var (
44
NoColor bool
55
NoBanner bool
66
Debug bool
7-
Version string
7+
Version string = "1.0.0"
88
MingwGccPath string
99
MingwObjcopyPath string
1010
MingwLdPath string

logic/MonolithCompiler.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
type MonolithCompiler struct {
1212
ProjectPath string
1313
OutputPath string
14+
GccFlags []string
1415
}
1516

1617
func (mc *MonolithCompiler) ValidateProjectPath() error {
@@ -72,6 +73,11 @@ func (mc *MonolithCompiler) Run() {
7273
"-I", filepath.Join(mc.ProjectPath, "include"),
7374
"-I", mc.ProjectPath,
7475
}
76+
77+
if len(mc.GccFlags) > 0 {
78+
params = append(params, mc.GccFlags...)
79+
}
80+
7581
params = append(params, sourceFiles...)
7682

7783
output := utils.MingwGcc(params...)

logic/init-template/README.md

Whitespace-only changes.

logic/init-template/core/pebwalker.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,5 @@
1010
#include <epic.h>
1111
#include <win32/windows.h>
1212

13-
#define MAX_DLL_NAME_SIZE 256
14-
1513
HMODULE GetDllFromMemory(const wchar_t* name);
1614
void* GetProcAddr(HMODULE dll, const char* funcName);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// EPIC (Extensible Position Independent Code)
2+
//
3+
// Source: github.com/Print3M/epic
4+
// Author: Print3M
5+
//
6+
#pragma once
7+
8+
#define _In_
9+
#define _In_opt_
10+
#define _Out_
11+
#define _Out_opt_
12+
#define _Inout_
13+
#define _Inout_opt_
14+
#define _Outptr_
15+
#define _Outptr_opt_
16+
#define _Reserved_
17+
#define _In_reads_(size)
18+
#define _Out_writes_(size)
19+
#define _Out_writes_bytes_(size)

logic/init-template/include/win32/windows.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
//
66
#pragma once
77
#include "wintypes.h"
8-
#include "winternl.h"
8+
#include "winternl.h"
9+
#include "sal.h"

logic/init-template/modules/hello/hello.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,31 @@
1010

1111
#define SW_SHOWNORMAL 0x1
1212

13-
typedef UINT(WINAPI* WinExecPtr)(LPCSTR lpCmdLine, UINT uCmdShow);
14-
typedef HMODULE(WINAPI* LoadLibraryAPtr)(LPCSTR lpLibFileName);
15-
typedef INT(WINAPI* MessageBoxAPtr)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
13+
typedef UINT (*WinExecPtr)(LPCSTR lpCmdLine, UINT uCmdShow);
14+
typedef HMODULE (*LoadLibraryAPtr)(LPCSTR lpLibFileName);
15+
typedef INT (*MessageBoxAPtr)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
1616

1717
namespace hello {
1818

1919
void calc() {
20-
auto kernel32 = GetDllFromMemory(L"KERNEL32.DLL");
21-
auto WinExec = (WinExecPtr)GetProcAddr(kernel32, "WinExec");
20+
auto kernel32 = GetDllFromMemory(L"KERNEL32.DLL");
21+
auto WinExec = (WinExecPtr)GetProcAddr(kernel32, "WinExec");
2222

23-
WinExec("calc.exe", SW_SHOWNORMAL);
23+
WinExec("calc.exe", SW_SHOWNORMAL);
2424
}
2525

26-
void message(const char* msg) {
27-
auto kernel32 = GetDllFromMemory(L"KERNEL32.DLL");
28-
auto LoadLibraryA = (LoadLibraryAPtr)GetProcAddr(kernel32, "LoadLibraryA");
26+
void message(const char *msg) {
27+
auto kernel32 = GetDllFromMemory(L"KERNEL32.DLL");
28+
auto LoadLibraryA = (LoadLibraryAPtr)GetProcAddr(kernel32, "LoadLibraryA");
2929

30-
auto user32 = LoadLibraryA("user32.dll");
31-
if (user32) {
32-
auto MessageBoxA = (MessageBoxAPtr)GetProcAddr(user32, "MessageBoxA");
30+
auto user32 = LoadLibraryA("user32.dll");
31+
if (user32) {
32+
auto MessageBoxA = (MessageBoxAPtr)GetProcAddr(user32, "MessageBoxA");
3333

34-
if (MessageBoxA) {
35-
MessageBoxA(NULL, msg, "EPIC", 0);
36-
}
34+
if (MessageBoxA) {
35+
MessageBoxA(NULL, msg, "EPIC", 0);
3736
}
37+
}
3838
}
3939

40-
} // namespace hello
40+
} // namespace hello

0 commit comments

Comments
 (0)