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.
Related
I have the following function and I am wondering if there is a way to pass string or char array instead of stdout into it so I can get the printed representation as a string.
void print_Type(Type t, FILE *f)
{
fprintf(f,"stuff ...");
}
print_Type(t, stdout);
I have already tried this:
int SIZE = 100;
char buffer[SIZE];
print_Type(t, buffer);
But this is what I am seeing:
�����
Something like this
FILE* f = fmemopen(buffer, sizeof(buffer), "w");
print_Type(t, f);
fclose(f);
The fmemopen(void *buf, size_t size, const char *mode) function opens a stream. The stream allows I/O to be performed on the string or memory buffer pointed to by buf.
Yes there is sprintf() notice the leading s rather than f.
int SIZE = 100;
char buffer[SIZE];
sprintf(buffer, "stuff %d", 10);
This function prints to a string s rather than a file f. It has exactly the same properties and parameters to fprintf() the only difference is the destination, which must be a char array (either statically allocated as an array or dynamical allocated (usually via malloc)).
Note: This function is dangerous as it does not check the length and can easily overrun the end of the buffer if you are not careful.
If you are using a later version of C (c99). A better function is snprintf this adds the extra buffer length checking.
The problem with fmemopen is that it cannot resize the buffer. fmemopen did exist in Glibc for quite some time, but it was standardized only in POSIX.1-2008. But that revision included another function that handles dynamic memory allocation: open_memstream(3):
char *buffer = NULL;
size_t size = 0;
FILE* f = open_memstream(&buffer, &size);
print_Type(t, f);
fclose(f);
buffer will now point to a null-terminated buffer, with size bytes before the extra null terminator! I.e. you didn't write null bytes, then strlen(buffer) == size.
Thus the only merit of fmemopen is that it can be used to write to a fixed location memory buffer or fixed length, whereas open_memstream should be used everywhere else where the location of the buffer does not matter.
For fmemopen there is yet another undesired feature - the writes may fail when the buffer is being flushed and not before. Since the target is in memory, there is no point in buffering the writes, so it is suggested that if you choose to use fmemopen, Linux manual page fmemopen(3) recommends disabling buffering with setbuf(f, NULL);
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.
Right now, I'm working on an example code that I wish to integrate into my program later. What essentially I'm trying to do is read a .dat file byte by byte and interpret the data (ie. interpret boot sector to output the sector size, reserved sectors etc.)
To do this, I am reading the data byte by byte and, using the descriptions in fat12 of https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html#ss1.3 , I translate the data into the information that I want. Right now, I can pull individual bytes from the file (Is it right to assume that the data pulled is in hex?). However, I need two bytes to have something meaningful. So, I need to combine two bytes into one, convert the hex data into decimal and output the information. Unfortunately, right now, I'm getting a seg fault and for the life of me, I can't figure out what's wrong. Thanks in advance!
int main (int argc, char **argv){
FILE *fp ,*fptest;
long lSize;
char *buffer;
//Open file
fptest= open("fat_volume.dat", "rb");
//Read file into buffer
fread(buffer,1,512,fptest);
//Parse the boot sector
char tmpA, tmpB;
tmpA = buffer[10]; //First byte
tmpB = buffer[11]; //Second byte
//Combine the two bytes into one
char combinedBytes[3];
strcpy (combinedBytes, tmpA);
strcat (combinedBytes, tmpB);
//Hex to decimal converter
long int li1;
li1 = strtol (combinedBytes,NULL,16);
printf ("The sector size is: %ld.\n", li1);
return 0;
}
You must allocate buffer; e.g.
char buffer[512];
or
char *buffer = malloc(512);
EDIT:
The string operations
strcpy (combinedBytes, tmpA);
strcat (combinedBytes, tmpB);
do not make sense either and access/copy too much data (the compiler will warn you about this!).
I suggest do read values as
unsigned char tmpA = buffer[10];
unsigned char tmpB = buffer[11];
unsigned int tmp = (tmpA << 8) | (tmpB << 0); /* or revert in in case of
little-endian */
To make things more efficient, I would write it as
struct fat_header {
uint8_t pad0[10];
uint16_t my_val;
uint8_t pad1[500];
} __attribute__((__packed__)); /* this is not portable and for gcc! */
...
struct fat_header hdr;
fread(&hdr, 1, sizeof hdr, f);
uint16_t val = be16toh(hdr.my_val); /* or le16toh() in case of le */
You are reading into a buffer you never allocated memory for.
What you're trying now is to read from some junk value in memory, who knows, which almost always leads to a segmentation fault.
Use:
char *buffer = malloc(512 * sizeof(char)); // this allocates 512 times the size of a single char of memory
If you don't specify the number inside malloc to be of a specific size (e.g. malloc(512) the number is in bytes, though I think it's better to always include it.
This specific error is called dereferencing a null pointer
EDIT:
I've managed to run this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
FILE *fp ,*fptest;
long lSize;
char *buffer;
//Open file
fptest = fopen("input.txt", "rb");
if (fptest == NULL)
{
printf("Error occurred when opening file");
return 1;
}
buffer = malloc(sizeof(char) * 512);
//Read file into buffer
fread(buffer,1,512,fptest);
//Parse the boot sector
char tmpA, tmpB;
tmpA = buffer[10]; //First byte
tmpB = buffer[11]; //Second byte
//Combine the two bytes into one
char combinedBytes[3];
strcpy (combinedBytes, &tmpA);
strcat (combinedBytes, &tmpB);
//Hex to decimal converter
long int li1;
li1 = strtol (combinedBytes,NULL,16);
printf ("The sector size is: %ld.\n", li1);
return 0;
}
You also used a function open() which must be fopen(), and you need to pass the address of tmpA and tmpB to strcpy and strcat.
This is why I don't understand why your compiler doesn't give any errors or warnings..
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.
So, for some reason, I need to make a external file (.DAT) to store data by appending the new one to the end of old data.
#include <stdio.h>
#include <stdlib.h>
int main () {
typedef struct {
char *Name;
int Index;
} DataFile;
static FILE *file;
size_t result;
DataFile *DataTable;
file = fopen("database.DAT","ab");
DataTable = (DataFile *) malloc (sizeof(DataFile));
DataTable[0].Name = "somefile.txt";
DataTable[0].Index = 7;
printf("%s %d \n",DataTable[0].Name,DataTable[0].Index);
result = fwrite(DataTable,sizeof(DataFile),1,file);
fclose(file);
free(DataTable);
return 0;
}
After running code above, I then check if the data stored correctly. So, I make this code below.
#include <stdio.h>
#include <stdlib.h>
int main () {
typedef struct {
char *Name;
int Index;
} DataFile;
static FILE *file;
size_t result;
long size;
int i;
DataFile *DataTable;
file = fopen("database.DAT","rb");
if (file == NULL) printf("Error1");
// Determine the size of file
fseek(file,0,SEEK_END);
size = ftell(file);
rewind(file);
DataTable = (DataFile *) malloc ((size/sizeof(DataFile)) * sizeof(DataFile));
if (DataTable == NULL) printf("Error2");
result = fread(DataTable,sizeof(DataFile),size/sizeof(DataFile),file);
fclose(file);
for (i=0; i<result; i++) {
printf("%s %d \n",DataTable[i].Name,DataTable[i].Index);
}
free(DataTable);
return 0;
}
However, it gives output
somefile.txt 7
from the first code block and
Error1 7
from the second code block.
I notice that the problem is not because the failure either when opening .DAT file or when allocating memory for DataTable. Also, it works for int type (Index) but not for char* type (Name) when reading from .DAT file. I have no idea what to do to solve this char*-type-reading problem (and where 'error1' comes from). (not even google gives me answer.)
Your structure DataFile stores one pointer and one integer. When you write it to the file, you write some program specific pointer to a string, and an integer.
When reading from it, you just refill your structure with the pointer and the integer, wich means that DataFile.Name will be a pointer to a probably-not-initialized memory segment. But since you created your file pointing to the first hard-coded string ("filename.txt"), some undefined but understandable behaviour happens, and your pointer in this case points to the first hard-coded string you wrote in you second program (which in your case is Error1)
What you really want to do is write the real string in your file.
A simple solution, if you want to the keep the hole writing structure thing is to create an array instead of a pointer
typedef struct {
char Name[512];
int Index;
} DataFile;
then initialize your data with
strncpy(DataTable[0].Name, "somefile.txt", sizeof(DataTable[0].Name) - 1); // just to make sure you dont overflow your array size
DataTable[0].Name[sizeof(DataTable[0].Name) - 1] = '\0';
and retreview your data the way you did.
A char* is only a pointer, i.e. the address of the character array containing your strings. You don't write the strings themselves to the file. After reading the file, as the same strings aren't in your memory at the same addresses any more, the application will fail.
You'll have to come up with a way to save the strings themselves to file as well. Probably by first writing their length, and then writing their content. Upon reading, you can use the length information to allocate memory dynamically, then read into that memory.
In your writing code you haven't allocated storage for char *Name. When you perform the DataTable[0].Name = "somefile.txt" instruction you're not actually copying the "somefile.txt" into memory pointed by Name, it's actually assigning a Name a value pointing to a constant characters string (moreover, it will become dangling pointer since the string is an rvalue, i.e. doesn't have a memory to be addressed via). Same goes for your file reading code.
You need to:
Allocate storage for your Name.
Copy the string using memcpy or similar into the allocated storage.