如何对内存中的地址执行十六进制内存转储?

How can I perform a hex memory dump on an address in memory?

我正在尝试为我的计算机机器组织编写一个 C++ 程序 class,我在其中对存储在内存中的某个地址执行十六进制内存转储。我真的不明白内存转储是什么,而且我对编写 C++ 还很陌生。我的问题是:

  1. 如何创建一个方法,该方法采用两个参数,并在其中指定内存中的地址?
  2. 如何进一步修改这些参数以指定恰好 4 个字节长的字地址?
  3. 我怎样才能将这些地址转换成十六进制值?

我知道这很多,但感谢您的任何建议。

对于任何需要它的人,这是我到目前为止的代码:

#include <stdio.h>

// Create something to do the methods on
char array[3] = {'a', 'b', 'c'};

void mdump(char start, char end){

    // Create pointers to get the address of the starting and ending characters
    char* pointer1 = (char *)& start;
    char* pointer2 = (char *)& end;

    // Check to see if starting pointer is in lower memory than ending pointer
    if(pointer1 < pointer2){
        printf("Passed");
    }
    else{
        printf("Failed");
    }

    // Modify both the arguments so that each of them are exactly 4 bytes
    // Create a header for the dump
    // Iterate through the addresses, from start pointer to end pointer, and produce lines of hex values
    // Declare a struct to format the values
    // Add code that creates printable ASCII characters for each memory location (print "cntrl-xx" for values 0-31, or map them into a blank)
    // Print the values in decimal and in ASCII form
}

int main(){
    mdump(array[0], array[2]);
    return 0;
}

如何在学习 C++ 的同时编写 Hex dump 工具:

  1. 从简单的事情开始:
#include <iostream>

int main()
{
  char test[32] = "My sample data";
  // output character
  std::cout << test[0] << '\n';
}

输出:

M

Live demo on coliru


  1. 打印 hex-value 而不是字符:
#include <iostream>

int main()
{
  char test[32] = "My sample data";
  // output a character as hex-code
  std::cout << std::hex << test[0] << '\n'; // Uh oh -> still a character
  std::cout << std::hex << (unsigned)(unsigned char)test[0] << '\n';
}

输出:

M
4d

Live demo on coliru

注:

char 的流输出运算符旨在打印一个字符(当然)。 unsigned 还有另一个流输出运算符,它更适合。为了实现它的使用,必须将 char 转换为 unsigned.

但要做好准备:C++ 标准不强制要求 char 是有符号的还是无符号的——这个决定留给编译器供应商。为了安全起见,'char'先转换为'unsigned char',然后再转换为unsigned


  1. 打印字符所在变量的地址:
#include <iostream>

int main()
{
  char test[32] = "My sample data";
  // output an address
  std::cout << &test[0] << '\n'; // Uh oh -> wrong output stream operator
  std::cout << (const void*)&test[0] << '\n';
}

输出:

My sample data
0x7ffd3baf9b70

Live demo on coliru

注:

const char* 有一个流输出运算符,用于打印 (zero-terminated) 字符串。这不是预期的。因此,转换为 const void* 的(丑陋的)技巧是必要的,它会触发另一个更适合的流输出运算符。


  1. 如果数据不是 2 位十六进制怎么办?
#include <iomanip>
#include <iostream>

int main()
{
  // output character as 2 digit hex-code
  std::cout << (unsigned)(unsigned char)'\x6' << '\n'; // Uh oh -> output not with two digits
  std::cout << std::hex << std::setw(2) << std::setfill('0')
    << (unsigned)(unsigned char)'\x6' << '\n';
}

输出:

6
06

Live demo on coliru

注:

I/O manipulators可用于修改(某些)流输出运算符的格式。


  1. 现在,将它们放在一起(在循环中)然后瞧瞧:hex-dump。
#include <iomanip>
#include <iostream>

int main()
{
  char test[32] = "My sample data";
  // output an address
  std::cout << (const void*)&test[0] << ':';
  // output the contents
  for (char c : test) {
    std::cout << ' '
      << std::hex << std::setw(2) << std::setfill('0')
      << (unsigned)(unsigned char)c;
  }
  std::cout << '\n';
}

输出:

0x7ffd345d9820: 4d 79 20 73 61 6d 70 6c 65 20 64 61 74 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Live demo on coliru


  1. 让它好看:
#include <algorithm>
#include <iomanip>
#include <iostream>

int main()
{
  char test[32] = "My sample data";
  // hex dump
  const size_t len = sizeof test;
  for (size_t i = 0; i < len; i += 16) {
    // output an address
    std::cout << (const void*)&test[i] << ':';
    // output the contents
    for (size_t j = 0, n = std::min<size_t>(len - i, 16); j < n; ++j) {
      std::cout << ' '
        << std::hex << std::setw(2) << std::setfill('0')
        << (unsigned)(unsigned char)test[i + j];
    }
    std::cout << '\n';
  }
}

输出:

0x7fffd341f2b0: 4d 79 20 73 61 6d 70 6c 65 20 64 61 74 61 00 00
0x7fffd341f2c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Live demo on coliru


  1. 让它成为一个函数:
#include <algorithm>
#include <iomanip>
#include <iostream>

void hexdump(const char* data, size_t len)
{
  // hex dump
  for (size_t i = 0; i < len; i += 16) {
    // output an address
    std::cout << (const void*)&data[i] << ':';
    // output the contents
    for (size_t j = 0, n = std::min<size_t>(len - i, 16); j < n; ++j) {
      std::cout << ' '
        << std::hex << std::setw(2) << std::setfill('0')
        << (unsigned)(unsigned char)data[i + j];
    }
    std::cout << '\n';
  }
}

int main()
{
  char test[32] = "My sample data";
  std::cout << "dump test:\n";
  hexdump(test, sizeof test);
  std::cout << "dump 4 bytes of test:\n";
  hexdump(test, 4);
  std::cout << "dump an int:\n";
  int n = 123;
  hexdump((const char*)&n, sizeof n);
}

输出:

dump test:
0x7ffe900f4ea0: 4d 79 20 73 61 6d 70 6c 65 20 64 61 74 61 00 00
0x7ffe900f4eb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
dump 4 bytes of test:
0x7ffe900f4ea0: 4d 79 20 73
dump an int:
0x7ffe900f4e9c: 7b 00 00 00

Live demo on coliru

注:

(const char*)&n 可能看起来有点冒险。事实上,指针的转换总是充其量是不必要的。但是,对于转储工具,这是访问任意数据字节的最简单方法。 (这是标准明确允许的罕见情况之一。)


可以在
中找到更好的 hexdump SO: How would I create a hex dump utility in C++?
(我事先推荐了 OP)。