IDA逆向技巧之美

IDA的逆向分析水平就是一个逆向工程师的水平;
7.1 IDA与OD的联合使用html

通常使用OD下断点,找到关键代码位置,而后使用IDA静态看流程。
须要注意的是IDA须要与OD基地址对齐,这样才方便在IDA中查找代码位置,具体方式以下:算法

Edit --->  Segment ----- Rebase  Program  : 设置基地址;数据库

在WINdbg中基地址在“符号”中查看;在OD中基地址在Model中查看;数组

IDA中G + 地址,便可找对对应位置;sass

 

 
7.2 数据不当心转换成为函数,如何处理?数据结构

若是不当心使用P将数据识别成了函数,可使用D,转换成数据,再用C转换成为代码;app

毕竟IDA不存在撤销功能;ide

 
7.3 IDA如何建立结构体?函数

7.3.1 结构体的建立   工具

IDA中结构体成员通常出如今:类初始化的地方(XX.dll);

根据成员的多少,咱们建立结构体的大小,注意虚表vt占4个字节;通常有三个地方有助于咱们建立结构体:初始化函数成员列表、memcpy函数的使用、数据库字段;

在初始化函数中看见最后一个成员为V1[239],能够 使用“Reset Point   Type” 能够改成:v1-> 1036,这样就能看到成员在的偏移,就能够设置结构体大小为1036 + 4.。

建立告终构体后,structure窗口中能够N改写字段的名称;

7.3.2 结构体的使用

建立好结构体后,咱们就可使用Y来修改分析的数据类型;

7.3.3 结构体的导入和导出使用

有时咱们须要在一个数据库中建立结构体,在另外的一个数据库中使用,具体方法:

在数据库A的localtype视图中选中须要导出的数据类型,右键 --- “export to header”,若是是多个结构体写到同一个文件,请选择追加方式(Append),导出到一个.h文件;

接下来是导入到另一个数据库,具体方法:

Ctrl + F9 :”选择一个C文件头去解析”,选择须要导入的一个文件,这样咱们就会能够在LocalType中查看咱们自建的结构体;

7.3.4 建立结构体  例子

通常方法构建结构体(方法1):在structure窗口,Insert 一个结构,本身命名(如struct_4),在end处使用D添加结构体数据,在成员处D 切换占有的字节数(db、dw、dd),在成员处使用Y来改变识别类型(int、float、double、LPVOID、BYTE field_60[1024]、)
使用: 在相应的rdata处,使用Y改变当前位置的识别类型为struct_4;
例如:

建立结构体数组:
00000000 struc4          struc ; (sizeof=0x28, mappedto_194)
00000000                                         ; XREF: .data:stru_A47A220/r
00000000 field_0         dw ?
00000002 field_2         db ?
00000003 field_3         db ?
00000004 field_4         dd ?
00000008 field_8         dd ?
0000000C field_C         db ?
0000000D field_D         db ?
0000000E field_E         db ?
0000000F field_F         db ?
00000010 field_10        dd ?
00000014 field_14        dd ?
00000018 field_18        dd ?
0000001C field_1C        dd ?
00000020 field_20        dd ?
00000024 field_24        dd ?
00000028 struc4          ends
例子: struc4 stru_A47A220[77]
数据区的 stru_A47A220    struc4 <0FC39h, 0, 0, 100h, 0, 0, 0, 0, 0, 1.0, 1.0, 0, 0, 1, 1>....
7.4 IDA如何建立虚表

虚表的建立方式与结构体很相似,关键是要找到虚表的位置,须要使用 OD来进行跟踪,虚表的地址通常存在于EAX中,对应找过去就能知道是那个库里面的函数集合;

虚表的获取: 都是先获得this 指针,而后获得虚表指针,再成员函数调用须要传递this指针到ecx,最后间接调用,具体:

mov  ecx, dword ptr[ebp - 14h]  ; ecx 获得this指针

mov  edx, dword ptr [ecx]  ; 获得虚表地址,this指针指向的第一个4字节就是虚表地址; edx 就是虚表地址;

mov esi,esp

mov ecx, dword ptr [ebp -14h]     ;成员函数调用,须要ecx保存this指针;

call dword ptr [edx + 4]      ;间接调用 虚函数;

 

 

 

能够直接写一个虚函数的调用例子,使用IDA来分析;

7.4.1  建立虚表 例子
创建虚表:
00000000 functionVT struc ; (sizeof=0x34, align=0x4, copyof_192)
00000000 sub_10001110    dd ?
00000004 sub_10002210    dd ?
00000008 sub_100010D0    dd ?
0000000C sub_10001000    dd ?
00000010 sub_10001090    dd ?....
functionVT ends
上面这个函数的虚表来自于rdata 中的虚函数列表:
.rdata:0A46F570 ??_7CJ2190_PID_Decoder@@6B@ dd offset sub_A411110
.rdata:0A46F570                                         ; DATA XREF: sub_A452B00+C
.rdata:0A46F574                 dd offset f_baseFuncton_sub_E282210 ;
.rdata:0A46F578                 dd offset sub_A4110D0
.rdata:0A46F57C                 dd offset sub_A411000
.rdata:0A46F580                 dd offset sub_A411090
…..

创建类:
00000000 basestructure struc ; (sizeof=0x51C, align=0x4, mappedto_193)
00000000 VT              dd ?                    ; offset
00000004 field_4         dd ?
00000008 field_8         dd ?
basestructure…ends
将:VT 识别为:functionVT*  就能够获得basestructure的虚表;
例如:
result =(*(unsigned __int8 *)(*(_DWORD *)a1 + 0x20))(a1);
将a1定义为 basestructure * 类型,就能识别成为:
result = a1->VT->sub_1000CAD0(a1);
优势:看到调用的函数,方便静态分析;

7.4.2  快捷添加虚表结构体的快捷的方式(方法二)

咱们知道编译后虚表存在数据区,找到虚表头就能够看到当前类中的全部虚函数列表;这样咱们在LocalType中 建立一个结构体,XXXVT ,将全部的虚表名称off_XXX 都赋值到结构体中,添加上类型int ,肯定,而后双击结构体名,此时,会提示是否导入结构体到数据库,YES,而后再structure 窗口中就能够看到定义的虚表结构体了,这样,就能够Y来识别虚表了;

这样经过C的方式导入结构体的方式比在structure窗口中逐个添加成员要快不少;

 

 
7.5 IDA如何肯定数据是数组类型?

Data区中被引用的地方通常是数组;

见:《如何提取DLL中的数据》

见:《如何访问DLL的函数》
7.6 IDA 如何使用UTF-8 显示中文字符

Alt + A 能够改变字符显示 格式,在DLL中全部的data区都是使用十六进制的数值显示的;

Alt + A : 设置---- “ASCII String style ”-----“set  default encoding”。

若是想要在Hex -rays的伪代码中显示出字符串,能够设置:“Edit”---plugins ---- Option----Analysis --- “Print only constant string literals”

 
7.7 IDA 的强大之处---- 交叉引用

X:一个地方引用另一个地方;

体现:双击、X、subView-Cross ref

在IDA-View-A 模式下,Xrefs graph to :表示该函数被其余哪些函数调用的信息;Xrefs graph  from :函数调用其余函数的信息;
字符串窗口和交叉引用 是IDA的强大之处,经常用于代码片断定位,很是关键;

 
7.8 IDA 反编译失败1--- Decomplication failure

IDA常常会解析错误,咱们要学会如何处理这些错误,才能获得伪代码;

可能缘由1:函数约定的错误;

可能缘由2:函数参数识别错误;

解决方法:分析函数的参数个数和调用约定,Y从新定义函数;

若是判断不出是哪一种约定,能够D成数据,再用tab进行转成伪代码,能够看到反编译后成为了Jumpout(xxxxx),屏蔽了细节,这种方式,只是用来随便看看代码;

 
7.9 IDA 反编译失败2--- SP- analysis failed

使用IDA -- Options ---Disassembly ---Display disassenmly  Line Parts ---- Stack Pointer,勾上能够看到SP,正常状况下SP的值在函数头和尾都是0000 ,表示堆栈是平衡的;

若是函数识别错误,Alt + p: 能够指定函数的头尾;

 
7.10 IDA 反编译失败3--- Positive sp value has  been found

有些汇编指令无函数名,表示是虚函数,IDA很容易出错;

如: call  dword   ptr[eax + 4]

V解决:ALT + K,设置SP当前为0x4X,这里X表示的是Call 以前有几个push。这样作能识别代码,能分析,可是会引发堆栈不平衡。

7.11 IDA 自动优化: Debug 和Release版本的不一样

常量、简单算法,在生成Release 版本的时候被优化; 相对而言, debug版本中有不少的无关逻辑的代码,例如:判断越界的函数等;

7.12 IDA 能够识别当前文件的类型

C#: Mircosoft.net  assembly [peldw]

7.13 IDA 如何修改数据库

 方式1、找到须要修改的位置,Edit---Patch pragram ----Assemble ;加入汇编语言,例如:给函数的返回值直接修改成2,反回;

mov eax,2

retn

若是是stdCal 的话,须要使用retn 4

修改后,在函数头P,函数对齐后,当前函数直接返回 2,而原先的逻辑都被注释掉了;
注意,此时修改并不会更新原始程序文件,实际只是修改了IDA的项目文件 idb。
最后,使用Edit---Patch pragram ----Apply patch to input file,这样就能修改原始文件。

方式2、使用UE打开,直接找到须要修改的函数的字节码,修改字节码也是同样的,例如 0x90 ----nop;

再使用Edit--- patch  program ----Apply patches  to input file ,OK 便可;
 

7.14 IDA Send Data 的识别

从Write File回溯,SendData通常被不少的地方调用;

7.15 IDA 取一个富含意义的名称,有助于理解。

7.16 IDA 跟踪技巧:注释+ 更名 :  雁过留声 很重要...

7.17 IDA  变量静态分析

7.17.1  X : type = W/O  时能够找到当前变量写的地方,能够直接看到关键逻辑,进而进行猜想;

7.17.2  数组的静态分析

dword_1002FEBE8 = HeapAlloc(hHeap, 8u, 8*g_count);

表示:分配内存8*count,每一个元素有8字节,分配的内存每每与数据库对应;

*(_BYTE*)(dword_10031AC4 + 8*V7 + 1) = g_DataArry[V8].size

表示:元素8字节,V7是偏移元素个数,1表示元素内偏移,_BYTE 表示取出的是一个字节,赋值给size;

7.17.3  函数的静态分析

一、看懂函数流程后肯定函数的意义;

二、若是调用dll中的函数,GetProAddress,函数名每每都是直接能够看到的;

 

7.18  根据lib文件制做sig文件(参考IDA权威指南)

Sig文件能使得IDA识别更多的符号,便于分析,F5刷新;

一、使用IDA打开lib,能够看出lib里面有多少个obj文件;

二、使用link.exe 将lib中的obj文件导出来(这个link.exe 来自于哪里?)

命令:link -lib /extract:testCplusplusCollect.obj  testCplusplusCollect.lib
获得的是testCplusplusCollect.obj
没找到Link.exe ,
其实,这个obj文件在lib文件编译生成时会在debug目录生成(我是直接拷过来的哈);

据说VC里面的Lib.exe 也有这个功能。据说能够直接使用pcf.exe [lib文件名].lib ,会生成[lib文件名].pat 。
    没试过,读者能够试试;

三、使用pcf.exe 将obj文件制做成为pat文件。

从IDA安装目录中找到pcf.exe,拷贝到testCplusplusCollect.lib 同级目录下;
命令:pcf testCplusplusCollect.lib
在同级目录获得了testCplusplusCollect.pat。

四、使用sigmake.exe将PAT文件转换成为sig文件。
IDA_65_Utils\flair65\bin\win\sigmake.exe
命令:sigmake.exe  testCplusplusCollect.pat  testCplusplusCollect.sig
在同级目录获得了testCplusplusCollect.sig。

五、在IDA中去加载sig文件
将testCplusplusCollect.sig 拷贝到IDA的sig目录,再使用FILE -> LoadFile àFILTER signature File;
 

7.19  IDA反编译失败:too big  Funtion

解决方法: MAX_FUNCSIZE 改大便可;

7.20 结构体:若是知道告终构体的C表示,IDA如何添加

在TypeLocal(shift + F1 )的界面,insert 跳出输入对话框,在里面复制结构体就好了。

双击添加后的类型,提示“是否加入当前的数据库”,选择能够,那么在structure试图中就能获得咱们想要的类型,能够在反编译试图中使用Y设置此类型;

 

7.30 若是将全局的字符串,显示在代码中?

Edit ---plugins --- Hex-Rays decomplier -Option -
Print only  constant string literals ”把这个勾去掉就能,将全局的字符串给显示出来了。

7.31 打标签与修更名字

修更名字:N
打标签:JUMP/Mark postion 中“标记当前的位置”而后可使用Ctrl + M 来快速跳转到标签的位置;

之前我一直这么作的: 分析到了哪一个函数,就将函数名字N一下,改为YY开头,这样我就能够在FUnctionList中快速找到我分析过的函数;

7.32 如何解决IDA key黑名单检测

提示:“sorry, this database has been  created by a pirate version of IDA”

这是由于IDA的key 黑名单检测,解决方法以下:十六进制工具将ida.dll 或 ida64.dll的地址0x277560 ~ 0x277750 的数据改成0 便可经过检测;这部分是全部的黑名单Key的MD5值。


7.33 如何使得IDA将全部的数值都用十六进制表示;

插件: Edit  ---Plugins --- Hex-Rays Decompiler ---- options ---“Default   radix”  填上16便可;

7.34 如何在伪代码中将全局的dword_454670 改成字符串显示?

将数据A转换为c-typle 字符串;而后:在伪代码中F5 就能将dword_454670 转成:

 

7.35  F5 反编译后提示: “Out of memory”

有时候函数太大,会这样提示,打开Hex-ray的选项,提示咱们能够在 HexXXX.cfg中修改max_funcszie.

好像只有7.0以后的IDA配置文件中有这个属性。

 

7.36  F5 反编译的代码分支太多,代码太长,如何作?

将分析过的分支缩进,方法: 右键--collapse item 就行,若是想看里面的内容,同样操做选uncollapse;

7.37 F5 的伪代码加上注释后,有时候注释不见了;
当伪代码很大的时候,你走过一遍流程,写下了不少的注释(特别是多行的注释),当分析清除一个数据结构体,改变代码的数据类型的是,就会发现字节写下的注释,莫名其妙的就没了,并且IDA不提供撤销功能。
缘由:多是识别为多行的伪代码,改变数据结构类型后,引发行数的变化,通常为缩减了不少行,此时会致使注释被掩住;
解决方法:没有想到好的方法,当须要逆向分析代码量大的时候,能够每作一个步骤,处处.c备份一次。

7.36 can't load file
当打开idb的时候,显示不能加载数据,那么,可能有两个缘由:
一、IDA是低版本的,idb是高版本生成的; 据说是有解决这个问题的插件;
二、IDA的路径不能为中文,改成英文目录;

7.38  在汇编处按Tab键发现反汇编的C预研与汇编指令对不上。
缘由:汇编指令没有识别成函数,因此反汇编不会显示对应的C伪代码。未识别的汇编指令段地址是暗红色的,识别出来的是黑色(颜色是默认色,能够设置);

7.38  arm 与 thumb 之间指令转换 按快捷键 Alt+g, Value 填 0,切换为 arm, Value 填 1,切换为 thumb。  

相关文章
相关标签/搜索