1

我用 C 语言编写了一个程序,它将从自己的地址空间读取特定内存地址的字节。

它是这样工作的:

  1. 首先它从文件中读取一个 DWORD。
  2. 然后它使用这个 DWORD 作为内存地址,并在当前进程的地址空间中从这个内存地址读取一个字节。

以下是代码摘要:

FILE *fp;
char buffer[4];

fp=fopen("input.txt","rb");

// buffer will store the DWORD read from the file

fread(buffer, 1, 4, fp);

printf("the memory address is: %x", *buffer);

// I have to do all these type castings so that it prints only the byte example:
// 0x8b instead of 0xffffff8b

printf("the byte at this memory address is: %x\n", (unsigned)(unsigned char)(*(*buffer)));

// And I perform comparisons this way

if((unsigned)(unsigned char)(*(*buffer)) == 0x8b)
{
    // do something
}

虽然该程序有效,但我想知道是否有另一种方法可以从特定内存地址读取字节并执行比较?因为每次,我都需要编写所有的类型转换。

另外,现在当我尝试使用以下语法将字节写入文件时:

// fp2 is the file pointer for the output file
fwrite(fp2, 1, 1, (unsigned)(unsigned char)(*(*buffer)));

我收到警告:

test.c(64) : warning C4047: 'function' : 'FILE *' differs in levels of indirectio
n from 'unsigned int'
test.c(64) : warning C4024: 'fwrite' : different types for formal and actual para
meter 4

谢谢。

4

3 回答 3

1

您可以使用 C 语言联合构造来表示您的类型的别名,如图所示

typedef union {
      char char[4];
      char *pointer;
   } alias;

alias buffer;

这假定为 32 位架构(您可以4在编译时调整,但随后还需要更改fread()字节数)。

然后,您可以简单地使用*(buffer.pointer)来引用内存位置的内容。

从您的问题来看,该应用程序尚不清楚,并且该技术似乎容易出错。当事情发生变化时,您如何考虑内存中地址的移动?使用链接器映射来提取位置的符号信息以避免绝对地址可能有一些意义。

于 2013-09-09T19:20:00.800 回答
1

注意 的定义fwrite

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

这意味着您问题最后一部分的警告是因为您应该从字符指针写入而不是写入字符的实际值。

您可以通过将从文件中读取的指针分配给另一个正确类型的变量来删除额外的类型转换。

要考虑的例子

#include <stdio.h>
int main() {
  union {
    char buffer[8];
    char *character;
    long long number;
  } indirect;
  /* indirect is a single 8-byte variable that can be accessed
   * as either a character array, a character pointer, or as
   * an 8-byte integer! */
  char *x = "hi";
  long long y;
  char *z;
  printf("stored in the memory beginning at x: '%s'\n", x); /* 'hi' */
  printf("bytes used to represent the pointer x: %ld\n", sizeof(x)); /* 8 */
  printf("exact value (memory location) of (pointed to by) the pointer x: %p\n", x); /* 4006c8 */
  y = (long long) x;
  printf("%llx\n", y); /* 4006c8 */
  z = (char *) y;
  printf("%s\n", z); /* 'hi' */
  /* the cool part--we can access the exact same 8 bytes of data
   * in three different ways, as a 64-bit character pointer,
   * as an 8-byte character buffer, or as
   * an 8-byte integer */
  indirect.character = z;
  printf("%s\n", indirect.character); /* 'hi' */
  printf("%s\n", indirect.buffer); /* binary garbage which is the raw pointer  */
  printf("%lld\n", indirect.number); /* 4196040 */
  return 0;
}

顺便说一句,从内存中读取任意位置似乎令人担忧。(您说您正在从程序自己的地址空间中的特定内存地址读取,但是您如何确保这一点?)

于 2013-09-09T19:02:48.220 回答
0
    fp=fopen("input.txt","rb");

该文件的扩展名为 .txt,您正尝试将其作为二进制文件读取。请相应地命名文件。如果在 Windows 上,使用 .bin 扩展名命名二进制文件。在 Linux 文件扩展名上无关紧要。

    // buffer will store the DWORD read from the file

    fread(buffer, 1, 4, fp);

如果要读取 4 个字节,请声明一个 unsinged int 变量并读取 4 个字节,如下所示

    fread(&uint, 1, 4, fp);

为什么要使用字符数组?这是不正确的。

    printf("the memory address is: %x", *buffer);

你想在这里做什么?buffer 是一个指向 const char 的指针,上面的语句打印数组中第一个字符的十六进制值。上面的语句等于

   printf("the memory address is: %x", buffer[0]);

   (*(*buffer)

这是如何工作的?没有任何编译器警告和错误吗?是 Windows 还是 Linux?(*buffer) 是一个 char 并且再次取消引用它应该抛出和错误,除非我看到你没有正确转换。

于 2013-09-11T16:56:51.340 回答