IDA 寄存器知识
IDA加载文件过程
在IDA中打开可执行文件时使用静态分析器分析该文件,也称为Loader。在这种装载程序模式下,该程序将不会执行而是交给IDA静态分析,并最终创建一个.idb文件,分析过程中存储信息(包括重命名)的数据库。变量,函数名,标题...都存在这个文件里。
而.idb文件将是分析过程间产生成的5个文件(.id0,.id1,.nam,.id2和.til)融合在一起:
IDA不具有“撤消”功能,分析过程中所做的任何更改都不会撤消,而是直接保存。但是这些更改仅是存储在idb文件里,不会直接影响到正在分析的原始二进制文件。
在加载程序模式下,没有“寄存器”窗口,“堆栈”等窗口以及加载程序使用的内存模块列表。在Debugger模式下执行和调试程序时,这些信息才会出现。
寄存器知识
寄存器被称为内置在处理器中的小型存储区(易失性内存-仅在计算机仍处于活动状态时才保存数据)。CPU执行命令时,必须从内存中检索指令和对指令进行解码,然后执行与指令目的相对应的操作。
在32位架构中,使用的寄存器是EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI和EIP,而64位架构会多出几个寄存器。
通用寄存器:
- EAX(寄存器寄存器-累加器):最常用于算术,逻辑和数据传输指令、乘法和除法运算使用此寄存器。对于Windows API函数,函数的返回值通常将存储在EAX寄存器中。
- EBX(基址寄存器):EBX寄存器可以直接访问存储器数据,它也是一个通用寄存器。
- ECX(计数寄存器):ECX是一个共享寄存器,可以用作各种命令的计数器。它还可能包含内存中的数据未对齐。使用计数器的命令是顺序,循环和LOOP / LOOPD指令。
- EDX(数据寄存器):是一个通用寄存器,用于包含乘法结果或除法结果的一部分。它还可以直接访问内存中的数据地址。
- EDI(目标索引):EDI通常用于处理字符串或数组的工作。该寄存器将指向目标字符串。此外它也是一个通用寄存器。
- ESI(源索引):与EDI一样,ESI也经常用于处理字符串或数组的操作。该寄存器将指向源字符串。
- EBP(基本指针):EBP指向内存位置,除了被共享外,还用作访问函数堆栈中的参数和局部变量的帧指针。
- ESP(堆栈指针):该寄存器始终指向当前堆栈顶部。根据堆栈的工作原理,该寄存器将被定向到低位地址。
因此共有8个通用的32位寄存器,即EAX,EBX,ECX,EDX,ESP,EBP,ESI和EDI。另外这些寄存器可以细分为16位和8位寄存器,如下所示:
例如,如果EAX寄存器的值为0x12345678,则AX是包含最后四位数字的16位寄存器:
AX寄存器可以被分成2个8位寄存器,它们是一对寄存器:AH包含两个数字5和6以及AL所包含的最后两个数字7和8:
可以想象,32位EAX寄存器被拆分为一个16位寄存器,称为AX。AX被分为两个称为AH和AL的 8位寄存器。同样,对于EBX寄存器(BX,BH和BL),ECX(CX,CH和CL)和EDX(DX,DH和DL),其余寄存器仅分为16位寄存器,不再细分为8位寄存器:
特殊寄存器
除了上面的通用寄存器,还有特殊寄存器,包括:
- EIP(指令指针):这是一个特殊的寄存器,它始终指向要执行的下一条指令。与其他寄存器不同,EIP不受指令直接影响。
另一个重要的寄存器是EFLAGS(标志寄存器),每个位用于反映操作的特定状态。根据计算结果启用这些标志寄存器,并根据这些标志来执行程序的执行分支。
零标志(ZF)是逆向中最常用的标志。通常用于条件分支指令中,根据先前的命令结果更改执行流程。
接下来是段寄存器,指向可执行文件的不同部分,例如CS = CODE,DS = DATA等。
使用寄存器和内存时,另一个重要的细节是最常用数据类型的大小:
重要的是要记住,BYTE为1字节,WORD为2字节,DWORD为4字节。
汇编(asm)指令
每个不同的系统/平台都会有自己的一套Asm命令。
IDA使用与调试器(例如OllyDbg / x64dbg)用不同的多种语法来解析ASM命令,因此熟悉用OllyDbg的人都会发现有点区别。
数据传输命令
- MOV
MOV dest,src:将源操作数(src)的内容复制到目标(dest)。操作:dest <-src。用于在寄存器之间,寄存器和存储单元之间传输数据或直接将数字传输到寄存器或存储单元。mov命令可以对应于高级语言中的assignment命令。
例子:第一步是将值从一个寄存器转移到另一个寄存器。
MOV EAX,EDI;EAX接收EDI的值;EDI不变,没有变化。
通常只能将数据值直接传送到寄存器或寄存器传送到寄存器,但EIP寄存器不能是目的或源。我们无法执行以下语句:
MOV EIP,EAX;此声明完全无效。
下一个示例将常量实现到寄存器中,如下所示:
MOV EAX,1;如果将数字1发送到EAX寄存器,则EAX寄存器的原先值将被覆盖(替换为新值)。
接下来是执行地址值传输到寄存器的mov语句。
下图是VEViewer.exe文件中的汇编指令(在此处下载:https://mega.nz/#!CLIgmS5S!s5qrzoxbRP5W9xblRf8bgVz5UWRcR9yGoICF-PpJbR4 )
在上面的示例中,EAX寄存器现在将获取一个内存地址的值。前面的偏移量前缀表示必须使用地址,而不是存储单元的内容。按IDA快捷键Q,IDA会将此语句转换为:
MOV EAX,46f038h;这是一个类似于OllyDbg的命令,但没有提供任何有关46f038h地址内容的信息。如果我们右键单击地址46f038,我们可以看到IDA显示的原始指令:
按IDA快捷方式G输入地址可以跳转到这条地址的位置:
这是在HEX选项卡内的信息,地址处存储的字节值为0x00,是一个DWORD:
如果返回反汇编选项卡并双击该地址,来到这里:
dword前缀在地址之前,这意味着地址的内容是DWORD,然后dd数据类型对应于DWORD,随后的0值存储在这个位置。
因此IDA告诉我们这个程序在使用这条地址存储DWORD,在右侧可以看到使用DWORD代码区域的引用。
如图所示,有两个参考点。每个箭头都是一个位置,当鼠标指针放在那里时,可以在每个位置中预览代码。
按快捷健X键,IDA可以显示引用于该地址的函数地址:
图中的第一条汇编指令读取我们在上面看到的地址dword_46F038,并将其保存到eax寄存器中。第二条语句是在地址0x46F038的内存内容中写入一个DWORD(也就是eax的值)。
总结以上的内容:
mov eax,偏移量dword_46F908
将地址0x46F908传输到EAX寄存器,即EAX = 0x46F908
mov eax,dword_46F908
将该地址指向的内容或值传递到EAX寄存器中,即EAX = 0x0
、
熟悉使用OllyDbg的话,这条命令在OLLY中显示是带有方括号的:
MOV EAX,DWORD PTR DS:[46f908]。
在IDA中当地址的前面有一个偏移量前缀时,它是指地址的数字值,而当用dword前缀是在使用内容/值。
如果遇到是方括号里用寄存器是啥?观察下图:
图中的命令使用方括号[],因为还不知道寄存器可以获取的静态值,也不知道从哪个方向获取更多信息。在这种情况下,如果EDI寄存器指向0x10000,那么这条命令是在这条内存地址中找到内容并复制到ECX寄存器中。
所以当IDA在地址前面使用偏移量前缀时,是对存储地址的引用,而不考虑存储地址上的内容。
再举一个例子:
在上图中,可以看到EAX接收0x45f4d0,因为它的前面有一个偏移量前缀unk_,说明IDA无法识别哪种数据类型会以unk(未知)作为前缀。
在图中标记的命令中,执行0x46fc50内容的第一个命令是DWORD值,使用这条命令下面的语句重定向自身,也就是0x46FC50指向的数值。
IDA可以看到存储在这条地址的值,地址0x42f302这里的mov语句将什么值传输到EAX ,双击0x46FC50可以看到以下内容:
如果没有执行引用列表中的另一个eax赋值命令,那么这条命令会将0值分配给EAX寄存器,并将另一个值存储在到0x46fc50这条地址里。
图中突出显示的语句会将DWORD值保存到内存地址,而其他命令只读取带偏移前缀的地址或读出地址当前存储的值。
除了上面的示例,当然也可以像我们之前看到的那样将常量分配给16位和8位寄存器:
上面的命令将值1分配给AL寄存器,并保留以前可从EAX寄存器获得的原始值。在这种情况下,仅更改寄存器的低字节。
上面的命令将内存地址0x459c24的内容分配给AX寄存器,并告诉我们检索到的值是WORD。
如图所示,初始值为0,但程序被执行时值将被更改。
在上图中,AX寄存器的值分配给EBX寄存器指向的地址内容。使用方括号[]表示写入EBX的内容。
上述命令是AX寄存器的值分配给ESI + 8的内容。
逆向环节-IAT表
继续逆向VEViewer.exe文件:
双击图片中显示出来很长的名称,IDA会跳转到这里:
IAT表是在执行文件在.idata或.rdata节中存储导入函数地址信息的表。如果在IDA的“十六进制视图(HEX View)”上查看,是没有函数值的,因为IAT表只在IDA执行程序调试时才会有。
IDA打开默认设置可能不太一样。要进行转换可以到“ Options ”菜单-“Demangle Names”,然后选择“ Names”:
要知道该函数来自哪个函数,双击QMetaObject 。向上滚动结果发现这些函数是从库QtCoreX.dll导入的,并且上面还有许多其他dll:
通过本文可以学习到MOV命令在IDA显示的不同例子。可以使用提供在文章里的VEViewer.exe文件在IDA进行练习和查看。
X86与X64文件架构的区别
x64体系结构被设计为x86的扩展,并且与x86指令集有很强的相似性。从代码分析的角度来看,存在一些差异:
- 32位(4字节)通用寄存器eax,ebx,ecx,edx,esi,edi,ebp和esp扩展为64位(8字节);这些寄存器分别命名为rax,rbx,rcx,rdx,rsi,rdi,rbp和rsp。
- 新增加的8个寄存器是r8,r9,r10,r11,r12,r13,r14和r15。
- 程序可以以64位(rax,rbx等),32位(eax,ebx等),16位(ax,bx等)或8位(al,bl,...)访问寄存器。 )。
- 通过在寄存器名称后面添加b,w,d或q,以字节,字,dword或qword的形式访问寄存器r8-r15。
- 在x86架构中,函数的参数在调用函数之前被压入堆栈,而在x64架构中,前四个参数传递给寄存器rcx,rdx,r8和r9。
PS:即使与x86不同,也是先压栈参数再提升堆栈分配内存给局部变量。(感谢大佬勘误,哈哈
附件文件下载
VEViewer.exe文件 https://mega.nz/#!CLIgmS5S!s5qrzoxbRP5W9xblRf8bgVz5UWRcR9yGoICF-PpJbR4