[原]逆向iOS SDK -- _UIImageAtPath 的实现(SDK 6.1)

 

汇编代码:

; 状态:R0 = imageFileName, R1 = mainBundle, R2 = isRetina

      PUSH    {R4-R7,LR} ; R0 = imageFileName, R1 = mainBundle, R2 = isRetina

      ADD      R7, SP, #0xC

      PUSH.W  {R8,R10,R11}

      STR.W    R2, [SP,#0x18+var_1C]!

      MOV      R4, R0  ; R4 = R0 = imageFileName

      MOV      R0, #(selRef_length - 0x17BB0) ; selRef_length

      MOV      R10, R1 ; R10 = R1 = mainBundle

      ADD      R0, PC ; selRef_length

      LDR      R1, [R0] ; "length"

      MOV      R0, R4  ; R0 = R4 = imageFileName

      BLX.W    _objc_msgSend ; [imageFileName length]

      MOVS     R6, #0  ; R6 = 0

      CMP      R0, #0  ; check if R0 is 0

      BEQ.W    loc_17D1C ; if R0 is 0, goto the label

      MOV      R0, R4  ; R0 = R4 = imageFileName

      MOV      R1, R10 ; R1 = R10 = mainBundle

      BL     __UICacheNameForImageAtPath ; arg_0:imageFileName, arg_1:mainBundle, result:com.proteas.hello_Default.png

      MOVW     R8, #(:lower16:(__MergedGlobals_36 - 0x17BD4))

      MOV      R5, R0  ; R5 = R0 = imageCacheName

      MOVT.W   R8, #(:upper16:(__MergedGlobals_36 - 0x17BD4))

      ADD      R8, PC ; __MergedGlobals_36

      ADD.W    R11, R8, #0x10 ; R11 = R8 + 16

      MOV      R0, R11 ; lock, OSSpinLock*, 访问全局变量,加锁

      BLX.W    _OSSpinLockLock ; arg_0: OSSpinLock*

      LDR.W    R0, [R8,#(dword_62C524 - 0x62C510)] ; R0 = cachedImageMap, key:imageCacheName, value:UIImageObject

      MOVS      R6, #0  ; R6 = 0

      CBZ       R0, loc_17BEC ; if cachedImageMap is nil, goto the label

      MOV       R1, R5  ; R1 = R5 = imageCacheName

      BLX.W _CFDictionaryGetValue ; CFDictionaryGetValue(cachedImageMap, imageCacheName)

      MOV       R6, R0  ; R6 = R0 = cachedUIImageObject

loc_17BEC:

      MOV       R0, #(selRef_retainCount - 0x17BF8) ; selRef_retainCount

      ADD       R0, PC ; selRef_retainCount

      LDR       R1, [R0] ; "retainCount"

      MOV       R0, R6  ; R0 = R6 = cachedUIImageObject

      BLX.W     _objc_msgSend ; [cachedUIImageObject retainCount]

      CBNZ     R0, loc_17C08 ; if retainCount of cachedUIImageObject is not 0, goto the label

      MOV      R0, R11 ; lock

      BLX.W    _OSSpinLockUnlock

      B        loc_17C50

loc_17C08:

      MOV      R0, #(selRef__isCached - 0x17C14) ; selRef__isCached

      ADD      R0, PC ; selRef__isCached

      LDR      R1, [R0] ; R1 = "_isCached"

      MOV      R0, R6  ; R0 = R6 = cachedUIImageObject

      BLX.W    _objc_msgSend ; R0 = isCached

      TST.W    R0, #0xFF ; check if R0 is true

      BNE      loc_17C46 ; if not cached, goto the label

      MOV      R0, #(selRef_retain - 0x17C2C) ; selRef_retain

      ADD      R0, PC ; selRef_retain

      LDR      R1, [R0] ; "retain"

      MOV      R0, R6  ; R0 = R6 = cachedUIImageObject

      BLX.W    _objc_msgSend ; [cachedUIImageObject retain]

      MOVW     R0, #(:lower16:(selRef__setCached_ - 0x17C40))

      MOVS     R2, #1  ; R2 = 1

      MOVT.W   R0, #(:upper16:(selRef__setCached_ - 0x17C40))

      ADD      R0, PC ; selRef__setCached_

      LDR      R1, [R0] ; "_setCached:"

      MOV      R0, R6  ; R0 = R6 = cachedUIImageObject

      BLX.W    _objc_msgSend ; [cachedUIImageObject _setCached:YES]

loc_17C46:

      MOV      R0, R11 ; lock

      BLX.W    _OSSpinLockUnlock ; 释放锁

      CMP      R6, #0  ; check if cachedUIImageObject is nil

      BNE      loc_17D1C ; if not nil, goto the label

loc_17C50:

      MOVW     R3, #(:lower16:(_GetImageAtPath+1 - 0x17C60))

      MOV      R0, R4  ; R0 = R4 = imageFileName

      MOVT.W   R3, #(:upper16:(_GetImageAtPath+1 - 0x17C60))

      LDR      R2, [SP,#0x1C+var_1C] ; R2 = isRetina

      ADD      R3, PC ; _GetImageAtPath ; R3 = _GetImageAtPath

      MOV      R1, R10 ; R1 = R10 = mainBundle

      BL    __UIImageCallFunctionForAppropriatePath ; arg_0:imageFileName, arg_1 = mainBundle, arg_2 = isRetina, arg_3 = _GetImageAtPath

      MOV      R6, R0  ; R6 = R0 = UIImageObject

      CMP      R6, #0  ; check if UIImageObject is nil

      BEQ      loc_17D1C ; if failed, goto label

      MOV      R0, R11 ; lock

      BLX.W    _OSSpinLockLock

      LDR.W    R0, [R8,#0x14] ; R0 = pointer to imageCacheMap

      CBNZ     R0, loc_17CAE ; R1 = R5 = imageCacheName

      MOVW     R0, #(:lower16:(_kCFTypeDictionaryKeyCallBacks_ptr - 0x17C86))

      MOVS     R1, #0  ; R1 = capacity = 0

      MOVT.W R0, #(:upper16:(_kCFTypeDictionaryKeyCallBacks_ptr - 0x17C86))

      MOVS     R3, #0  ; R3 = valueCallBacks = 0

      ADD      R0, PC ; _kCFTypeDictionaryKeyCallBacks_ptr

      LDR      R2, [R0] ; _kCFTypeDictionaryKeyCallBacks

      MOVS     R0, #0  ; R0 = allocator = NULL

      BLX.W    _CFDictionaryCreateMutable ; R0 = cachedImageMap

      MOVW     R1, #(:lower16:(_kCFTypeDictionaryValueCallBacks_ptr - 0x17C9E))

      MOVS     R2, #0  ; R2 = keyCallBacks = NULL

      MOVT.W          R1, #(:upper16:(_kCFTypeDictionaryValueCallBacks_ptr - 0x17C9E))

      STR.W   R0, [R8,#0x14]

      ADD      R1, PC ; _kCFTypeDictionaryValueCallBacks_ptr

      MOVS     R0, #0  ; R0 = allocator = NULL

      LDR      R3, [R1] ; _kCFTypeDictionaryValueCallBacks

      MOVS     R1, #0  ; R1 = capacity = 0

      BLX.W    _CFDictionaryCreateMutable

      STR.W    R0, [R8,#0x18]

      LDR.W    R0, [R8,#0x14]

loc_17CAE:

      MOV      R1, R5  ; R1 = R5 = imageCacheName

      BLX.W    _CFDictionaryContainsKey

      CBNZ     R0, loc_17CF8 ; if has cached, goto the label

      MOVW     R0, #(:lower16:(selRef__setNamed_ - 0x17CC4))

      MOVS     R2, #1  ; R2 = YES

      MOVT.W   R0, #(:upper16:(selRef__setNamed_ - 0x17CC4))

      ADD      R0, PC ; selRef__setNamed_

      LDR      R1, [R0] ; "_setNamed:"

      MOV      R0, R6  ; R0 = R6 = UIImageObject

      BLX.W    _objc_msgSend ; [UIImageObject _setNamed:YES]

      MOVW     R0, #(:lower16:(selRef__setCached_ - 0x17CD8))

      MOVS     R2, #1

      MOVT.W   R0, #(:upper16:(selRef__setCached_ - 0x17CD8))

      ADD      R0, PC ; selRef__setCached_

      LDR      R1, [R0] ; "_setCached:"

      MOV      R0, R6

      BLX.W   _objc_msgSend ; [UIImageObject _setCached:YES]

      LDR.W    R0, [R8,#0x14] ; R0 = cachedImageMap

      MOV      R1, R5  ; R1 = R5 = imageCacheName

      MOV      R2, R6  ; R2 = R6 = UIImageObject

      BLX.W   _CFDictionarySetValue ; arg_0:cachedImageMap, arg_1 = imageCacheName, arg_2 = imageObject

      LDR.W    R0, [R8,#0x18]

      MOV      R1, R6  ; R1 = R6 = UIImageObject

      MOV      R2, R5  ; R2 = R5 = imageCacheName

      BLX.W  _CFDictionarySetValue ; arg_0: dictionary, arg_1: imageObject, arg_2 = imageCacheName

      B        loc_17D16

loc_17CF8:

      MOV     R0, #(selRef_release - 0x17D04) ; selRef_release

      ADD     R0, PC ; selRef_release

      LDR     R1, [R0] ; "release"

      MOV     R0, R6  ; R0 = R6 = UIImageObject

      BLX.W  _objc_msgSend ; [UIImageObject release]

      LDR.W  R0, [R8,#0x14] ; R0 = cachedImageMap

      MOV    R1, R5  ; R1 = R5 = imageCacheName

      BLX.W  _CFDictionaryGetValue

      MOV    R6, R0  ; R6 = R0 = result UIImage instance

loc_17D16:

      MOV    R0, R11 ; lock

      BLX.W  _OSSpinLockUnlock ; release spin lock

loc_17D1C:

      MOV    R0, R6  ; R0 = R6 = nil

      ADD    SP, SP, #4

      POP.W  {R8,R10,R11}

      POP     {R4-R7,PC}

 

伪代码:

 

NSDictionary *gCachedImageMapNameToImage = nil;

NSDictionary *gCachedImageMapImageToName = nil;

 

_UIImageAtPath(NSString *imageFileName, NSBundle *mainBundle, BOOL isRetina) {

      if ([imageFileName length] == 0)

           returnnil;

   

      if (gCachedImageMapNameToImage == nil) {

           gCachedImageMapNameToImage = [[NSMutableDictionaryalloc] init];

           gCachedImageMapImageToName = [[NSMutableDictionaryalloc] init];

      }

     

      NSString *imageCacheName = _UICacheNameForImageAtPath(imageFileName, mainBundle);

      UIImage *cachedImage = [gCachedImageMapNameToImageobjectForKey:imageCacheName];

      if (cachedImage == nil) {

           cachedImage = _UIImageCallFunctionForAppropriatePath(imageFileName, mainBundle, isRetina, _UIImageAtPath);

           if (cachedImage == nil) {

                 returnnil;

           } else {

                 [gCachedImageMapNameToImagesetObject:cachedImage forKey:imageCacheName];

                 [gCachedImageMapImageToNamesetObject:imageCacheName forKey:cachedImage];

                

                 [cachedImage _setNamed:YES];

                 [cachedImage _setCached:YES];

           }

      } else {

           if (![cachedImage _isCached]) {

                 [cachedImage _setCached:YES];

           }

      }

      return cachedImage;

}