diff --git a/blutter/src/DartDumper.cpp b/blutter/src/DartDumper.cpp index 5715e29..70930d8 100644 --- a/blutter/src/DartDumper.cpp +++ b/blutter/src/DartDumper.cpp @@ -96,11 +96,20 @@ void DartDumper::Dump4Ida(std::filesystem::path outDir) for (auto dartFn : cls->Functions()) { const auto ep = dartFn->Address(); auto name = getFunctionName4Ida(*dartFn, cls_prefix); - of << std::format("ida_funcs.add_func({:#x}, {:#x})\n", ep, ep + dartFn->Size()); + const auto fnSize = dartFn->Size(); + if (fnSize > 0) { + of << std::format("ida_funcs.add_func({:#x}, {:#x})\n", ep, ep + fnSize); + } of << std::format("idaapi.set_name({:#x}, \"{}_{}::{}_{:x}\")\n", ep, lib_prefix, cls_prefix, name.c_str(), ep); if (dartFn->HasMorphicCode()) { - of << std::format("idaapi.set_name({:#x}, \"{}_{}::{}_{:x}_miss\")\n", dartFn->PayloadAddress(), lib_prefix, cls_prefix, name.c_str(), ep); - of << std::format("idaapi.set_name({:#x}, \"{}_{}::{}_{:x}_check\")\n", dartFn->MonomorphicAddress(), lib_prefix, cls_prefix, name.c_str(), ep); + const auto payloadAddr = dartFn->PayloadAddress(); + const auto morphicAddr = dartFn->MonomorphicAddress(); + if (payloadAddr != 0 && payloadAddr != ep) { + of << std::format("idaapi.set_name({:#x}, \"{}_{}::{}_{:x}_miss\")\n", payloadAddr, lib_prefix, cls_prefix, name.c_str(), ep); + } + if (morphicAddr != 0 && morphicAddr != ep && morphicAddr != payloadAddr) { + of << std::format("idaapi.set_name({:#x}, \"{}_{}::{}_{:x}_check\")\n", morphicAddr, lib_prefix, cls_prefix, name.c_str(), ep); + } } } } diff --git a/scripts/frida.template.js b/scripts/frida.template.js index 83e2177..98712eb 100644 --- a/scripts/frida.template.js +++ b/scripts/frida.template.js @@ -113,6 +113,57 @@ function getDartTypedArrayValues(ptr, cls, elementSize, readValFn) { return vals; } +function getDartClosure(ptr, cls) { + let ep = ptr.add(cls.epOffset).readPointer(); + let fnName = 'unknown'; + if (libapp !== null) { + let offset = ep.sub(libapp); + fnName = 'fn_' + offset.toString(16); + } + return `Closure(${fnName})`; +} + +function getDartLinkedHashData(ptr, cls, depthLeft, isMap) { + const usedData = ptr.add(cls.usedOffset).readU32() >> 1; + let arrPtr = ptr.add(cls.dataOffset); + let dataCls = Classes[CidArray]; + + if (isMap) { + let result = {}; + for (let i = 0; i < usedData; i += 2) { + try { + let keyPtr = arrPtr.add(dataCls.dataOffset + i * CompressedWordSize).readPointer(); + let valPtr = arrPtr.add(dataCls.dataOffset + (i + 1) * CompressedWordSize).readPointer(); + const [kTptr, kCls, kVal] = getTaggedObjectValue(keyPtr, depthLeft - 1); + const [vTptr, vCls, vVal] = getTaggedObjectValue(valPtr, depthLeft - 1); + if (kCls.id === CidNull) continue; + let keyStr = (kCls.id === CidString || kCls.id === CidTwoByteString) ? kVal : `${kCls.name}@${kTptr.toString().slice(2)}`; + result[keyStr] = vVal; + } catch(e) { break; } + } + return result; + } else { + let items = []; + for (let i = 0; i < usedData; i++) { + try { + let valPtr = arrPtr.add(dataCls.dataOffset + i * CompressedWordSize).readPointer(); + const [vTptr, vCls, vVal] = getTaggedObjectValue(valPtr, depthLeft - 1); + if (vCls.id === CidNull) continue; + items.push(vVal); + } catch(e) { break; } + } + return items; + } +} + +function getDartMap(ptr, cls, depthLeft) { + return getDartLinkedHashData(ptr, cls, depthLeft, true); +} + +function getDartSet(ptr, cls, depthLeft) { + return getDartLinkedHashData(ptr, cls, depthLeft, false); +} + function isFieldNative(fieldBitmap, offset) { const idx = offset / CompressedWordSize; return (fieldBitmap & (1 << idx)) !== 0; @@ -157,6 +208,12 @@ function getObjectValue(ptr, cls, depthLeft = MaxDepth) { return getDartTypedArrayValues(ptr, cls, 8, (p) => p.readU64()); case CidInt64Array: return getDartTypedArrayValues(ptr, cls, 8, (p) => p.readS64()); + case CidClosure: + return getDartClosure(ptr, cls); + case CidSet: + return getDartSet(ptr, cls, depthLeft); + case CidMap: + return getDartMap(ptr, cls, depthLeft); } if (cls.id < NumPredefinedCids) { @@ -282,4 +339,4 @@ function decompressPointer(dptr) { return HeapAddress.add(dptr.toInt32()); } return dptr; -} +} \ No newline at end of file