Skip to content

Commit f989152

Browse files
committed
security: ktfp writeup
1 parent 5eb5c5a commit f989152

File tree

8 files changed

+243
-151
lines changed

8 files changed

+243
-151
lines changed

Config.xcconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
// https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project
1010

1111
VERSION = 0.9.0
12-
BUILD_NUMBER = 20260223.102.US.seanistethered
12+
BUILD_NUMBER = 20260224.23.US.seanistethered

Nyxian.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@
251251
LindChain/ProcEnvironment/tfp.m,
252252
LindChain/ProcEnvironment/Utils/fd.c,
253253
LindChain/ProcEnvironment/Utils/klog.m,
254+
LindChain/ProcEnvironment/Utils/ktfp.m,
254255
LindChain/Utils/Swizzle.m,
255256
UI/Settings/CertificateManagement.swift,
256257
UI/Settings/CertificateViewController.swift,
@@ -323,6 +324,7 @@
323324
LindChain/ProcEnvironment/tfp.m,
324325
LindChain/ProcEnvironment/Utils/fd.c,
325326
LindChain/ProcEnvironment/Utils/klog.m,
327+
LindChain/ProcEnvironment/Utils/ktfp.m,
326328
LindChain/Utils/LDEDebouncer.m,
327329
LindChain/Utils/Swizzle.m,
328330
LindChain/Utils/Zip.m,

Nyxian/LindChain/Debugger/MachServer.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020
#ifndef LINDCHAIN_DEBUGGER_MACHSERVER_H
2121
#define LINDCHAIN_DEBUGGER_MACHSERVER_H
2222

23-
void machServerInit(void);
23+
#include <mach/mach.h>
2424

25-
void ktfp_setup(void);
26-
task_t obtainTaskPortWithExceptionRecvRight(mach_port_t recv);
25+
void machServerInit(void);
2726

2827
#endif /* LINDCHAIN_DEBUGGER_MACHSERVER_H */

Nyxian/LindChain/Debugger/MachServer.m

Lines changed: 1 addition & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
along with Nyxian. If not, see <https://www.gnu.org/licenses/>.
1818
*/
1919

20+
#import <LindChain/Debugger/MachServer.h>
2021
#import <Foundation/Foundation.h>
2122
#include <pthread.h>
2223
#include <stdio.h>
@@ -609,145 +610,3 @@ void machServerInit(void)
609610
pthread_detach(serverThread);
610611
});
611612
}
612-
613-
#if !JAILBREAK_ENV
614-
615-
void* ktfp_exception_self_server(void *arg)
616-
{
617-
// Our task is the target, the exception port as the receive side of the kernel exception messages, the mask is basically controlling to what our exception server reacts to
618-
task_t task = mach_task_self();
619-
mach_port_t exceptionPort = MACH_PORT_NULL;
620-
exception_mask_t mask = EXC_MASK_BREAKPOINT;
621-
622-
if(arg == NULL)
623-
{
624-
// Allocating mach port and setting it up with our process
625-
mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exceptionPort);
626-
mach_port_insert_right(task, exceptionPort, exceptionPort, MACH_MSG_TYPE_MAKE_SEND);
627-
628-
task_set_exception_ports(task, mask, exceptionPort, EXCEPTION_DEFAULT, ARM_THREAD_STATE64);
629-
630-
environment_syscall(SYS_handoffep, exceptionPort);
631-
632-
__builtin_trap();
633-
634-
mach_port_deallocate(mach_task_self(), exceptionPort);
635-
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
636-
637-
return NULL;
638-
}
639-
else
640-
{
641-
exceptionPort = *((mach_port_t*)arg);
642-
}
643-
644-
// Thanks to microsoft, without you this wouldnt be possible and I wouldnt understand yet what to do. The request is send by the kernel to our mach port
645-
__Request__exception_raise_t *request = NULL;
646-
size_t request_size = round_page(sizeof(*request));
647-
kern_return_t kr;
648-
mach_msg_return_t mr;
649-
650-
// Allocating the request structure to have a writing destination
651-
kr = vm_allocate(mach_task_self(), (vm_address_t *) &request, request_size, VM_FLAGS_ANYWHERE);
652-
if(kr != KERN_SUCCESS)
653-
{
654-
// Shouldn't happen ...
655-
fprintf(stderr, "Unexpected error in vm_allocate(): %x\n", kr);
656-
return NULL;
657-
}
658-
659-
while(1)
660-
{
661-
klog_log(@"machserver", @"listening to %d", exceptionPort);
662-
663-
// Now requesting the message and waiting on a reply from the kernel.. happens on exception
664-
request->Head.msgh_local_port = exceptionPort;
665-
request->Head.msgh_size = (mach_msg_size_t)request_size;
666-
mr = mach_msg(&request->Head,
667-
MACH_RCV_MSG | MACH_RCV_LARGE,
668-
0,
669-
request->Head.msgh_size,
670-
exceptionPort,
671-
MACH_MSG_TIMEOUT_NONE,
672-
MACH_PORT_NULL);
673-
674-
klog_log(@"machserver", @"got answer from %d -> %d", exceptionPort, mr);
675-
676-
// Microsofts code to handle if the exception message send by the kernel is valid to process
677-
if(mr != MACH_MSG_SUCCESS && mr == MACH_RCV_TOO_LARGE)
678-
{
679-
// Determine the new size (before dropping the buffer)
680-
request_size = round_page(request->Head.msgh_size);
681-
682-
// Drop the old receive buffer
683-
vm_deallocate(mach_task_self(), (vm_address_t) request, request_size);
684-
685-
// Re-allocate a larger receive buffer
686-
kr = vm_allocate(mach_task_self(), (vm_address_t *) &request, request_size, VM_FLAGS_ANYWHERE);
687-
if(kr != KERN_SUCCESS)
688-
{
689-
// Shouldn't happen ...
690-
fprintf(stderr, "Unexpected error in vm_allocate(): 0x%x\n", kr);
691-
return NULL;
692-
}
693-
694-
continue;
695-
696-
}
697-
else if (mr != MACH_MSG_SUCCESS)
698-
exit(-1);
699-
700-
// Sanity checks
701-
if(request->Head.msgh_size < sizeof(*request) || request_size - sizeof(*request) < (sizeof(mach_exception_data_type_t) * request->codeCnt))
702-
exit(-1);
703-
704-
klog_log(@"machserver", @"exception: %s", exceptionName(request->exception));
705-
706-
/* we got it */
707-
mach_port_mod_refs(mach_task_self(), request->task.name, MACH_PORT_RIGHT_SEND, 1);
708-
*((mach_port_t*)arg) = request->task.name;
709-
710-
klog_log(@"machserver", @"task: %d | thread: %d", request->task.name, request->thread.name);
711-
712-
/* now manipulate thread state */
713-
struct arm64_thread_full_state *state = thread_save_state_arm64(request->thread.name);
714-
state->thread.__pc += 4;
715-
thread_restore_state_arm64(request->thread.name, state);
716-
717-
kr = KERN_SUCCESS;
718-
719-
// The faulting thread will be stopped until the reply was send to the kernel
720-
__Reply__exception_raise_t reply;
721-
memset(&reply, 0, sizeof(reply));
722-
reply.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request->Head.msgh_bits), 0);
723-
reply.Head.msgh_id = request->Head.msgh_id + 100;
724-
reply.Head.msgh_local_port = MACH_PORT_NULL;
725-
reply.Head.msgh_remote_port = request->Head.msgh_remote_port;
726-
reply.Head.msgh_size = sizeof(reply);
727-
reply.NDR = NDR_record;
728-
reply.RetCode = kr;
729-
mr = mach_msg(&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
730-
if(mr != KERN_SUCCESS)
731-
exit(-1);
732-
else
733-
{
734-
return NULL;
735-
}
736-
}
737-
}
738-
739-
void ktfp_setup(void)
740-
{
741-
static dispatch_once_t onceToken;
742-
dispatch_once(&onceToken, ^{
743-
ktfp_exception_self_server(NULL);
744-
});
745-
}
746-
747-
task_t obtainTaskPortWithExceptionRecvRight(mach_port_t recv)
748-
{
749-
ktfp_exception_self_server(&recv);
750-
return recv;
751-
}
752-
753-
#endif /* !JAILBREAK_ENV */

Nyxian/LindChain/ProcEnvironment/Surface/sys/compat/handoffep.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#import <LindChain/ProcEnvironment/Surface/proc/def.h>
2222
#import <LindChain/ProcEnvironment/Surface/proc/copy.h>
2323
#import <LindChain/ProcEnvironment/Utils/klog.h>
24-
#import <LindChain/Debugger/MachServer.h>
24+
#import <LindChain/ProcEnvironment/Utils/ktfp.h>
2525
#import <pthread.h>
2626

2727
typedef struct {
@@ -33,7 +33,7 @@
3333
{
3434
khandoffep_t *hep = (khandoffep_t*)work;
3535

36-
task_t task = obtainTaskPortWithExceptionRecvRight(hep->ep);
36+
task_t task = ktfp(KTFP_AQUIRE_FROM_RECV(hep->ep));
3737
klog_log(@"handoffep:helper", @"got task kernel port right: %d", task);
3838

3939
if(!kvo_retain(hep->proc))
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
Copyright (C) 2025 cr4zyengineer
3+
4+
This file is part of Nyxian.
5+
6+
Nyxian is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
Nyxian is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with Nyxian. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef KTFP_KTFP_H
21+
#define KTFP_KTFP_H
22+
23+
#include <mach/mach.h>
24+
25+
#define KTFP_GUEST 0
26+
#define KTFP_AQUIRE_FROM_RECV(recv) recv
27+
28+
typedef mach_port_t obtain_token_t;
29+
30+
task_t ktfp(obtain_token_t token);
31+
32+
#endif /* KTFP_KTFP_H */

0 commit comments

Comments
 (0)