返回
函数返参揭秘:揭开 iOS 逆向安防神秘面纱
IOS
2024-01-13 08:48:50
我们已经深入探讨了函数的参数,现在让我们转而研究函数的返回值,看看是否能有更多令人惊喜的发现。
普通返回值
在大多数情况下,函数只返回一个值。我们来探究一下这个值是如何存储和获取的。
为了实现这个目的,我们需要使用 LLVM 反汇编器来查看函数的汇编代码。对于那些不熟悉 LLVM 的人来说,它是一种低级语言,用于表示代码。
在 LLVM 反汇编中,我们可以看到以下内容:
define i32 @foo(i32 %a) {
%0 = add i32 %a, 1
ret i32 %0
}
在这里,@foo
是函数名称,i32 %a
是函数参数,%0
是函数返回值。我们可以看到,返回值被存储在寄存器 %0
中。
要获取返回值,我们需要使用 ret
指令。ret i32 %0
指令表示将 %0
寄存器中的值作为返回值返回。
结构体返回值
我们已经讨论了普通返回值。接下来我们看看如果返回值是一个结构体时会发生什么。
struct Point {
int x;
int y;
};
struct Point foo() {
struct Point p;
p.x = 1;
p.y = 2;
return p;
}
在这里,foo
函数返回一个 Point
结构体。
在 LLVM 反汇编中,我们可以看到以下内容:
define %struct.Point @foo() {
%0 = alloca %struct.Point
%1 = getelementptr inbounds %struct.Point, %struct.Point* %0, i32 0, i32 0
store i32 1, i32* %1
%2 = getelementptr inbounds %struct.Point, %struct.Point* %0, i32 0, i32 1
store i32 2, i32* %2
%3 = load %struct.Point, %struct.Point* %0
ret %struct.Point %3
}
在这里,我们可以看到 %0
寄存器用于存储 Point
结构体。
getelementptr
指令用于获取结构体的成员。%1
指令获取 x
成员,%2
指令获取 y
成员。
store
指令用于将值存储到结构体的成员中。%1
指令将值 1
存储到 x
成员中,%2
指令将值 2
存储到 y
成员中。
最后,load
指令用于加载结构体。%3
指令加载 Point
结构体,并将它作为返回值返回。
总结
函数的返回值可以是各种类型,包括普通值和结构体。了解返回值是如何存储和获取的,对于理解 iOS 逆向安防至关重要。