回到sel_getUid()的原始行为

时间:2015-04-15 22:24:27

标签: objective-c selector objective-c-runtime

TL; DR:如何检查具有给定名称的选择器是否已注册,而未​​实际注册?

谢谢!


嗨,我有一个Objective-C应用程序和一堆NSObject,它们通过用objc编写的简单代理库导出到Lua状态。所有Lua这样的电话都是这样的:

exported_objc_object:myMethodName(...)

-- same as --
exported_objc_object.myMethodName(exported_objc_object, ...)

-- same as --
key = 'myMethodName'
exported_objc_object[key](exported_objc_object, ...)
转发

,好像有人打电话:

[objc_object lua_myMethodName:L];

// declared as
- (int)lua_myMethodName:(lua_State *)L { ... }

实际上,Lua导出对象上的任何“get”操作码都会返回一个缓存的Lua闭包,在调用时,它将通过由sprintf(s, "lua_%s:", key))&&组成的选择器调用相应的Objective-C方法。 sel_getUid(s)(包括所有检查)。如果生成的选择器未按-[respondsToSelector:]实施,则exported_objc_object.myMethodName只会返回nil

显然,代理库必须通过sel_getUid()sel_registerName()进行动态查询(我相信@selectorNSSelectorFromString()也会在那里结束)。该手册指出sel_getUid()旨在查找选择器名称(而不是立即将它们注册到SEL注册表中),但它的现代实现现在与sel_registerName()相同,因为当时某人的代码中存在错误

我可以坚持使用sel_registerName()行为,但这留下了内存食用攻击向量,因为某些恶意脚本可能会在循环中通过sml object[makeRandomKey()]开始查找长的随机/无效选择器,从而溢出SEL注册表永远。如果sel_getUid()按计划工作,则代理lib将能够测试选择器的存在,然后实际检查对象是否响应它,而无需过多注册。但事实并非如此。

1 个答案:

答案 0 :(得分:4)

这是一个可行的hack,它使用依赖于实现的事实,即选择器是C字符串。

sel_isMapped((SEL)(void *)"lua_myMethodName:")