Last active
April 26, 2023 23:15
-
-
Save JJTech0130/c8a0d6c77586db444a60b2267d533b7a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var m = 'libsystem_trace.dylib'; | |
// bool os_log_type_enabled(os_log_t oslog, os_log_type_t type); | |
var isEnabledFunc = Module.findExportByName(m, 'os_log_type_enabled'); | |
// _os_log_impl(void *dso, os_log_t log, os_log_type_t type, const char *format, uint8_t *buf, unsigned int size); | |
var logFunc = Module.findExportByName(m, '_os_log_impl'); | |
Interceptor.attach(isEnabledFunc, { | |
onLeave: function (ret) { | |
// console.log('log_enabled', ret); | |
ret.replace(0x1); | |
} | |
}); | |
const ENDCOLOR = "\x1B[0m"; | |
const RED = "\x1B[31m"; | |
const GREEN = "\x1B[32m"; | |
const YELLOW = "\x1B[33m"; | |
const BLUE = "\x1B[34m"; | |
const LIGHTBLUE = "\x1B[94m"; | |
const DARKGRAY = "\x1B[90m"; | |
const MAROON = "\x1B[35m"; | |
function parseFmtBuf(buf) { | |
//console.log(buf); | |
let firstByte = buf.readU8(); | |
buf = buf.add(1); | |
if (firstByte != 2 && firstByte != 0) { | |
//throw "Expected first byte to be 2, got " + firstByte; | |
console.log("Unknown first byte: " + firstByte); | |
//return []; | |
} | |
let items = buf.readU8(); | |
buf = buf.add(1); | |
let out = []; | |
for (let i = 0; i < items; i++) { | |
let type = buf.readU8(); | |
buf = buf.add(1); | |
let size = buf.readU8(); | |
buf = buf.add(1); | |
let bytes = []; | |
for (let j = 0; j < size; j++) { | |
bytes.push(buf.readU8()); | |
buf = buf.add(1); | |
} | |
//if (size == 8) { | |
// let ptr = buf.sub(8).readPointer(); | |
//} | |
bytes = bytes.reverse(); // Reverse the bytes so that they're in the correct order | |
//console.log("Type: " + type + " Size: " + size + " Bytes: " + bytes); | |
out.push({ | |
type: type, | |
size: size, | |
bytes: bytes, | |
//ptr: ptr | |
}); | |
} | |
return out; | |
} | |
function hexFromBytes(bytes) { | |
let out = ""; | |
for (let i = 0; i < bytes.length; i++) { | |
// Get the hex string for the byte and pad it with a 0 if it's only 1 character | |
let hex = bytes[i].toString(16); | |
if (hex.length == 1) { | |
hex = "0" + hex; | |
} | |
out += hex; | |
} | |
return "0x" + out; | |
} | |
function parseFmt(fmt, subs) { | |
//console.log("Parsing fmt: " + fmt + " with subs: " + JSON.stringify(subs)); | |
let out = ""; | |
let i = 0; | |
let s = 0; | |
while (i < fmt.length) { | |
if (fmt[i] == "%") { | |
//console.log("Parsing sub: " + s); | |
i++; | |
let opt = "" | |
if (fmt[i] == "{") { | |
i++;// pass over initial { | |
while (fmt[i] != "}") { // Not at a } | |
opt += fmt[i]; // Add the character to the opt string | |
i++; // Next char | |
} | |
i++; // pass over final } | |
//console.log("Opt: " + opt); | |
} | |
let end_color = false; | |
let bool = false; | |
let opts = opt.split(","); | |
for (let j = 0; j < opts.length; j++) { | |
if (opts[j] == "private") { | |
out += GREEN; | |
end_color = true; | |
} else if (opts[j] == "public") { | |
out += BLUE; | |
end_color = true; | |
} else if (opts[j] == "bool") { | |
bool = true; | |
} else if (opts[j] != "") { | |
out += RED + opts[j] + ENDCOLOR; | |
} | |
} | |
while (fmt[i] == "l") { | |
i++; // pass over length modifiers | |
} | |
if (fmt[i] == "s") { | |
let ptr = new NativePointer(hexFromBytes(subs[s].bytes)); | |
if (ptr < 0x10000) { | |
throw "ptr is too small: " + ptr; // Try and protect against null ptrs | |
} | |
out += ptr.readCString(); | |
s++; | |
} else if (fmt[i] == "@") { | |
while (subs[s].type == 0x70) { | |
// Skip over the 0x70 types, don't know what they are | |
s++; | |
} | |
if (subs[s].type != 0x40 && subs[s].type != 0x42 && subs[s].type != 0x41) { | |
throw "Expected type 0x40 or 0x42 for %@, got " + subs[s].type; | |
} | |
// Convert the Bytes to a NativePointer | |
let ptr = new NativePointer(hexFromBytes(subs[s].bytes)); | |
// if (ptr < 0x10000) { | |
// throw "ptr is too small: " + ptr; // Try and protect against null ptrs | |
// } | |
// Convert the NativePointer to an ObjC.Object | |
let obj = new ObjC.Object(ptr); | |
// Read the ObjC.Object's description | |
// Using toString rather than description so that it works on nil | |
out += obj.toString(); | |
s++; | |
} else if (fmt[i] == "d" || fmt[i] == "%u") { | |
let val = parseInt(hexFromBytes(subs[s].bytes)); | |
if (bool) { | |
if (val == 0) { | |
out += "NO"; | |
} else { | |
out += "YES"; | |
} | |
} else { | |
out += val; | |
} | |
s++; | |
} else if (fmt[i] == "x" || fmt[i] == "p") { | |
out += hexFromBytes(subs[s].bytes); | |
s++; | |
} else if (fmt[i] == "c") { | |
out += String.fromCharCode(parseInt(hexFromBytes(subs[s].bytes))); | |
s++; | |
} else { | |
out += "%" + fmt[i]; | |
s++; | |
} | |
if (end_color) { | |
out += ENDCOLOR; | |
} | |
} else { | |
out += fmt[i]; | |
} | |
i++; | |
} | |
return out; | |
} | |
Interceptor.attach(logFunc, { | |
onEnter: function (args) { | |
let type = args[2]; | |
let fmt = args[3].readCString(); | |
let buf = args[4]; | |
let size = args[5]; | |
if (type == 0) { | |
type = "default"; | |
} else if (type == 1) { | |
type = LIGHTBLUE + "info"; | |
} else if (type == 2) { | |
type = DARKGRAY + "debug"; | |
} else if (type == 16) { | |
type = RED + "error"; | |
} else if (type == 17) { | |
type = MAROON + "fault"; | |
} else { | |
type = YELLOW + "0x" + type.toString(16); | |
} | |
type += ENDCOLOR; | |
try { | |
let fmtd = parseFmt(fmt, parseFmtBuf(buf)); | |
console.log("[" + type + "] " + fmtd); | |
} catch (e) { | |
console.log("Error parsing format: " + e + " for fmt: " + fmt + " and subs: " + JSON.stringify(parseFmtBuf(buf)) + " (raw subs len: " + size + ")"); | |
} | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment