bulk page write & txm check (#216)

* bulk page write

* txm check

Co-authored-by: Stossy11 <stossy11@users.noreply.github.com>

---------

Co-authored-by: Stossy11 <stossy11@users.noreply.github.com>
This commit is contained in:
Huge_Black 2025-07-09 23:34:39 +08:00 • committed by GitHub
parent aa151dbba2
commit 1808dafed3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 123 additions and 0 deletions

View file

@ -31,3 +31,96 @@ NSString* handleJSContextSendDebugCommand(JSContext* context, NSString* commandS
idevice_string_free(attach_response);
return commandResponse;
}
// 0 <= val <= 15
char u8toHexChar(uint8_t val) {
if(val < 10) {
return val + '0';
} else {
return val + 87;
}
}
void calcAndWriteCheckSum(char* commandStart) {
uint8_t sum = 0;
char* cur = commandStart;
for(; *cur != '#'; ++cur) {
sum += *cur;
}
cur[1] = u8toHexChar((sum & 0xf0) >> 4);
cur[2] = u8toHexChar(sum & 0xf);
}
// support up to 9 digit
void writeAddress(char* writeStart, uint64_t addr) {
writeStart[0] = u8toHexChar((addr & 0xf00000000) >> 32);
writeStart[1] = u8toHexChar((addr & 0xf0000000) >> 28);
writeStart[2] = u8toHexChar((addr & 0xf000000) >> 24);
writeStart[3] = u8toHexChar((addr & 0xf00000) >> 20);
writeStart[4] = u8toHexChar((addr & 0xf0000) >> 16);
writeStart[5] = u8toHexChar((addr & 0xf000) >> 12);
writeStart[6] = u8toHexChar((addr & 0xf00) >> 8);
writeStart[7] = u8toHexChar((addr & 0xf0) >> 4);
writeStart[8] = u8toHexChar((addr & 0xf));
}
// you need to free generated buffer
char* getBulkMemWriteCommand(uint64_t startAddr, uint64_t JITPagesSize, uint32_t* commandCountOut, uint32_t* bufferLengthOut) {
// $M10c128000,1:69#12
uint32_t commandCount = (uint32_t)(JITPagesSize >> 14);
uint32_t commandBufferSize = commandCount * 19;
*commandCountOut = commandCount;
*bufferLengthOut = commandBufferSize;
char* buffer = malloc(commandBufferSize + 1);
char* bufferEnd = buffer + commandBufferSize;
buffer[commandBufferSize] = 0;
uint64_t curAddr = startAddr;
for(char* curBufferPtr = buffer; curBufferPtr < bufferEnd; curBufferPtr += 19) {
curBufferPtr[0] = '$';
curBufferPtr[1] = 'M';
curBufferPtr[11] = ',';
curBufferPtr[12] = '1';
curBufferPtr[13] = ':';
curBufferPtr[14] = '6';
curBufferPtr[15] = '9';
curBufferPtr[16] = '#';
writeAddress(curBufferPtr + 2, curAddr);
calcAndWriteCheckSum(curBufferPtr + 1);
curAddr += 16384;
}
return buffer;
}
NSString* handleJITPageWrite(JSContext* context, uint64_t startAddr, uint64_t JITPagesSize, DebugProxyHandle* debugProxy) {
uint32_t bufferLength = 0;
uint32_t commandCount = 0;
char* commandBuffer = getBulkMemWriteCommand(startAddr, JITPagesSize, &commandCount, &bufferLength);
// we send 1024 commands at a time
for(int curCommand = 0; curCommand < commandCount; curCommand += 1024) {
uint32_t commandsToSend = (commandCount - curCommand > 1024) ? 1024 : (commandCount - curCommand);
IdeviceFfiError* err = debug_proxy_send_raw(debugProxy, (const uint8_t *)commandBuffer + curCommand * 19, commandsToSend * 19);
if(err) {
context.exception = [JSValue valueWithObject:[NSString stringWithFormat:@"error code %d, msg %s", err->code, err->message] inContext:context];
free(commandBuffer);
idevice_error_free(err);
return nil;
}
for(int i = 0; i < commandsToSend; ++i) {
char* response = 0;
IdeviceFfiError* err = debug_proxy_read_response(debugProxy, &response);
if(response) {
idevice_string_free(response);
}
if(err) {
context.exception = [JSValue valueWithObject:[NSString stringWithFormat:@"error code %d, msg %s", err->code, err->message] inContext:context];
free(commandBuffer);
idevice_error_free(err);
return nil;
}
}
}
free(commandBuffer);
return @"OK";
}

View file

@ -9,3 +9,4 @@
#include "../idevice/jit.h"
NSString* handleJSContextSendDebugCommand(JSContext* context, NSString* commandStr, DebugProxyHandle* debugProxy);
NSString* handleJITPageWrite(JSContext* context, uint64_t startAddr, uint64_t JITPagesSize, DebugProxyHandle* debugProxy);

View file

@ -50,9 +50,19 @@ class RunJSViewModel: ObservableObject {
}
}
let prepareMemoryRegionFunction: @convention(block) (UInt64, UInt64) -> String = { startAddr, regionSize in
return handleJITPageWrite(self.context, startAddr, regionSize, self.debugProxy) ?? ""
}
let hasTXMFunction: @convention(block) () -> Bool = {
return ProcessInfo.processInfo.hasTXM
}
context = JSContext()
context?.setObject(hasTXMFunction, forKeyedSubscript: "hasTXM" as NSString)
context?.setObject(getPidFunction, forKeyedSubscript: "get_pid" as NSString)
context?.setObject(sendCommandFunction, forKeyedSubscript: "send_command" as NSString)
context?.setObject(prepareMemoryRegionFunction, forKeyedSubscript: "prepare_memory_region" as NSString)
context?.setObject(logFunction, forKeyedSubscript: "log" as NSString)
context?.evaluateScript(scriptContent)

View file

@ -0,0 +1,19 @@
//
// Extensions.swift
// StikDebug
//
// Created by s s on 2025/7/9.
//
extension FileManager {
func filePath(atPath path: String, withLength length: Int) -> String? {
guard let file = try? contentsOfDirectory(atPath: path).filter({ $0.count == length }).first else { return nil }
return "\(path)/\(file)"
}
}
public extension ProcessInfo {
var hasTXM: Bool {
{ if let boot = FileManager.default.filePath(atPath: "/System/Volumes/Preboot", withLength: 36), let file = FileManager.default.filePath(atPath: "\(boot)/boot", withLength: 96) { return access("\(file)/usr/standalone/firmware/FUD/Ap,TrustedExecutionMonitor.img4", F_OK) == 0 } else { return (FileManager.default.filePath(atPath: "/private/preboot", withLength: 96).map { access("\($0)/usr/standalone/firmware/FUD/Ap,TrustedExecutionMonitor.img4", F_OK) == 0 }) ?? false } }()
}
}