9.IDA-重新设置函数类型、创建数组结构
2012-06-16 21:25
323 查看
1.重新设置函数类型
写一个简单的代码做测试:int fun(int a, double b) { return 0; } int _tmain(int argc, _TCHAR* argv[]) { int c = fun(1, 2); return 0; }release生成,去掉pdb,由于fun内部没有任何操作,所以IDA是无法通过类型传播来得到正确的函数参数和数据类型的,默认,IDA会生成如下函数:
为此我们来修正下它,参看下调用处的汇编
008 sub esp, 8 ; 参看标识1可知此处开始压参,此处压了8,结合下面,为double 010 fld ds:dbl_4020E8 010 fstp [esp+0Ch+var_C] 010 push 1 ; 此处压最左参数int 014 call sub_401000 ; 此处堆栈是偏移0x14,0x14-0xc = 0x8处,标识1 014 add esp, 0Ch ; 加0xc!说明是c调用,调用者平衡从而,使用Edit▶Functions▶Set Function Type命令,或者在函数名称上右击鼠标并在上下文菜单中选择SetFunction Type(或使用热键Y)来设置函数的类型
F5反汇编一下:
最后,IDA会向新修改的函数的所有调用方传播这些信息,从而改进对此处显示的所有相关函数调用的附加说明
2.创建数组结构
示例1.局部数组
先逐步分析:
修正函数
对应逆向代码如下
void *sub_401000() { void *result; // eax@1 int i; // [sp+0h] [bp-194h]@1 int array_int[100]; // [sp+4h] [bp-190h]@1 array_int[0] = 0; result = memset(&array_int[1], 0, 0x18Cu); array_int[20] = 15; for ( i = 0; i < 100; ++i ) { result = (void *)i; array_int[i] = i; } return result; }
示例2.全局数组
.text:00401000 sub_401000 proc near ; CODE XREF: _main+3p .text:00401000 .text:00401000 var_4 = dword ptr -4 .text:00401000 .text:00401000 push ebp .text:00401001 mov ebp, esp .text:00401003 push ecx .text:00401004 mov [ebp+var_4], 2 .text:0040100B mov dword_403018, 0Ah .text:00401015 mov dword_40301C, 14h .text:0040101F mov dword_403020, 1Eh .text:00401029 mov eax, [ebp+var_4] .text:0040102C mov dword_403018[eax*4], 28h .text:00401037 mov esp, ebp .text:00401039 pop ebp .text:0040103A retn
先逐步分析:
.text:0040102C mov dword_403018[eax*4], 28h ; 暗示dword_406018为dword数组
基于IDA分配的哑名,我们知道,全局数组由从地址00403018开始的12个字节组成。在编译过程中,编译器使用了固定索引(0、1、2)来计算数组中对应元素的具体地址(00403018、0040301c和00403020),所以跳转到地址00403018
创建数组结构
要创建数组,首先选择数组中的第一个元素(这里我们选择的是dword_403018)1.在创建数组之前,首先要保证第一个元素的大小更改为适当的值(使用D键切换,由Option—>Setup Data Types选中项来决定轮换),即确认数组中元素的大小
2.然后通过Edit▶Array命令打开如图所示的“创建数组”对话框
•Array element Width(数组元素宽度)。这个值表示各数组元素的大小(这里为1字节),它由你在打开对话框时选择的数据值的大小决定。
•Maximum possible size(最大可能大小)。这个值由自动计算得出,它决定在遇到另一个已定义的数据项之前,可包含在数组中的元素(不是字节)的最大数目。你可以指定一个更大的值,但这需要随后的数据项为未定义数据项,以将它们吸收到数组中。
•Number of elements(元素数量)。你可以在这里指定数组的具体大小。数组占用的总字节数可通过“元素数量×数组元素宽度”计算得出。
•Items on a line(行中的项目)。指定在每个反汇编行显示的元素的数量。通过它可以减少显示数组所需的空间。
•Element width(元素宽度)。这个值仅用于格式化。当一行显示多个项目时,它控制列宽。
•Use“dup”construct(使用重复结构)。这个选项可将相同的数据值合并起来,用一个重复说明符组合成一项。
•Signed elements(有符号元素)。表示将数据显示为有符号还是无符号的值。
•Display indexes(显示索引)。使数组索引以常规注释的形式显示。如果你需要定位大型数组中的特定数据,可以使用这个选项。选择该选项还将启用Indexes单选按钮,这样就可以选择每个索引值的显示格式。
•Create as array(创建为数组)。不选择这个选项似乎有悖于本对话框的目的,该选项默认处于选中状态。如果你只希望指定一定数量的连续项目,而不是将它们组合成一个数组,即可取消该选项。
•Items on a line(行中的项目)。指定在每个反汇编行显示的元素的数量。通过它可以减少显示数组所需的空间。•Array element Width(数组元素宽度)。这个值表示各数组元素的大小(这里为1字节),它由你在打开对话框时选择的数据值的大小决定。 •Maximum possible size(最大可能大小)。这个值由自动计算得出,它决定在遇到另一个已定义的数据项之前,可包含在数组中的元素(不是字节)的最大数目。你可以指定一个更大的值,但这需要随后的数据项为未定义数据项,以将它们吸收到数组中。
•Number of elements(元素数量)。你可以在这里指定数组的具体大小。数组占用的总字节数可通过“元素数量×数组元素宽度”计算得出。基于IDA分配的哑名,我们知道,全局数组由从地址0040B720开始的12个字节组成。在编译过程中,编译器使用了固定索引(0、1、2)来计算数组中对应元素的具体地址(0040B720、0040B724和0040B728)
示例3.栈分配的数组
编译器几乎以完全相同的方式处理栈分配的数组和全局分配的数组。sub_401000 proc near var_10= dword ptr -10h var_C= dword ptr -0Ch var_8= dword ptr -8 var_4= dword ptr -4 push ebp mov ebp, esp sub esp, 10h mov [ebp+var_10], 2 mov [ebp+var_C], 10 mov [ebp+var_8], 20 mov [ebp+var_4], 30 mov eax, [ebp+var_10] mov [ebp+eax*4+var_C], 40 mov esp, ebp pop ebp retn先逐步分析:
mov [ebp+eax*4+var_C], 40 ; 暗示var_C为int数组双击var_C,使用array分配:
push ebp mov ebp, esp sub esp, 10h mov [ebp+var_10], 2 mov [ebp+var_C], 10 mov [ebp+var_C+4], 20 mov [ebp+var_C+8], 30 mov eax, [ebp+var_10] mov [ebp+eax*4+var_C], 40 ; 暗示var_C为int数组其代码如下:
int L_array[3]; int idx = 2; L_array[0] = 10; L_array[1] = 20; L_array[2] = 30; L_array[idx] = 40;
示例4.堆分配的数组
处理堆分配的数组的主要区别在于,它必须根据内存分配函数返回的地址值,生成对数组的所有引用push ebp mov ebp, esp sub esp, 0Ch push 0Ch ; unsigned int call ??2@YAPAXI@Z ; operator new(uint) add esp, 4 mov [ebp+var_C], eax mov eax, [ebp+var_C] mov [ebp+var_8], eax mov [ebp+var_4], 2 mov ecx, [ebp+var_8] mov dword ptr [ecx], 0Ah mov edx, [ebp+var_8] mov dword ptr [edx+4], 14h mov eax, [ebp+var_8] mov dword ptr [eax+8], 1Eh mov ecx, [ebp+var_4] mov edx, [ebp+var_8] mov dword ptr [edx+ecx*4], 28h mov esp, ebp pop ebp retn
先逐步分析:
call ??2@YAPAXI@Z ; operator new(uint) add esp, 4 mov [ebp+var_C], eax ; eax保存了new的堆指针 mov eax, [ebp+var_C] mov [ebp+var_8], eax ; var_8保存了new的堆指针 mov [ebp+var_4], 2 ; var_4 = 2 mov ecx, [ebp+var_8] ; ecx保存了new的堆指针 mov dword ptr [ecx], 0Ah ; new的堆指针(int[0]=0a) mov edx, [ebp+var_8] ; edx保存了new的堆指针 mov dword ptr [edx+4], 14h ; int[1]=0x14 mov eax, [ebp+var_8] ; eax保存了new的堆指针 mov dword ptr [eax+8], 1Eh ; int[2]=0x1e mov ecx, [ebp+var_4] ; ecx=2 mov edx, [ebp+var_8] ; edx保存了new的堆指针 mov dword ptr [edx+ecx*4], 28h ; int[2]=0x28其代码如下:
int *heap_array = new int[3]; int idx = 2; heap_array[0] = 10; heap_array[1] = 20; heap_array[2] = 30; heap_array[idx] = 40;
相关文章推荐
- 9.IDA-重新设置函数类型、创建数组结构
- 数组和指针、数组指针和指针数组、函数指针和指针函数、数组标识符的意义、静态和动态创建的数组的本质区别、标识符类型判断方法
- 类型之间进行隐式和显示转换&创建使用枚举&创建使用结构类型&创建使用数组&;如何处理字符串值
- IDA设置函数类型
- 利用函数重载分别创建三个函数,分别是计算2个数的和,3个数的和,4个数的和/利用函数重载分别创建三个函数,分别计算int类型数组中最大值,stirng 类型数组中最长的字符串,double类型数组中最
- 关于结构指针类型数组做函数参数的一个问题#include<stdio.h>typede
- 测试常用shell语句——数值,数组类型;函数创建
- JavaScript DOM 中创建元素 用 setAttribute()函数设置属性值
- 如何设置IQueryable的类型为函数返回的类型??
- C语言 与结构体相关 函数 指针 数组
- 【Unity&C#&数组】如何创建一个存放任何类型变量的数组
- PHP快速创建数组的函数
- //4.创建一个数组, //实现函数init()初始化数组、 //实现empty()清空数组、 //实现reverse()函数完成数组元素的逆置。 //要求:自己设计函数的参数,返回值。
- C语言中值得深入知识点----数组做函数参数、数组名a与&a区别、数组名a的"数据类型"
- 函数_内存结构_数组_排序_选择排序_冒泡排序_折半查找_插入排序_进制转换数组
- 创建一个同种类型数据的数组
- C Primer Plus学习 四十八 使用结构数组的函数
- JavaScript引用类型:使用对象和创建并操作数组
- C机顶盒开发实战常用初始化类型:数组、结构、指针
- C#中Array类创建动态类型、长度的数组