zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

iOS小技能:装箱和拆箱(boxing、unboxing)​

ios 技能 装箱 拆箱
2023-06-13 09:11:18 时间

引言

  1. get 和post 布尔值参数处理( 使用NSNumber 传BOOL值)
  2. 全局的const常量代替宏常量,节省内存空间。
  3. 敏感逻辑的保护: 把函数名隐藏在结构体里,以函数指针成员的形式存储。

编译后,只留了下地址,去掉了名字和参数表,提高了逆向成本和攻击门槛

I 装箱和拆箱

1.1 Java包装类

  • Java包装类(装箱和拆箱)

全部被final修饰,顺便提一下,java.lang.Math,System,String也被final修饰

包装类是使用面向对象的思想把简单的数据类型封装成类

  1. 特点 包装类把简单的数据类型包装成类。注:简单数据类型不是类,使用简单数据类型主要为了提高代码的运行效率
  2. 装箱和拆箱把简单数据类型包装成对应的包装类称为boxing(示例:Integer i=1;将1包装成Integer再使用Object引用Integer对象)

把包装类型转换成简单数据类型称为unboxing(示例:Integer i=1,int p=i;//将包装类Integer转化成简单数据类型int)

注:Integer的拆箱方法为 int intValue(),其他的包装类以此类推。

1)包装类都重写了toString方法,equals方法,hashCode方法 2)Integer的API:String toBinaryString(int i); 将int类型的数据以二进制字符串形式返回int parseInt(String) 将字符串转化成int类型int parseInt(Stringstr,int i ) 将字符串转化成对应的进制 类型,str为被转换的字符串,i为进制类型(10,8,16)Integer valueof(String str) 将字符串转换成Integer类型。

1.2 iOS 装箱:快速构造数字对象

Objective-C's boxing capability:The printf function NSLog offers a number of substitution tokens for printing numbers (%d, %ld, %f, %d, for example). As a convenience, you can use Objective-C's boxing capability to save time and avoid compiler warnings.

  • For example

在这里插入图片描述

平常也可以使用@ 来快速包装数字类型以对象的形式进行存储和传参

    [discountArray addObject:[[ self class] mj_objectWithKeyValues:@{@"placeholder":QCTLocal(@"please_input_card_num"),@"btnContent":QCTLocal(@"member_see"),@"EnterModelType":@2,@"isEnabled":@1,@"isLast":@1,@"block":block}]];

II The Truth About NSNumber and BOOL

Name

Typedef

Header

True Value

False Value

BOOL

signed char

objc.h

YES

NO

bool

_Bool (int)

stdbool.h

true

false

Boolean

unsigned char

MacTypes.h

TRUE

FALSE

NSNumber

__NSCFBoolean

Foundation.h

@(YES)

@(NO)

CFBooleanRef

struct

CoreFoundation.h

kCFBooleanTrue

kCFBooleanFalse

BOOL不如bool好用

BOOL表示 1是YES , 所以非1是NO. 而bool表示0是false,所以非0是true;

2.1 NSCFBoolean

NSCFBoolean是NSNumber类簇中的一个私有的类,它是通往CFBooleanRef类型的桥梁。NSCFBoolean被用来给Core Foundation的属性列表和集合封装布尔数值。

CFBoolean定义了常量kCFBooleanTrue和kCFBooleanFalse。

NSLog(@"%@", [@(YES) class]);

__NSCFBoolean

2.1 get 和post 布尔值参数处理( 使用NSNumber 传BOOL值)

使用NSNumber 传BOOL值的时候,get 和post对应的参数不一致。get请求对应的0和1,post对应true/false。

[params setValue:[NSNumber numberWithBool:self.viewModel.multipleSwitchCellTableViewCellModel.IsSon] forKey:@"IsSon"];

这个代码使用Post 会将请求参数IsSon 自动转为true/false

若服务端Bool 参数没有支持0和1格式,只支持true false的时候,就需要特殊处理。

//get  需要自己处理
    if(self.viewModel.multipleSwitchCellTableViewCellModel.IsSon){
        [params setValue:@"true" forKey:@"IsSon"];//

        
    }else{
        
        [params setValue:@"false" forKey:@"IsSon"];//

    }

————————————————
版权声明:本文为CSDN博主「iOS逆向」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/z929118967/article/details/105138207

在这里插入图片描述———————————————— 版权声明:本文为CSDN博主「iOS逆向」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/z929118967/article/details/105138207

II 常量

2.1 对象常量

随着Apple 的 LLVM 4.0 编译器的发布,让我们欣喜的是NSNumber,NSArray和NSDictionary常量被添加了。

  • @"":返回一个由引号内 Unicode 内容初始化的 NSString 对象。
  • @42,@3.14,@YES,@'Z':返回一个由相关类构造初始化的 NSNumber 对象

比如 @42 → [NSNumber numberWithInteger:42],或者 @YES → [NSNumber numberWithBool:YES]。支持使用后缀进一步指定类型,如 @42U → [NSNumber numberWithUnsignedInt:42U]。

  • @[]:返回一个由冒号分隔的对象列表作为内容的 NSArray 对象。

比如,@[@"A", @NO, @2.718] → [NSArray arrayWithObjects:@"A", @NO, @2.718, nil] (注意在数组常量中结束标记nil是不需要的)。

  • @{}:返回一个由特定键-值对初始化作为内容的NSDictionary对象,格式: @{@"someKey" : @"theValue"}
  • @():动态评估封装的表达,并返回基于其值的合适的对象常量,这也是使用数字常量和枚举值的指定方式。

(比如,const char*返回NSString,int返回NSNumber。)

2.2 Objective-C 常量

选择器和协议可以作为方法参数。@selector()@protocol()作为伪常量指令返回一个指向特定选择器(SEL)或协议(Protocol *)的指针。

  • @selector():返回一个指向有特定名称的选择器的 SEL 指针。

-performSelector:withObject:

  • @protocol():返回一个指向有特定名称的协议的 Protocol * 指针。

-conformsToProtocol:

2.3 全局的const常量代替宏常量,节省内存空间。

使用字符串常量来代替宏的使用

  1. 定义const 全局常量 ,保证只在一处定义,多处进行引用。
  2. 全局的const常量代替宏常量,节省内存空间(内存只有一份)。


#define KNClientId @""//宏会在编译时,将所有引用宏变量的地方,进行值的替换,造成很多相同的临时字面量,浪费内存
NSString * const KNClientId = @"";// 全局的const常量代替宏常量,节省内存空间。内存只有一份

III 扩展:敏感逻辑的保护

https://blog.csdn.net/z929118967/article/details/115857706

3.1 把函数名隐藏在结构体里,以函数指针成员的形式存储

把函数名隐藏在结构体里,以函数指针成员的形式存储。

编译后,只留了下地址,去掉了名字和参数表,提高了逆向成本和攻击门槛


#import <Foundation/Foundation.h>

@interface KNUtil : NSObject



/**
 把函数名隐藏在结构体里,以函数指针成员的形式存储。
 
 编译后,只留了下地址,去掉了名字和参数表,提高了逆向成本和攻击门槛
 */
typedef struct _util {
    void (*checkKNSign)(char *keys[], unsigned char *output);
}CheckKNSignUtil_t ;


#define ShareKNUtil ([KNUtil sharedUtil])

+ (CheckKNSignUtil_t *)sharedUtil;
  • 调用方法
     ShareKNUtil->checkKNSign(key, output);

3.2 使用宏进行替换字符串

  • 根据前缀搜索出需要混淆的类名、方法名, 生成对应的宏文件
#define run OmWJoTZfCqoPshvr
#define iosre egnjoOFDrFiQVRgr

静态分析时hopper等反汇编工具无法根据string搜索到关键字符

see also

#小程序:iOS逆向