I have written a program in C which will read the bytes at a specific memory address from its own address space.
it works like this:
first it reads a DWORD from a File.
then it uses this DWORD as a memory address and reads a byte from this memory address in the current process' address space.
Here is a summary of the code:
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
}
While this program works, I wanted to know if there is another way to read the byte from a specific memory address and perform comparisons? Because each time, I need to write all the type castings.
Also, now when I try to write the byte to a file using the following syntax:
// fp2 is the file pointer for the output file
fwrite(fp2, 1, 1, (unsigned)(unsigned char)(*(*buffer)));
I get the warnings:
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
thanks.
You can use the C language union construct to represent an alias for your type as shown
typedef union {
char char[4];
char *pointer;
} alias;
alias buffer;
This assumes a 32-bit architecture (you could adjust the 4 at compile time, but would then also need to change the fread() byte count).
Then, you can simply use *(buffer.pointer) to reference the contents of the memory location.
From your question, the application is not clear, and the technique seems error prone. How do you take into account the movement of addresses in memory as things change? There may be some point in using the linker maps to extract symbolic information for locations to avoid the absolute addresses.
Take note of the definition of fwrite,
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
which means that the warnings at the last part of your question are because you should be writing from a character pointer rather than writing the actual value of the character.
You can remove the extra type castings by assigning the pointer you read from the file to another variable of the correct type.
Examples to think about:
#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;
}
By the way, reading arbitrary locations from memory seems concerning. (You say that you are reading from a specific memory address within the program's own address space, but how do you make sure of that?)
fp=fopen("input.txt","rb");
The file has an extension of .txt and you are trying to read it as a binary file. Please name files accordingly. If on Windows, name binary files with .bin extention. On Linux file extension do not matter.
// buffer will store the DWORD read from the file
fread(buffer, 1, 4, fp);
If you want to read 4 bytes, declare an unsinged int variable and read 4 bytes into it as shown below
fread(&uint, 1, 4, fp);
Why do you want to use a character array ? That is incorrect.
printf("the memory address is: %x", *buffer);
What are you trying to do here ? buffer is a pointer to a const char and the above statement prints the hex value of the first character in the array. The above statement is equal to
printf("the memory address is: %x", buffer[0]);
(*(*buffer)
How is this working ? Aren't there any compiler warnings and errors ? Is it Windows or Linux ? (*buffer) is a char and again de-referencing it should throw and error unless properly cast which I see you are not doing.
Related
I am working in Ubuntu 16.04 VM
I have a C program that takes in one argument that is expected to be a hexadecimal number between 0-7ffffffffffffff.
How do I check if the memory address specified is allocated in the virtual memory of my program and access the single byte of memory at the address?
EDIT:
so I can see the contents of my mapping via:
FILE *fptr = fopen("/proc/self/maps", "r");
c = fgetc(fptr);
while (c != EOF){
print("%c\n", c);
c = fgetc(fptr);
}
and I'm using the following function:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
that returns a pointer to the allocated region
however when I try using the command line argument, I type cast (void *) addr and it changes it to the hex value when I'm to assume that it is already in hex and I don't know how to avoid it unnecessarily converting.
I have a binary file which contains 3 differents structs and a christmas text. On the first line of the binaryfile have they provided me with a int which represents the size of a package inside the file. A package contains 3 structs ,the chistmastext and the size.
The structs lies in a file called framehdr.h and the binary file I'm reading is called TCPdump.
Now am I trying to create a program att will read each package at a time and then withdraw the text.
I have started with something like this:
#pragma warning(disable: 4996)
#include <stdio.h>
#include <stdlib.h>
#include "framehdr.h"
#include <crtdbg.h>
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
FILE *fileOpen;
char *buffer;
size_t dataInFile;
long filesize;
// The three structs
struct ethernet_hdr ethHdr;
struct ip_hdr ipHdr;
struct tcp_hdr tcpHDr;
fileOpen = fopen("C:\\Users\\Viktor\\source\\repos\\Laboration_3\\Laboration_3\\TCPdump", "rb");
if (fileOpen == NULL)
{
printf("Error\n");
}
else
{
printf("Success\n");
}
char lenOf[10];
size_t nr;
// Reads until \n comes
fgets(lenOf, sizeof(lenOf), fileOpen);
sscanf(lenOf, "%d", &nr);
// Withdraw the size of a package and check if it's correct
printf("Value: %d\n", nr);
printf("Adress: %d\n", &nr);
void *ptr;
fread(&ptr, nr, 1, fileOpen);
int resEth = 14;
printf("resEth: %d\n", resEth);
int resIP = IP_HL((struct ip_hdr*)ptr);
printf("ResIP: %d\n", resIP);
int resTcp = TH_OFF((struct tcp_hdr*)ptr);
printf("tcpIP: %d\n", resTcp);
int res = resEth + resIP + resTcp;
printf("Total: %d", res);
fclose(fileOpen);
//free(buffer);
system("pause");
return 0;
}
I know that the first struct ethernet will always have the size of 14 but I need to get the size of the other 2 and I'm suppose to use IP_HL and TH_OFF for that.
But my problems lies in that I can't seem to read the entire package to one
void * with the fread. I get noting in my *ptr.
Which in turn makes the code break when I try to convert the void * to one of the structs ones.
What I'm doing wrong with the void *?
Two problems:
First you should not really use text functions when reading binary files. Binary files doesn't really have "lines" in the sense that text file have it.
Secondly, with
void *ptr;
fread(&ptr, nr, 1, fileOpen);
you are passing a pointer to the pointer variable, you don't actually read anything into memory and then make ptr point to that memory. What happens now is that the fread function will read nr bytes from the file, and then write it to the memory pointed to by &ptr, which will lead to undefined behavior if nr > sizeof ptr (as then the data will be written out of bounds).
You have to allocate nr bytes of memory, and then pass a pointer to the first element of that:
char data[nr];
fread(data, nr, 1, fileOpen);
You should also get into the habit of checking for errors. What if the fread function fails? Or the file is truncated and there isn't nr bytes left to read?
You can check for these conditions by checking what fread returns.
And not only check for fread, there are more functions than fopen that can fail.
I have a struct carrying multiple members with different type. I want to copy this struct to a buffer, then concatenate a message for later use (separate them and read the struct and message, which I didn't do it here). Here is my code.
#define DAT "d"
#define ACK "a"
#define SYN "s"
#define FIN "f"
#define RST "r"
typedef struct Headers { //total 20 bytes
unsigned char _magic_[7];
unsigned char _type_[1];
union {
unsigned int _seq_; //4 bytes
unsigned int _ack_; //4 bytes
} no;
unsigned int _length_; //4 bytes
unsigned short _size_; //2 bytes
} Header;
int main() {
Header receiver_header;
char buffer[1024];
strcpy(receiver_header._magic_, "ABCDEF");
strcpy(receiver_header._type_, DAT);
receiver_header.no._ack_ = 0;
receiver_header._length_ = 900;
receiver_header._size_ = 10240;
char foo[] = "A random message";
memcpy(buffer, &receiver_header, sizeof(Header));
strcat(buffer, foo);
printf("%s\n", buffer);
}
And the output is
ABCDEFA random message
My questions are
Do you need to cast the members to same type in order to copy them into the buffer?
Why is the rest of the members disappeared in the buffer even I have declared the correct pointer of the source and length of it?
The first member of your Header, _magic_, holds 7 chars. You copied 6 chars ("ABCDEF") followed by a null character. strcat copies the source string into the destination string at the first null character it encounters. Therefore, it appends "A random message" right after the first six bytes of the Header. If you want to append the message after the entire struct, you need to specify an offset to copy to, like so.
strcpy(buffer + sizeof(Header), foo);
However, it won't print the entire struct since the null character is still right after "ABCDEF", even though foo has been appended at the correct offset. If you want to print everything in your struct, just print out each member explicitly, like so.
printf("%s %c %u %u %hu %s",
receiver_header._magic_,
receiver_header._type[0],
reveiver_header.no._ack_,
receiver_header._length_,
receiver_header._size_,
foo);
Do you need to cast the members to same type in order to copy them into the buffer?
No. memcpy() can copy the whole representation of any object. But you do have some other apparent misconceptions and strangeness:
If Header._magic_ is meant to hold a string then its element type should be char, not unsigned char. On the other hand, if it's meant to hold binary data then you should not use strcpy() to copy data into it.
Header._type_ has space for a single byte, but you strcpy() a one-character string into it. The string requires two bytes when you count the terminator; these don't both fit into _type_. Probably you should perform an ordinary assignment of a single (unsigned) char instead.
The struct representation that you copy into the buffer is not collectively the contents of a C string, if only on account of having internal null bytes. Therefore, you cannot safely append to it with strcat(). More generally, you ought not be manipulating general data with string functions.
It is also unreasonable to try to print the structure representation as if it were a string. Even if there were no internal null bytes, but there were a terminating null byte, your struct has numeric fields. Their representation is binary, not textual, and printing them as if they were textual will not produce anything useful.
Why is the rest of the members disappeared in the buffer even I have declared the correct pointer of the source and length of it?
Because you overwrote them when you strcat()ed the message onto the buffer.
I have a case in which I have a uint64_t*, a char* (6 chars long), and a uint16_t* that point to the addresses x, x+2, and x respectively. So if the char* points to "This i" then the uint16_t* should point to the value 0 dec, and the uint64_t* should point to the value 115, 588, 096, 157, 780 dec.
But when I look at these values I am getting 0 dec for the uint64_t I do not understand why this would be. Could someone explain?
Edit (added code):
FILE *file = fopen("/Users/Justin/Desktop/test.txt", "rb");
uint64_t *window = malloc(8);
char *buffer = (char*)(window+2);
uint16_t *data = (uint16_t*)window;
uint16_t *read = (uint16_t*)(window+6);
fread(buffer, 6, 1, file);
printf("%p\n", window);
printf("%p\n", buffer);
printf("%p\n", data);
printf("%p\n", read);
printf("%s\n", buffer);
printf("%llu\n", *window);
and the output is:
0x100105440
0x100105450
0x100105440
0x100105470
This i
0
You're getting tripped up by pointer math.
As window is declared as uint64_t *, window + 2 does not increment the address by two bytes; it increments it by 2 * sizeof(uint64_t) (that is, sixteen bytes). As a result, the memory you're looking at is uninitialized (and, in fact, lies outside the allocated block).
If you actually want the address to be incremented by two bytes, you'll need to cast the pointer to char * before adding 2 to it:
char *buffer = ((char *) window) + 2;
I think you're misunderstanding what the +2 does here:
uint64_t *window = malloc(8);
char *buffer = (char*)(window+2);
It helps to visualize the data that we got back from malloc, using | to help show 8-byte boundaries:
|-------|-------|-------|-------|-------|-------|-------|-------
^
window
Now, buffer doesn't point two bytes ahead of window. It points two uint64_t's ahead. Or in other words, ((char*)window) + 2 * sizeof(*window):
|-------|-------|-------|-------|-------|-------|-------|-------
^ ^
window buffer
which you then fread into
|-------|-------This i--|-------|-------|-------|-------|-------
^ ^
window buffer
If you want to just point two bytes ahead, you have to add the 2 to a char*:
char* buffer = ((char*)window) + 2;
In addition to the pointer math issues that #duskwuff pointed out and #Barry clarified, there is also another issue. The answer you get will depend on the computer architecture on which this code runs.
On big-endian machines you'll get one answer, on little-endian machines you'll get a different answer.
Oh, and one more thing. Writing buffer using %s is very dangerous. If there are no zero bytes in the data read from the file, it will wander through memory until it finds one.
Edit: I am not sure if this code does what I think it does. Could someone tell me how to test it? I.e. what should the buffer in my main function look like? I am assuming that a buffer has data of two fields in the following order type(16 bits), length(32 bits). I'm assuming that the buffer is read in from a file and each of the fields is separated by a space. The fields are stored in network byte order and when I read them I have to convert them back to host byte order.
I'm expecting that the code will read the contents from the file (which should be in network byte order) and display the contents in host byte order. I'm a bit confused about type conversions and what the network byte order will be inside of a file, so I don't know what values to use to test it. Also, I'm not sure if my code is written correctly, could someone who does this sort of thing or knows a bit more about such conversions tell me if my code is correct?
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printRecords(char *buffer)
{
unsigned int recordType;
unsigned long recordLength;
char *data;
char *index;
if (!buffer)
printf("Empty buffer\n");
while(*buffer)
{
memcpy(&recordType,(const void *) buffer,2);
buffer += 3;
recordType = ntohs(recordType);
printf("Record type normal: %u\n",recordType);
memcpy(&recordLength,(const void *) buffer,4);
buffer += 5;
recordLength = ntohl(recordLength);
printf("Record Length normal: %l\n",recordLength);
break;
}
}
void main()
{
char * buffer = "0000000000000001 00000000000000000000000000000001";
printRecords(buffer);
}
char *buffer = malloc(sizeof(buf));
sizeof means "size of buf's type", ie the size of a pointer to char; you probably want
malloc(strlen(buf) + 1); /* 1 for trailing '\0' */
Then you are mistaking the value of the bytes for their conversion to string:
"256" is byte '2' followed by byte '5' and '6' -- '2' is not equals to 2, '5' is not equals to 5 etc.
The 256 you are talking about is 00000001 00000000 instead (try dumping the bytes to stdout and you'll see).
Also, recordType should be of type uint16_t, not unsigned -- you're never too paranoid.
EDIT: atoi takes a pointer to char, as in
atoi("123")
not a pointer to int!