mach_vm_read returns unexpected data

69 views Asked by At
unsigned char* read_memory(void *address, mach_msg_type_number_t count) {
    int kr = 0;
    kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, FALSE, VM_PROT_READ | VM_PROT_COPY);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_protect() failed with error: 0x%x", kr);
        return NULL;
    }

    unsigned char *buffer = malloc(count);
    if (buffer == NULL) {
        RDErrorLog("malloc() failed");
        return NULL;
    }

    mach_msg_type_number_t actualCount = count;
    kr = mach_vm_read(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, (vm_offset_t *) buffer, &actualCount);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_read() failed with error: 0x%x", kr);
        free(buffer);
        return NULL;
    }

    if (actualCount != count) {
        RDErrorLog("mach_vm_read() failed due to invalid count");
        free(buffer);
        return NULL;
    }

    kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
    if (kr != KERN_SUCCESS) {
        free(buffer);
        RDErrorLog("mach_vm_protect() failed with error: 0x%x", kr);
        return NULL;
    }

    return buffer;
}

and I call it like that:

intptr_t baseAddress;
[self.baseAddress getValue:&baseAddress];

NSLog(@"baseAddress: 0x%lX", baseAddress);

intptr_t targetAddress = baseAddress + 0x10035A90C;

unsigned char *buffer = read_memory((void *)targetAddress, 8);
if (buffer == NULL) {
    NSLog(@"read memory failed");
    return;
}

NSLog(@"print at %lX", targetAddress - baseAddress);

char *s = (char *)malloc(sizeof(char) * 3 * 8);
for (size_t i = 0; i < 8; i++) {
    sprintf(s + i * 3, "%02X ", buffer[i]);
}

NSLog(@"%s", s);

free(s);
free(buffer);

I know as a fact the address is correct... I use the same code on some other methods (mach_vm_write) and it works fine.

However the printed string is not as expected... it's garbage and changes every time although it should have some static bytes.

1

There are 1 answers

0
Fauna Muirgen On BEST ANSWER
unsigned char* read_memory(void *address, mach_msg_type_number_t count) {
    int kr = 0;
    kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, FALSE, VM_PROT_READ | VM_PROT_COPY);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_protect() failed with error: 0x%x", kr);
        return NULL;
    }

    unsigned char *buffer = malloc(count);
    if (buffer == NULL) {
        RDErrorLog("malloc() failed");
        return NULL;
    }

    mach_msg_type_number_t actualCount = count;
    vm_offset_t vmOffset;
    kr = mach_vm_read(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, &vmOffset, &actualCount);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_read() failed with error: 0x%x", kr);
        free(buffer);
        return NULL;
    }

    memcpy(buffer, (const void*)vmOffset, actualCount);

    kr = mach_vm_deallocate(mach_task_self(), vmOffset, (mach_vm_size_t)actualCount);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_deallocate() failed with error: 0x%x", kr);
        free(buffer);
        return NULL;
    }

    if (actualCount != count) {
        RDErrorLog("mach_vm_read() failed due to invalid count");
        free(buffer);
        return NULL;
    }

    kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
    if (kr != KERN_SUCCESS) {
        free(buffer);
        RDErrorLog("mach_vm_protect() failed with error: 0x%x", kr);
        return NULL;
    }

    return buffer;
}

I was trying to use buffer directly as the buffer for storing the read data. However, mach_vm_read expects a pointer to the buffer (vm_offset_t *), not the buffer itself.

Also, I now use the variable vmAddress as an offsets into the virtual memory space and then copy the data from the virtual memory space (vmOffset) to the allocated buffer (buffer), since the data in the target task's virtual memory space is not directly accessible to the program.