刚才写了如何Hook ObjC的不定参数方法,现在突然有了一个使用不定参数来保护App的想法。
设想这样一个情况,假定我们不对代码做混淆处理,App需要某个文件解密,使用的方法为:
- (void)decryptFileAt:(NSString *)arg1 Password:(NSString *)arg2;
现在这样class-dump一下子就能出来:
- (void) decryptFileAt:(id)arg1 Password:(id)arg2;
攻击者可以马上对arg1和arg2调用class方法,得出arg1和arg2都是NSString,并且直接拿到它们的值。
那要怎么用不定参数来保护App呢?
让我们把方法声明成这个样子:
- (void)decryptFileAt:(long long)arg1, ... NS_REQUIRES_NIL_TERMINATION;
这样攻击者在class-dump之后只能看见:
- (void)decryptFileAt:(long long)arg1;
那么我们要怎么拿到原来的参数呢?别急,下面就是具体实现。
{
/*!
* @brief params数组用于保存参数
*/
NSMutableArray *params = [[NSMutableArray alloc] init];
va_list args;
va_start(args, arg1);
/*!
* @brief 强制将long long转为id类型
*
* @return 第一个参数的值
*/
id obj = reinterpret_cast<id>(arg1);
/*!
* @brief 依次拿剩下的参数的值
*/
while (obj != nil){
[params addObject:obj];
/*!
* @brief va_arg的第二个参数是下一个不定参数的类型, 请根据实际情况处理
*
* @param id 下一个不定参数的类型
*
* @return 下一个不定参数
*/
obj = va_arg(args, id);
}
/*!
* @brief 处理拿到的参数
*/
}
好的,那我们要怎么调用呢?
我们原本是需要2个参数就好的,现在怎么传了4个?
这是为了防止看出了这种手法的攻击者,现在他手上有4个参数,有两个是NSString,一个char和一个char *。如果他不作处理,直接addObject:到一个数组中的话,程序自然就crash了。
而我们自己拥有源代码,可以轻松的处理这些参数。当无用参数传得再多一点的时候,他就不得不去看汇编或者动态调试了,如果他看烦了的话,说不定就放弃了。在一定程度上可起到保护App的作用。
当然我们还可以改一下方法名,让它看上去与实际功能无关,更具有迷惑性,比如:
- (void)isOddNumber:(long long) arg1, ... NS_REQUIRES_NIL_TERMINATION;
但是如果你碰上了不搞出来不罢休的攻击者,那也没办法了,道高一尺,魔高一丈,有防必有攻,剩下的只是攻击者的时间和精力问题而已。
我觉得确实可以防住一部分class-dumper,但class-dumper的危害通常没那么大,所以防住这些人其实也没防住什么东西,但这个思路是极好的!