Adding example Mach IPC client-server with and without MIG

This commit is contained in:
Karmaz95
2024-12-15 17:56:29 +01:00
parent 0b585a6e33
commit 25dd6a7ef2
7 changed files with 265 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
# Makefile for Mach IPC example with MIG
# Compiler settings
CC = gcc
CFLAGS = -Wall -Werror
# Default target
all: server client
# Generate MIG files from definition
mig_files: message.defs
mig message.defs
# Build server with MIG-generated files
server: mig_files server.c messageServer.c
$(CC) $(CFLAGS) server.c messageServer.c -o server
# Build client with MIG-generated files
client: mig_files client.c messageUser.c
$(CC) $(CFLAGS) client.c messageUser.c -o client
# Clean generated files and executables
clean:
rm -f server client message.h messageUser.c messageServer.c
.PHONY: all clean mig_files

View File

@@ -0,0 +1,29 @@
// client.c - MIG version
#include <stdio.h>
#include <string.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include "message.h" // MIG-generated header
int main(int argc, char *argv[]) {
// Validate command line arguments
if (argc != 2) {
printf("Usage: %s <message>\n", argv[0]);
return 1;
}
// Get bootstrap port for service lookup
mach_port_t port;
kern_return_t kr = bootstrap_look_up(bootstrap_port,
"xyz.hacktricks.mig",
&port);
if (kr != KERN_SUCCESS) {
printf("Service not found\n");
return 1;
}
// Use MIG-generated function to send message
// This handles all the message structure creation internally
USER_send_message(port, (pointer_t)argv[1], strlen(argv[1]));
return 0;
}

View File

@@ -0,0 +1,17 @@
// message.defs - MIG Interface Definition
subsystem message 400; // Define subsystem name and ID
// Prefix for generated client and server function names
userprefix USER_;
serverprefix SERVER_;
// Include necessary Mach type definitions
#include <mach/mach_types.defs>
#include <mach/std_types.defs>
// Define our message passing routine
// 'simpleroutine' means one-way communication (no reply expected)
// pointer_t is used for variable-length data
simpleroutine send_message(
server_port : mach_port_t; // Port to send message to
message : pointer_t); // Message data

View File

@@ -0,0 +1,39 @@
// server.c - MIG version
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include "message.h"
// Function prototype for MIG-generated server function
extern boolean_t message_server(
mach_msg_header_t *InHeadP,
mach_msg_header_t *OutHeadP);
// Implementation of our message handling function
// This is called by MIG-generated code when a message arrives
kern_return_t SERVER_send_message(
mach_port_t server_port,
vm_offset_t message,
mach_msg_type_number_t messageCnt)
{
// Simply print the received message
printf("Received message: %s\n", (char*)message);
return KERN_SUCCESS;
}
int main() {
mach_port_t port;
kern_return_t kr;
// Register our service with the bootstrap server
kr = bootstrap_check_in(bootstrap_port, "xyz.hacktricks.mig", &port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_check_in() failed with code 0x%x\n", kr);
return 1;
}
// Start message handling loop using MIG-generated server function
// 4096 is the maximum message size
mach_msg_server(message_server, 4096, port, MACH_MSG_TIMEOUT_NONE);
return 0;
}

View File

@@ -0,0 +1,22 @@
# Makefile for Mach IPC example without MIG
# Compiler settings
CC = gcc
CFLAGS = -Wall -Werror
# Default target
all: server client
# Build server
server: server.c
$(CC) $(CFLAGS) server.c -o server
# Build client
client: client.c
$(CC) $(CFLAGS) client.c -o client
# Clean generated files and executables
clean:
rm -f server client
.PHONY: all clean

View File

@@ -0,0 +1,77 @@
// client.c
#include <stdio.h>
#include <string.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
/*
* Message structure for IPC communication
* Consists of two parts:
* 1. mach_msg_header_t h - Standard Mach message header required for all IPC
* 2. char d[1024] - Data buffer for the actual message content
*/
typedef struct {
mach_msg_header_t h; // Header must be first member
char d[1024]; // Data buffer follows immediately after header
} msg_t;
int main(int argc, char *argv[]) {
// Validate command line arguments
if (argc != 2) {
printf("Usage: %s <message>\n", argv[0]);
return 1;
}
// Step 1: Get the bootstrap port
// Bootstrap server is the central name server in Mach IPC
mach_port_t bootstrap_port;
task_get_special_port(mach_task_self(),
TASK_BOOTSTRAP_PORT,
&bootstrap_port);
// Step 2: Look up the service port using bootstrap server
// This finds our server process using the registered name
mach_port_t service_port;
kern_return_t kr = bootstrap_look_up(bootstrap_port,
"com.crimson.message_service",
&service_port);
if (kr != KERN_SUCCESS) {
printf("Service not found\n");
return 1;
}
// Step 3: Prepare the message structure
// Initialize message structure to zero
msg_t message = {0};
// Configure message header
message.h.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND); // Set message type to copy-send
message.h.msgh_size = sizeof(msg_t); // Total size of message struct
message.h.msgh_remote_port = service_port; // Destination port
message.h.msgh_local_port = MACH_PORT_NULL; // No reply port needed
message.h.msgh_id = 0; // Message ID (unused in this case)
// Copy the user's message into data buffer
// Using strncpy to prevent buffer overflow
strncpy(message.d, argv[1], sizeof(message.d) - 1);
message.d[sizeof(message.d) - 1] = '\0'; // Ensure null termination
// Step 4: Send the message
kr = mach_msg(
&message.h, // Message header pointer
MACH_SEND_MSG, // Send-only operation
sizeof(msg_t), // Size of entire message
0, // Maximum receive size (unused for send)
MACH_PORT_NULL, // Destination port (unused for send)
MACH_MSG_TIMEOUT_NONE,// No timeout
MACH_PORT_NULL // No notify port
);
// Step 5: Check for errors and return status
if (kr != KERN_SUCCESS) {
printf("Failed to send message\n");
return 1;
}
return 0;
}

View File

@@ -0,0 +1,55 @@
// server.c
#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
int main() {
// Step 1: Get the bootstrap port
mach_port_t bootstrap_port;
task_get_special_port(mach_task_self(),
TASK_BOOTSTRAP_PORT,
&bootstrap_port);
// Step 2: Register our service with the bootstrap server
// This allows clients to find us using the service name
mach_port_t service_port;
kern_return_t kr = bootstrap_check_in(bootstrap_port,
"com.crimson.message_service",
&service_port);
if (kr != KERN_SUCCESS) {
printf("Failed to register service\n");
return 1;
}
printf("Server running...\n");
// Allocate buffer for receiving messages
// Buffer must be large enough for header + maximum message size
char buffer[2048];
mach_msg_header_t *msg = (mach_msg_header_t*)buffer;
// Main message receive loop
while (1) {
// Receive message
kr = mach_msg(
msg, // Buffer to receive message
MACH_RCV_MSG, // Receive-only operation
0, // Send size (unused for receive)
sizeof(buffer), // Maximum receive size
service_port, // Port to receive on
MACH_MSG_TIMEOUT_NONE, // No timeout
MACH_PORT_NULL // No notify port
);
// Process received message
if (kr == KERN_SUCCESS) {
// Message data follows immediately after header
char *data = (char*)(msg + 1);
printf("Received: %s\n", data);
} else {
printf("Error receiving message\n");
}
}
return 0; // Never reached in this example
}