How to print memory as hex to console, syslog, kernellog.

April 1, 2016

Currently I am developing Linux Kernel modules and normal user-mode applications in parallel. I needed a function which prints the content of a char array to the console, the syslog and the kernel log. Finding such function via google was difficult. In the end I did some thinkering and implemented a function on my own.

If you use the function in your project you have to enable / disable the corresponding printf / syslog / printk line.

/*
 * Prints count chars of mem to console or log.
 */
void printMemory(const unsigned char mem[], int count) {
    int i, k = 0;
    char hexbyte[11] = "";
    char hexline[126] = "";
    for (i=0; i<count; i++) { // traverse through mem until count is reached
        sprintf(hexbyte, "0x%02X|", mem[i]); // add current byte to hexbyte
        strcat(hexline, hexbyte); // add hexbyte to hexline
        // print line every 16 bytes or if this is the last for-loop
        if (((i+1)%16 == 0) && (i != 0) || (i+1==count)) { 
            k++;
            // choose your favourite output:
            printf("l%d: %s\n",k , hexline); // print line to console
            //syslog(LOG_INFO, "l%d: %s",k , hexline); // print line to syslog
            //printk(KERN_INFO "l%d: %s",k , hexline); // print line to kernellog
            memset(&hexline[0], 0, sizeof(hexline)); // clear hexline array
        }
    }
}

The implementation is straight forward. You call the function with mem, the address of the first byte you want to print, and define the number of bytes you want to print with count. I choosed

An example could look like this:

unsigned char test_plain_text[64] =   {    
    0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,
    0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51,
    0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef,
    0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10};

printf("Call with array:\n");
printMemory(test_plain_text, 32);
printf("Call with address: %p\n", &test_plain_text);
printMemory(&test_plain_text, 32);

The output:

$ ./main
Call with array:
l1: 0x6B|0xC1|0xBE|0xE2|0x2E|0x40|0x9F|0x96|0xE9|0x3D|0x7E|0x11|0x73|0x93|0x17|0x2A|
l2: 0xAE|0x2D|0x8A|0x57|0x1E|0x03|0xAC|0x9C|0x9E|0xB7|0x6F|0xAC|0x45|0xAF|0x8E|0x51|
Call with address: 0x6052a0
l1: 0x6B|0xC1|0xBE|0xE2|0x2E|0x40|0x9F|0x96|0xE9|0x3D|0x7E|0x11|0x73|0x93|0x17|0x2A|
l2: 0xAE|0x2D|0x8A|0x57|0x1E|0x03|0xAC|0x9C|0x9E|0xB7|0x6F|0xAC|0x45|0xAF|0x8E|0x51|

It seems strange that the output is the same regardless of calling the functions with the array or its address. But thats exactly what the compiler is doing, it uses the adress of the array in the function call.

This gets interesting when calling the function with an char pointer array:

Pointer to array of pointers

On Stackexchange someone proposed an initialization of a char array the following way. I copied it without thinking and was highly confused about the result of the printMemory function.

unsigned char *ptest_plain_text[64] =   {   
    0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,
    0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51,
    0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef,
    0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10};

printf("Call with array:\n");
printMemory(ptest_plain_text, 32);
printf("Call with address: %p\n", &ptest_plain_text);
printMemory(&ptest_plain_text, 32);

Instead of defining a normal char array he defined a char pointer array.

The output:

main.c:34:6: note: expected ‘const unsigned char *’ but argument is of type ‘unsigned char **’
 void printMemory(const unsigned char mem[], int count) \{


$ ./main
Call with array:
l1: 0x6B|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xC1|0x00|0x00|0x00|0x00|0x00|0x00|0x00|
l2: 0xBE|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xE2|0x00|0x00|0x00|0x00|0x00|0x00|0x00|
Call with address: 0x6050a0
l1: 0x6B|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xC1|0x00|0x00|0x00|0x00|0x00|0x00|0x00|
l2: 0xBE|0x00|0x00|0x00|0x00|0x00|0x00|0x00|0xE2|0x00|0x00|0x00|0x00|0x00|0x00|0x00|

Okay, at first we get the gcc notice that our argument is not a char pointer but a char pointer pointer. The result can be seen in the output. We get the first byte 0x6B then 7 zero's then the next byte 0xC1.

So what is happening here. The initialization of the char pointer array means that gcc saves pointers in the 64 fields of ptest_plain_text instead of actual char vars. One pointer is 8 byte long. These saved pointers should point to char variables. The given bytes (0x6b,0xc1,0xbe, ..) are interpreted as pointer addresses to these char variables.

This interpretation is nonsense and not that what the user on stackoverflow wanted. He wanted a simple char array. Instead he got a pointer to an array of pointers which point to chars at impossible adresses. If you call *ptest_plain_text[0] to get the char value, your computer tries to access the value at adress 00 00 00 00 00 00 00 6B and retrieves a segmentation fault.

Photo

So if you get strange segmentation faults in the future, simply debug your program and have a look at the actuall memory. In kernel-space it is more difficult to debug because the kernel halts if you run in a segmentation fault and you are unable to have a look at the memory. This print memory function will help you to debug your arrays hopefully before the kernel halts.