加载命令
这里只要分析一个段和段中的一节就好其它都是同样的解析方式,MachO与 ELF 在段与节的分布(这里说的是内存分布,如何加载另说)上没有什么区别。都是文件头后面就是段。段可能包含很多节。只是它增加了一项加载命令。而 ELF 分俩种视图。
// LoadCommands.h
/*
* LoadCommands.h
* MachOView
*
* Created by psaghelyi on 20/07/2010.
*
*/
#import "MachOLayout.h"
//类扩展
@interface MachOLayout (LoadCommands)
//获取加载命令的名称
- (NSString *)getNameForCommand:(uint32_t)cmd;
//创建一个用于窗口显示的加载命令项
-(MVNode *)createLoadCommandNode:(MVNode *)parent
caption:(NSString *)caption
location:(uint32_t)location
length:(uint32_t)length
command:(uint32_t)command;
@end
// LoadCommands.mm
/*
* LoadCommands.mm
* MachOView
*
* Created by psaghelyi on 20/07/2010.
*
*/
#include <string>
#include <vector>
#include <set>
#include <map>
#import "Common.h"
#import "LoadCommands.h"
#import "ReadWrite.h"
#import "DataController.h"
using namespace std;
//============================================================================
@implementation MachOLayout (LoadCommands)
//-----------------------------------------------------------------------------
//获取加载命令名称
- (NSString *)getNameForCommand:(uint32_t)cmd
{
switch(cmd)
{
default: return @"???";
case LC_SEGMENT: return @"LC_SEGMENT";
case LC_SYMTAB: return @"LC_SYMTAB";
case LC_SYMSEG: return @"LC_SYMSEG";
case LC_THREAD: return @"LC_THREAD";
case LC_UNIXTHREAD: return @"LC_UNIXTHREAD";
case LC_LOADFVMLIB: return @"LC_LOADFVMLIB";
case LC_IDFVMLIB: return @"LC_IDFVMLIB";
case LC_IDENT: return @"LC_IDENT";
case LC_FVMFILE: return @"LC_FVMFILE";
case LC_PREPAGE: return @"LC_PREPAGE";
case LC_DYSYMTAB: return @"LC_DYSYMTAB";
case LC_LOAD_DYLIB: return @"LC_LOAD_DYLIB";
case LC_ID_DYLIB: return @"LC_ID_DYLIB";
case LC_LOAD_DYLINKER: return @"LC_LOAD_DYLINKER";
case LC_ID_DYLINKER: return @"LC_ID_DYLINKER";
case LC_PREBOUND_DYLIB: return @"LC_PREBOUND_DYLIB";
case LC_ROUTINES: return @"LC_ROUTINES";
case LC_SUB_FRAMEWORK: return @"LC_SUB_FRAMEWORK";
case LC_SUB_UMBRELLA: return @"LC_SUB_UMBRELLA";
case LC_SUB_CLIENT: return @"LC_SUB_CLIENT";
case LC_SUB_LIBRARY: return @"LC_SUB_LIBRARY";
case LC_TWOLEVEL_HINTS: return @"LC_TWOLEVEL_HINTS";
case LC_PREBIND_CKSUM: return @"LC_PREBIND_CKSUM";
case LC_LOAD_WEAK_DYLIB: return @"LC_LOAD_WEAK_DYLIB";
case LC_SEGMENT_64: return @"LC_SEGMENT_64";
case LC_ROUTINES_64: return @"LC_ROUTINES_64";
case LC_UUID: return @"LC_UUID";
case LC_RPATH: return @"LC_RPATH";
case LC_CODE_SIGNATURE: return @"LC_CODE_SIGNATURE";
case LC_SEGMENT_SPLIT_INFO: return @"LC_SEGMENT_SPLIT_INFO";
case LC_REEXPORT_DYLIB: return @"LC_REEXPORT_DYLIB";
case LC_LAZY_LOAD_DYLIB: return @"LC_LAZY_LOAD_DYLIB";
case LC_ENCRYPTION_INFO: return @"LC_ENCRYPTION_INFO";
case LC_ENCRYPTION_INFO_64: return @"LC_ENCRYPTION_INFO_64";
case LC_DYLD_INFO: return @"LC_DYLD_INFO";
case LC_DYLD_INFO_ONLY: return @"LC_DYLD_INFO_ONLY";
case LC_LOAD_UPWARD_DYLIB: return @"LC_LOAD_UPWARD_DYLIB";
case LC_VERSION_MIN_MACOSX: return @"LC_VERSION_MIN_MACOSX";
case LC_VERSION_MIN_IPHONEOS: return @"LC_VERSION_MIN_IPHONEOS";
case LC_FUNCTION_STARTS: return @"LC_FUNCTION_STARTS";
case LC_DYLD_ENVIRONMENT: return @"LC_DYLD_ENVIRONMENT";
case LC_MAIN: return @"LC_MAIN";
case LC_DATA_IN_CODE: return @"LC_DATA_IN_CODE";
case LC_SOURCE_VERSION: return @"LC_SOURCE_VERSION";
case LC_DYLIB_CODE_SIGN_DRS: return @"LC_DYLIB_CODE_SIGN_DRS";
case LC_LINKER_OPTION: return @"LC_LINKER_OPTION";
case LC_LINKER_OPTIMIZATION_HINT: return @"LC_LINKER_OPTIMIZATION_HINT";
}
}
//-----------------------------------------------------------------------------
//struct segment_command_64 { /* for 64-bit architectures */
// uint32_t cmd; 命令加载类型
// uint32_t cmdsize; 命令加载的大小
// char segname[16]; 16 字节的段名
// uint64_t vmaddr; 段的虚拟内存地址 VA
// uint64_t vmsize; 段的在虚拟内存有大小
// uint64_t fileoff; 段在文件中的偏移
// uint64_t filesize; 段在文件中的大小
// vm_prot_t maxprot; 段页要所需要的最高内存保护(4=r,2=w,1=x)
// vm_prot_t initprot; 段页面初始化的内存保护
// uint32_t nsects; 段中包含 section 的数量
// uint32_t flags; 其它杂项标志位
//};
//加载命令的显示方式
- (MVNode *)createLCSegmentNode:(MVNode *)parent
caption:(NSString *)caption
//数据的地址
location:(uint32_t)location
segment_command:(struct segment_command const *)segment_command
{
//DataController.h中的一个结构
// struct MVNodeSaver
// {
// MVNodeSaver();
// ~MVNodeSaver();
//
// void setNode(MVNode * node) { m_node = node; }
//
// private:
// MVNodeSaver(MVNodeSaver const &);
// MVNodeSaver & operator=(MVNodeSaver const &);
//
// MVNode * __weak m_node;
// };
MVNodeSaver nodeSaver;
//DataController.h中的一个类
//初始化一个MVNode
MVNode * node = [parent insertChildWithDetails:caption location:location length:segment_command->cmdsize saver:nodeSaver];
//创建一个NSRange
NSRange range = NSMakeRange(location,0);
NSString * lastReadHex;
//获取 hex 位置为range.location
////获取十六进制 lastReadHex缓冲区
//- (uint32_t)read_uint32:(NSRange &)range lastReadHex:(NSString **)lastReadHex
//{
// //缓冲区
// uint32_t buffer;
// //创建一个range
// range = NSMakeRange(NSMaxRange(range),sizeof(uint32_t));
// //可修改的NSMutableData * fileData;
// //获取指定范围的数据
// [fileData getBytes:&buffer range:range];
// //判断lastReadHex是否可以用
// if (lastReadHex)
// //转十六进制
// *lastReadHex = [NSString stringWithFormat:@"%.8X",buffer];
// //可修改的NSMutableData * realData;
// //重新读
// [realData getBytes:&buffer range:range];
// //返回数据
// return buffer;
//}
[dataController read_uint32:range lastReadHex:&lastReadHex];
// MVTable * details
//offsetStr = col0;
//dataStr = col1;
//descriptionStr = col2;
//valueStr = col3;
//右边表格追加一行
[node.details appendRow:
//地址(文件偏移地址或者vm内存地址)
[NSString stringWithFormat:@"%.8lX", range.location]
//Date数据
:lastReadHex
//描述
:@"Command"
//加载命令的值(名称)
:[self getNameForCommand:segment_command->cmd]];
//设置加载命令的结构体(那个俩字段的结构体)颜色为greenColor
//MVCellColorAttributeName = @"MVCellColorAttribute";
[node.details setAttributes:MVCellColorAttributeName,[NSColor greenColor],nil];
//重新获取 hex
[dataController read_uint32:range lastReadHex:&lastReadHex];
//显示Command Size字段
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Command Size"
:[NSString stringWithFormat:@"%u", segment_command->cmdsize]];
//显示颜色
[node.details setAttributes:MVCellColorAttributeName,[NSColor greenColor],
MVUnderlineAttributeName,@"YES",nil];
//重新取 hex
[dataController read_string:range fixlen:16 lastReadHex:&lastReadHex];
//显示字段Segment Name
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Segment Name"
:[NSString stringWithFormat:@"%s", string(segment_command->segname,16).c_str()]];
//VM Address
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"VM Address"
:[NSString stringWithFormat:@"0x%X", segment_command->vmaddr]];
//VM Size
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"VM Size"
:[NSString stringWithFormat:@"%u", segment_command->vmsize]];
//File Offset
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"File Offset"
:[NSString stringWithFormat:@"%u", segment_command->fileoff]];
//File Size
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"File Size"
:[NSString stringWithFormat:@"%u", segment_command->filesize]];
//Maximum VM Protection
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Maximum VM Protection"
:@""];
//段页面不能超过的最高内存保护 注意这里是八进制
//无最高保护
if (segment_command->maxprot == VM_PROT_NONE) [node.details appendRow:@"":@"":@"00000000":@"VM_PROT_NONE"];
//可执行
if (segment_command->maxprot & VM_PROT_READ) [node.details appendRow:@"":@"":@"00000001":@"VM_PROT_READ"];
//可写
if (segment_command->maxprot & VM_PROT_WRITE) [node.details appendRow:@"":@"":@"00000002":@"VM_PROT_WRITE"];
//可读
if (segment_command->maxprot & VM_PROT_EXECUTE) [node.details appendRow:@"":@"":@"00000004":@"VM_PROT_EXECUTE"];
//重新读
[dataController read_uint32:range lastReadHex:&lastReadHex];
//段内最初始的内存保护
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Initial VM Protection"
:@""];
//0 1 2 4
if (segment_command->initprot == VM_PROT_NONE) [node.details appendRow:@"":@"":@"00000000":@"VM_PROT_NONE"];
if (segment_command->initprot & VM_PROT_READ) [node.details appendRow:@"":@"":@"00000001":@"VM_PROT_READ"];
if (segment_command->initprot & VM_PROT_WRITE) [node.details appendRow:@"":@"":@"00000002":@"VM_PROT_WRITE"];
if (segment_command->initprot & VM_PROT_EXECUTE) [node.details appendRow:@"":@"":@"00000004":@"VM_PROT_EXECUTE"];
//段中节的数量
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Number of Sections"
:[NSString stringWithFormat:@"%u", segment_command->nsects]];
//其它标志
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Flags"
:@""];
//该段的文件内容是VM空间的高部分,低部分为零填充(在核心文件用于堆栈)
if (segment_command->flags & SG_HIGHVM) [node.details appendRow:@"":@"":@"00000001":@"SG_HIGHVM"];
//此段是由固定的VM library分配的VM,用于链接编辑器中的重叠检查
if (segment_command->flags & SG_FVMLIB) [node.details appendRow:@"":@"":@"00000002":@"SG_FVMLIB"];
//无重定位
if (segment_command->flags & SG_NORELOC) [node.details appendRow:@"":@"":@"00000004":@"SG_NORELOC"];
//这个部分是受保护的,如果段在文件偏移0处开始,则段的第一页不受保护,该段的所有其他页都受到保护。
if (segment_command->flags & SG_PROTECTED_VERSION_1) [node.details appendRow:@"":@"":@"00000008":@"SG_PROTECTED_VERSION_1"];
//返回加载命令 显示结点
return node;
}
//struct section_64 { /* for 64-bit architectures */
// char sectname[16]; 节名
// char segname[16]; 节的所属段名
// uint64_t addr; 节的内存中的起始地址
// uint64_t size; 节的大小
// uint32_t offset; 节的文件偏移
// uint32_t align; 节的对齐粒度
// uint32_t reloff; 重定位入口的文件偏移
// uint32_t nreloc; 需要重定位的入口数量
// uint32_t flags; 其它标志 包含包含节的type和attributes
// uint32_t reserved1; 记录了它们在dysymtab_command结构中indirectsymoff字段所对应的起始项
//对于 symbol pointer sections 和 stubs sections 来说,reserved1 表示 indirect table 数组的 index。用来索引 section's entries
// uint32_t reserved2; 记录了条目的大小或者个数
// uint32_t reserved3; /* reserved */
//};
//-----------------------------------------------------------------------------
//节
- (MVNode *)createSectionNode:(MVNode *)parent
caption:(NSString *)caption
location:(uint32_t)location
section:(struct section const *)section
{
MVNodeSaver nodeSaver;
MVNode * node = [parent insertChildWithDetails:caption location:location length:sizeof(struct section) saver:nodeSaver];
NSRange range = NSMakeRange(location,0);
NSString * lastReadHex;
[dataController read_string:range fixlen:16 lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Section Name"
:[NSString stringWithFormat:@"%s", string(section->sectname,16).c_str()]];
[dataController read_string:range fixlen:16 lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Segment Name"
:[NSString stringWithFormat:@"%s", string(section->segname,16).c_str()]];
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Address"
:[NSString stringWithFormat:@"0x%X", section->addr]];
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Size"
:[NSString stringWithFormat:@"%u", section->size]];
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Offset"
:[NSString stringWithFormat:@"%u", section->offset]];
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Alignment"
:[NSString stringWithFormat:@"%u", (1 << section->align)]];
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Relocations Offset"
:[NSString stringWithFormat:@"%u", section->reloff]];
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Number of Relocations"
:[NSString stringWithFormat:@"%u", section->nreloc]];
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:@"Flags"
:@""];
//节类型
switch (section->flags & SECTION_TYPE)
{
case S_REGULAR: [node.details appendRow:@"":@"":@"00000000":@"S_REGULAR"]; break;
case S_ZEROFILL: [node.details appendRow:@"":@"":@"00000001":@"S_ZEROFILL"]; break;
case S_CSTRING_LITERALS: [node.details appendRow:@"":@"":@"00000002":@"S_CSTRING_LITERALS"]; break;
case S_4BYTE_LITERALS: [node.details appendRow:@"":@"":@"00000003":@"S_4BYTE_LITERALS"]; break;
case S_8BYTE_LITERALS: [node.details appendRow:@"":@"":@"00000004":@"S_8BYTE_LITERALS"]; break;
case S_LITERAL_POINTERS: [node.details appendRow:@"":@"":@"00000005":@"S_LITERAL_POINTERS"]; break;
case S_NON_LAZY_SYMBOL_POINTERS: [node.details appendRow:@"":@"":@"00000006":@"S_NON_LAZY_SYMBOL_POINTERS"]; break;
case S_LAZY_SYMBOL_POINTERS: [node.details appendRow:@"":@"":@"00000007":@"S_LAZY_SYMBOL_POINTERS"]; break;
case S_SYMBOL_STUBS: [node.details appendRow:@"":@"":@"00000008":@"S_SYMBOL_STUBS"]; break;
case S_MOD_INIT_FUNC_POINTERS: [node.details appendRow:@"":@"":@"00000009":@"S_MOD_INIT_FUNC_POINTERS"]; break;
case S_MOD_TERM_FUNC_POINTERS: [node.details appendRow:@"":@"":@"0000000A":@"S_MOD_TERM_FUNC_POINTERS"]; break;
case S_COALESCED: [node.details appendRow:@"":@"":@"0000000B":@"S_COALESCED"]; break;
case S_GB_ZEROFILL: [node.details appendRow:@"":@"":@"0000000C":@"S_GB_ZEROFILL"]; break;
case S_INTERPOSING: [node.details appendRow:@"":@"":@"0000000D":@"S_INTERPOSING"]; break;
case S_16BYTE_LITERALS: [node.details appendRow:@"":@"":@"0000000E":@"S_16BYTE_LITERALS"]; break;
case S_DTRACE_DOF: [node.details appendRow:@"":@"":@"0000000F":@"S_DTRACE_DOF"]; break;
case S_LAZY_DYLIB_SYMBOL_POINTERS: [node.details appendRow:@"":@"":@"00000010":@"S_LAZY_DYLIB_SYMBOL_POINTERS"]; break;
case S_THREAD_LOCAL_REGULAR: [node.details appendRow:@"":@"":@"00000011":@"S_THREAD_LOCAL_REGULAR"]; break;
case S_THREAD_LOCAL_ZEROFILL: [node.details appendRow:@"":@"":@"00000012":@"S_THREAD_LOCAL_ZEROFILL"]; break;
case S_THREAD_LOCAL_VARIABLES: [node.details appendRow:@"":@"":@"00000013":@"S_THREAD_LOCAL_VARIABLES"]; break;
case S_THREAD_LOCAL_VARIABLE_POINTERS: [node.details appendRow:@"":@"":@"00000014":@"S_THREAD_LOCAL_VARIABLE_POINTERS"]; break;
case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS: [node.details appendRow:@"":@"":@"00000015":@"S_THREAD_LOCAL_INIT_FUNCTION_POINTERS"]; break;
}
if (section->flags & S_ATTR_PURE_INSTRUCTIONS) [node.details appendRow:@"":@"":@"80000000":@"S_ATTR_PURE_INSTRUCTIONS"];
if (section->flags & S_ATTR_NO_TOC) [node.details appendRow:@"":@"":@"40000000":@"S_ATTR_NO_TOC"];
if (section->flags & S_ATTR_STRIP_STATIC_SYMS) [node.details appendRow:@"":@"":@"20000000":@"S_ATTR_STRIP_STATIC_SYMS"];
if (section->flags & S_ATTR_NO_DEAD_STRIP) [node.details appendRow:@"":@"":@"10000000":@"S_ATTR_NO_DEAD_STRIP"];
if (section->flags & S_ATTR_LIVE_SUPPORT) [node.details appendRow:@"":@"":@"08000000":@"S_ATTR_LIVE_SUPPORT"];
if (section->flags & S_ATTR_SELF_MODIFYING_CODE) [node.details appendRow:@"":@"":@"04000000":@"S_ATTR_SELF_MODIFYING_CODE"];
if (section->flags & S_ATTR_DEBUG) [node.details appendRow:@"":@"":@"02000000":@"S_ATTR_DEBUG"];
if (section->flags & S_ATTR_SOME_INSTRUCTIONS) [node.details appendRow:@"":@"":@"00000400":@"S_ATTR_SOME_INSTRUCTIONS"];
if (section->flags & S_ATTR_EXT_RELOC) [node.details appendRow:@"":@"":@"00000200":@"S_ATTR_EXT_RELOC"];
if (section->flags & S_ATTR_LOC_RELOC) [node.details appendRow:@"":@"":@"00000100":@"S_ATTR_LOC_RELOC"];
//符号索引
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:(section->flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
(section->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
(section->flags & SECTION_TYPE) == S_LAZY_DYLIB_SYMBOL_POINTERS ||
(section->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ? @"Indirect Sym Index" : @"Reserved1"
:[NSString stringWithFormat:@"%u", section->reserved1]];
//字号大小或者数量
[dataController read_uint32:range lastReadHex:&lastReadHex];
[node.details appendRow:[NSString stringWithFormat:@"%.8lX", range.location]
:lastReadHex
:(section->flags & SECTION_TYPE) == S_SYMBOL_STUBS ? @"Size of Stubs" : @"Reserved2"
:[NSString stringWithFormat:@"%u", section->reserved2]];
return node;
}