Question: I want to make simple functions that given an offset (and knowing the base address of a library) can retrieve or set the value located in there.

Questions:

What are the pratical differences between types of memory?

What I want to know exactly is: with what do I have to be concerned with, to make it work transparently. For example, depending on the type of memory, do I have to use a different flag or setting to "Read + Write + Execute" works for all of them? And what about differences between Windows and Linux?

Answer: 
Read, Write and Execute is possible under Linux, due to the nature of their elf32 linker when compiling programs, for instance, you can have one segment as read only, in another segment you can have it write only. Not sure if a linker under Windows can do that, I know they can have a segment that is shared by other programs...

Now, to make it work transparently, I assume you mean that for both windows and linux? Memory under both platforms are similar in concept, in that the kernel has put in protection in place between user land programs and kernel code. 

In the old days of DOS, memory was split up into segment:offset which when combined together like this:

```

segment +
offset
---------
physical memory for that segment

for example:
B800 +
 0000
------
B8000  

```

That was to get around the quirk in the memory addressing mode as the DOS environment can only access 2^20 bytes of memory hence the segment+offset pair, which was used in 16bit mode. 

Here's an example of 16bit code that can determine how many lines there are in a DOS screen:

```
int heightScreen(void)
{
    return (*(unsigned char far *) 0x484) + 1;
}

```

The segment is 0x484 which is located in the BIOS that tells how many lines there are.

In 32bit mode, it was just segment selector:segment (I think... not sure as I'm writing this from memory), depending on how the OS is designed, there are different ways of accessing the memory from the context of demand-paged, virtual and flat mode...the references to this can be found in the intel document in pdf on the internet here...the relevant document is '24143004.pdf' in which you can search)

The processor has ring0 mode which can execute privileged instructions and access to memory only. ring3 is where the user land domain of applications run in, they have restricted access to the privileged instructions (or none at all) and can access their own memory space. ring2 would be typically occupied by the device drivers which act as a middle-man between the kernel and user-land space. Also, the kernel would have provided call-gates or traps in there to request a certain privilege (only device drivers can do that).

If you want to access privileged memory and risk bringing the system down to its knees, under Linux, supply the suid bit to the program in question or run it as root. For Windows, you need to elevate the permissions of the code or perform code injection into the process memory, or more aptly, write a device driver to interact with kernel code/memory space and provide an API for the user land code to interact with.

If you do try to access a privileged instruction or memory that you have no access to, the kernel will shut down your program by killing the process as if saying "get lost, no way jose".

Hope this brief summary helps.
You didn't state what language you are programming in, so I'm going to assume C and derivatives.

If you have an address, you can read the the byte at that address by casting it to a pointer and dereferencing:

```
unsigned char value = *(unsigned char *)address;

```

And if you want to write it:

```
*(unsigned char *)address = value;

```

In order for this to work, the page the address is in must be mapped into your address space with the appropriate permissions. If the page is not mapped or if you don't have the appropriate permissions, the OS will usually terminate your program (on Linux, it will generate a segment violation aka SEGV).