#include <stdio.h>
int main() {
char *address = (char*)0x004452FC;
volatile char value;
printf("Test 1");
while (1) {
value = *address;
printf("Test 2");
if (value == 1) {
printf("Test 3");
break;
}
}
return 0;
}
If I run this code, I never reach "Test 2" and it gives me the exitcode 322122547. I am running the program in VSC but it also didn't work in cmd with administrator permissions. The address is from a .exe game I am running and it is the number of a stage I am currently in.
The reason why you can't read from or write data to this memory address is that every process on Linux/Windows/macOS has its own virtual memory address space. This means that a memory address like 0x004452FC does not refer to an address in your physical memory, it is only virtual. Before the CPU can access the data from a virtual memory address, it must first translate it to a physical address using a page table.
Since these page tables are process-specific, the same virtual address in two processes will most likely belong to two different physical addresses. These page tables are managed by the operating system, and you can't really look up the physical address of an entry, nor would the operating system allow you to read/write to physical addresses directly (with the exception of kernel drivers). Before you can use a memory address (or more accurately, a page of memory), you must ask the operating system to create a mapping for that virtual memory address. Since you didn't ask for a mapping for 0x004452FC, you tried to access non-existent memory and the OS killed your process.
If you want to change the memory contents of other processes, you must use special APIs provided by the operating system. On Windows this would be ReadProcessMemory/WriteProcessMemory, on Linux you need to use ptrace and for macOS you need vm_read/vm_write.
Related
I have this simple test C program which leaks 4 bytes of memory:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* x = malloc(sizeof(int));
printf( "Address: %p\n", x);
return 0;
}
I compile it with gcc -o leak leak.c, and then run it:
$ leak
Address: 0x55eb2269a260
Then I create another test C program that will try to free the leaked memory:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void *addr = (void*)0x55eb2269a260;
printf( "Trying to free address: %p\n", addr);
free(addr);
return 0;
}
I compile it with gcc -o myfree free.c and then run it:
$ myfree
Trying to free address: 0x55eb2269a260
Segmentation fault (core dumped)
What is happening here? Why is it not possible to free the leaked memory?
Assuming we are talking about Unix-like operating systems (this also applies to Windows and the majority of other modern operating systems)...
What is happening here? Why is it not possible to free the leaked memory?
First of all: every running process have it's own virtual address space (or VAS). This VAS is a way the operating system have to lay out and organize the physical memory between different processes. It ranges from 0x0 to 0xFFFFFFFF on 32 bits processors and contains all the memory of the process - its code, static data, stack, heap, etc, it is all in the process VAS. A virtual address (or VA) is a specific address inside the virtual address space.
When you allocate memory with malloc the system will search for a valid unallocated memory on the process heap and if it finds, return a pointer of it (i.e. malloc essentially returns a virtual address).
After the process ends its VAS will be automatically "freed" by the operating system, so that memory is no longer valid, or allocated in that matter. Asides that, each process have its own virtual address space. You can not directly access a process VAS (virtual address space) using a VA (virtual address) of another process - by doing that what you actually end up doing is trying to access that VA in the running process which in your example is very likely to result in an unhandled ACCESS_VIOLATION exception and crashes the process.
Each process has its own virtual memory space due to process isolation. Memory addresses in one process are not the same memory addresses in another process. You cannot just access dynamic memory by the address in another process.
Just to complete the answer of dedecos, the virtual address space of a process is always different for a different process in the same machine. This means that what for process A is at 0x55eb2269a260, in process B has no counterpart. No address at Process B matches the same memory as it does for process A. So then, it's impossible to address from B any of the addresses of process A.
The thing is that there is a memory manager at the operating system kernel that handles processes memory to be always disjoint, so even if two processes have the same variable at the same address, those variables are different (e.g. two versions of ls command executing at the same time will have the data segment at the same address, as the linker put it there) their address spaces (the same data addresses, for example) map to different memory pages for each process. This way, you can run the same program several times in parallel without clashing their data segments.
Operating systems offer ways for two processes to share a memory segment, so they can share common data, but even in that case, the addresses of both visuals of the same segment haven't to be placed at the same address (as one of those processes can have occupied the address given to the other for something else), so the conclusion is that what an address means for a process is not valid outside it.
The question is particulary about QNX and pretty much stated in the title.
I tried logging the variable addresses after modifying them in both processes, assuming copy-on-write doesn't work anymore and they are not identical, so I expected the addresses to be different. But they are the same (virtual addresses, but still).
So how can I check that one process doesn't affect another without printing variables value, maybe there's a simpler solution?
int q;
q = 3;
...
if (pid == 0) {
// in child
q = 5;
printf("%d\n", &q);
} else {
// in parent
q = 9;
printf("%d\n", &q);
}
The virtual addresses you print will be identical — the child process is an almost exact copy of its parent. The physical addresses the programs access will be separate as soon as one process tries to modify the data in that page, but that will be completely hidden from the two processes. That's the beauty of virtual memory.
Note that you're using the wrong format for printing addresses; you should use %p and cast the address to void *:
printf("%p\n", (void *)&q);
or use <inttypes.h> and uintptr_t and PRIXPTR (or PRIdPTR is you really want the address in decimal rather than hex):
printf("0x%" PRIXPTR "\n", (uintptr_t)&q);
Print the numbers too — and do so several times in a loop with sleeps of some sort in them. You will see that despite the same logical (virtual) address, the physical addresses are different. You won't be able to find the physical address easily, though.
If you have created a new process, rather than a new thread, then it has its own process address space by definition.
Every process address space will have the same virtual address range - 0x00000000 - 0xffffffff on a 32-bit machine. Every process will have a virtual address of n, what it is used for and whether it maps to anything which physically exists will differ. Some of that address space will be used by the kernel, some might be shared (see also man mmap).
After a fork() you should not be surprised if the virtual addresses are identical in both processes (although that cannot be guaranteed for new memory operations after the fork) - it does not mean that copy-on-write is not working, that is invisible to normal code.
Pages do not necessarily reside in RAM (physical memory) but can sit in a swap or paging file (terms used vary) until required. The virtual address refers to a page table that knows where its page really lives. When copy-on-write kicks in it means a new page is created, it does not mean that the virtual address changes, it will stay the same but in the page table will refer to a different physical location.
Why would you want to know anyway? That kind of operation is in the domain of the operating system.
I wrote this code so I can see the address of variable foo.
#include <stdio.h>
#include <stdlib.h>
int main(){
char* foo=(char*) malloc(1);
*foo='s';
printf(" foo addr : %p\n\n" ,&foo);
int pause;
scanf("%d",&pause);
return 0;
}
Then pause it and use the address of foo in here:
#include <stdio.h>
int main(){
char * ptr=(char *)0x7ffebbd57fc8; //this was the output from the first code
printf("\n\n\n\n%c\n\n\n",*ptr);
}
but I keep getting segmentation fault. Why is this code not working?
This is not a C question/problem but a matter of runtime support. On most OS programs run in a virtual environment, especially concerning their memory space. In such case memory is a virtual memory which means that when a program access a given address x the real (physical) memory is computed as f(x). f is a function implemented by the OS to ensure that a given process (object which represent the running of a code in the OS) have its own reserved memory separated from memory dedicated to other processes. This is called virtual memory.
Oups, your problem is not related to C language, but really depends of the OS, if any.
First let us read it from a pure C language point of view:
char * ptr=(char *)0x7ffebbd57fc8;
your are converting an unsigned integer to a char *. As you get the integer value from the other program, you can be sure that is has an acceptable range, so you indeed get a pointer pointing to that address. As it is a char * pointer, you can use it to read the byte representation of any object that will lie at that address. Still fine until there. But common systems use virtual addresses and limit each process to access only its own pages, so by default a process cannot access the memory of another process. In addition, with the common usage of virtual memory, there are no reasons that any two non kernel processes share common addresses. Exceptions for real addresses are:
real memory OS (MS/DOS and derivatives like FreeDOS, CP/M, and other anthic systems)
kernel mode: the kernel can access the whole memory of the system - who could load your program?
special functions: some OS provide special API to let one process read the memory of another one (Windows does), but it not as simple as directly reading an address...
As I assume that you are not in any of the first two cases, nothing is mapped at that address from the current process, hence the error.
On systems use virtual memory, you have a range of logical addresses that are available to user processes. These address ranges are subdivided into units called PAGES whose size depends upon the processor (512b to 1MB).
Pages are not valid until they are mapped into the process. The operating system will have system calls that allow the application to map pages. If you try to access a page that is not valid you get some kind of exception.
While the operating system only allocates memory pages, applications are used to calls, such as malloc(), that allocate memory blocks of arbitrary sizes.
Behind the scenes, malloc() is mapping pages (ie making them valid) to create a pool of memory that is uses to return small amounts of memory.
When you omit your malloc(), the memory is not being mapped.
Note that each process has its own range of logical addresses. One process's page containing 0x7ffebbd57fc8 is likely to be mapped to a different physical page frame than another process's 0x7ffebbd57fc8. If that were not the case, one user could muck with another. (There is always a range of addresses shared by all processes but this is can only be accessed in kernel mode.)
Your problem is further complicated by the fact that many systems these days randomly map processes to different locations in the logical address space. On such systems you could run your first program multiple times and get different addresses.
Why is this code not working?
You would need to call the system service on your operating system that maps memory into the process and make the page containing 0x7ffebbd57fc8 accessible.
The following is an excerpt from my simple driver code.
int vprobe_ioctl( struct file *filep, unsigned int cmd, void *UserInp)
{
case IOCTL_GET_MAX_PORTS:
*(int*)UserInp = TotalPorts;
#if ENABLED_DEBUG
printk("Available port :%u \n ", TotalPorts);
#endif
break;
}
I was not aware about the function copy_to_user which should be used while writing on user space memory. The code directly accesses the user address. But still I am not getting any kernel crash in my development system(x86_64 architecture). It works as expected.
But sometimes I could see kernel crash when I insert the .ko file in some other x86_64 machines. So, I replaced direct accessing with copy_to_user, and it works.
Could anyone please explain,
i) How direct accessing of user address works?
ii) Why am I seeing kernel crash in some systems whereas it works well in some other systems. Is there any kernel configuration mismatch between the systems because of which the kernel could access the user process's virtual address directly?
Note : All the systems I have used have same OS and kernel.-same image generated thru kickstart. - There is no possibility of any differences.
Thanks in advance.
would be interesting to see the crash. now what I'm saying is an assumption based on my knowledge about how the memory works.
user space memory is virtual. it means that the specific process address X is now located on some physical memory, this physical memory is a memory page that is currently allocated to your process. copy to user first checks that the memory given really belongs to the process and other security checks. beside that there is mapping issues.
the kernel memory has its own address space that need to map virtual to physical address. the kernel use the help of mmu (this is different per architecture). In x86 the mapping between the kernel virtual and user virtual is 1:1 (there are different issues here). In other system this is not always true.
I know how to work with pointers. But I don't know how do this:
I have an hex address that's of course it has a any value from any app.
I know to find the address that I want.
I want to write a C Code to pass this address to a pointer variable, and then I could capture the value from that address and so on.
For example:
hex 0x00010010
int *pointer;
How can I pass this address to the pointer, what's the syntax for that?
By using int* you are assuming the data you are point to is an int (4 bytes, on most OS's).
Shouldn't we use a void* instead? Later, if you want to access it's data using a particular type, all you need to do is cast.
void *addr = (void*)0x0023FF74; // valid memory address within my app
printf("Address: %p\n", addr);
getchar();
printf("Data (4bytes): %d\n", *(int*)addr); // print the first 4 bytes of data as int
getchar();
EDIT:
Help me understand what you are trying to do, because this statement confused me:
There is app using that address, I know the value in it, but the (int)pointer don't access the value.
Are you trying to write an application that will modify the memory of another application that is running your system? Your current approach won't work, and this is why: When the Operating System loads your application into a process, it reserves a memory region to be used by the process and assigns a range of virtual addresses to this region. These virtual addresses do not map directly to memory addresses in RAM, so the OS has to keep an internal table for that.
On Windows, each process loaded receives the same range of virtual addresses, but this area is only visible to the process that is running inside it. For instance, (on Windows) processes are loaded in memory address 0x00400000, which mean each process has it's own memory address 0x00400000, and therefore you can't assign X memory address to a pointer in your application and expect Windows to magically know that you are reffering to address X that is inside another application.
What you are trying to accomplish it's called Code Injection, and there's a lot of information on the web about it.
In typical modern operating systems, you cannot access another process' (app's) address space. The addresses are virtual, so the same numerical value means different things to different processes.
If you are on a system with a true "flat" address space (where processes directly work with actual physical memory addresses) such as Amiga OS on the 680x0, you can do something like:
int *pointer = (int *) 0x00010010;