Search code examples
cwindowsmemoryhexdump

Trying to print out useful data from Memory


void update_memblock(MEMBLOCK *mb)
{
    static unsigned char tempbuf[128 * 1024];
    SIZE_T bytes_left;
    SIZE_T total_read;
    SIZE_T bytes_to_read;
    SIZE_T bytes_read;

    bytes_left = mb->size;
    total_read = 0;

    while (bytes_left)
    {
        bytes_to_read = (bytes_left > sizeof(tempbuf)) ? 
sizeof(tempbuf) : bytes_left;
        ReadProcessMemory(mb->hProc, mb->addr + total_read, 
tempbuf, bytes_to_read, &bytes_read);
        if (bytes_read != bytes_to_read) break;

        memcpy(mb->buffer + total_read, tempbuf, bytes_read);

        bytes_left -= bytes_read;
        total_read += bytes_read;
    }
    mb->size = total_read;
}

This is the current code I have, I am initially reading another process' memory using ReadProcessMemory. Now I have the temporary data stored in tempbuf. I am able to output the data from tempbuf in hexadecimal form. But I was planning to display it as shown in the picture, also another complexity I'm facing here is if bytes_left > sizeof(tempbuf) I'm only reading enough data equivalent to the size of tempbuf. How do I read more data as the array I defined can only support as much data?

in_this_format


Solution

  • If I understand correctly, your main question is about how to mimic the output from hex editors.

    This can be broken up into 3 parts:

    1. Printing the address
    2. Printing the hex value of each byte
    3. Printing the ASCII value for each byte

    Printing an address in hex is easy. We can use %p to print the address of a pointer like this:

    char* mem = malloc(99);
    printf("%p\n", (void*)mem);
    // output: 0xc17080
    

    Next you can print the hex value of a byte using %02x on a char (1 byte). The 02 specifies a zero padded field width of 2. In this case it's just to make 0 print as 00 to make things line up and look pretty.

    printf("%02x", mem[0]);
    // output: 0A
    

    Lastly, printing ASCII is the easiest of all... almost. We can use %c to print a byte for some ASCII values, but we don't want to print things like \nor \t. To solve this we can limit the use of %c to the character/symbol region of the ASCII table and print . for everything else.

    char c = mem[0];
    if ( ' ' <= c && c <= '~' ) {
         printf("%c", c);
    }
    else {
         printf(".");
    }
    //output: .
    

    Now we just need to combine these all together. You can decide how many bytes you want to display per line and print "[address] [n hex bytes] [n ascii bytes]" and repeat until you've gone through the entire memory region. I've given a sample function below and you can run it for yourself here.

    void display_mem(void* mem, int mem_size, int line_len) {
       /*
            mem         - pointer to beggining of memory region to be printed
            mem_size    - number of bytes mem points to
            line_len    - number of bytyes to display per line
       */
    
        unsigned char* data = mem;
        int full_lines = mem_size / line_len;
        unsigned char* addr = mem;
    
        for (int linno = 0; linno < full_lines; linno++) {
            // Print Address
            printf("0x%x\t", addr);
    
            // Print Hex
            for (int i = 0; i < line_len; i++) {
                printf(" %02x", data[linno*line_len + i]);
            }
            printf("\t");
    
            // Print Ascii
            for (int i = 0; i < line_len; i++) {
                char c = data[linno*line_len + i];
                if ( 32 < c && c < 125) {
                    printf(" %c", c);
                }
                else {
                    printf(" .");
                }
            }
            printf("\n");
    
            // Incremement addr by number of bytes printed
            addr += line_len;
        }
    
        // Print any remaining bytes that couldn't make a full line
        int remaining = mem_size % line_len;
        if (remaining > 0) {
            // Print Address
            printf("0x%x\t", addr);
    
            // Print Hex
            for (int i = 0; i < remaining; i++) {
                printf(" %02x", data[line_len*full_lines + i]);
            }
            for (int i = 0; i < line_len - remaining; i++) {
                printf("  ");
            }
            printf("\t");
    
            // Print Hex
            for (int i = 0; i < remaining; i++) {
                char c = data[line_len*full_lines + i];
                if ( 32 < c && c < 125) {
                    printf(" %c", c);
                }
                else {
                    printf(" .");
                }
            }
            printf("\n");
         }
     }
    

    Sample output:

    0x1e79010        74 65 73 74 79 2a 6e    t e s t y * n
    0x1e79017        0c 3e 24 45 5e 33 27    . > $ E ^ 3 '
    0x1e7901e        18 51 09 2d 76 7e 4a    . Q . - v . J
    0x1e79025        12 53 0f 6e 0b 1a 6d    . S . n . . m
    0x1e7902c        31 6e 03 2b 01 2f 2c    1 n . + . / ,
    0x1e79033        72 59 1c 76 18 38 3c    r Y . v . 8 <
    0x1e7903a        6e 6b 5b 00 36 64 25    n k [ . 6 d %
    0x1e79041        2d 5c 6f 38 30 00 27    - \ o 8 0 . '
    0x1e79048        33 12 15 5c 01 18 09    3 . . \ . . .
    0x1e7904f        02 40 2d 6c 1a 41 63    . @ - l . A c
    0x1e79056        2b 72 18 1a 5e 74 12    + r . . ^ t .
    0x1e7905d        0d 51 38 33 26 28 6b    . Q 8 3 & ( k
    0x1e79064        56 20 0b 0b 32 20 67    V . . . 2 . g
    0x1e7906b        34 30 68 2e 70 0f 1c    4 0 h . p . .
    0x1e79072        04 50                   . P
    

    As for the second part of your question, if you cannot increase the size of tempbuf then you are stuck dealing with that amount of memory at any moment in time.

    However, if all you want to do is display the memory as described above you can display each section of memory in chunks. You can get a chunk of memory, display it, then get a new chunk, display the new chunk, repeat.

    Something along the lines of

    while (bytes_left) {
        ReadProcessMemory(mb->hProc, mb->addr + total_read, tempbuf, bytes_to_read, &bytes_read);
        // Get new chunk
        memcpy(mb->buffer + total_read, tempbuf, bytes_read);
    
        // Display chunk
        display_mem(tempbuf, bytes_read);
    
        bytes_left -= bytes_read;
    }
    

    You will need to do a little more work to check for errors and make everything look nice but hopefully that gives you a good idea of what could be done.