MacMark
Jakob Lebel
- Registriert
- 01.01.05
- Beiträge
- 4.874
Noch krasser: Du kannst nicht auf Adressräume zugreifen die einem andern Prozess gehören.
Dann zaubern wir mal ein bißchen:
Ein Programm "write" schreibt in den Speicher des anderen Programmes "wait", genauer gesagt in die Variable "myInt", die den Wert 0 hat, des anderen Programmes "wait". Sobald diese Variable den Wert 1 ("true" in der if-Abfrage) hat, beendet sich "wait". Programm "wait" ändert den Wert nicht selbst, sondern hängt ansonsten in einer Endlosschleife (while (true aka 1)) fest.
Das Programm "write" holt sich vollen Zugriff auf "wait" mit Hilfe von task_for_pid() und schreibt an die Speicherstelle in dem Adreßraum von "wait", an dem "myInt" liegt. Die PID von "wait" ist Input für "write".
Der Mach-Port, der zur Task mit gegebener Prozeß-ID gehört, gibt dem aufrufenden Prozeß volle Kontrolle über den anderen.
KeyWest:taskforpid macmark$ cat wait.c
Code:
#include <stdio.h>
static int myInt = 0;
int main(int argc, char* argv[])
{
fprintf(stdout, "Waiting with int %d on address %p.\n", myInt, &myInt);
while (1) {
if (myInt) {
fprintf(stdout, "Someone else changed the value of myInt.\n");
return 1;
}
}
}
KeyWest:taskforpid macmark$ gcc -Wall wait.c -o wait -arch i386
Wir müssen die Adresse von myInt rausfinden:
KeyWest:taskforpid macmark$ nm wait | grep myInt
0000203c b _myInt
Nun verwenden wir Adresse 0x203c in "write":
KeyWest:taskforpid macmark$ cat write.c
Code:
#include <stdlib.h>
#include <mach-o/dyld.h>
#include <mach/mach_traps.h>
#include <mach/mach_init.h>
#include <mach/message.h>
#include <mach/vm_map.h>
#include <mach/vm_region.h>
#include <stdio.h>
#include <mach/mach_port.h>
#include <mach-o/fat.h>
#include <mach-o/nlist.h>
#define TARGETADDRESS 0x203c
int main(int argc, char* argv[])
{
mach_port_name_t task;
int pid = atoi(argv[1]);
int error = task_for_pid((mach_port_name_t)task_self_trap(), pid,(mach_port_name_t *) &task);
if (error) {
fprintf(stderr, "Could not access task for pid %d.\n", pid);
return error;
}
else {
fprintf(stdout, "Got the process %d's task Mach port : %x\n", pid, task);
}
long newValue = 1;
error = vm_write( task, (vm_address_t) TARGETADDRESS, (vm_address_t) &newValue, sizeof(newValue));
if ( error ) {
fprintf(stderr, "Error writing.\n");
return error;
} else {
fprintf(stdout, "Successful written.\n");
}
return 0;
}
KeyWest:taskforpid macmark$ gcc -Wall write.c -o write -arch i386
KeyWest:taskforpid macmark$ ./wait &
[1] 725
KeyWest:taskforpid macmark$ Waiting with int 0 on address 0x203c.
sudo ./write 725
Password:
Got the process 725's task Mach port : 1107
Successful written.
KeyWest:taskforpid macmark$ Someone else changed the value of myInt.
[1]+ Exit 1 ./wait
Falls sich jemand um die Sicherheit sorgt: Die Funktion task_for_pid() prüft die UserIDs der betroffenen Prozesse und konsultiert, falls die UserIDs genehm waren, auch noch den taskgated-Dämon, der dann immer noch nein sagen kann.