#include "kernel_check.h"
#include <mach/kmod.h>
#include <libc.h>
#include "fat_util.h"
#include "macho_util.h"
struct _uuid_stuff {
unsigned int uuid_size;
char * uuid;
};
macho_seek_result uuid_callback(
struct load_command * load_command,
const void * file_end,
uint8_t swap __unused,
void * user_data)
{
struct _uuid_stuff * uuid_stuff = (struct _uuid_stuff *)user_data;
if (load_command->cmd == LC_UUID) {
struct uuid_command * uuid_command = (struct uuid_command *)load_command;
if (((void *)load_command + load_command->cmdsize) > file_end) {
return macho_seek_result_error;
}
uuid_stuff->uuid_size = sizeof(uuid_command->uuid);
uuid_stuff->uuid = (char *)uuid_command->uuid;
return macho_seek_result_found;
}
return macho_seek_result_not_found;
}
int copyKextUUID(
mach_port_t host_port,
const char * filename,
const char * bundle_id,
char ** uuid,
unsigned int * uuid_size)
{
int result = -1;
fat_iterator iter = NULL;
if (!uuid || !uuid_size) {
goto finish;
}
*uuid = NULL;
*uuid_size = 0;
if (!filename) {
kern_return_t kern_result;
char * kern_uuid = 0;
unsigned int kern_uuid_size = 0;
if (!MACH_PORT_VALID(host_port)) {
goto finish;
}
if (bundle_id) {
kern_uuid_size = 1 + strlen(bundle_id);
if (KERN_SUCCESS != vm_allocate(mach_task_self(), (vm_address_t *)&kern_uuid,
kern_uuid_size, VM_FLAGS_ANYWHERE)) {
goto finish;
}
bzero(kern_uuid, kern_uuid_size);
memcpy(kern_uuid, bundle_id, kern_uuid_size);
}
kern_result = kmod_control(host_port, 0, KMOD_CNTL_GET_UUID,
(kmod_args_t *)&kern_uuid, &kern_uuid_size);
if (kern_result == KERN_INVALID_ARGUMENT || kern_result == KERN_FAILURE) {
result = 0;
goto finish;
} else if (kern_result != KERN_SUCCESS) {
goto finish;
}
*uuid = (char *)malloc(kern_uuid_size);
if (!*uuid) {
goto finish;
}
memcpy(*uuid, kern_uuid, kern_uuid_size);
*uuid_size = kern_uuid_size;
vm_deallocate(mach_task_self(), (vm_address_t)kern_uuid, kern_uuid_size);
result = 1;
} else {
struct mach_header * file = NULL;
void * file_end = NULL;
iter = fat_iterator_open(filename, 1);
if (!iter) {
goto finish;
}
file = (struct mach_header *)fat_iterator_find_host_arch(
iter, &file_end);
if (!file) {
goto finish;
}
result = copyMachoUUIDFromMemory(file, file_end,
uuid, uuid_size);
}
finish:
if (iter) fat_iterator_close(iter);
return result;
}
int copyMachoUUIDFromMemory(
struct mach_header * file,
void * file_end,
char ** uuid,
unsigned int * uuid_size)
{
int result = -1;
macho_seek_result seek_result;
struct _uuid_stuff seek_uuid;
if (!uuid || !uuid_size) {
goto finish;
}
*uuid = NULL;
*uuid_size = 0;
seek_result = macho_scan_load_commands(
file, file_end,
uuid_callback, (const void **)&seek_uuid);
if (seek_result != macho_seek_result_found) {
result = 0; goto finish;
}
*uuid = (char *)malloc(seek_uuid.uuid_size);
if (!*uuid) {
goto finish;
}
memcpy(*uuid, seek_uuid.uuid, seek_uuid.uuid_size);
*uuid_size = seek_uuid.uuid_size;
result = 1;
finish:
return result;
}
int machoUUIDsMatch(
mach_port_t host_port,
const char * file_1,
const char * file_2)
{
int result = -1;
char * uuid1;
char * uuid2;
unsigned int uuid1_length, uuid2_length;
if (!copyKextUUID(host_port, file_1, NULL, &uuid1, &uuid1_length)) {
goto finish;
}
if (!copyKextUUID(host_port, file_2, NULL, &uuid2, &uuid2_length)) {
goto finish;
}
result = 0;
if (uuid1_length == uuid2_length &&
0 == memcmp(uuid1, uuid2, uuid1_length)) {
result = 1;
}
finish:
if (uuid1) free(uuid1);
if (uuid2) free(uuid2);
return result;
}
int machoFileMatchesUUID(
const char * file,
char * running_uuid,
unsigned int running_uuid_size)
{
int result = -1;
char * file_uuid = NULL; unsigned int file_uuid_size = 0;
if (1 == copyKextUUID(MACH_PORT_NULL, file, NULL,
&file_uuid, &file_uuid_size)) {
result = 0;
if (file_uuid_size == running_uuid_size &&
0 == memcmp(running_uuid, file_uuid, file_uuid_size)) {
result = 1;
}
}
if (file_uuid) free(file_uuid);
return result;
}