测试代码
#includeint check (int num) { if (num == 10) { printf("Correct\n"); return 1; } return -1; } int main() { int num; printf("Please input a number:\n"); scanf("%d", &num); while (1) { if (check(num) == 1) { break; } else { printf("Wrong number\n"); printf("Please input a number:\n"); scanf("%d", &num); } } }
IDA Pro界面
打开后有New(新建), Go(运行), Previous(上一个),一般选Go就可以了。
然后直接把要分析的文件拖进IDA里面,在Load a new file界面里默认设置就可以,直接点ok。可能会弹出一个DWARF info found界面,也是直接ok就可以了。
加载成功后的界面
上面是菜单栏,下面是Output window(消息窗口),左边的Functions window(函数表) Graph overview(流程图),主窗口里面还有
IDA View-A(分析视图窗口)
Hex View-1(十六进制视图窗口)
Structures(添加结构体信息窗口)
Enums(添加枚举信息窗口)
Imports(分析文件中的导入函数信息窗口)
Exports(分析文件中的导出函数信息窗口)
IDA代码段
通常IDA对一个PE文件逆向出来的代码中,
存在四个最基本的段text、idata、rdata、data,
四个段为PE文件的结构中对应的段。
text段
该段位程序代码段,在该段一开始就可以看到:
.text:00401000 ; Segment type: Pure code .text:00401000 ; Segment permissions: Read/Execute
这里的段类型跟权限说明很清楚: 分别为代码段和可读可执行。需要注意的是,borland这里叫做code,而不是text
idata、rdata、data段
从命名上可以看出,三个段全为存放特殊数据的段,但IDA根据PE文件的格式将数据段中不同类型的数据区分开来。
VC开发工具将INC,LIB,RES放在数据段,DELPHI也类似,同时由于Delphi的窗体文件*.dfm在源代码中使用编译指令{$R *dfm}作为res资源放在数据段中,因此像delphi的反汇编工具dede就根据这些窗体资源数据,分析出相当清晰的源代码与窗体事件的对应地址,当然实现代码还是汇编代码。
1) idata段:
该段在一开始一般有类似下面的说明:
.idata:0049B000 ; Section 2. (virtual address 0009B000) .idata:0049B000 ; Virtual size : 0001717E ( 94590.) .idata:0049B000 ; Section size in file : 00018000 ( 98304.) .idata:0049B000 ; Offset to raw data for section: 0009B000 .idata:0049B000 ; Flags 40000040: Data Readable .idata:0049B000 ; Alignment : default .idata:0049B000 ; .idata:0049B000 ; Imports from ADVAPI32.dll .idata:0049B000 ; .idata:0049B000 ; =========================================================================== .idata:0049B000 .idata:0049B000 ; Segment type: Externs .idata:0049B000 ; _idata
明显是一个Imports函数的代码段,这里集中所有外部函数地址,代码中会先跳到该地址后再执行,PE文件加载器在开始会获取真实的函数地址来修补idata段中的函数地址。
与之对应的exports是edata,
表面上看PE文件对该段的定位是特殊数据段。
2)rdata段
名字上看就是资源数据段,程序用到什么资源数据都在这里,资源包括你自己封包的,也包括开发工具自动封包的。
3)data段
这个段存放程序的全局数据、全局常量等。
简单分析
分析的时候我们要先找到主函数,可以在函数表里面找到main函数,
也可以在分析视图窗口里点击main函数后按下空格进入汇编代码窗口,
进入后可以按下f5查看伪代码(不能f5时就只能看汇编代码了)
伪代码和实际代码可能有些不同,但逻辑都一致。
按下'/'对代码进行注释。
点击变量或者函数名
按下'N'可以修改变量或者函数的名字,
按下'X'可以看到哪些地方使用了改变量或者函数,
按下'G'可以看到该变量或者函数的地址
双击函数名可以进入该函数。
IDA pro快捷键
main函数汇编代码
.text:00401486 ; =============== S U B R O U T I N E ======================================= .text:00401486 .text:00401486 ; Attributes: bp-based frame .text:00401486 .text:00401486 ; int main() .text:00401486 public _main .text:00401486 _main proc near ; CODE XREF: sub_4011B0+D3p .text:00401486 push ebp .text:00401487 mov ebp, esp .text:00401489 and esp, 0FFFFFFF0h .text:0040148C sub esp, 20h .text:0040148F call ___main .text:00401494 mov dword ptr [esp], offset aPleaseInputANu ; "Please input a number:" .text:0040149B call _puts .text:004014A0 lea eax, [esp+1Ch] .text:004014A4 mov [esp+4], eax .text:004014A8 mov dword ptr [esp], offset aD ; "%d" .text:004014AF call _scanf .text:004014B4 .text:004014B4 loc_4014B4: ; CODE XREF: _main+70j .text:004014B4 mov eax, [esp+1Ch] .text:004014B8 mov [esp], eax ; num .text:004014BB call __Z5checki ; check(int) .text:004014C0 cmp eax, 1 .text:004014C3 setz al .text:004014C6 test al, al .text:004014C8 jnz short loc_4014F8 .text:004014CA mov dword ptr [esp], offset aWrongNumber ; "Wrong number" .text:004014D1 call _puts .text:004014D6 mov dword ptr [esp], offset aPleaseInputANu ; "Please input a number:" .text:004014DD call _puts .text:004014E2 lea eax, [esp+1Ch] .text:004014E6 mov [esp+4], eax .text:004014EA mov dword ptr [esp], offset aD ; "%d" .text:004014F1 call _scanf .text:004014F6 jmp short loc_4014B4 .text:004014F8 ; --------------------------------------------------------------------------- .text:004014F8 .text:004014F8 loc_4014F8: ; CODE XREF: _main+42j .text:004014F8 nop .text:004014F9 mov eax, 0 .text:004014FE leave .text:004014FF retn .text:004014FF _main endp
汇编代码
main函数伪代码
和原代码差不多
int main() { int v1; // [sp+1Ch] [bp-4h]@1 __main(); puts("Please input a number:"); scanf("%d", &v1); while ( check(v1) != 1 ) { puts("Wrong number"); puts("Please input a number:"); scanf("%d", &v1); } return 0; }
字符串搜索
在IDA里也可以利用字符串搜索的方式来找到特定的函数,按下Shift+F12 IDA就会在Strings window列出所有的字符串,然后按下Alt+T进行精确搜索想要的字符串,Ctrl+T重复上一次的搜索(程序里多个地方用到该字符串),选中的3个字符串就是我们程序用的的字符串
双击任意一个字符串就会自动跳转到分析视图窗口的rdata段,并且前面地址会高亮显示,在Hex view里也可以看到字符串对应的16进制码
双击DATA XREF:后面的函数名就可以跳转到对应的函数
代码修改
如果我们想要把check函数里的if(num == 10)修改成if(num == 1),可以利用Hex view窗口来进行修改。
先找到这一条语句相对应的地址,单击这个地址,然后转到Hex view窗口,高亮显示的就是我们需要修改的地方了。
10对应的16进制是0A,所以只要修改0A就可以了,右键选择Edit或者按下F2,把光标移动到0A的位置,
然后直接输入数值,修改后的地方会变成红色,修改完成后右键选择Apply changes或者按下F2保存修改。
这时候回到分析视图窗口就会发现10变成1了伪代码里也修改了。在IDA中验证修改正确后,可以使用UltraEdit或010Editor来修改原始程序文件。
IDC脚本
在IDA里按下Shift+F2可以打开IDC脚本编辑界面或者在菜单栏中File->Script file载入idc文件
IDC脚本语法
auto str = 0x00405064; // Correct字符串第一个字符的地址 auto i, x; // 定义2个变量 for(i = 0; i < 8; i++) { // for循环 x = Byte(str); // 每次取一个Byte Message("%s", x); // 打印这个Byte的字符 str = str + 1; // 更新到下一个字符的地址 }
点击run后在Output window中会显示运行结果
IDA动态调试
在IDA里可以对汇编代码进行动态调试
先在菜单栏里找到Debugger选项,然后在下拉框里选择Switch debugger然后选择Local Win32 Debugger。或者在工具栏里的下拉框里直接选择Local Win32 Debugger。
在分析视图窗口中的左边可以单击蓝色的小圆点来设置断点,设置后那一整条语句会被红色高亮显示。
在工具栏的Open breakpoints window里可以看到设置的所有断点。
按下F9或者点击工具栏里的绿色箭头就可以对汇编代码进行动态调试了。
F7单步步入调试会进入函数内部。
F8进行单步步过调试不进入函数内部。
F9让程序继续运行直到遇到断点。
汇编代码动态调试界面
工作区
工作区一共有3个主窗口,2个副窗口,我们主要用到的是第一个主窗口(Debug view)和它的两个副窗口IDA View-EIP(汇编代码窗口),Breakpoints(断点窗口)。
寄存器窗口
这个窗口里会显示每个寄存器里放的数据
寄存器介绍
Comments | NOTHING