mach-o格式浅析(二)

水平有限,错误在所难免,求指点。

本篇以阿里旺旺mac版本 分析一下如果是object-c编写的程序所对应的mach-o文件结构,试着解析出静态的object-class的信息。

旺旺版本

010 editor 打开 /Applications/AliWangwang.app/Contents/MacOS/AliWangwang, 如图 xx

可以看到AliWangwang最开始的四个字节为 0xfeedfacf, 根据mach-o的定义,文件开始的开始对应的结构体为mach_header_64(如下图定义), 也就是说此文件不是个fat格式的复合文件,该文件只包含的一套指令集,同时从mach_header_64.cpu_type字段,我们可以知道包含的指令集是x64格式的。

xx

segment_command_64结构紧跟在mach_header_64头后面,也是从文件偏移的0x20处开始套上load_command结构体继续分析。 这里主要查看TEXT 和 DATA 2个segment。

xx

xx

从segment_command_64.nsects 字段可以得到该segment所带的section64的个数,并且套上section64的结构信息,可以得到section的信息。得到的section的名字列表如下

__TEXT segment下的 section 用途
__text 主程序的代码
__stubs 用于动态链接的存根
__text 主程序的代码
__stubs 用于动态链接的存根
__stub_helper 用于动态链接的存根
__const 程序中const关键字修饰的常量变量
__objc_methname object-c的方法名字
__cstring 程序中硬编码的ANSI的字符串
__objc_classname object-c类的名字
__objc_methtype object-c方法的类型
__gcc_except_tab 异常处理相关
__ustring unicode字符串
__unwind_info 异常处理相关
__eh_frame 异常处理相关

__DATA segment下的 section 用途
__nl_symbol_ptr 动态符号链接相关,其实是个指针数组
__got 全局偏移表, Global Offset Table
__la_symbol_ptr 动态符号链接相关,也是指针数组,通过dyld_stub_binder辅助链接
__mod_init_func 初始化的全局函数地址,会在main之前被调用
__const const常量
__cfstring core foundation用到的字符串
__objc_classlist object-c的类列表
__objc_nlclslist object-c的+load函数列表,比__mod_init_func更早被执行
__objc_catlist object-c的category列表
__objc_protolist object-c的协议列表
__objc_imageinfo object-c的映像信息
__objc_const object-c的常量
__objc_selrefs object-c 自引用
__objc_protorefs object-c 协议引用
__objc_classrefs object-c 类的引用
__objc_superrefs object-c 父类引用
__objc_ivar ivar变量信息
__objc_data class信息
__data 初始化的可变的变量
__common
__bss 未初始化的静态变量

object-c是门很动态的语言,实际上编译完成后,类的信息就被保存在mach-o格式里面了,__objc_classlist section保存了所有用到的object-c的类列表信息, 从 section64.offset字段,得到object-c的class信息存储在 0x27bdc0 位置, 此处是个指针的数组,数组的大小为 section64.size / 8, 也就是 0x770 / 8.

xx

取数组的第一项进行分析,也就是 0x01002df618, 0x01002df618 是虚拟地址偏移,需要转换为文件地址便宜,也就是需要减去 DATA.vm_addr , 再加上 DATA.offset得到文件偏移, 也就是 0x01002df618 - 100267000h + 267000h = 0x2df618;

010 editor 中跳到 0x2df618, 根据apple文档,此处数据对应的结构体信息为class64_t 贴个下面用到的结构体的定义的头文件,下面的解析都依赖于此头文件。

struct class64_ro_t { uint32_t flags; uint32_t instanceStart; uint32_t instanceSize; uint32_t reserved; uint64_t ivarLayout; // const uint8_t * (64-bit pointer) uint64_t name; // const char * (64-bit pointer) uint64_t baseMethods; // const method_list_t * (64-bit pointer) uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer) uint64_t ivars; // const ivar_list_t * (64-bit pointer) uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer) uint64_t baseProperties; // const struct objc_property_list * (64-bit pointer) };

struct class64_t { uint64_t isa; // class_t * (64-bit pointer) uint64_t superclass; // class_t * (64-bit pointer) uint64_t cache; // Cache (64-bit pointer) uint64_t vtable; // IMP * (64-bit pointer) uint64_t data; // class_ro_t * (64-bit pointer) };

struct objc_property64_list { uint32_t entsize; uint32_t count; // struct objc_property first; These structures follow inline };

struct objc_property64 { uint64_t name; // const char * (64-bit pointer) uint64_t attributes; // const char * (64-bit pointer) };

struct method64_list_t { uint32_t entsize; uint32_t count; // struct method_t first; These structures follow inline };

struct method64_t { uint64_t name; // SEL (64-bit pointer) uint64_t types; // const char * (64-bit pointer) uint64_t imp; // IMP (64-bit pointer) };

struct ivar64_list_t { uint32_t entsize; uint32_t count; // struct ivar_t first; These structures follow inline };

struct ivar64_t { uint64_t offset; // uintptr_t * (64-bit pointer) uint64_t name; // const char * (64-bit pointer) uint64_t type; // const char * (64-bit pointer) uint32_t alignment; uint32_t size; };

struct protocol64_list_t { uint64_t count; // uintptr_t (a 64-bit value) // struct protocol_t * list[0]; These pointers follow inline };

struct protocol64_t { uint64_t isa; // id * (64-bit pointer) uint64_t name; // const char * (64-bit pointer) uint64_t protocols; // struct protocol_list_t * (64-bit pointer) uint64_t instanceMethods; // method_list_t * (64-bit pointer) uint64_t classMethods; // method_list_t * (64-bit pointer) uint64_t optionalInstanceMethods; // method_list_t * (64-bit pointer) uint64_t optionalClassMethods; // method_list_t * (64-bit pointer) uint64_t instanceProperties; // struct objc_property_list * (64-bit pointer) };

struct objc_property64_list { uint32_t entsize; uint32_t count; // struct objc_property first; These structures follow inline };

struct objc_property64 { uint64_t name; // const char * (64-bit pointer) uint64_t attributes; // const char * (64-bit pointer) };

struct category64_t { uint64_t name; // const char * (64-bit pointer) uint64_t cls; // struct class_t * (64-bit pointer) uint64_t instanceMethods; // struct method_list_t * (64-bit pointer) uint64_t classMethods; // struct method_list_t * (64-bit pointer) uint64_t protocols; // struct protocol_list_t * (64-bit pointer) uint64_t instanceProperties; // struct objc_property_list * (64-bit pointer) };

xx 对应上结构体数据偏移可知 * isa = 0x01002df640 * superclass = 0 * cache = 0 * vtable = 0 * data = 0x010027de88

以上的偏移均为虚拟地址偏移,需要计算得到文件。 如 class64_t.data文件偏移 = 0x010027de88 - 100267000h + 267000h = 27de88h; 从27de88h 按结构体class64_ro_t解析,可知。 * flags = 0x0194 * instanceStart = 0x8 * instanceSize = 0x68 * reserved = 0 * ivarLayout = 0x010021a629 * name = 0x010021a59a * baseMethods = 0x010027d908 * baseProtocols = 0x010027d890 * ivars = 10027DCE8 * weakIvarLayout = 0 * baseProperties = 0x10027DE70

以上的地址皆为虚拟地址,再次相对地址计算可得到文件偏移,

class name在 21a59a 处, 也就是 WWAppDelegate xx

baseMethods 文件地址偏移在0x27d908处,套上method_list_t可知 method_list_t.obsolete = 0x18, method_list_t.method_count = 0x29, 也就是后面有29个method方法,而且每个方法的结构体大小是0x18,

以第一组为例,套上method64_t结构体信息,可得 method64_t.name = 1001DEE3D, method64_t.types = 0x10021CEDB, method64_t.imp = 0x1000026D8。 再次从虚拟地址转换到文件地址偏移。得到method name为1DEE3Dh,method types = 21CEDBh,

xx xx

也就是说第一个method是 -dealloc, 同样遍历数组,可以得到所有的method名字,如下,


-dealloc
-init
-checkOSVersion -showLoginWindow -showMainWindowAfterLoginSuccess -checkForUpgrade -bestValidUpdateInAppcast:forUpdater: -applicationDidFinishLaunching: -applicationDidResignActive: -applicationShouldHandleReopen:hasVisibleWindows: -applicationWillTerminate: -applicationShouldTerminate: -handleURLEvent:withReplyEvent: -doCheckImportLugeEmotions -wwLoginResultNotification: -wwClientWillLogoutNotification: -wwClientDisconnectedNotification: -applicationDockMenu: -chatTo: -newWangwangProcess: -showMainWindow -showMainWindow: -showFileTransfersWindow: -showPerferences: -validateMenuItem: -showFindUserPanel: -showFindUserPanel:withSearchText: -showCustomEmotions: -showAddFriendsNotification: -wwSearchContact: -showAboutWindow: -visitFAQPage: -downloadBrowserPlugin: -setEventUrlString: -eventUrlString -mainWindow -mainWindowController -updaterShouldRelaunchApplication: -.cxx_destruct -updateTimer -setUpdateTimer:

baseProtocols 在0x27d890处,套上protocol_list_t,可知 protocol64_list_t.count = 4, 也就是实现了4个protocol, 后面跟着的是protocol64_t* 数组, 第一个为0x1002E4080, 也就是文件地址偏移的0x2E4080,此处的对应结构体信息为protocol64_t,可知 protocol64_t.name = 0x10021a5a8, 换成文件地址偏移,也就是0x21a5a8, 得到NSApplicationDelegate,重复操作,可得到4个protocol名字如下,


NSApplicationDelegate
NSOutlineViewDataSource
NSOutlineViewDelegate
ASIHTTPRequestDelegate

xx xx

ivars 在虚拟地址0x10027DCE8处,也就是文件地址偏移的0x27DCE8, 套上ivar64_list_t可知,ivar64_list_t.count = 0xc, ivar64_list_t.entry = 0x20。 ivar64_t结构体紧跟其后,可知第一个ivar64_t[0].name = 0x1001E0876,换成文件地址偏移,得到 字符串mainWindowController。重复操作,可以得到0xc个ivars变量,如下。


ivar mainWindowController
ivar loginWindowController
ivar aboutWindowController
ivar preferenceMenuItem
ivar findUserMenuItem
ivar customEmotionsItem
ivar mainWindowMenuItem
ivar attentionRequest
ivar isTerminating
ivar userNotificationCenter
ivar eventUrlString
ivar updateTimer
xx xx

baseProperties在虚拟地址0x10027DE70处,也就是文件偏移的27DE70h,套上objc_property64_list结构体信息,可知objc_property64_list.count = 1, objc_property64_list.entsize = 0x10 , protocol64_t结构体紧随其后,可知第一个objc_property64_list[0].name = 0x1001FEBA0, 也就是文件偏移的 0x1FEBA0


NSTimer updateTimer
xx xx

综合以上protocol, ivar, property, method 信息。可以得到WWAppDelegate的定义为


 @class WWAppDelegate : NSObject < NSApplicationDelegate, NSOutlineViewDataSource, NSOutlineViewDelegate, ASIHTTPRequestDelegate> {
      @property NSTimer updateTimer
        ivar mainWindowController
        ivar loginWindowController
        ivar aboutWindowController
        ivar preferenceMenuItem
        ivar findUserMenuItem
        ivar customEmotionsItem
        ivar mainWindowMenuItem
        ivar attentionRequest
        ivar isTerminating
        ivar userNotificationCenter
        ivar eventUrlString
        ivar updateTimer
        -dealloc
        -init
        -checkOSVersion
        -showLoginWindow
        -showMainWindowAfterLoginSuccess
        -checkForUpgrade
        -bestValidUpdateInAppcast:forUpdater:
        -applicationDidFinishLaunching:
        -applicationDidResignActive:
        -applicationShouldHandleReopen:hasVisibleWindows:
        -applicationWillTerminate:
        -applicationShouldTerminate:
        -handleURLEvent:withReplyEvent:
        -doCheckImportLugeEmotions
        -wwLoginResultNotification:
        -wwClientWillLogoutNotification:
        -wwClientDisconnectedNotification:
        -applicationDockMenu:
        -chatTo:
        -newWangwangProcess:
        -showMainWindow
        -showMainWindow:
        -showFileTransfersWindow:
        -showPerferences:
        -validateMenuItem:
        -showFindUserPanel:
        -showFindUserPanel:withSearchText:
        -showCustomEmotions:
        -showAddFriendsNotification:
        -wwSearchContact:
        -showAboutWindow:
        -visitFAQPage:
        -downloadBrowserPlugin:
        -setEventUrlString:
        -eventUrlString
        -mainWindow
        -mainWindowController
        -updaterShouldRelaunchApplication:
        -.cxx_destruct
        -updateTimer
        -setUpdateTimer:
    }

参考文章或代码

https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/MachORuntime/ http://opensource.apple.com/tarballs/ http://sourceforge.net/projects/machoview/?source=directory

posted @ 2015-04-28 12:56  tieyan  阅读(1071)  评论(1编辑  收藏  举报