IDA 技巧(79)处理变量重用

admin 2024年11月29日14:29:30评论8 views字数 2963阅读9分52秒阅读模式

之前我们讨论过如何通过映射将变量的副本减少为一个,从而减少伪代码中使用的变量数量。然而,有时你可能会遇到相反的问题:一个变量可能会被用于不同的目的。

重用的栈槽

一个常见的情况是编译器重用了局部变量或甚至是传入栈参数的栈位置,用于不同的目的。例如,在这样的代码片段中:

vtbl = DiaSymbol->vtbl;vtbl->get_symTag(DiaSymbol, (int *)&DiaSymbol);Symbol->Tag = (int)DiaSymbol;

调用的第二个参数显然是一个输出参数,其含义和类型与调用前的DiaSymbol不同。在这种情况下,你可以使用“强制新变量”命令(快捷键Shift–F)。由于实现细节,有时如果你右键点击变量本身,选项不会显示;在这种情况下,尝试右键点击伪代码行的开头。

IDA 技巧(79)处理变量重用
Image

反编译器在相同的栈位置创建了一个新变量,初始类型相同:

IDiaSymbol *v14; // [esp+30h] [ebp+8h] FORCED BYREFvtbl = DiaSymbol->vtbl;vtbl->get_symTag(DiaSymbol, (int *)&v14);Symbol->Tag = (int)v14;

当然,你可以将其类型和名称更改为更合适的:

int tag; // [esp+30h] [ebp+8h] FORCED BYREFvtbl = DiaSymbol->vtbl;vtbl->get_symTag(DiaSymbol, &tag);Symbol->Tag = tag;

使用联合体表示多态变量

不幸的是,“强制新变量”不适用于寄存器变量(在IDA 7.7中)。在这种情况下,使用联合体可能有效。例如,考虑ntdll.dllLdrRelocateImage函数中的这个片段:

int v6; // esiint v7; // eaxint v8; // ediint v9; // eax  v6 = 0;  v20 = 0;  v7 = RtlImageNtHeader(a1);  v8 = v7;if ( !v7 )return-1073741701;  v9 = *(unsigned __int16 *)(v7 + 24);if ( v9 == IMAGE_NT_OPTIONAL_HDR32_MAGIC )  {    v18 = *(_DWORD *)(v8 + 52);    v16 = 0;  }else  {if ( v9 != IMAGE_NT_OPTIONAL_HDR64_MAGIC )return-1073741701;    v18 = *(_DWORD *)(v8 + 48);    v16 = *(_DWORD *)(v8 + 52);  }

函数RtlImageNtHeader返回给定地址处PE镜像的IMAGE_NT_HEADERS结构的指针。在更改其原型和变量类型后,代码变得更易读:

int v6; // esi  PIMAGE_NT_HEADERS v7; // eax  PIMAGE_NT_HEADERS v8; // ediint Magic; // eaxint v10; // edxint v11; // eaxunsignedint v12; // ecxint v13; // ecxint v15; // [esp+Ch] [ebp-10h]unsignedint v16; // [esp+10h] [ebp-Ch]int v17; // [esp+10h] [ebp-Ch]unsignedint v18; // [esp+14h] [ebp-8h]char *v19; // [esp+14h] [ebp-8h]int v20; // [esp+18h] [ebp-4h] BYREF  v6 = 0;  v20 = 0;  v7 = RtlImageNtHeader(a1);  v8 = v7;if ( !v7 )return-1073741701;  Magic = v7->OptionalHeader.Magic;if ( Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC )  {    v18 = v8->OptionalHeader.ImageBase;    v16 = 0;  }else  {if ( Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC )return-1073741701;    v18 = v8->OptionalHeader.BaseOfData;    v16 = v8->OptionalHeader.ImageBase;  }

然而,有一个小问题。根据魔术值的检查,代码可以处理32位和64位图像,但当前的PIMAGE_NT_HEADERS类型是32位(PIMAGE_NT_HEADERS32),因此else子句中的代码可能不正确。如果我们将v8更改为PIMAGE_NT_HEADERS64,则if子句变得不正确:

if ( Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC )  {    ImageBase = HIDWORD(v8->OptionalHeader.ImageBase);    v16 = 0;  }else  {if ( Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC )return-1073741701;    ImageBase = v8->OptionalHeader.ImageBase;    v16 = HIDWORD(v8->OptionalHeader.ImageBase);  }

我们不能强制新变量,因为v8是在寄存器中分配的,而不是在栈上。我们还能同时使用这两种类型吗?

答案是肯定的:我们可以使用一个联合体来结合这两种类型。以下是如何在此示例中完成的:

  1. 打开本地类型(Shift-F1);
  2. 添加新类型(Ins);
  3. 输入以下定义:
union nt_headers {    PIMAGE_NT_HEADERS32 hdr32;    PIMAGE_NT_HEADERS64 hdr64;};
  1. v8的类型更改为nt_headers,并使用“选择联合字段”在if的每个分支中选择正确的字段:
  Magic = v7->OptionalHeader.Magic;if ( Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC )  {    ImageBase = v8.hdr32->OptionalHeader.ImageBase;    ImageBaseHigh = 0;  }else  {if ( Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC )return-1073741701;    ImageBase = v8.hdr64->OptionalHeader.ImageBase;    ImageBaseHigh = HIDWORD(v8.hdr64->OptionalHeader.ImageBase);  }

在这个特定示例中,差异很小,你可能可以通过一些注释来解决,但在某些情况下,这种方法可能会产生真正的差异。请注意,这种方法也可以用于栈变量。

学习资源

立即关注【二进制磨剑】公众号

👉👉👉【IDA 技巧合集】👈👈👈
👉👉👉【Github 安全项目合集】👈👈👈
学习零基础学习 IDA 逆向
【课程完结!内容揭秘!】7 天打造 IDA 9.0 大师:从零基础到逆向精英
🔥🔥🔥 新课抽奖中 🔥🔥🔥🔥
【新课来袭】第 2 期-Android 逆向内核攻防

原文始发于微信公众号(二进制磨剑):IDA 技巧(79)处理变量重用

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月29日14:29:30
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   IDA 技巧(79)处理变量重用https://cn-sec.com/archives/3449249.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息