Pau*_*nne 19 code-injection ios swift
我正在阅读有关Cycript和Cydia Substrate以及它们如何用于iOS应用程序的代码注入攻击的内容.如果您在高安全性环境中工作,这样的代码应该吓到您.(忽略/ etc/password部分,只考虑使用crackedMessage替换originalMessage的能力.)
cy# MS.hookFunction(fopen, function(path, mode) {
cy> if (path == "/etc/passwd")
cy> path = "/var/passwd-fake";
cy> var file = (*oldf)(path, mode);
cy> log.push([path, mode, file]);
cy> return file;
cy> }, oldf)
Run Code Online (Sandbox Code Playgroud)
我读了一篇博客(我没有保存)说Swift没有Objective-C那么脆弱,因为它没有那么动态.然后,我还读到你可以在Swift中进行方法调配,所以我不清楚Swift是否提供任何针对代码注入攻击的保护措施.
那么,Swift是否容易受到代码注入攻击?
zne*_*eak 37
最终,如果你让它在他们的设备上运行,就没有办法阻止某人劫持你的程序.有办法让它变得更难,但没有办法让它变得不可能.
我可以想到将代码注入应用程序的这些主要方法:
并且没有100%有效的方法来防止用户完全控制的环境中的任何这些.您应根据您的威胁模型决定是否担心.
方法调配是一种技术,您可以使用任意不同的代码(通常用于不同的目的)在运行时更改方法的实现.常见用例是绕过检查或记录参数.
在Objective-C中调度是一件很大的事情,因为运行时需要元数据来识别每个方法和每个实例字段.我不知道任何其他编译为本机机器代码的语言,并且保留了这么多的元数据.如果你有类似的东西-[AccessControl validatePassword:],你只是让坏人变得非常容易.有了method_setImplementation,这只是乞求发生.
由于Swift类可以继承Objective-C类,因此仍然需要寻找.但是,从Objective-C类继承的类的新方法只有在具有该@objc属性的情况下(或者如果类本身具有该@objc属性)才会暴露给Objective-C运行时,因此与Objective-C相比,这限制了攻击面. .
此外,Swift编译器可以绕过Objective-C运行时来调用,虚拟化或内联未标记的Swift方法dynamic,即使它们已被标记@objc.这意味着在某些情况下,只有通过Objective-C调度的调用才能进行调配.
当然,如果您的类或方法未暴露于Objective-C运行时,则完全不可能.
但是,您不需要Objective-C运行时来交换方法实现.Swift仍然为其虚拟方法提供虚拟表,截至2015年2月,它们位于__DATA可执行文件的段中.它是可写的,所以如果能找到合适的位来改变,应该可以调用Swift虚拟方法.没有方便的API.
可以类似地修改C++类,但默认情况下Swift方法是虚拟的,攻击面要大得多.如果发现没有覆盖,则允许编译器将方法虚拟化为优化,但是依赖编译器优化作为安全功能是不负责任的.
默认情况下,部署的Swift可执行文件是strip ped.对于非信息public/ open符号被丢弃,这使得确定要改变这种比较,Objective-C的更难的符号.Public/ open符号不会被剥离,因为假设其他外部代码客户端可能需要它们.
但是,如果有人确定他们想要换出哪个功能实现,他们所要做的就是在正确的虚拟表槽中写入新实现的地址.他们可能需要制作自己的Mach-O解析器,但这肯定不会超出制作像Cycript这样的人的范围.
最后,final方法降低了这种风险,因为编译器不需要通过vtable调用它们.此外,struct方法永远不是虚拟的.
如果所有其他方法都失败了,攻击者仍然可以遍历您的机器代码,并将bl或call指令操作数更改为他们更喜欢的任何地方.这更加复杂,相当困难/不可能通过自动化方法100%正确,特别是如果缺少符号,但有足够的人能够做到这一点.您决定是否有人最终会发现为您的应用程序执行此操作是值得的.
这适用于虚拟和非虚拟方法.但是,当编译器内联调用时,这是非常困难的.
任何导入的符号,无论其编写的语言及其使用的语言,都容易受到混乱的影响.这是因为外部符号在运行时绑定.无论何时使用外部库中的函数,编译器都会在查找表中生成一个条目.这是一个示例,fopen如果您将可执行文件返回到C代码,调用可能会是什么样子:
FILE* locate_fopen(const char* a, const char* b) {
fopen_stub = dyld->locate("fopen"); // find actual fopen and replace stub pointer to it
return fopen_stub(a, b);
}
FILE* (*fopen_stub)(const char*, const char*) = &locate_fopen;
int main() {
FILE* x = fopen_stub("hello.txt", "r");
}
Run Code Online (Sandbox Code Playgroud)
初始调用fopen_stub找到实际的fopen,并fopen_stub用它替换指向的地址.这样,dyld在开始运行之前不需要解析程序及其库中使用的数千个外部符号.但是,这意味着攻击者可以替换fopen_stub为他们想要调用的任何函数的地址.这是您的Cycript示例所做的.
如果没有编写自己的链接器和动态链接器,那么针对此类攻击的唯一保护就是不使用共享库或框架.在现代开发环境中,这不是一个可行的解决方案,因此您可能不得不处理它.
可能有办法确保存根达到您期望的位置,但它会有点不稳定,并且这些检查总是可以nop由坚定的攻击者完成.此外,您无法在无法控制调用导入符号的共享库之前插入这些检查.如果攻击者决定用他们控制的共享库替换共享库,那么这些检查也将毫无用处.
另外,启动闭包允许dyld 3用预先绑定的信息替换这些查找表.我不认为启动闭包当前是只读的,但看起来它们最终可能是.如果是,那么混合符号将变得更难.
Dyld 支持将库强制加载到您的可执行文件中.此功能可用于替换可执行文件使用的任何导入符号.不喜欢正常fopen吗?写一个dylib重新定义它!
如果可执行文件被标记为受限制,则Dyld将不会与此方法配合使用.有三种方法可以达到这种状态(寻找pruneEnvironmentVariables):
__restrict的段中调用一个部分__RESTRICT.您可以使用以下"其他链接器标志" 创建__restrict节和__RESTRICT段:
-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
Run Code Online (Sandbox Code Playgroud)
请注意,所有这些都很容易打破.当用户控制执行环境时,setuid和setgid位很容易清除,代码签名很容易删除,并且必须重命名部分或段以摆脱受限状态.
如果所有其他方法都失败了,攻击者仍然可以替换您的可执行文件使用的共享库,以使其执行任何他们喜欢的操作.你无法控制它.
在Swift应用程序中注入代码比使用Objective-C应用程序更难,但它仍然可行.大多数可用于注入代码的方法都是与语言无关的,这意味着没有语言可以让您更安全.
在大多数情况下,你无法做任何事情来保护自己免受这种伤害.只要用户控制执行环境,您的代码就作为其系统上的guest虚拟机运行,并且他们几乎可以随意执行任何操作.
| 归档时间: |
|
| 查看次数: |
2540 次 |
| 最近记录: |