A WinAPI C++ program for printing the master boot record of the hard drive
Idiomatic is relative. I guess it's a coding style you could find in older code-bases (and many winapi based applications are rather old), but you wouldn't write C++ like this today. Consider for instance:

#include &lt;iostream&gt;
#include &lt;iomanip&gt;
#include &lt;iterator&gt;
#include &lt;algorithm&gt;
#include &lt;numeric&gt;
#include &lt;array&gt;

constexpr std::size_t MBR_SIZE = 255;
constexpr std::size_t BYTES_PER_COLUMN = 4;
constexpr char LINE_DELIMITER = '\n';
constexpr const char* COL_DELIMITER = " ";

int main() {
    std::array&lt;unsigned char, MBR_SIZE&gt; mbr;
    std::iota(std::begin(mbr), std::end(mbr), 0); // filling it for testing purposes

    std::cout &lt;&lt; std::hex &lt;&lt; std::setfill('0');
    std::size_t index = 0;
    std::transform(std::begin(mbr), std::end(mbr), std::ostream_iterator&lt;int&gt;(std::cout, COL_DELIMITER), [index](auto c) mutable {
        if (index++ % BYTES_PER_COLUMN == 0) std::cout &lt;&lt; LINE_DELIMITER;
        std::cout &lt;&lt; std::setw(2); // setw must be applied for each output
        return c;
    });
    std::cout &lt;&lt; std::endl;
}


In a dozen of lines you get the same result as printMBR and its two auxiliary functions (at least I believe so, I haven't had the chance to run your code), which are longer and more complicated.

To be more specific about your code:


don't declare a variable before you're ready to define it, and don't define it before you're ready to use it.
don't std::move your return value, it prevents copy elision
don't declare free functions static, it's a java thing
inside ReadMBR there's a char* buffer = new char[MBR_SIZE]; you don't use afterwards
I'm not a fan of that many using directives; prefix the names with std:: and be done with it, unless you prefer to set up aliases: then using string = std::string is clearer
use standard algorithms, such as std::copy, std::accumulate, etc (in headers &lt;algorithm&gt; and &lt;numeric&gt;) or range-base for loops (for auto item : sequence) instead of "raw" loops. For instance, charToHex could be written


like this:

std::string s;
for (auto nibble : { (c &gt;&gt; 4) &amp; 0xf, c &amp; 0xf }) 
    s += fourBitsToString(nibble);
return s;


or:

char lo = c &amp; 0xf;
char hi = (c &gt;&gt; 4) &amp; 0xf;
char chars[] = {hi, lo};

return std::accumulate(std::begin(chars), std::end(chars), std::string(), [](auto init, auto elem) {
    return init += (fourBitsToString(elem));
});


And, on a more aesthetic note, a four-bits aggregate can be called a half-byte or a nibble.