如何获取结构数据的十六进制转储

Posted

技术标签:

【中文标题】如何获取结构数据的十六进制转储【英文标题】:how to get hexdump of a structure data 【发布时间】:2011-12-08 05:26:02 【问题描述】:
 ....
 finalize(char *hdrs, sendip_data *headers[], int index,
                    sendip_data *data, sendip_data *pack)
 

 ........

出于调试目的,我想要datapack 结构的十六进制转储,它们的类型为sendip_data,一个非常复杂的结构。实际上它们包含一些二进制信息,所以我不确定我的项目的输出是否正确。因此出于调试目的,我想将数据写入文件,以便可以按如下方式使用 hexdump -

$hexdump -C file.txt

由于这是运行时生成的一个/w数据包,所以我也不确定datapack结构的长度,我认为fread / fwrite需要..所以请给我一些建议。

【问题讨论】:

不知道从哪里开始。 sizeof(sendip_data) 将给出该结构的大小,但您是说它包含指向您也希望成为输出的一部分的其他数据的指针? 另见***.com/questions/29242/off-the-shelf-c-hex-dump-code 【参考方案1】:

以下代码将为您提供代码中任意内存的十六进制转储。

#include <stdio.h>

// Usage:
//     hexDump(desc, addr, len, perLine);
//         desc:    if non-NULL, printed as a description before hex dump.
//         addr:    the address to start dumping from.
//         len:     the number of bytes to dump.
//         perLine: number of bytes on each output line.

void hexDump (
    const char * desc,
    const void * addr,
    const int len,
    int perLine
) 
    // Silently ignore silly per-line values.

    if (perLine < 4 || perLine > 64) perLine = 16;

    int i;
    unsigned char buff[perLine+1];
    const unsigned char * pc = (const unsigned char *)addr;

    // Output description if given.

    if (desc != NULL) printf ("%s:\n", desc);

    // Length checks.

    if (len == 0) 
        printf("  ZERO LENGTH\n");
        return;
    
    if (len < 0) 
        printf("  NEGATIVE LENGTH: %d\n", len);
        return;
    

    // Process every byte in the data.

    for (i = 0; i < len; i++) 
        // Multiple of perLine means new or first line (with line offset).

        if ((i % perLine) == 0) 
            // Only print previous-line ASCII buffer for lines beyond first.

            if (i != 0) printf ("  %s\n", buff);

            // Output the offset of current line.

            printf ("  %04x ", i);
        

        // Now the hex code for the specific character.

        printf (" %02x", pc[i]);

        // And buffer a printable ASCII character for later.

        if ((pc[i] < 0x20) || (pc[i] > 0x7e)) // isprint() may be better.
            buff[i % perLine] = '.';
        else
            buff[i % perLine] = pc[i];
        buff[(i % perLine) + 1] = '\0';
    

    // Pad out last line if not exactly perLine characters.

    while ((i % perLine) != 0) 
        printf ("   ");
        i++;
    

    // And print the final ASCII buffer.

    printf ("  %s\n", buff);


// Very simple test harness.

int main (int argc, char *argv[]) 
    char my_str[] = "a char string greater than 16 chars";
    hexDump ("my_str", &my_str, sizeof (my_str), 16);
    return 0;

您向hexDump 传递描述、内存地址、长度以及每行需要多少字节。

它将输出一个十六进制转储(包括字符数据)以供检查。当您使用包含的main 运行它时,输出为:

my_str:
  0000  61 20 63 68 61 72 20 73 74 72 69 6e 67 20 67 72  a char string gr
  0010  65 61 74 65 72 20 74 68 61 6e 20 31 36 20 63 68  eater than 16 ch
  0020  61 72 73 00                                      ars.

【讨论】:

不错..真的很有帮助:) 将 if ((pc[i] 0x7e)) 替换为 if (!isprint(pc[i])) 谢谢你的好精神。我喜欢你的功能,我会把它包括在我的创作中......你的部分想法现在活在我身上...... main 中的示例看起来不对。第二个参数是&amp;my_str,应该是my_str @frakman1,在这种情况下,没有区别。结果类型不同(指向 char 的指针而不是指向 char 数组的指针),但它们在这里的处理方式相同(在函数中强制为 void*/char*)。我更喜欢&amp;something 形式,因为如果您有非数组类型,则需要它,例如:int my_int; hexDump ("my_int", &amp;my_int, sizeof (my_int));。请参阅***.com/questions/2528318/… 了解更多详情。【参考方案2】:

android 的十六进制转储,应该也适用于其他平台。

LOGD(),和DLOG()一样,扮演printf()的角色,因为printf()在Android中不起作用。对于Android以外的平台,您可以#define DLOG printf

dlog.h:

// Android logging
#include <android/log.h>
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG  , "~~~~~~", __VA_ARGS__)
#define DLOG(...) __android_log_print(ANDROID_LOG_DEBUG  , "~~~~~~", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "~~~~~~", __VA_ARGS__)
#define ELOG(...) __android_log_print(ANDROID_LOG_ERROR  , "~~~~~~", __VA_ARGS__)

#ifdef __cplusplus
extern "C" 
#endif

void log_dump(const void*addr,int len,int linelen);
void log_dumpf(const char*fmt,const void*addr,int len,int linelen);

#ifdef __cplusplus

#endif

dump.cpp:

#include <dlog.h>
//#include <alloca.h>

inline char hdigit(int n)return "0123456789abcdef"[n&0xf];;

#define LEN_LIMIT 8
#define SUBSTITUTE_CHAR '`'

static const char* dumpline(char*dest, int linelen, const char*src, const char*srcend)

    if(src>=srcend) 
        return 0;
    
    int i;
    unsigned long s = (unsigned long)src;
    for(i=0; i<8; i++) 
        dest[i] = hdigit(s>>(28-i*4));
    
    dest[8] = ' ';
    dest += 9;
    for(i=0; i<linelen/4 ; i++) 
        if(src+i<srcend) 
            dest[i*3] = hdigit(src[i]>>4);
            dest[i*3+1] = hdigit(src[i]);
            dest[i*3+2] = ' ';
            dest[linelen/4*3+i] = src[i] >= ' ' && src[i] < 0x7f ? src[i] : SUBSTITUTE_CHAR;
        else
            dest[i*3] = dest[i*3+1] = dest[i*3+2] = dest[linelen/4*3+i] = ' ';
        
    
    return src+i;


void log_dumpf(const char*fmt,const void*addr,int len,int linelen)

#if LEN_LIMIT
    if(len>linelen*LEN_LIMIT) 
        len=linelen*LEN_LIMIT;
    
#endif
    linelen *= 4;
    static char _buf[4096];
    char*buf = _buf;//(char*)alloca(linelen+1); // alloca() causes the initialization to fail!!!!
    buf[linelen]=0;
    const char*start = (char*)addr;
    const char*cur = start;
    const char*end = start+len;
    while(!!(cur = dumpline(buf,linelen,cur,start+len)))DLOG(fmt,buf);


void log_dump(const void*addr,int len,int linelen)

    log_dumpf("%s\n",addr,len,linelen);

使用示例:

log_dumpf("args: %s\n", &p, 0x20, 0x10);

输出:

args: 61efadc4 00 3c 17 01 6d bc 59 61 02 00 00 00 80 ae ef 61 `<``m`Ya```````a
args: 61efadd4 00 3c 17 01 00 00 00 00 31 a5 59 61 80 ae ef 61 `<``````1`Ya```a

更新: 参见reDroid (github) 中的dump.cpp 和re_dump.h,它包含一个检查指针是否有效的递归转储。

【讨论】:

很高兴有一个更新,但并没有提供很多便利,因为存储库中没有说明,并且链接的文件引用了其中的其他文件。

以上是关于如何获取结构数据的十六进制转储的主要内容,如果未能解决你的问题,请参考以下文章

如何获取可执行文件的字符串转储?

powershell 获取文件的十六进制转储

svnadmin 只转储文本,没有二进制文件

显示字符串的十六进制转储

如何在bash中创建仅包含十六进制字符而不包含空格的文件的十六进制转储?

SIM CARD APDU解析工具