From 6620a4dc5a4dfafcf30fb42f838d0a04828621d5 Mon Sep 17 00:00:00 2001 From: eugeneyang Date: Wed, 5 Oct 2016 05:24:25 +0800 Subject: [PATCH] add source code --- .gitignore | 110 ++++++ .gitmodules | 3 + README.md | 72 ++++ app2dylib.xcodeproj/project.pbxproj | 372 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + class-dump | 1 + makefile | 14 + src/app2dylib_template.hpp | 145 +++++++ src/main.mm | 140 +++++++ 9 files changed, 864 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 app2dylib.xcodeproj/project.pbxproj create mode 100644 app2dylib.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 160000 class-dump create mode 100644 makefile create mode 100644 src/app2dylib_template.hpp create mode 100644 src/main.mm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..373d0d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,110 @@ +app2dylib + + +# svn +*.svn* + +# mac +__MACOSX +*.DS_Store* +*._* +*.lock +*.Spotlight-V100 +*.Trashes +*ehthumbs.db +*Thumbs.db + +# Python +*.pyc +__pycache__/ + + +# Vim +*.swp +*.swo +*.swn + +# Xcode +*~.nib +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.xcscmblueprint +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate + +# generated files +bin/ +gen/ + +# built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# Local configuration file (sdk path, etc) +local.properties + +# Eclipse project files +.classpath +.project +.settings/ + +# Proguard folder generated by Eclipse +proguard/ + +# Intellij project files +*.iml +*.ipr +*.iws +.idea/ + +#Pod +Pods/ +!podfile +!podfile.lock + +# Gradle files +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +#Android studio For eclipse +#build.gradle +#gradle/ +#gradlew +#gradlew.bat +#.gradle/ +# + + + +#tweak +_/ +.theos/ +obj/ +*.deb + + + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..70367dd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "class-dump"] + path = class-dump + url = https://github.com/0xced/class-dump diff --git a/README.md b/README.md index 3a947de..2803334 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,74 @@ # app2dylib A reverse engineering tool to convert iOS app to dylib + + +# Usage + +``` + +git clone --recursive https://github.com/tobefuturer/app2dylib.git +cd app2dylib && make +./app2dylib + +``` + +example : + +``` + +./app2dylib /tmp/AlipayWallet -o /tmp/libAlipayApp.dylib + +``` + +You can use libAlipayApp.dylib as a normal dynamic library. + +Call OC method or call C function like this: + +``` + +#import +#import + +#import +#import +#import + +int main(int argc, char * argv[]) { + NSString * dylibName = @"libAlipayApp"; + NSString * path = [[NSBundle mainBundle] pathForResource:dylibName ofType:@"dylib"]; + if (dlopen(path.UTF8String, RTLD_NOW) == NULL){ + NSLog(@"dlopen failed ,error %s", dlerror()); + return 0; + }; + + uint32_t dylib_count = _dyld_image_count(); + uint64_t slide = 0; + for (int i = 0; i < dylib_count; i ++) { + const char * name = _dyld_get_image_name(i); + if ([[NSString stringWithUTF8String:name] isEqualToString:path]) { + slide = _dyld_get_image_vmaddr_slide(i); + } + } + assert(slide != 0); + + + Class c = NSClassFromString(@"aluSecurity"); + NSString * plain = @"alipay"; + NSString * pubkey = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZ6i9VNEGEaZaYE7XffA9XRj15cp/ZKhHYY43EEva8LIhCWi29EREaF4JjZVMwFpUAfrL+9gpA7NMQmaMRHbrz1KHe2Ho4HpUhEac8M9zUbNvaDKSlhx0lq/15TQP+57oQbfJ9oKKd+he4Yd6jpBI3UtGmwJyN/T1S0DQ0aXR8OQIDAQAB"; + NSString * cipher = [c performSelector:NSSelectorFromString(@"rsaEncryptText:pubKey:") withObject:plain withObject:pubkey]; + NSLog(@"ciphertext: %@", cipher); + + typedef int (*BASE64_ENCODE_FUNC_TYPE) (char * output, int * output_size , char * input, int input_length); + + /** get function pointer*/ + BASE64_ENCODE_FUNC_TYPE base64_encode = (BASE64_ENCODE_FUNC_TYPE)(slide + 0xa798e4); + char output[1000] = {0}; + int length = 1000; + char * input = "alipay"; + base64_encode(output, & length, input, (int)strlen(input)); + NSLog(@"base64 length: %d , %s", length, output); + +} + + +``` diff --git a/app2dylib.xcodeproj/project.pbxproj b/app2dylib.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1f3e1bb --- /dev/null +++ b/app2dylib.xcodeproj/project.pbxproj @@ -0,0 +1,372 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 8F54CA371DA4298500221131 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8F54CA361DA4298500221131 /* main.mm */; }; + 8F54CA521DA4363200221131 /* libMachObjC.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F54CA421DA429A600221131 /* libMachObjC.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 8F54CA411DA429A600221131 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 013D1F1113A5AE5A00BF0A67; + remoteInfo = MachObjC; + }; + 8F54CA431DA429A600221131 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 01EB825F13A590D9003EDE60; + remoteInfo = "class-dump"; + }; + 8F54CA451DA429A600221131 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 013D1EFB13A5A0F100BF0A67; + remoteInfo = deprotect; + }; + 8F54CA471DA429A600221131 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 01B02CFF13A5B0DC0047BC53; + remoteInfo = formatType; + }; + 8F54CA491DA429A600221131 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 0165B8B11827137D00CC647F; + remoteInfo = UnitTests; + }; + 8F9B90F71DA5028700F54214 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 013D1F1013A5AE5A00BF0A67; + remoteInfo = MachObjC; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8F54CA291DA4292900221131 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 8F54CA2B1DA4292900221131 /* app2dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = app2dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + 8F54CA361DA4298500221131 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; + 8F54CA381DA429A600221131 /* class-dump.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "class-dump.xcodeproj"; path = "class-dump/class-dump.xcodeproj"; sourceTree = ""; }; + 8F54CA5A1DA441E000221131 /* app2dylib_template.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = app2dylib_template.hpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8F54CA281DA4292900221131 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8F54CA521DA4363200221131 /* libMachObjC.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8F54CA221DA4292900221131 = { + isa = PBXGroup; + children = ( + 8F54CA381DA429A600221131 /* class-dump.xcodeproj */, + 8F54CA351DA4296700221131 /* src */, + 8F54CA2C1DA4292900221131 /* Products */, + ); + sourceTree = ""; + }; + 8F54CA2C1DA4292900221131 /* Products */ = { + isa = PBXGroup; + children = ( + 8F54CA2B1DA4292900221131 /* app2dylib */, + ); + name = Products; + sourceTree = ""; + }; + 8F54CA351DA4296700221131 /* src */ = { + isa = PBXGroup; + children = ( + 8F54CA361DA4298500221131 /* main.mm */, + 8F54CA5A1DA441E000221131 /* app2dylib_template.hpp */, + ); + path = src; + sourceTree = ""; + }; + 8F54CA391DA429A600221131 /* Products */ = { + isa = PBXGroup; + children = ( + 8F54CA421DA429A600221131 /* libMachObjC.a */, + 8F54CA441DA429A600221131 /* class-dump */, + 8F54CA461DA429A600221131 /* deprotect */, + 8F54CA481DA429A600221131 /* formatType */, + 8F54CA4A1DA429A600221131 /* UnitTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8F54CA2A1DA4292900221131 /* app2dylib */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8F54CA321DA4292900221131 /* Build configuration list for PBXNativeTarget "app2dylib" */; + buildPhases = ( + 8F54CA271DA4292900221131 /* Sources */, + 8F54CA281DA4292900221131 /* Frameworks */, + 8F54CA291DA4292900221131 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 8F9B90F81DA5028700F54214 /* PBXTargetDependency */, + ); + name = app2dylib; + productName = app2dylib; + productReference = 8F54CA2B1DA4292900221131 /* app2dylib */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8F54CA231DA4292900221131 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0800; + ORGANIZATIONNAME = Jun; + TargetAttributes = { + 8F54CA2A1DA4292900221131 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 8F54CA261DA4292900221131 /* Build configuration list for PBXProject "app2dylib" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 8F54CA221DA4292900221131; + productRefGroup = 8F54CA2C1DA4292900221131 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 8F54CA391DA429A600221131 /* Products */; + ProjectRef = 8F54CA381DA429A600221131 /* class-dump.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 8F54CA2A1DA4292900221131 /* app2dylib */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 8F54CA421DA429A600221131 /* libMachObjC.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libMachObjC.a; + remoteRef = 8F54CA411DA429A600221131 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 8F54CA441DA429A600221131 /* class-dump */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.executable"; + path = "class-dump"; + remoteRef = 8F54CA431DA429A600221131 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 8F54CA461DA429A600221131 /* deprotect */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.executable"; + path = deprotect; + remoteRef = 8F54CA451DA429A600221131 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 8F54CA481DA429A600221131 /* formatType */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.executable"; + path = formatType; + remoteRef = 8F54CA471DA429A600221131 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 8F54CA4A1DA429A600221131 /* UnitTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = UnitTests.xctest; + remoteRef = 8F54CA491DA429A600221131 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXSourcesBuildPhase section */ + 8F54CA271DA4292900221131 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8F54CA371DA4298500221131 /* main.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 8F9B90F81DA5028700F54214 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = MachObjC; + targetProxy = 8F9B90F71DA5028700F54214 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 8F54CA301DA4292900221131 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 8F54CA311DA4292900221131 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + 8F54CA331DA4292900221131 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/class-dump/Source/**"; + }; + name = Debug; + }; + 8F54CA341DA4292900221131 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/class-dump/Source/**"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8F54CA261DA4292900221131 /* Build configuration list for PBXProject "app2dylib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8F54CA301DA4292900221131 /* Debug */, + 8F54CA311DA4292900221131 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8F54CA321DA4292900221131 /* Build configuration list for PBXNativeTarget "app2dylib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8F54CA331DA4292900221131 /* Debug */, + 8F54CA341DA4292900221131 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8F54CA231DA4292900221131 /* Project object */; +} diff --git a/app2dylib.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/app2dylib.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..03e32bd --- /dev/null +++ b/app2dylib.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/class-dump b/class-dump new file mode 160000 index 0000000..a8877b6 --- /dev/null +++ b/class-dump @@ -0,0 +1 @@ +Subproject commit a8877b6695f317816322134944a410de09da4911 diff --git a/makefile b/makefile new file mode 100644 index 0000000..6403957 --- /dev/null +++ b/makefile @@ -0,0 +1,14 @@ + +.PHONY:app2dylib + +TMP_FILE := libMachObjC.a app2dylib.dSYM/ build/ + +restore-symbol: + rm -f app2dylib + xcodebuild -project "app2dylib.xcodeproj" -target "app2dylib" -configuration "Release" CONFIGURATION_BUILD_DIR="$(shell pwd)" -jobs 4 build + rm -rf $(TMP_FILE) + + +clean: + rm -rf app2dylib $(TMP_FILE) + diff --git a/src/app2dylib_template.hpp b/src/app2dylib_template.hpp new file mode 100644 index 0000000..7934b11 --- /dev/null +++ b/src/app2dylib_template.hpp @@ -0,0 +1,145 @@ +// +// app2dylib_template.h +// app2dylib +// +// Created by EugeneYang on 16/10/5. +// Copyright © 2016年 Jun. All rights reserved. +// + +#ifndef app2dylib_template_h +#define app2dylib_template_h + + +#import +#include +#include +#import "CDFile.h" +#import "CDMachOFile.h" +#import "CDLCSymbolTable.h" +#import "CDLCSegment.h" +#import "CDSymbol.h" +#import "CDLCDynamicSymbolTable.h" +#import "CDLCLinkeditData.h" +#import "CDClassDump.h" +#import "CDFatFile.h" +#import "CDLCDyldInfo.h" +#import "CDSection.h" + +#define round(v,r) ( (v + (r-1) ) & (-r) ) + +extern NSMutableSet * rebasePointerSet; + + +#define PAGEZERO_SIZE_AFTER_MODIFY 0x4000 + +template +void app2dylib(NSString *inpath, NSString * outpath){ + + NSString * dylibName = [outpath lastPathComponent]; + NSString * dylibPath = [@"/usr/lib/" stringByAppendingString:dylibName]; + + NSMutableData * outData = [[NSMutableData alloc] initWithContentsOfFile:inpath]; + + CDFile * ofile = [CDFile fileWithContentsOfFile:inpath searchPathState:nil]; + + CDMachOFile * machOFile = (CDMachOFile *)ofile; + CDLCSegment * pagezeroSeg = [machOFile segmentWithName:@"__PAGEZERO"]; + [machOFile.dyldInfo performSelector:@selector(logRebaseInfo)]; + + auto seg_cmd = (segment_command_t *)((char *)outData.mutableBytes + pagezeroSeg.commandOffset); + const uint64 PAGEZERO_SIZE_DELTA = seg_cmd -> vmsize - PAGEZERO_SIZE_AFTER_MODIFY; + + auto header = (mach_header_t * )outData.mutableBytes; + header -> filetype = MH_DYLIB; + header -> flags = MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL | MH_NO_REEXPORTED_DYLIBS; + + for (CDLCSegment *seg in [machOFile segments]) { + auto seg_cmd = (segment_command_t *)((char *)outData.mutableBytes + seg.commandOffset); + assert([seg.name isEqualToString:pagezeroSeg.name] || seg_cmd -> vmaddr > PAGEZERO_SIZE_DELTA); + seg_cmd -> vmaddr -= PAGEZERO_SIZE_DELTA; + + + char * segment_end = (char *)seg_cmd + (seg.cmdsize); + for (auto sec = (section_t *)(seg_cmd + 1); (char *)sec < (char*)segment_end; sec += 1) { + assert(sec -> addr > PAGEZERO_SIZE_DELTA); + sec -> addr -= PAGEZERO_SIZE_DELTA; + } + } + + auto __pagezero_seg_cmd = (segment_command_t *) ((char *)outData.mutableBytes + sizeof(mach_header_t)); + __pagezero_seg_cmd -> vmaddr = 0; + __pagezero_seg_cmd -> vmsize = PAGEZERO_SIZE_AFTER_MODIFY; + __pagezero_seg_cmd -> maxprot = 0x3; + __pagezero_seg_cmd -> initprot = 0x3; + strcpy(__pagezero_seg_cmd -> segname, "__ZERO"); + + + + + + CDLCDyldInfo *dyldInfo = machOFile.dyldInfo; + uint32 dylib_cmd_size = round((int)dylibPath.length + 1,8) + sizeof(dylib_command_t); + auto dylib_cmd = (dylib_command_t *)((char *)outData.mutableBytes + dyldInfo.commandOffset); + char *loadcmd_end = (char *)outData.mutableBytes + sizeof(mach_header_t) + header -> sizeofcmds; + + { + CDLCSegment *TEXT_seg = [machOFile segmentWithName:@"__TEXT"]; + CDSection *text_sec = [TEXT_seg sectionWithName:@"__text"]; + + uint64_t fileOffset_text_sec = [text_sec fileOffsetForAddress:text_sec.addr]; + + uint64_t need_space = sizeof(mach_header_t) + header -> sizeofcmds + dylib_cmd_size; + if (fileOffset_text_sec < need_space) { + NSLog(@"It seem there is not empty sapce to insert dylib_command"); + exit(1); + } + } + + + long movesize = loadcmd_end - (char *)dylib_cmd; + void *moveto = (char * )dylib_cmd + dylib_cmd_size; + memmove(moveto, dylib_cmd, movesize); + + dylib_cmd -> cmd = LC_ID_DYLIB; + dylib_cmd -> cmdsize = dylib_cmd_size; + dylib_cmd -> dylib.name.offset = sizeof(dylib_command_t); + dylib_cmd -> dylib.timestamp = 1; + dylib_cmd -> dylib.current_version = 0x10000; + dylib_cmd -> dylib.compatibility_version = 0x10000; + strcpy((char *)dylib_cmd + sizeof(dylib_command_t), dylibPath.UTF8String); + + + header -> ncmds += 1; + header -> sizeofcmds += dylib_cmd_size; + + + for (NSNumber * num in rebasePointerSet) { + uint64_t addr = [num unsignedLongLongValue]; + uint64_t offset = [machOFile dataOffsetForAddress:addr]; + auto locationToFix = (IntTypeForPointer *) ((char *)outData.mutableBytes + (uint32_t)offset); + (* locationToFix) -= PAGEZERO_SIZE_DELTA; + } + + + + char * nlistsData = (char *)outData.mutableBytes + machOFile.symbolTable.symoff; + + + nlist_t * list = (nlist_t * )nlistsData; + for (int i = 0; i < machOFile.symbolTable.nsyms; i ++){ + if(((list[i].n_type & N_TYPE) == N_SECT) && (list[i].n_sect != NO_SECT)){ + if (list[i].n_value > PAGEZERO_SIZE_DELTA) { + list[i].n_value -= PAGEZERO_SIZE_DELTA; + } + } + } + + + [outData writeToFile:outpath atomically:true]; + chmod(outpath.UTF8String, 0755); + +} + + + +#endif /* app2dylib_template_h */ diff --git a/src/main.mm b/src/main.mm new file mode 100644 index 0000000..251e741 --- /dev/null +++ b/src/main.mm @@ -0,0 +1,140 @@ +// +// main.m +// restore-symbol +// +// Created by EugeneYang on 16/8/16. +// +// + +#import +#include +#include +#import "CDFile.h" +#import "CDMachOFile.h" +#import "CDLCSymbolTable.h" +#import "CDLCSegment.h" +#import "CDSymbol.h" +#import "CDLCDynamicSymbolTable.h" +#import "CDLCLinkeditData.h" +#import "CDClassDump.h" +#import "CDFatFile.h" +#import "CDLCDyldInfo.h" +#import "CDSection.h" + + +#include +#include +#include +#include + + + +#import "app2dylib_template.hpp" + + + + +NSMutableSet* rebasePointerSet = nil; + + +@implementation CDLCDyldInfo (app2dylib) + +//categories overwrite the original method(empty implement) to get callback for every rebase address +- (void)rebaseAddress:(uint64_t)address type:(uint8_t)type; +{ + if (self.machOFile.uses64BitABI) { + [rebasePointerSet addObject:[NSNumber numberWithUnsignedLongLong:address]]; + } +} + +@end + + +#define APP2DYLIB_BASE_VERSION "1.0 (64 bit)" + + +void print_usage(void) +{ + NSLog(@ + "\n" + "app2dylib %s\n" + "\n" + "Usage: app2dylib -o \n" + "\n" + " app-mach-o-file : an executable file for app (decrypted)\n" + "\n" + , + APP2DYLIB_BASE_VERSION + ); +} + + + + + + +int main(int argc, char * argv[]) { + + + NSString * inpath = nil; + + NSString * outpath = nil; + + int ch; + + struct option longopts[] = { + { "output", required_argument, NULL, 'o' }, + { NULL, 0, NULL, 0 }, + }; + + + while ( (ch = getopt_long(argc, argv, "o:", longopts, NULL)) != -1) { + switch (ch) { + case 'o': + outpath = [NSString stringWithUTF8String:optarg]; + break; + default: + break; + } + } + + if (optind < argc) { + inpath = [NSString stringWithUTF8String:argv[optind]]; + } + + + if (inpath.length == 0 || outpath.length == 0) { + print_usage(); + exit(1); + } + + + rebasePointerSet = [NSMutableSet set]; + + CDFile * ofile = [CDFile fileWithContentsOfFile:inpath searchPathState:nil]; + + + if ([ofile isKindOfClass:[CDFatFile class]] ) { + NSLog(@"app2dylib supports armv7 and arm64 archtecture, but not support fat file. Please use lipo to thin the image file first."); + exit(1); + } + + + + + CDMachOFile * machOFile = (CDMachOFile *)ofile; + if ((machOFile.flags & MH_PIE) == 0){ + NSLog(@"%@ is not a position-independent executable, can\'t convert to dylib.", inpath); + exit(1); + } + + const bool Is32Bit = ! machOFile.uses64BitABI; + if (Is32Bit) { + app2dylib< uint32_t , struct mach_header, struct segment_command, struct section, struct nlist, struct dylib_command>(inpath, outpath); + } else { + app2dylib< uint64_t , struct mach_header_64, struct segment_command_64, struct section_64, struct nlist_64, struct dylib_command>(inpath, outpath); + } + + NSLog(@"Remember to codesign the generated dylib."); + fprintf(stderr,"=========== Finish ============\n"); +}