在处理已编译的二进制代码时,反编译器缺乏源代码中存在的信息,比如函数原型,因此必须猜测或依赖用户提供的信息(这时其交互功能就显得很有用)。
一个特别棘手的情况是间接调用:在没有确切的调用目标信息时,反编译器只能尝试分析在调用前初始化的寄存器或堆栈槽,并试图通过这种方式推断出可能的函数原型。例如,查看这个来自UEFI模块的代码片段:
对于涉及qword_21D40
的几个间接调用,反编译器不得不猜测参数并添加类型转换。
如果我们从入口点分析模块,可以找到变量初始化的位置,并发现它实际上是标准UEFI全局变量gBS
,类型为EFI_BOOT_SERVICES *
:
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
EFI_STATUS __fastcall UefiBootServicesTableLibConstructor(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
gImageHandle = ImageHandle;
if ( DebugAssertEnabled() && !gImageHandle )
DebugAssert(
"u:\MdePkg\Library\UefiBootServicesTableLib\UefiBootServicesTableLib.c",
0x33ui64,
"gImageHandle != ((void *) 0)");
gST = SystemTable;
if ( DebugAssertEnabled() && !gST )
DebugAssert(
"u:\MdePkg\Library\UefiBootServicesTableLib\UefiBootServicesTableLib.c",
0x39ui64,
"gST != ((void *) 0)");
// gBS was qword_21D40
gBS = SystemTable->BootServices;
if ( DebugAssertEnabled() && !gBS )
DebugAssert(
"u:\MdePkg\Library\UefiBootServicesTableLib\UefiBootServicesTableLib.c",
0x3Fui64,
"gBS != ((void *) 0)");
return 0i64;
}
在重命名和更改全局变量的类型后,原始函数由于标准UEFI类型库的类型信息而略有改进:
即使反编译器现在有了函数指针的原型,比如LocateDevicePath
(在弹出窗口中显示)或FreePool
,它仍然需要添加类型转换,因为传递给调用的参数与原型不匹配。要告诉反编译器依赖类型信息而不是猜测参数,请使用上下文菜单中的命令强制调用类型:
在间接调用上运行该命令时,反编译器还使用类型信息来更新参数的类型(除了那些已由用户设置的),使伪代码更加简洁:
学习资源
立即关注【二进制磨剑】公众号
原文始发于微信公众号(二进制磨剑):IDA技巧(119)强制调用类型
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论