Skip to content

Instantly share code, notes, and snippets.

@JJTech0130
Last active April 26, 2023 23:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JJTech0130/c8a0d6c77586db444a60b2267d533b7a to your computer and use it in GitHub Desktop.
Save JJTech0130/c8a0d6c77586db444a60b2267d533b7a to your computer and use it in GitHub Desktop.
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