试图从内存中打印出有用的数据
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;
}
这是我当前的代码,我最初使用 ReadProcessMemory
读取另一个进程的内存。现在我将临时数据存储在 tempbuf
中。我能够以十六进制形式从 tempbuf
输出数据。但我打算如图所示显示它,我在这里面临的另一个复杂性是 if bytes_left > sizeof(tempbuf) 我只读取了与 tempbuf 大小相当的足够数据。我定义的数组只能支持多少数据,如何读取更多数据?
无法存储比您 space 分配的数据更多的数据。如果您需要存储更多数据,则需要在某处分配更多 space(更多 RAM、磁盘文件等)。压缩将允许您在分配的 space 中存储更多数据,但您不会获得那么多。对于几乎无限的存储,您将需要写入磁盘。
或者,如果您只需要显示一次就可以忘记,读入 16 个字节,显示该行,然后将接下来的 16 个字节读入同一内存。
如果我没理解错的话,你的主要问题是关于如何模拟十六进制编辑器的输出。
这可以分为 3 个部分:
- 打印地址
- 打印每个字节的十六进制值
- 打印每个字节的 ASCII 值
以十六进制打印地址很容易。我们可以使用 %p
来打印这样一个指针的地址:
char* mem = malloc(99);
printf("%p\n", (void*)mem);
// output: 0xc17080
接下来您可以使用 %02x
在 char(1 字节)上打印字节的十六进制值。 02
指定零填充字段宽度为 2。在这种情况下,它只是使 0
打印为 00
以使内容对齐并看起来漂亮。
printf("%02x", mem[0]);
// output: 0A
最后,打印 ASCII 是最简单的……几乎。我们可以使用 %c
为某些 ASCII 值打印一个字节,但我们不想打印像 \n
或 \t
这样的东西。为了解决这个问题,我们可以将 %c
的使用限制在 ASCII table 的 character/symbol 区域,并为其他所有内容打印 .
。
char c = mem[0];
if ( ' ' <= c && c <= '~' ) {
printf("%c", c);
}
else {
printf(".");
}
//output: .
现在我们只需要将这些组合在一起。您可以决定每行要显示多少字节并打印“[address] [n hex bytes] [n ascii bytes]”并重复直到遍历整个内存区域。我在下面给出了一个示例函数,您可以 运行 自己 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");
}
}
示例输出:
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
至于你问题的第二部分,如果你不能增加 tempbuf
的大小,那么你随时都无法处理那么多的内存。
但是,如果您只想按上述方式显示内存,则可以分块显示内存的每个部分。你可以获取一块内存,显示它,然后获取一个新的内存块,显示新的内存块,重复。
类似于
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;
}
您需要做更多的工作来检查错误并使一切看起来都不错,但希望这能让您清楚地知道可以做什么。
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;
}
这是我当前的代码,我最初使用 ReadProcessMemory
读取另一个进程的内存。现在我将临时数据存储在 tempbuf
中。我能够以十六进制形式从 tempbuf
输出数据。但我打算如图所示显示它,我在这里面临的另一个复杂性是 if bytes_left > sizeof(tempbuf) 我只读取了与 tempbuf 大小相当的足够数据。我定义的数组只能支持多少数据,如何读取更多数据?
无法存储比您 space 分配的数据更多的数据。如果您需要存储更多数据,则需要在某处分配更多 space(更多 RAM、磁盘文件等)。压缩将允许您在分配的 space 中存储更多数据,但您不会获得那么多。对于几乎无限的存储,您将需要写入磁盘。
或者,如果您只需要显示一次就可以忘记,读入 16 个字节,显示该行,然后将接下来的 16 个字节读入同一内存。
如果我没理解错的话,你的主要问题是关于如何模拟十六进制编辑器的输出。
这可以分为 3 个部分:
- 打印地址
- 打印每个字节的十六进制值
- 打印每个字节的 ASCII 值
以十六进制打印地址很容易。我们可以使用 %p
来打印这样一个指针的地址:
char* mem = malloc(99);
printf("%p\n", (void*)mem);
// output: 0xc17080
接下来您可以使用 %02x
在 char(1 字节)上打印字节的十六进制值。 02
指定零填充字段宽度为 2。在这种情况下,它只是使 0
打印为 00
以使内容对齐并看起来漂亮。
printf("%02x", mem[0]);
// output: 0A
最后,打印 ASCII 是最简单的……几乎。我们可以使用 %c
为某些 ASCII 值打印一个字节,但我们不想打印像 \n
或 \t
这样的东西。为了解决这个问题,我们可以将 %c
的使用限制在 ASCII table 的 character/symbol 区域,并为其他所有内容打印 .
。
char c = mem[0];
if ( ' ' <= c && c <= '~' ) {
printf("%c", c);
}
else {
printf(".");
}
//output: .
现在我们只需要将这些组合在一起。您可以决定每行要显示多少字节并打印“[address] [n hex bytes] [n ascii bytes]”并重复直到遍历整个内存区域。我在下面给出了一个示例函数,您可以 运行 自己 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");
}
}
示例输出:
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
至于你问题的第二部分,如果你不能增加 tempbuf
的大小,那么你随时都无法处理那么多的内存。
但是,如果您只想按上述方式显示内存,则可以分块显示内存的每个部分。你可以获取一块内存,显示它,然后获取一个新的内存块,显示新的内存块,重复。
类似于
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;
}
您需要做更多的工作来检查错误并使一切看起来都不错,但希望这能让您清楚地知道可以做什么。