/* fixobjc2.idc ... IDA Pro 5.x script to fix ObjC ABI 2.0 for iPhoneOS binaries. Copyright (C) 2010 KennyTM~ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #define RO_META 1 static offsetize(name) { auto base, ea; base = SegByBase(SegByName(name)); if (base >= 0) { for (ea = SegStart(base); ea != SegEnd(base); ea = ea + 4) { OpOff(ea, 0, 0); } } } static functionize (ea, is_meta, cls, sel) { auto is_thumb, head_ea, ea_flags; is_thumb = ea & 1; ea = ea & ~1; ea_flags = GetFlags(ea); if (!isCode(ea_flags) || GetReg(ea, "T") != is_thumb) { head_ea = !isHead(ea_flags) ? PrevHead(ea, 0) : ea; MakeUnkn(head_ea, DOUNK_EXPAND); SetRegEx(ea, "T", is_thumb, SR_autostart); MakeCode(ea); } MakeFunction(ea, BADADDR); MakeName(ea, (is_meta ? "@" : "") + cls + "." + sel); SetFunctionCmt(ea, (is_meta ? "+" : "-") + "[" + cls + " " + sel + "]", 1); } static methodize (m_ea, is_meta, cl_name) { auto m_size, m_count, m_i, m_sname, m_cname; if (m_ea <= 0) return; m_size = Dword(m_ea); m_count = Dword(m_ea + 4); MakeStruct(m_ea, "method_list_t"); MakeName(m_ea, cl_name + (is_meta ? "_$classMethods" : "_$methods")); m_ea = m_ea + 8; for (m_i = 0; m_i < m_count; m_i = m_i + 1) { MakeStruct(m_ea, "method_t"); m_sname = GetString(Dword(m_ea), -1, ASCSTR_C); functionize(Dword(m_ea + 8), is_meta, cl_name, m_sname); m_ea = m_ea + m_size; } } static classize (c_ea, is_meta) { auto cd_ea, cl_name, c_name, i_ea, i_count, i_size, i_i, i_sname; MakeStruct(c_ea, "class_t"); cd_ea = Dword(c_ea + 16); MakeStruct(cd_ea, "class_ro_t"); cl_name = GetString(Dword(cd_ea + 16), -1, ASCSTR_C); MakeName(c_ea, (is_meta ? "_OBJC_METACLASS_$_" : "_OBJC_CLASS_$_") + cl_name); MakeName(cd_ea, cl_name + (is_meta ? "_$metaData" : "_$classData")); // methods methodize(Dword(cd_ea + 20), is_meta, cl_name); // ivars i_ea = Dword(cd_ea + 28); if (i_ea > 0) { i_size = Dword(i_ea); i_count = Dword(i_ea + 4); MakeStruct(i_ea, "ivar_list_t"); MakeName(i_ea, cl_name + (is_meta ? "_$classIvars" : "_$ivars")); i_ea = i_ea + 8; for (i_i = 0; i_i < i_count; i_i = i_i + 1) { MakeStruct(i_ea, "ivar_t"); i_sname = GetString(Dword(i_ea+4), -1, ASCSTR_C); MakeDword(Dword(i_ea)); MakeName(Dword(i_ea), "_OBJC_IVAR_$_" + cl_name + "." + i_sname); i_ea = i_ea + i_size; } } } static categorize(c_ea) { auto cat_name, cl_name, s_name; cat_name = GetString(Dword(c_ea), -1, ASCSTR_C); s_name = substr(Name(Dword(c_ea + 4)), 14, -1); cl_name = s_name + "(" + cat_name + ")"; methodize(Dword(c_ea + 8), 0, cl_name); methodize(Dword(c_ea + 12), 1, cl_name); } static main () { auto cl_ea, cl_base, c_ea, s_base, s_ea, s_name, cr_base, cr_ea, cr_target; auto cat_base, cat_ea; if (GetLongPrm(INF_FILETYPE) != 25 || (GetLongPrm(INF_PROCNAME) & 0xffffff) != 0x4d5241) { Warning("fixobjc2.idc only works for Mach-O binaries with ARM processors."); return; } offsetize("__objc_classrefs"); offsetize("__objc_classlist"); offsetize("__objc_catlist"); offsetize("__objc_protolist"); offsetize("__objc_superrefs"); offsetize("__objc_selrefs"); // find all methods & ivars. cl_base = SegByBase(SegByName("__objc_classlist")); if (cl_base >= 0) { for (cl_ea = SegStart(cl_base); cl_ea != SegEnd(cl_base); cl_ea = cl_ea + 4) { c_ea = Dword(cl_ea); classize(c_ea, 0); classize(Dword(c_ea), 1); } } // name all selectors s_base = SegByBase(SegByName("__objc_selrefs")); if (s_base >= 0) { for (s_ea = SegStart(s_base); s_ea != SegEnd(s_base); s_ea = s_ea + 4) { s_name = GetString(Dword(s_ea), -1, ASCSTR_C); MakeRptCmt(s_ea, "@selector(" + s_name + ")"); } } // name all classrefs cr_base = SegByBase(SegByName("__objc_classrefs")); if (cr_base >= 0) { for (cr_ea = SegStart(cr_base); cr_ea != SegEnd(cr_base); cr_ea = cr_ea + 4) { cr_target = Dword(cr_ea); if (cr_target > 0) { MakeRptCmt(cr_ea, Name(cr_target)); } } } // categories. cat_base = SegByBase(SegByName("__objc_catlist")); if (cat_base >= 0) { for (cat_ea = SegStart(cat_base); cat_ea != SegEnd(cat_base); cat_ea = cat_ea + 4) { categorize(Dword(cat_ea)); } } }