IDA官网发布的每周技巧4----选取可以实现的更多功能

hex-rays官方发布了一套《Igor的IDA每周技巧》系列文章,内容不错,故进行跟踪翻译,期望对大家有所帮助。

第四篇原文:Igor’s tip of the week #04: More selection!

上一篇文章中,我们讨论了在IDA中选取操作的基本用法。本文我们讨论基于选取操作的更多功能。

分析固件、纯二进制文件

当反汇编一个纯二进制文件时,IDA无法确定哪些是代码,你需要通过不断试错来找到整个地址范围中哪些是代码,这个过程是很耗时的。在这种情况下,下面这一系列简单的操作在最初的侦查阶段很有用:

  • 跳转到IDA数据库的起始地址(Ctrl-PgUp)
  • 开始选取(Alt-L)
  • 跳转到IDA数据库的结尾地址(Ctrl-PgDn)。也可以跳转到你认为是代码区域结束的位置。(比如大块的0或0xFF之前)。
  • 选择Edit->Code,或者直接按c。将弹出一个对话框让你选择执行哪种行为:

  • 如果你判断所选区域内的大部分内容都是代码,点击“Force”。如果你判断所选区域中有数据,点击“Analyze”。
  • IDA将遍历所选区域,尝试将所有未定义的字节转换为指令。如果在这个区域内,确实包含代码,你将在函数窗口看到IDA分析出来的函数(但可能是错的)。

 Struct offsets

另一个使用选取区域能提高效率的操作是,对多个指令应用某个结构的偏移。

例如下面的UEFI模块:

.text:0000000000001A64 sub_1A64        proc near               ; CODE XREF: sub_15A4+EB↑p
.text:0000000000001A64                                         ; sub_15A4+10E↑p
.text:0000000000001A64
.text:0000000000001A64 var_28          = qword ptr -28h
.text:0000000000001A64 var_18          = qword ptr -18h
.text:0000000000001A64 arg_20          = qword ptr  28h
.text:0000000000001A64
.text:0000000000001A64                 push    rbx
.text:0000000000001A66                 sub     rsp, 40h
.text:0000000000001A6A                 lea     rax, [rsp+48h+var_18]
.text:0000000000001A6F                 xor     r9d, r9d
.text:0000000000001A72                 mov     rbx, rcx
.text:0000000000001A75                 mov     [rsp+48h+var_28], rax
.text:0000000000001A7A                 mov     rax, cs:gBS
.text:0000000000001A81                 lea     edx, [r9+8]
.text:0000000000001A85                 mov     ecx, 200h
.text:0000000000001A8A                 call    qword ptr [rax+50h]
.text:0000000000001A8D                 mov     rax, cs:gBS
.text:0000000000001A94                 mov     r8, [rsp+48h+arg_20]
.text:0000000000001A99                 mov     rdx, [rsp+48h+var_18]
.text:0000000000001A9E                 mov     rcx, rbx
.text:0000000000001AA1                 call    qword ptr [rax+0A8h]
.text:0000000000001AA7                 mov     rax, cs:gBS
.text:0000000000001AAE                 mov     rcx, [rsp+48h+var_18]
.text:0000000000001AB3                 call    qword ptr [rax+68h]
.text:0000000000001AB6                 mov     rax, [rsp+48h+var_18]
.text:0000000000001ABB                 add     rsp, 40h
.text:0000000000001ABF                 pop     rbx
.text:0000000000001AC0                 retn
.text:0000000000001AC0 sub_1A64        endp

如果我们已知gBS是指向EFI_BOOT_SERVICES的指针,我们就可以把对gBS加一个偏移的访问操作,转换为对该结构内某偏移处的成员的访问操作。我们可以人工找到所有对gBS加固定偏移的访问操作,并人工将访问操作重命名为对EFI_BOOT_SERVICES结构的成员的访问操作,但这太费事了。

这时选取操作能带来很大便利。我们选择访问结构成员的指令,按T(structure offset),将弹出一个新窗口:

你可选择哪个寄存器为结构的基地址,对这个寄存器应用哪个结构。在右边的窗口中,列出了IDA自动分析的包含该寄存器加固定偏移的所有指令,这些都可能是对该结构成员的访问。但IDA也会存在分析错误的情况,你可以在这里勾选哪些指令不应用该结构进行分析。

在本例中,选择rax和EFI_BOOT_SERVICES后,反汇编代码变得更可读了:

.text:0000000000001A64 sub_1A64        proc near               ; CODE XREF: sub_15A4+EB↑p
.text:0000000000001A64                                         ; sub_15A4+10E↑p
.text:0000000000001A64
.text:0000000000001A64 Event           = qword ptr -28h
.text:0000000000001A64 var_18          = qword ptr -18h
.text:0000000000001A64 Registration    = qword ptr  28h
.text:0000000000001A64
.text:0000000000001A64                 push    rbx
.text:0000000000001A66                 sub     rsp, 40h
.text:0000000000001A6A                 lea     rax, [rsp+48h+var_18]
.text:0000000000001A6F                 xor     r9d, r9d        ; NotifyContext
.text:0000000000001A72                 mov     rbx, rcx
.text:0000000000001A75                 mov     [rsp+48h+Event], rax ; Event
.text:0000000000001A7A                 mov     rax, cs:gBS
.text:0000000000001A81                 lea     edx, [r9+8]     ; NotifyTpl
.text:0000000000001A85                 mov     ecx, 200h       ; Type
.text:0000000000001A8A                 call    [rax+EFI_BOOT_SERVICES.CreateEvent]
.text:0000000000001A8D                 mov     rax, cs:gBS
.text:0000000000001A94                 mov     r8, [rsp+48h+Registration] ; Registration
.text:0000000000001A99                 mov     rdx, [rsp+48h+var_18] ; Event
.text:0000000000001A9E                 mov     rcx, rbx        ; Protocol
.text:0000000000001AA1                 call    [rax+EFI_BOOT_SERVICES.RegisterProtocolNotify]
.text:0000000000001AA7                 mov     rax, cs:gBS
.text:0000000000001AAE                 mov     rcx, [rsp+48h+var_18] ; Event
.text:0000000000001AB3                 call    [rax+EFI_BOOT_SERVICES.SignalEvent]
.text:0000000000001AB6                 mov     rax, [rsp+48h+var_18]
.text:0000000000001ABB                 add     rsp, 40h
.text:0000000000001ABF                 pop     rbx
.text:0000000000001AC0                 retn
.text:0000000000001AC0 sub_1A64        endp

强制转换为字符串

当指令对字符串进行操作时,IDA通常都能识别出被操作的是个字符串,并将被操作的字节串转换为字符串。但是有些情况下,IDA不会进行自动转换:

  • 字符串包含非ASCII字符
  • 字符串不以NULL结尾

常见的一个例子是,Linux内核使用一个特殊的字节串来区分不同内核消息类型。例如,joydev.ko内核模块的这个函数:

 因为以非ASCII字符开头,导致IDA没有自动在地址IBC8处创建字符串。我们可以选择该字符串的所有字节,并按A(转换为字符串),IDA就会强制创建一个字符串:

从数据内容创建结构

 这个操作在分析结构时很有用。我们假设有一个如下结构组成的表:

struct copyentry {
 void *source;
 void *dest;
 int size;
 void* copyfunc;
};

我们可以人工在结构窗口创建这个结构。通常我们会先确定每个数据的类型,然后创建一个包含这些数据类型的结构。但在确定每个数据的类型后,我们也可以直接选取这些数据并右键,然后选择“Create struct from selection”:

 IDA会自动创建一个能表示所选数据的结构,之后我们可以直接使用这个自动创建的结构来分析其它使用该结构的代码:

欢迎关注我的微博:大雄_RE。专注软件逆向,分享最新的好文章、好工具,追踪行业大佬的研究成果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值