__builtin_return_address(0)返回当前函数的返回地址
__builtin_return_address(1)返回当前函数的调用函数的返回地址
__builtin_return_address(2)返回当前函数的调用函数的调用函数的返回地址
void tt1()
void tt2()
void tt3()
由此可见就是使用 FP 串联了整个函数调用堆栈,上述的 函数(__builtin_return_address) 也就是通过串联起来的 [FP,#0x4] 操作完成了对上一级 LR 的查找
由此可以可以配合 dobby 对函数hook并打印出 lr 调用链
这个写法比较简陋了,也算是偷懒借用内建函数(__builtin_return_address)完成了栈的回溯,当然也可以稍微麻烦一点,dobby 配合 asm内嵌汇编 完成每一个函数栈的拆解,本质都是用到了 FP 串联起了整个函数调用链这样一个大思路
对于gcc 没法使用 大于0的参数 这里补充一个arm32版本的实现
简单看一下IDA帮我们反汇编的效果
实战效果,感觉还不错
void tt3(){
LOGD(
"tt3 called %p"
,__builtin_return_address(
0
));
LOGD(
"tt3 called %p"
,__builtin_return_address(
1
));
LOGD(
"tt3 called %p"
,__builtin_return_address(
2
));
}
void tt2(){
LOGD(
"tt2 called %p"
,__builtin_return_address(
0
));
LOGD(
"tt2 called %p"
,__builtin_return_address(
1
));
tt3();
}
void tt1(){
LOGD(
"tt1 called 0 %p"
,__builtin_return_address(
0
));
tt2();
}
void tt3(){
LOGD(
"tt3 called %p"
,__builtin_return_address(
0
));
LOGD(
"tt3 called %p"
,__builtin_return_address(
1
));
LOGD(
"tt3 called %p"
,__builtin_return_address(
2
));
}
void tt2(){
LOGD(
"tt2 called %p"
,__builtin_return_address(
0
));
LOGD(
"tt2 called %p"
,__builtin_return_address(
1
));
tt3();
}
void tt1(){
LOGD(
"tt1 called 0 %p"
,__builtin_return_address(
0
));
tt2();
}
int
level
=
4
;
u_long lr0,lr1,lr2,lr3,lr4;
[&]()
-
>void {
/
/
调用这个 registerLR 本身也会触发一次函数调用 会有一个lr,故从
1
开始
switch (level) {
case
1
:
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
LOGD(
"LR -> %p"
,(void
*
)(lr0
-
soAddr));
break
;
case
2
:
lr1
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
2
));
LOGD(
"LR -> %p %p"
,(void
*
)(lr0
-
soAddr),(void
*
)(lr1
-
soAddr));
break
;
case
3
:
lr2
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
lr1
=
reinterpret_cast<u_long>(__builtin_return_address(
2
));
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
3
));
LOGD(
"LR -> %p %p %p"
,(void
*
)(lr0
-
soAddr),(void
*
)(lr1
-
soAddr),(void
*
)(lr2
-
soAddr));
break
;
case
4
:
lr3
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
lr2
=
reinterpret_cast<u_long>(__builtin_return_address(
2
));
lr1
=
reinterpret_cast<u_long>(__builtin_return_address(
3
));
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
4
));
LOGD(
"LR -> %p %p %p %p"
,(void
*
)(lr0
-
soAddr),(void
*
)(lr1
-
soAddr),(void
*
)(lr2
-
soAddr),(void
*
)(lr3
-
soAddr));
break
;
case
5
:
lr4
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
lr3
=
reinterpret_cast<u_long>(__builtin_return_address(
2
));
lr2
=
reinterpret_cast<u_long>(__builtin_return_address(
3
));
lr1
=
reinterpret_cast<u_long>(__builtin_return_address(
4
));
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
5
));
LOGD(
"LR -> %p %p %p %p %p"
,(void
*
)(lr0
-
soAddr),(void
*
)(lr1
-
soAddr),(void
*
)(lr2
-
soAddr),(void
*
)(lr3
-
soAddr),(void
*
)(lr4
-
soAddr));
break
;
}
}();
int
level
=
4
;
u_long lr0,lr1,lr2,lr3,lr4;
[&]()
-
>void {
/
/
调用这个 registerLR 本身也会触发一次函数调用 会有一个lr,故从
1
开始
switch (level) {
case
1
:
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
LOGD(
"LR -> %p"
,(void
*
)(lr0
-
soAddr));
break
;
case
2
:
lr1
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
2
));
LOGD(
"LR -> %p %p"
,(void
*
)(lr0
-
soAddr),(void
*
)(lr1
-
soAddr));
break
;
case
3
:
lr2
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
lr1
=
reinterpret_cast<u_long>(__builtin_return_address(
2
));
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
3
));
LOGD(
"LR -> %p %p %p"
,(void
*
)(lr0
-
soAddr),(void
*
)(lr1
-
soAddr),(void
*
)(lr2
-
soAddr));
break
;
case
4
:
lr3
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
lr2
=
reinterpret_cast<u_long>(__builtin_return_address(
2
));
lr1
=
reinterpret_cast<u_long>(__builtin_return_address(
3
));
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
4
));
LOGD(
"LR -> %p %p %p %p"
,(void
*
)(lr0
-
soAddr),(void
*
)(lr1
-
soAddr),(void
*
)(lr2
-
soAddr),(void
*
)(lr3
-
soAddr));
break
;
case
5
:
lr4
=
reinterpret_cast<u_long>(__builtin_return_address(
1
));
lr3
=
reinterpret_cast<u_long>(__builtin_return_address(
2
));
lr2
=
reinterpret_cast<u_long>(__builtin_return_address(
3
));
lr1
=
reinterpret_cast<u_long>(__builtin_return_address(
4
));
lr0
=
reinterpret_cast<u_long>(__builtin_return_address(
5
));
LOGD(
"LR -> %p %p %p %p %p"
,(void
*
)(lr0
-
soAddr),(void
*
)(lr1
-
soAddr),(void
*
)(lr2
-
soAddr),(void
*
)(lr3
-
soAddr),(void
*
)(lr4
-
soAddr));
break
;
}
}();
extern
"C"
void builtin_return_address(){
/
/
todo ...
}
extern
"C"
void builtin_return_address(){
void
*
FP
=
nullptr;
void
*
lr0
=
nullptr;
void
*
lr1
=
nullptr;
void
*
lr2
=
nullptr;
void
*
lr3
=
nullptr;
xASM(
"MOV R4, LR"
:::
"r4"
);
xASM(
"MOV %0, r4"
:
"=r"
(lr0)::);
xASM(
"MOV %0, FP"
:
"=r"
(FP)::);
xASM(
"LDR R4, [R11]"
:::
"r4"
);
xASM(
"LDR %0, [R4,#4]"
:
"=r"
(lr1)::);
xASM(
"CMP %0, #0"
::
"r"
(lr1));
xASM(
"BEQ END"
);
xASM(
"LDR R4, [R11]"
:::
"r4"
);
xASM(
"LDR R4, [R4]"
:::
"r4"
);
xASM(
"LDR %0, [R4,#4]"
:
"=r"
(lr2)::);
xASM(
"CMP %0, #0"
::
"r"
(lr2));
xASM(
"BEQ END"
);
xASM(
"LDR R4, [R11]"
:::
"r4"
);
xASM(
"LDR R4, [R4]"
:::
"r4"
);
xASM(
"LDR R4, [R4]"
:::
"r4"
);
xASM(
"LDR %0, [R4,#4]"
:
"=r"
(lr3)::);
xASM(
"CMP %0, #0"
::
"r"
(lr3));
xASM(
"BEQ END"
);
xASM(
"END:MOV R0,R0"
);
LOGE(
"LR BRA --->%p(FP) %p %p %p %p"
,FP,lr0,lr1,lr2,lr3);
}
NOINLINE
void
*
test3(){
LOGE(
"LR SRC ---> %p %p %p %p"
,BRA(
3
),BRA(
2
),BRA(
1
),BRA(
0
));
builtin_return_address();
return
nullptr;
}
NOINLINE
void
*
test2(){
test3();
return
nullptr;
}
MAIN NOINLINE
void test1(){
test2();
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2022-3-11 12:49
被唱过阡陌编辑
,原因: 评论区的问题完善