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。专注软件逆向,分享最新的好文章、好工具,追踪行业大佬的研究成果。