IDA实例教程详解.docx
- 文档编号:3539851
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:42
- 大小:171.84KB
IDA实例教程详解.docx
《IDA实例教程详解.docx》由会员分享,可在线阅读,更多相关《IDA实例教程详解.docx(42页珍藏版)》请在冰豆网上搜索。
IDA实例教程详解
IDA实例教程详解
作者:
笨笨雄(转载)
邮箱:
1软件环境
静态分析有很多好处,例如加壳程序(尽管对于高手来说这并不会耗费太多时间),我们不需要寻找OEP,也不需要解除自校验,只要修复IAT,DUMP下来就可以动手分析了。
假如你需要修改程序,可以使用内存补丁技术。
动态与静态,调试器与反汇编器结合可以简化分析任务,帮助我们理解代码。
因此掌握一种反汇编器是非常必要。
IDA可以说是这方面首选工具,它为我们提供了丰富功能,以帮助我们进行逆向分析。
这从IDA复杂工作界面便可以知道。
种类繁多工具栏
在分辨率不高情况,这些工具栏与反汇编窗口挤在小屏幕里,看起来不爽。
我一般把它关闭(查看=>工具栏=>主工具栏)以获得更好视觉效果。
当我们需要这些功能时候,直接使用快捷键就可以了。
下面是常用快捷键清单:
快捷键
功能
注释
C
转换为代码
一般在IDA无法识别代码时使用这两个功能整理代码
D
转换为数据
A
转换为字符
N
为标签重命名
方便记忆,避免重复分析。
;
添加注释
R
把立即值转换为字符
便于分析立即值
H
把立即值转换为10进制
Q
把立即值转换为16进制
B
把立即值转换为2进制
G
跳转到指定地址
X
交叉参考
便于查找API或变量引用
SHIFT+/
计算器
ALT+ENTER
新建窗口并跳转到选中地址
这四个功能都是方便在不同函数之间分析(尤其是多层次调用)。
具体使用看个人喜好
ALT+F3
关闭当前分析窗口
ESC
返回前一个保存位置
CTRL+ENTER
返回后一个保存位置
在工具栏下面便是工作窗口。
主要窗口分页有“IDAView-A”、“Name”、“Strings”、“Exports”和“Imports”。
对于后面3项相信大家都不会陌生了,它们分别是字符参考,输出函数参考和输入函数参考。
Name是命名窗口,在那里可以看到我们命名函数或者变量。
这四个窗口都支持索引功能,可以通过双击来快速切换到分析窗口中相关内容,使用起来十分方便。
简单输入几个字符即可定位目标
IDAView-A是分析窗口,支持两种显示模式,除了常见反汇编模式之后,还提供图形视图以与其他有趣功能。
IDA反汇编窗口
一般我们在分析时候,并不关心程序机械码,所以IDA为我们自动隐藏了这些信息。
如果你有需要,可以通过以下步骤来设置:
选项=>常规=>反汇编=>显示反汇编行部分=>机械码字节数=>修改为你允许显示大小
现在让我们以论坛脱壳版块置顶帖那个经典为例,看看图形视图表现。
首先我们到以下连接下载:
你能通过图形视图与其缩略图快速找到壳出口吗?
如图所示,标签40EA0E便是壳出口代码地址。
在OD中直接跳到该地址,下断点,然后运行到该处,再单步便能看到OEP了。
假如希望通过跳转法找OEP,相信图形视图比你在OD一个一个跳转跟随,要快得多。
再来看看这个壳另类脱法。
直接运行该程序,DUMP下来,再使用IMPORTRECIATAutoSearch功能修复输入表。
用IDA打开修复了输入表DUMP文件。
在IMPORT窗口随便选一个API,随便通过交叉参考跳转到一个函数代码。
此处为文件输入表位置
我选了RegQueryValueExA,通过交叉参考,来到Sub_402488处函数代码。
用鼠标拖动缩略图中虚线框到上方,便能看到该CALL头部了。
然后按下图指示操作:
在函数标记上点击鼠标右键
处于最上层函数,便是OEP了,使用PE工具修改文件入口为10CC。
现在函数可以正常工作了。
这个方法原理是通常我们写程序都有如下流程:
Mainproc
//代码
CALLFUN1
//代码
CALLFUN2
//代码
ENDproc
所以处于函数调用最上层便是MAIN函数了。
当然这个方法局限性很大,这里只是对该功能一种介绍。
我们留意到图表功能有两个选项,在上面例子中,我们使用是“交叉参考到”。
我想细心朋友大概能通过“交叉参考来自”左边小图标猜出它用途了。
该功能可以显示目标函数调用了什么函数,当然也包括API。
这样除了观察函数输入参数来判断是否关键CALL之外,又多了一个参考途径。
2强大IDC
有时我们需要分析一些非文件格式代码,例如ShellCode,远线程注入和病毒。
这些代码特点便是动态获取API,这给静态分析带来困难。
尽管IDA支持分析2进制文件,但是缺少IAT情况下,分析起来跟不方便。
频繁切换调试器查看并不是一个好方法。
IDC是IDA脚本语言,它功能强大,为我们提供了另一条与调试器交互途径。
如何使调试器获得IDA分析得出符号?
IDA提供多种文件格式输出,调试器可以通过解释这些文件获得一些符号。
你可以通过文件菜单中“创建文件”获得更多信息。
以OD为例,它GODUP插件支持解释MAP文件(还能加载IDASIG)。
在IDA中使用如下步骤:
菜单:
文件=>创建文件=>创建MAP文件
即可创建MAP文件,然后切换到OD,使用如下步骤便能获得符号了:
菜单:
插件=>GODUPPlugin=>MapLoader=>Loadlabels
仍然以那个经典UPX加壳NOTEPAD为例子,这次我们用OD打开,在到达OEP之后DUMP下来,不修复输入表,直接用IDA载入后看到下图:
丰富文件载入选项
需要注意是Makeimportssegment是PE文件特有选项,该选项会隐藏输入表区域所有数据,同时你获得好处便是能在图表功能中看到API调用。
假如你希望查看在输入表范围内代码或者数据,你需要使用从菜单中选择“编辑”=>“区段”以删除遮挡数据部分区段。
为了更真实模拟从内存中截取代码情况,在这里选择Binaryfile,载入偏移量选400000(根据实际代码在内存中基址来选择),然后IDA就开始尝试分析可能存在于该文件中代码了。
对照OD中OEP地址,在IDA中可以看到以下代码:
seg000:
004010CCpushebp
seg000:
004010CDmovebp,esp
seg000:
004010CFsubesp,44h
seg000:
004010D2pushesi
seg000:
004010D3callds:
dword_4063E4
seg000:
004010D9movesi,eax
seg000:
004010DBmoval,[eax]
seg000:
004010DDcmpal,22h
seg000:
004010DFjnzshortloc_4010FC
OEP处部分代码
OD中对应显示:
004010D3FF15E4634000calldwordptr[4063E4];kernel32.GetCommandLineA
使用以下ollyscript(附件中ollyGetSym.txt)提取IAT符号:
varea
varEcount//0分隔号记数器
varoFile
ask"请输入IAT起始地址"
cmp$RESULT,0
jeECancel
movea,$RESULT
ask"输出文件?
"
cmp$RESULT,0
jeECancel
movoFile,$RESULT
TryGetSym:
GN[ea]//获取该地址符号
cmp$RESULT,00000000//OLLYSCRIPT是区分00000000和0
jeETest
WRTAoFile,$RESULT_2
movEcount,0
addea,4
jmpTryGetSym
ECancel:
msg"无效输入"
ret
ETest:
cmpEcount,1//不同模块地址以0分隔
jeSend//若存在两个DWORD0则认为是末尾
addEcount,1
addea,4
jmpTryGetSym
SEnd:
Ret
使用下面IDC脚本获取符号并对相应地址重命名:
#include
staticmain(){
autoSbuffer,ea,zcount,;
=AskFile(0,"*.*","打开IAT符号文件");
CustEa=AskAddr(0,"目标IAT地址");
=fopen(,"r");
for(ea=CustEa;zcount<2;ea=ea+4){
if(Dword(ea)!
=0){
Sbuffer=readstr();
if(strlen(Sbuffer)<2){//ollyscript输出文件存在无效字符Sbuffer=readstr();//如果字符无效则再取一次字符
}
MakeNameEx(ea,Sbuffer,SN_AUTO);//为对应DWORD改名
zcount=0;
}
else{
zcount=zcount+1;
}
}
fclose();
}
GetSym.idc
正如ollyscript接近于ASM,IDC函数与其语法也近似于C语言(详见IDA帮助),在编写几个脚本之后,便能轻松掌握它用法。
seg000:
004010CCpushebp
seg000:
004010CDmovebp,esp
seg000:
004010CFsubesp,44h
seg000:
004010D2pushesi
seg000:
004010D3callds:
GetCommandLineA_
seg000:
004010D9movesi,eax
seg000:
004010DBmoval,[eax]
seg000:
004010DDcmpal,22h
seg000:
004010DFjnzshortloc_4010FC
现在可以正常显示函数调用API了
下面来看看另外一个例子中IDC表现。
附件中Exvirus.v是一个木马程序。
当然这里并不是要分析这个木马,更不会运行它,在静态分析环境下,很安全。
几乎都是乱码窗口
加密了字符,总要在使用之前解密。
也就是说可以通过加密字符交叉引用定位解密代码。
leaedx,[ebp+var_4]
moveax,offsets_XsXQqSxUsSq;"抿遽翦燥镬桢祓巢宇狃箬雉"
callsub_404BEE
通过交叉引用定位函数
由字符参考中“SOFTWARE\Borland\Delphi\RTL”可以判断该木马是用Delphi编写(也可从函数参数传递约定判断)。
在详细分析之前,先在菜单中进行如下步骤操作:
文件=>加载文件=>加载FLIRT签名文件=>Delphi7RTL/VCL/CLX
现在IDA将会根据Delphi函数特征识别出一些库函数,这样可以减少很多工作量。
CODE:
00404C2Cmov[ebp+var_8],1//已处理字符记数器
CODE:
00404C2C
CODE:
00404C33
CODE:
00404C33loc_404C33:
;CODEXREF:
sub_404BEE+6Aj
CODE:
00404C33moveax,[ebp+var_4]
CODE:
00404C36movedx,[ebp+var_8]
CODE:
00404C39movbl,[eax+edx-1]//单字节取字符解密
CODE:
00404C3Daddbl,80h
CODE:
00404C40leaeax,[ebp+var_C]
CODE:
00404C43movedx,ebx
CODE:
00404C45call@System@@LStrFromChar$qqrr17System@AnsiStringc
CODE:
00404C45
CODE:
00404C4Amovedx,[ebp+var_C]
CODE:
00404C4Dmoveax,edi
CODE:
00404C4Fcall@System@@LStrCat$qqrv
CODE:
00404C4F
CODE:
00404C54inc[ebp+var_8]
CODE:
00404C57decesi//字符长度=0跳出循环,解密完毕
CODE:
00404C58jnzshortloc_404C33
函数较长,这里只列出关键代码。
判断这部分为关键代码主要是因为整个函数就只有该处是循环。
解密是对一定长度数据进行运算,因此会有一个循环对字符中数据逐一解密。
然后从输入参数与寄存器或者堆栈关联便可以理解函数关键部分是如何工作。
由于IDA已经为我们识别出Delphi库函数,所以这里很容易便知道解密方便是对目标字符每个字节都加上80h。
下面来看看我如何使用IDC来完成解密字符工作。
#include"idc.idc"
staticmain(){
autoea,x,y,z,zbyte,SRange,TStrLen,DeCodeBuffer,DeCodeCounter,NotTarget;
x=0x404bee;
for(y=RfirstB(x);y!
=BADADDR;y=RnextB(x,y)){//通过交叉参考取得函数调用地址
for(SRange=4;SRange<0x50;SRange++){
z=y-SRange;
zbyte=Byte(z);
if(zbyte==0xb8){//moveax,mem32机械码是b8
zbyte=Dword(z+1);
ea=Dword(zbyte);
if(ea!
=0xFFFFFFFF){//判断mem32是否有效,防止识别错指令
if(Byte(zbyte-1)==1){//在字符指针前一个字节写入处理标记
break;//避免重复处理
}
PatchByte(zbyte-1,1);
TStrLen=0;
while(TStrLen<0x30){//解密循环
DeCodeCounter=zbyte+TStrLen;
DeCodeBuffer=Byte(DeCodeCounter)+0x80;
if(DeCodeBuffer==0x80)break;
PatchByte(DeCodeCounter,DeCodeBuffer);
TStrLen++;
}
MakeUnknown(zbyte,TStrLen,0);//取消IDA原来分析结果
MakeStr(zbyte,DeCodeCounter);//把该位置标记为字符
break;
}
}
}
}
}
Decode.idc
既然可以通过加密字符定位目标函数,那么也可以通过加密函数定位加密字符。
通过使用解密函数交叉引用,往上搜索,解密第一条moveax,mem32中字符。
当然这里个脚本写得有点简陋,并不能完全解决程序中加密字符。
这个就任务就留给读者来挑战吧。
这里要注意是我在编写IDC过程中遇到很多BUG,这是因为IDA区分大小写(调试了很久才知道)。
此外要转换数据类型得先把原来分析结果取消才可以。
最后要看到下图窗口,在运行脚本后,你需要重新打开字符参考窗口(不会自动刷新)。
解密后字符参考窗口
3静态脱壳
上一节我们用IDC完成了字符解密工作,既然脱壳过程实际就是对源程序解密,现在让我们来尝试在不运行壳情况下把壳解决掉。
首先到下面连接下载一个壳:
主页对这个壳介绍是可以作为Unpackme练练手,现在就以该壳主程序作为例子讲解如何静态脱壳。
首先用IDA加载该壳主程序。
seg005:
004560FAloc_4560FA:
;CODEXREF:
start:
loc_4560F4j
seg005:
004560FAcallsub_456109
seg005:
004560FA
seg005:
004560FAstartendp//入口函数结尾
seg005:
004560FA
seg005:
004560FF
seg005:
004560FF
seg005:
004560FF
seg005:
004560FFsub_4560FFprocnear;CODEXREF:
seg005:
00456104p
seg005:
004560FF;sub_456109p//红色
seg005:
004560FFcallsub_456DEF
seg005:
004560FF
seg005:
004560FFsub_4560FFendp
seg005:
004560FF
seg005:
00456104callsub_4560FF
seg005:
00456104
seg005:
00456109
seg005:
00456109
seg005:
00456109
seg005:
00456109sub_456109procnear;CODEXREF:
start:
loc_4560FAp
seg005:
00456109callnearptrsub_4560FF+1//+1表示反汇编出现混乱
正常交叉参考标记是绿色,当显示为红色时则证明与其他部分反汇编代码产生冲突。
另外在jcc,jmp和call后面出现“+X”符号(X为任意数字),一般也为反汇编出现混乱。
在正式分析之前,我们必须找到花指令规律,编写脚本,除去它影响。
现在我们从最初产生影响地方开始。
点击地址4560FF,按D
seg005:
004560FFbyte_4560FFdb0E8h;CODEXREF:
seg005:
00456p
seg005:
00456100unk_456100db0EBh;?
;CODEXREF:
sub_456109p
seg005:
00456101db0Ch
seg005:
00456102db0
seg005:
00456103db0
seg005:
00456104callnearptrbyte_4560FF
注意00456104处也是花指令之一,它作用就是让IDA误以为004560FF处为有效指令。
因此也在该位置上按D,将其转换为数据。
而在00456100处按C转换为代码。
seg005:
004560FAcallsub_456109
seg005:
004560FA
seg005:
004560FAstartendp
seg005:
004560FA
seg005:
004560FA;---------------------------------------------------------------------------
seg005:
004560FFdb0E8h
seg005:
00456100;---------------------------------------------------------------------------
seg005:
00456100
seg005:
00456100loc_456100:
;CODEXREF:
sub_456109p
seg005:
00456100jmpshortloc_45610E
seg005:
00456100
seg005:
00456100;---------------------------------------------------------------------------
seg005:
00456102db0
seg005:
00456103db0
seg005:
00456104db0E8h
seg005:
00456105db0F6h;?
seg005:
00456106db0FFh
seg005:
00456107db0FFh
seg005:
00456108db0FFh
seg005:
00456109
seg005:
00456109
seg005:
00456109sub_456109procnear;CODEXREF:
start:
loc_4560FAp
seg005:
00456109callloc_456100
seg005:
00456109
seg005:
0045610E
seg005:
0045610Eloc_45610E:
;CODEXREF:
seg005:
loc_456100j
seg005:
0045610Eaddesp,8
现在我们手动修正了一处被花掉代码。
我们知道OPCODEE8和EB后面实际是一个相对地址偏移,而不是地址编码(反汇编翻译成地址是便于分析)。
因此可能你已经想到通过搜索内存中相应指令序列,然后告诉IDA什么是代码,什么则不是。
读者可以先试试自己找出壳中花指令规律,然后对比一下结果。
经过手动整理之后,发现壳使用了下面4种花指令代码:
calllabel1
db0E8h
label2:
jmplabel3
db0
db0
db0E8h
db0F6h;
db0FFh
db0FFh
db0FFh
label1:
calllabel2
label3:
addesp,8
花指令1
Jzlabel1
Jnzlabel1
db0EBh
db2
label1:
jmplabel2
db81h
label2:
花指令2
pusheax
calllabel1
db29h
db5Ah
label1:
popeax
imuleax,3
Calllabel2
db29h
db5Ah
label2:
addesp,4
popeax
花指令3
Jmplabel1
db68h
Label1:
Jmplabel2
db0CDh,20h
Label2:
Jmplabel3
db0E8h
Label3:
花指令4
在知道花指令结构之后,容易写出下面脚本用NOP(0x90h)来代替干扰反汇编器数据:
staticPatchJunkCode(){
autox,FBin,ProcRange;
FBin="E80A000000E8EB0C0000E8F6FFFFFF";
//花指令1特征码
for(x=FindBinary(MinEA(),0x03,FBin);x!
=BADADDR;x=FindBinary(x,0x03,FBin)){
x=x+5;
PatchByte(x,0x90);
x=x+3;
PatchByte
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- IDA 实例教程 详解