macho_id.cc revision 4ac61acb3a7dad6ce722fe07564be8ec92713228
1fd98b2af3773437487af0df22c428f3db630949awaylonis// Copyright (c) 2006, Google Inc. 2fd98b2af3773437487af0df22c428f3db630949awaylonis// All rights reserved. 3fd98b2af3773437487af0df22c428f3db630949awaylonis// 4fd98b2af3773437487af0df22c428f3db630949awaylonis// Redistribution and use in source and binary forms, with or without 5fd98b2af3773437487af0df22c428f3db630949awaylonis// modification, are permitted provided that the following conditions are 6fd98b2af3773437487af0df22c428f3db630949awaylonis// met: 7fd98b2af3773437487af0df22c428f3db630949awaylonis// 8fd98b2af3773437487af0df22c428f3db630949awaylonis// * Redistributions of source code must retain the above copyright 9fd98b2af3773437487af0df22c428f3db630949awaylonis// notice, this list of conditions and the following disclaimer. 10fd98b2af3773437487af0df22c428f3db630949awaylonis// * Redistributions in binary form must reproduce the above 11fd98b2af3773437487af0df22c428f3db630949awaylonis// copyright notice, this list of conditions and the following disclaimer 12fd98b2af3773437487af0df22c428f3db630949awaylonis// in the documentation and/or other materials provided with the 13fd98b2af3773437487af0df22c428f3db630949awaylonis// distribution. 14fd98b2af3773437487af0df22c428f3db630949awaylonis// * Neither the name of Google Inc. nor the names of its 15fd98b2af3773437487af0df22c428f3db630949awaylonis// contributors may be used to endorse or promote products derived from 16fd98b2af3773437487af0df22c428f3db630949awaylonis// this software without specific prior written permission. 17fd98b2af3773437487af0df22c428f3db630949awaylonis// 18fd98b2af3773437487af0df22c428f3db630949awaylonis// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19fd98b2af3773437487af0df22c428f3db630949awaylonis// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20fd98b2af3773437487af0df22c428f3db630949awaylonis// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21fd98b2af3773437487af0df22c428f3db630949awaylonis// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22fd98b2af3773437487af0df22c428f3db630949awaylonis// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23fd98b2af3773437487af0df22c428f3db630949awaylonis// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24fd98b2af3773437487af0df22c428f3db630949awaylonis// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25fd98b2af3773437487af0df22c428f3db630949awaylonis// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26fd98b2af3773437487af0df22c428f3db630949awaylonis// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27fd98b2af3773437487af0df22c428f3db630949awaylonis// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28fd98b2af3773437487af0df22c428f3db630949awaylonis// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29e5dc60822e5938fea2ae892ccddb906641ba174emmentovai 30fd98b2af3773437487af0df22c428f3db630949awaylonis// macho_id.cc: Functions to gather identifying information from a macho file 31fd98b2af3773437487af0df22c428f3db630949awaylonis// 32fd98b2af3773437487af0df22c428f3db630949awaylonis// See macho_id.h for documentation 33fd98b2af3773437487af0df22c428f3db630949awaylonis// 34fd98b2af3773437487af0df22c428f3db630949awaylonis// Author: Dan Waylonis 35fd98b2af3773437487af0df22c428f3db630949awaylonis 368aef89f021c687e96c66cb99b5dac312324e785cladderbreakerextern "C" { // necessary for Leopard 378aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <fcntl.h> 388aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <mach-o/loader.h> 398aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <mach-o/swap.h> 408aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <openssl/md5.h> 418aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <openssl/sha.h> 428aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <stdio.h> 438aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <stdlib.h> 448aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <string.h> 458aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <sys/time.h> 468aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <sys/types.h> 478aef89f021c687e96c66cb99b5dac312324e785cladderbreaker #include <unistd.h> 488aef89f021c687e96c66cb99b5dac312324e785cladderbreaker} 49fd98b2af3773437487af0df22c428f3db630949awaylonis 50fd98b2af3773437487af0df22c428f3db630949awaylonis#include "common/mac/macho_id.h" 51fd98b2af3773437487af0df22c428f3db630949awaylonis#include "common/mac/macho_walker.h" 52255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek#include "common/mac/macho_utilities.h" 53fd98b2af3773437487af0df22c428f3db630949awaylonis 54fd98b2af3773437487af0df22c428f3db630949awaylonisnamespace MacFileUtilities { 55fd98b2af3773437487af0df22c428f3db630949awaylonis 564ac61acb3a7dad6ce722fe07564be8ec92713228dmaclachMachoID::MachoID(const char *path) 574ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach : file_(0), 584ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach crc_(0), 594ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach md5_context_(), 604ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach sha1_context_(), 614ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach update_function_(NULL) { 62fd98b2af3773437487af0df22c428f3db630949awaylonis strlcpy(path_, path, sizeof(path_)); 63fd98b2af3773437487af0df22c428f3db630949awaylonis file_ = open(path, O_RDONLY); 64fd98b2af3773437487af0df22c428f3db630949awaylonis} 65fd98b2af3773437487af0df22c428f3db630949awaylonis 66fd98b2af3773437487af0df22c428f3db630949awaylonisMachoID::~MachoID() { 67fd98b2af3773437487af0df22c428f3db630949awaylonis if (file_ != -1) 68fd98b2af3773437487af0df22c428f3db630949awaylonis close(file_); 69fd98b2af3773437487af0df22c428f3db630949awaylonis} 70fd98b2af3773437487af0df22c428f3db630949awaylonis 71fd98b2af3773437487af0df22c428f3db630949awaylonis// The CRC info is from http://en.wikipedia.org/wiki/Adler-32 72fd98b2af3773437487af0df22c428f3db630949awaylonis// With optimizations from http://www.zlib.net/ 73fd98b2af3773437487af0df22c428f3db630949awaylonis 74fd98b2af3773437487af0df22c428f3db630949awaylonis// The largest prime smaller than 65536 75fd98b2af3773437487af0df22c428f3db630949awaylonis#define MOD_ADLER 65521 76fd98b2af3773437487af0df22c428f3db630949awaylonis// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1 77fd98b2af3773437487af0df22c428f3db630949awaylonis#define MAX_BLOCK 5552 78fd98b2af3773437487af0df22c428f3db630949awaylonis 79fd98b2af3773437487af0df22c428f3db630949awaylonisvoid MachoID::UpdateCRC(unsigned char *bytes, size_t size) { 80fd98b2af3773437487af0df22c428f3db630949awaylonis// Unrolled loops for summing 81fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO1(buf,i) {sum1 += (buf)[i]; sum2 += sum1;} 82fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); 83fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); 84fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); 85fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO16(buf) DO8(buf,0); DO8(buf,8); 86fd98b2af3773437487af0df22c428f3db630949awaylonis // Split up the crc 87fd98b2af3773437487af0df22c428f3db630949awaylonis uint32_t sum1 = crc_ & 0xFFFF; 88fd98b2af3773437487af0df22c428f3db630949awaylonis uint32_t sum2 = (crc_ >> 16) & 0xFFFF; 89fd98b2af3773437487af0df22c428f3db630949awaylonis 90fd98b2af3773437487af0df22c428f3db630949awaylonis // Do large blocks 91fd98b2af3773437487af0df22c428f3db630949awaylonis while (size >= MAX_BLOCK) { 92fd98b2af3773437487af0df22c428f3db630949awaylonis size -= MAX_BLOCK; 93fd98b2af3773437487af0df22c428f3db630949awaylonis int block_count = MAX_BLOCK / 16; 94fd98b2af3773437487af0df22c428f3db630949awaylonis do { 95fd98b2af3773437487af0df22c428f3db630949awaylonis DO16(bytes); 96fd98b2af3773437487af0df22c428f3db630949awaylonis bytes += 16; 97fd98b2af3773437487af0df22c428f3db630949awaylonis } while (--block_count); 98fd98b2af3773437487af0df22c428f3db630949awaylonis sum1 %= MOD_ADLER; 99fd98b2af3773437487af0df22c428f3db630949awaylonis sum2 %= MOD_ADLER; 100fd98b2af3773437487af0df22c428f3db630949awaylonis } 101fd98b2af3773437487af0df22c428f3db630949awaylonis 102fd98b2af3773437487af0df22c428f3db630949awaylonis // Do remaining bytes 103fd98b2af3773437487af0df22c428f3db630949awaylonis if (size) { 104fd98b2af3773437487af0df22c428f3db630949awaylonis while (size >= 16) { 105fd98b2af3773437487af0df22c428f3db630949awaylonis size -= 16; 106fd98b2af3773437487af0df22c428f3db630949awaylonis DO16(bytes); 107fd98b2af3773437487af0df22c428f3db630949awaylonis bytes += 16; 108fd98b2af3773437487af0df22c428f3db630949awaylonis } 109fd98b2af3773437487af0df22c428f3db630949awaylonis while (size--) { 110fd98b2af3773437487af0df22c428f3db630949awaylonis sum1 += *bytes++; 111fd98b2af3773437487af0df22c428f3db630949awaylonis sum2 += sum1; 112fd98b2af3773437487af0df22c428f3db630949awaylonis } 113fd98b2af3773437487af0df22c428f3db630949awaylonis sum1 %= MOD_ADLER; 114fd98b2af3773437487af0df22c428f3db630949awaylonis sum2 %= MOD_ADLER; 115fd98b2af3773437487af0df22c428f3db630949awaylonis crc_ = (sum2 << 16) | sum1; 116fd98b2af3773437487af0df22c428f3db630949awaylonis } 117fd98b2af3773437487af0df22c428f3db630949awaylonis} 118fd98b2af3773437487af0df22c428f3db630949awaylonis 119fd98b2af3773437487af0df22c428f3db630949awaylonisvoid MachoID::UpdateMD5(unsigned char *bytes, size_t size) { 120fd98b2af3773437487af0df22c428f3db630949awaylonis MD5_Update(&md5_context_, bytes, size); 121fd98b2af3773437487af0df22c428f3db630949awaylonis} 122fd98b2af3773437487af0df22c428f3db630949awaylonis 123fd98b2af3773437487af0df22c428f3db630949awaylonisvoid MachoID::UpdateSHA1(unsigned char *bytes, size_t size) { 124fd98b2af3773437487af0df22c428f3db630949awaylonis SHA_Update(&sha1_context_, bytes, size); 125fd98b2af3773437487af0df22c428f3db630949awaylonis} 126fd98b2af3773437487af0df22c428f3db630949awaylonis 1274ac61acb3a7dad6ce722fe07564be8ec92713228dmaclachvoid MachoID::Update(MachoWalker *walker, off_t offset, size_t size) { 12887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis if (!update_function_ || !size) 12987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis return; 13087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis 13187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis // Read up to 4k bytes at a time 13287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis unsigned char buffer[4096]; 13387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis size_t buffer_size; 13487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis off_t file_offset = offset; 13587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis while (size > 0) { 13687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis if (size > sizeof(buffer)) { 13787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis buffer_size = sizeof(buffer); 13887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis size -= buffer_size; 13987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis } else { 14087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis buffer_size = size; 14187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis size = 0; 14287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis } 14387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis 14487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis if (!walker->ReadBytes(buffer, buffer_size, file_offset)) 14587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis return; 14687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis 14787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis (this->*update_function_)(buffer, buffer_size); 14887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis file_offset += buffer_size; 14987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis } 150fd98b2af3773437487af0df22c428f3db630949awaylonis} 151fd98b2af3773437487af0df22c428f3db630949awaylonis 152fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) { 153255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek struct breakpad_uuid_command uuid_cmd; 154fd98b2af3773437487af0df22c428f3db630949awaylonis MachoWalker walker(path_, UUIDWalkerCB, &uuid_cmd); 155fd98b2af3773437487af0df22c428f3db630949awaylonis 156fd98b2af3773437487af0df22c428f3db630949awaylonis uuid_cmd.cmd = 0; 157fd98b2af3773437487af0df22c428f3db630949awaylonis if (!walker.WalkHeader(cpu_type)) 158fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 159fd98b2af3773437487af0df22c428f3db630949awaylonis 160fd98b2af3773437487af0df22c428f3db630949awaylonis // If we found the command, we'll have initialized the uuid_command 161fd98b2af3773437487af0df22c428f3db630949awaylonis // structure 162fd98b2af3773437487af0df22c428f3db630949awaylonis if (uuid_cmd.cmd == LC_UUID) { 163fd98b2af3773437487af0df22c428f3db630949awaylonis memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid)); 164fd98b2af3773437487af0df22c428f3db630949awaylonis return true; 165fd98b2af3773437487af0df22c428f3db630949awaylonis } 166fd98b2af3773437487af0df22c428f3db630949awaylonis 167fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 168fd98b2af3773437487af0df22c428f3db630949awaylonis} 169fd98b2af3773437487af0df22c428f3db630949awaylonis 170fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) { 171fd98b2af3773437487af0df22c428f3db630949awaylonis struct dylib_command dylib_cmd; 172fd98b2af3773437487af0df22c428f3db630949awaylonis MachoWalker walker(path_, IDWalkerCB, &dylib_cmd); 173fd98b2af3773437487af0df22c428f3db630949awaylonis 174fd98b2af3773437487af0df22c428f3db630949awaylonis dylib_cmd.cmd = 0; 175fd98b2af3773437487af0df22c428f3db630949awaylonis if (!walker.WalkHeader(cpu_type)) 176fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 177fd98b2af3773437487af0df22c428f3db630949awaylonis 178fd98b2af3773437487af0df22c428f3db630949awaylonis // If we found the command, we'll have initialized the dylib_command 179fd98b2af3773437487af0df22c428f3db630949awaylonis // structure 180fd98b2af3773437487af0df22c428f3db630949awaylonis if (dylib_cmd.cmd == LC_ID_DYLIB) { 1811a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker // Take the hashed filename, version, and compatability version bytes 1821a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker // to form the first 12 bytes, pad the rest with zeros 1831a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker 1841a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker // create a crude hash of the filename to generate the first 4 bytes 1851a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker identifier[0] = 0; 1861a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker identifier[1] = 0; 1871a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker identifier[2] = 0; 1881a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker identifier[3] = 0; 1891a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker 1904ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) { 1911a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker identifier[j%4] += path_[i]; 1921a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker } 1931a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker 194fd98b2af3773437487af0df22c428f3db630949awaylonis identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF; 195fd98b2af3773437487af0df22c428f3db630949awaylonis identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF; 196fd98b2af3773437487af0df22c428f3db630949awaylonis identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF; 197fd98b2af3773437487af0df22c428f3db630949awaylonis identifier[7] = dylib_cmd.dylib.current_version & 0xFF; 198fd98b2af3773437487af0df22c428f3db630949awaylonis identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF; 199fd98b2af3773437487af0df22c428f3db630949awaylonis identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF; 200fd98b2af3773437487af0df22c428f3db630949awaylonis identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF; 201fd98b2af3773437487af0df22c428f3db630949awaylonis identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF; 202baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker identifier[12] = (cpu_type >> 24) & 0xFF; 203baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker identifier[13] = (cpu_type >> 16) & 0xFF; 204baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker identifier[14] = (cpu_type >> 8) & 0xFF; 205baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker identifier[15] = cpu_type & 0xFF; 206fd98b2af3773437487af0df22c428f3db630949awaylonis 207fd98b2af3773437487af0df22c428f3db630949awaylonis return true; 208fd98b2af3773437487af0df22c428f3db630949awaylonis } 209fd98b2af3773437487af0df22c428f3db630949awaylonis 210fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 211fd98b2af3773437487af0df22c428f3db630949awaylonis} 212fd98b2af3773437487af0df22c428f3db630949awaylonis 213fd98b2af3773437487af0df22c428f3db630949awaylonisuint32_t MachoID::Adler32(int cpu_type) { 214fd98b2af3773437487af0df22c428f3db630949awaylonis MachoWalker walker(path_, WalkerCB, this); 215fd98b2af3773437487af0df22c428f3db630949awaylonis update_function_ = &MachoID::UpdateCRC; 216fd98b2af3773437487af0df22c428f3db630949awaylonis crc_ = 0; 217fd98b2af3773437487af0df22c428f3db630949awaylonis 218fd98b2af3773437487af0df22c428f3db630949awaylonis if (!walker.WalkHeader(cpu_type)) 219fd98b2af3773437487af0df22c428f3db630949awaylonis return 0; 220fd98b2af3773437487af0df22c428f3db630949awaylonis 221fd98b2af3773437487af0df22c428f3db630949awaylonis return crc_; 222fd98b2af3773437487af0df22c428f3db630949awaylonis} 223fd98b2af3773437487af0df22c428f3db630949awaylonis 224fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::MD5(int cpu_type, unsigned char identifier[16]) { 225fd98b2af3773437487af0df22c428f3db630949awaylonis MachoWalker walker(path_, WalkerCB, this); 226fd98b2af3773437487af0df22c428f3db630949awaylonis update_function_ = &MachoID::UpdateMD5; 227fd98b2af3773437487af0df22c428f3db630949awaylonis 228fd98b2af3773437487af0df22c428f3db630949awaylonis if (MD5_Init(&md5_context_)) { 229fd98b2af3773437487af0df22c428f3db630949awaylonis if (!walker.WalkHeader(cpu_type)) 230fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 231fd98b2af3773437487af0df22c428f3db630949awaylonis 232fd98b2af3773437487af0df22c428f3db630949awaylonis MD5_Final(identifier, &md5_context_); 233fd98b2af3773437487af0df22c428f3db630949awaylonis return true; 234fd98b2af3773437487af0df22c428f3db630949awaylonis } 235fd98b2af3773437487af0df22c428f3db630949awaylonis 236fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 237fd98b2af3773437487af0df22c428f3db630949awaylonis} 238fd98b2af3773437487af0df22c428f3db630949awaylonis 239fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::SHA1(int cpu_type, unsigned char identifier[16]) { 240fd98b2af3773437487af0df22c428f3db630949awaylonis MachoWalker walker(path_, WalkerCB, this); 241fd98b2af3773437487af0df22c428f3db630949awaylonis update_function_ = &MachoID::UpdateSHA1; 242fd98b2af3773437487af0df22c428f3db630949awaylonis 243fd98b2af3773437487af0df22c428f3db630949awaylonis if (SHA_Init(&sha1_context_)) { 244fd98b2af3773437487af0df22c428f3db630949awaylonis if (!walker.WalkHeader(cpu_type)) 245fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 246fd98b2af3773437487af0df22c428f3db630949awaylonis 247fd98b2af3773437487af0df22c428f3db630949awaylonis SHA_Final(identifier, &sha1_context_); 248fd98b2af3773437487af0df22c428f3db630949awaylonis return true; 249fd98b2af3773437487af0df22c428f3db630949awaylonis } 250fd98b2af3773437487af0df22c428f3db630949awaylonis 251fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 252fd98b2af3773437487af0df22c428f3db630949awaylonis} 253fd98b2af3773437487af0df22c428f3db630949awaylonis 254fd98b2af3773437487af0df22c428f3db630949awaylonis// static 255fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, 256fd98b2af3773437487af0df22c428f3db630949awaylonis bool swap, void *context) { 257fd98b2af3773437487af0df22c428f3db630949awaylonis MachoID *macho_id = (MachoID *)context; 258fd98b2af3773437487af0df22c428f3db630949awaylonis 259fd98b2af3773437487af0df22c428f3db630949awaylonis if (cmd->cmd == LC_SEGMENT) { 260fd98b2af3773437487af0df22c428f3db630949awaylonis struct segment_command seg; 261fd98b2af3773437487af0df22c428f3db630949awaylonis 262fd98b2af3773437487af0df22c428f3db630949awaylonis if (!walker->ReadBytes(&seg, sizeof(seg), offset)) 263fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 264fd98b2af3773437487af0df22c428f3db630949awaylonis 265fd98b2af3773437487af0df22c428f3db630949awaylonis if (swap) 266fd98b2af3773437487af0df22c428f3db630949awaylonis swap_segment_command(&seg, NXHostByteOrder()); 267fd98b2af3773437487af0df22c428f3db630949awaylonis 268983264848d5372d8e64d62eb67f672c71e4b6470waylonis struct mach_header_64 header; 269983264848d5372d8e64d62eb67f672c71e4b6470waylonis off_t header_offset; 270983264848d5372d8e64d62eb67f672c71e4b6470waylonis 271983264848d5372d8e64d62eb67f672c71e4b6470waylonis if (!walker->CurrentHeader(&header, &header_offset)) 272983264848d5372d8e64d62eb67f672c71e4b6470waylonis return false; 273983264848d5372d8e64d62eb67f672c71e4b6470waylonis 27487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis // Process segments that have sections: 27587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis // (e.g., __TEXT, __DATA, __IMPORT, __OBJC) 27687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis offset += sizeof(struct segment_command); 27787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis struct section sec; 27887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis for (unsigned long i = 0; i < seg.nsects; ++i) { 27987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis if (!walker->ReadBytes(&sec, sizeof(sec), offset)) 28087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis return false; 28187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis 28287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis if (swap) 28387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis swap_section(&sec, 1, NXHostByteOrder()); 28487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis 2852e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker // sections of type S_ZEROFILL are "virtual" and contain no data 2862e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker // in the file itself 2872e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0) 2882e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker macho_id->Update(walker, header_offset + sec.offset, sec.size); 2892e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker 29087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis offset += sizeof(struct section); 29187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis } 292fd98b2af3773437487af0df22c428f3db630949awaylonis } else if (cmd->cmd == LC_SEGMENT_64) { 293fd98b2af3773437487af0df22c428f3db630949awaylonis struct segment_command_64 seg64; 294fd98b2af3773437487af0df22c428f3db630949awaylonis 295fd98b2af3773437487af0df22c428f3db630949awaylonis if (!walker->ReadBytes(&seg64, sizeof(seg64), offset)) 296fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 297fd98b2af3773437487af0df22c428f3db630949awaylonis 298fd98b2af3773437487af0df22c428f3db630949awaylonis if (swap) 299255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek breakpad_swap_segment_command_64(&seg64, NXHostByteOrder()); 300fd98b2af3773437487af0df22c428f3db630949awaylonis 301983264848d5372d8e64d62eb67f672c71e4b6470waylonis struct mach_header_64 header; 302983264848d5372d8e64d62eb67f672c71e4b6470waylonis off_t header_offset; 303983264848d5372d8e64d62eb67f672c71e4b6470waylonis 304983264848d5372d8e64d62eb67f672c71e4b6470waylonis if (!walker->CurrentHeader(&header, &header_offset)) 305983264848d5372d8e64d62eb67f672c71e4b6470waylonis return false; 306983264848d5372d8e64d62eb67f672c71e4b6470waylonis 30787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis // Process segments that have sections: 30887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis // (e.g., __TEXT, __DATA, __IMPORT, __OBJC) 30987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis offset += sizeof(struct segment_command_64); 31087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis struct section_64 sec64; 31187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis for (unsigned long i = 0; i < seg64.nsects; ++i) { 31287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis if (!walker->ReadBytes(&sec64, sizeof(sec64), offset)) 313fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 314fd98b2af3773437487af0df22c428f3db630949awaylonis 31587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis if (swap) 316255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek breakpad_swap_section_64(&sec64, 1, NXHostByteOrder()); 31787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis 3182e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker // sections of type S_ZEROFILL are "virtual" and contain no data 3192e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker // in the file itself 3202e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0) 3214ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach macho_id->Update(walker, 3224ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach header_offset + sec64.offset, 3234ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach (size_t)sec64.size); 3242e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker 32587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis offset += sizeof(struct section_64); 326fd98b2af3773437487af0df22c428f3db630949awaylonis } 327fd98b2af3773437487af0df22c428f3db630949awaylonis } 328fd98b2af3773437487af0df22c428f3db630949awaylonis 329fd98b2af3773437487af0df22c428f3db630949awaylonis // Continue processing 330fd98b2af3773437487af0df22c428f3db630949awaylonis return true; 331fd98b2af3773437487af0df22c428f3db630949awaylonis} 332fd98b2af3773437487af0df22c428f3db630949awaylonis 333fd98b2af3773437487af0df22c428f3db630949awaylonis// static 334fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, 335fd98b2af3773437487af0df22c428f3db630949awaylonis bool swap, void *context) { 336fd98b2af3773437487af0df22c428f3db630949awaylonis if (cmd->cmd == LC_UUID) { 337255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek struct breakpad_uuid_command *uuid_cmd = 338255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek (struct breakpad_uuid_command *)context; 339fd98b2af3773437487af0df22c428f3db630949awaylonis 340255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command), 341255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek offset)) 342fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 343fd98b2af3773437487af0df22c428f3db630949awaylonis 344fd98b2af3773437487af0df22c428f3db630949awaylonis if (swap) 345255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek breakpad_swap_uuid_command(uuid_cmd, NXHostByteOrder()); 346fd98b2af3773437487af0df22c428f3db630949awaylonis 347fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 348fd98b2af3773437487af0df22c428f3db630949awaylonis } 349fd98b2af3773437487af0df22c428f3db630949awaylonis 350fd98b2af3773437487af0df22c428f3db630949awaylonis // Continue processing 351fd98b2af3773437487af0df22c428f3db630949awaylonis return true; 352fd98b2af3773437487af0df22c428f3db630949awaylonis} 353fd98b2af3773437487af0df22c428f3db630949awaylonis 354fd98b2af3773437487af0df22c428f3db630949awaylonis// static 355fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, 356fd98b2af3773437487af0df22c428f3db630949awaylonis bool swap, void *context) { 357fd98b2af3773437487af0df22c428f3db630949awaylonis if (cmd->cmd == LC_ID_DYLIB) { 358fd98b2af3773437487af0df22c428f3db630949awaylonis struct dylib_command *dylib_cmd = (struct dylib_command *)context; 359fd98b2af3773437487af0df22c428f3db630949awaylonis 360fd98b2af3773437487af0df22c428f3db630949awaylonis if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset)) 361fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 362fd98b2af3773437487af0df22c428f3db630949awaylonis 363fd98b2af3773437487af0df22c428f3db630949awaylonis if (swap) 364fd98b2af3773437487af0df22c428f3db630949awaylonis swap_dylib_command(dylib_cmd, NXHostByteOrder()); 365fd98b2af3773437487af0df22c428f3db630949awaylonis 366fd98b2af3773437487af0df22c428f3db630949awaylonis return false; 367fd98b2af3773437487af0df22c428f3db630949awaylonis } 368fd98b2af3773437487af0df22c428f3db630949awaylonis 369fd98b2af3773437487af0df22c428f3db630949awaylonis // Continue processing 370fd98b2af3773437487af0df22c428f3db630949awaylonis return true; 371fd98b2af3773437487af0df22c428f3db630949awaylonis} 372fd98b2af3773437487af0df22c428f3db630949awaylonis 373fd98b2af3773437487af0df22c428f3db630949awaylonis} // namespace MacFileUtilities 374