-1

I made 10 fragments of binary executable and kept them in separate memory blocks. I used setter like this.

  void SetCDataStream(u_char* _cDataStream, size_t _sizeData)
    {
        cDataStream = new u_char [_sizeData]; 
        memmove(cDataStream,_cDataStream, _sizeData);
    }

And I'm getting these blocks using getter like this

u_char *GetCDataStream()
{
    return cDataStream;
}

And putting it into vector in proper order from beginning to end of file content

std::vector<u_char*> vecCDataStream;

I want to concatenate each entry of the vector to form original file and should be able to execute it. is there better way to do this?

byxor
  • 4,720
  • 4
  • 25
  • 39
Yubraj Rai
  • 33
  • 1
  • 11
  • 1
    You need to remember the size of each block as well, as I bet each "memory block" can contain NUL bytes. – Botje Jan 31 '20 at 12:41
  • 2
    You should make the fragments already *vectors* of u_char (there is a vector constructor which takes two pointers and initializes the vector with the data between the pointers). Then it's not difficult to [concatenate them.](https://stackoverflow.com/q/201718/3150802). `std::vector::data()` can be used to eventually get at the bytes in the large vector. Whether you then are able to actually *execute* the code stored in the concatenated vector is a different matter. I remember that some guy demonstrated how to execute a function stored in a char array but it was not trivial. – Peter - Reinstate Monica Jan 31 '20 at 12:48
  • Actually, [it doesn't look difficult](https://stackoverflow.com/q/39867396/3150802) once one knows how to put the array in memory with execute permission, which needs some system magic. – Peter - Reinstate Monica Jan 31 '20 at 12:52
  • @Botje I've the size of each block as well and it may contains null bytes too. – Yubraj Rai Jan 31 '20 at 12:54
  • Oh, and if you use vector chunks already the GetCDataStream() can simply return vectors *by value* (if you are modern C++); modern C++ with move constructors makes that efficient. No need to struggle with raw pointers. – Peter - Reinstate Monica Jan 31 '20 at 12:54
  • @Peter-ReinstateMonica Actually I know how to do it using memcpy and dump the bytes to file. but I was just wondering, if there is better way. Thanks anyway – Yubraj Rai Jan 31 '20 at 12:55
  • Your question is unclear and lacks motivation. If you are coding some ELF linker, there are better ways. Look inside the C++ source code of the [GNU gold](https://en.wikipedia.org/wiki/Gold_(linker)) linker – Basile Starynkevitch Feb 02 '20 at 01:12
  • If you are generating code on the fly, consider also [libgccjit](https://gcc.gnu.org/onlinedocs/jit/) perhaps with [dlopen](http://man7.org/linux/man-pages/man3/dlopen.3.html) – Basile Starynkevitch Feb 02 '20 at 01:18

2 Answers2

2

Assuming that each Block has a GetSize() member and a GetCDataStream() member, you can simply create an std::ofstream object and write each block using the std::ofstream::write method:

std::ofstream out("test.bin", std::ios::binary | std::ios::out);
for (Block& b : blocks) {
    out.write(b.GetCDataStream(), b.GetSize());
}
out.close();

Note that it is up to you that the concatenation of all blocks is a valid executable for your platform (PE on Windows, ELF on Linux, Mach-O on macOS).

Botje
  • 15,729
  • 2
  • 22
  • 32
  • Thanks. Its ELF on Linux. But I wanted to first assemble all the chunks in single memory block and dump the bytes to file. you have any suggestion? – Yubraj Rai Jan 31 '20 at 13:02
2

If I understand it correctly, you don't need manual memory management at all and you don't need to preserve the original memory blocks positions in memory. In that case, you could use std::vector to store the blocks - and squash them into one big block if you wish.

Example:

#include <cstddef>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <vector>

// A class to keep a number of blocks
class BlockMaster {
public:
    using block_t = std::vector<uint8_t>;

    explicit BlockMaster(size_t init_size = 0) : blocks{init_size} {}

    // Add a new block
    void AddDataStream(const uint8_t* begin, const uint8_t* end) {
        blocks.emplace_back(begin, end);
    }

    size_t size() const noexcept { return blocks.size(); }

    // random access to the stored blocks
    block_t& operator[](size_t block_number) noexcept {
        return blocks[block_number];
    }
    const block_t& operator[](size_t block_number) const noexcept {
        return blocks[block_number];
    }

    // support for iterating over the stored blocks
    auto cbegin() const noexcept { return blocks.cbegin(); }
    auto cend() const noexcept { return blocks.cend(); }
    auto begin() const noexcept { return cbegin(); }
    auto end() const noexcept { return cend(); }
    auto begin() noexcept { return blocks.begin(); }
    auto end() noexcept { return blocks.end(); }

    // create a BlockMaster with one huge block from the stored blocks
    BlockMaster GetSquashedBlocks() {
        BlockMaster result(1);
        for(const block_t& block : *this) {
            result[0].insert(result[0].end(), block.begin(), block.end());
        }
        return result;
    }

private:
    std::vector<block_t> blocks;
};

// stream all the stored blocks to a file (as if they were one big block, so
// you don't need to squash them for this)
std::ofstream& operator<<(std::ofstream& ofs, const BlockMaster& bm) {
    for(const auto& block : bm)
        ofs.write(reinterpret_cast<const char*>(block.data()),
                  static_cast<std::streamsize>(block.size()));
    return ofs;
}

int main() {
    unsigned char memory[]{1, 2, 3, 4, 5, 6, 7, 8, 9};

    BlockMaster bm;
    bm.AddDataStream(memory + 0, memory + 3);
    bm.AddDataStream(memory + 4, memory + 8);

    std::cout << bm.size() << "\n--\n";

    for(const auto& block : bm) {
        std::cout << ' ' << block.size() << '\n';
    }

    bm = bm.GetSquashedBlocks();

    std::cout << "--\n";

    std::cout << bm.size() << "\n--\n";
    for(const auto& block : bm) {
        std::cout << ' ' << block.size() << '\n';
    }
}

Output:

2    // blockmasters number of stored blocks
--
 3   // first blocks size
 4   // second blocks size
--
1    // blockmasters number of stored blocks after squashing
--
 7   // size of the one block after squashing
Ted Lyngmo
  • 37,764
  • 5
  • 23
  • 50