2025年3月17日 星期一 甲辰(龙)年 月十六 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 软件应用 > 开发工具(IDE)

IDA 分析数组,结构体在反汇编中存储

时间:09-29来源:作者:点击数:29

IDA分析数组存储

测试代码如下:

  • /************************************************************************/
  • /*@Author : 玄都大法师
  • /*@Data : 2023/09/11
  • /*@Description : 汇编学习
  • /************************************************************************/
  • #include <stdio.h>
  • int main()
  • {
  • int arr[5] = { 1, 2, 3, 4, 5 };
  • int n = 2;
  • arr[2] = 20;
  • return 0;
  • }

去除main函数的栈帧汇编,留下有关数组的部分

  • .text:004143F5 mov [ebp+var_18], 1
  • .text:004143FC mov [ebp+var_14], 2
  • .text:00414403 mov [ebp+var_10], 3
  • .text:0041440A mov [ebp+var_C], 4
  • .text:00414411 mov [ebp+var_8], 5
  • .text:00414418 mov [ebp+var_24], 2
  • .text:0041441F mov eax, 4
  • .text:00414424 shl eax, 1
  • .text:00414426 mov [ebp+eax+var_18], 14h

进入到main函数的堆栈空间查看

数组在内存堆栈中存储是一段连续的空间,数组名就是这段空间的首地址

得到数组地址是 0x00B5FEB4

在内存搜索

数组数据的存储是从首地址开始的

在IDA分析数组,这是在对数组初始化,[EBP-18h]就是数组的首地址

双击var_18进入main的堆栈空间,修改var_18的名字为arr

把这段数据转换为数组形式,需要设置整个数组的元素个数,从首地址开始转换

IDA数组部分汇编发生了变化

可以总结出来一个公式,访问数组的元素就是通过 数组首地址+偏移量

&arr[n] = arr + 4*n

分析如下:

  • .text:004143F5 mov [ebp+arr], 1 ; 数组第一个元素
  • .text:004143FC mov [ebp+arr+4], 2 ; 数组第二个元素
  • .text:00414403 mov [ebp+arr+8], 3 ; 数组第三个元素
  • .text:0041440A mov [ebp+arr+0Ch], 4 ; 数组第四个元素
  • .text:00414411 mov [ebp+arr+10h], 5 ; 数组第五个元素
  • .text:00414418 mov [ebp+var_24], 2 ; int n = 2; 给变量n赋值
  • .text:0041441F mov eax, 4
  • .text:00414424 shl eax, 1 ; 配合上一条 4 = 0100 shL偏移一位
  • .text:00414426 mov [ebp+eax+arr], 14h ; 修改数组第三个元素 arr[2] = 20;
  • .text:0041442E xor eax, eax ; return 0

IDA分析结构体存储

测试代码

  • /************************************************************************/
  • /*@Author : 玄都大法师
  • /*@Data : 2023/09/11
  • /*@Description : 汇编学习
  • /************************************************************************/
  • #include <stdio.h>
  • struct MyStruct
  • {
  • int nNum;
  • float fNum;
  • char chA;
  • };
  • void Print(MyStruct stc)
  • {
  • printf("int %d, y %f,z %c", stc.nNum, stc.fNum, stc.chA);
  • }
  • int main()
  • {
  • MyStruct stc = {1, 2.2, 'A'};
  • stc.fNum = 5.5;
  • Print(stc);
  • return 0;
  • }

分析和结构相关的汇编代码

  • .text:004143E0 ; int __cdecl main_0(int argc, const char **argv, const char **envp)
  • .text:004143E0 _main_0 proc near ; CODE XREF: _main↑j
  • .text:004143E0
  • .text:004143E0 var_14 = byte ptr -14h
  • .text:004143E0 var_10 = dword ptr -10h
  • .text:004143E0 var_C = dword ptr -0Ch
  • .text:004143E0 var_8 = dword ptr -8
  • .text:004143E0 argc = dword ptr 8
  • .text:004143E0 argv = dword ptr 0Ch
  • .text:004143E0 envp = dword ptr 10h
  • .text:004143E0
  • .text:004143E0 push ebp
  • .text:004143E1 mov ebp, esp
  • .text:004143E3 sub esp, 0D4h
  • .text:004143E9 push ebx
  • .text:004143EA push esi
  • .text:004143EB push edi
  • .text:004143EC lea edi, [ebp+var_14]
  • .text:004143EF mov ecx, 5
  • .text:004143F4 mov eax, 0CCCCCCCCh
  • .text:004143F9 rep stosd
  • .text:004143FB mov ecx, offset unk_41C003
  • .text:00414400 call j_@__CheckForDebuggerJustMyCode@4 ; __CheckForDebuggerJustMyCode(x)
  • .text:00414405 mov [ebp+var_10], 1
  • .text:0041440C movss xmm0, ds:dword_417BE0 ; 浮点数的存储应该和编译器有关
  • .text:00414414 movss [ebp+var_C], xmm0 ; 浮点数的赋值往往借助xmm0寄存器
  • .text:00414419 mov byte ptr [ebp+var_8], 41h ; 'A'
  • .text:0041441D movss xmm0, ds:dword_417BE4 ; 字符的赋值也是往往借助xmm0寄存器
  • .text:00414425 movss [ebp+var_C], xmm0
  • .text:0041442A sub esp, 0Ch ; 这种函数传参也很有意思
  • .text:0041442D mov eax, esp ; 把esp给eax,通过eax来实现参数压入栈
  • .text:0041442F mov ecx, [ebp+var_10]
  • .text:00414432 mov [eax], ecx ; [eax]是对eax存储的地址引用,相当于 esp
  • .text:00414434 mov edx, [ebp+var_C]
  • .text:00414437 mov [eax+4], edx
  • .text:0041443A mov ecx, [ebp+var_8]
  • .text:0041443D mov [eax+8], ecx
  • .text:00414440 call sub_4113C0
  • .text:00414445 add esp, 0Ch
  • .text:00414448 xor eax, eax
  • .text:0041444A push edx
  • .text:0041444B mov ecx, ebp ; Esp
  • .text:0041444D push eax
  • .text:0041444E lea edx, Fd ; Fd
  • .text:00414454 call j_@_RTC_CheckStackVars@8 ; _RTC_CheckStackVars(x,x)
  • .text:00414459 pop eax
  • .text:0041445A pop edx
  • .text:0041445B pop edi
  • .text:0041445C pop esi
  • .text:0041445D pop ebx
  • .text:0041445E add esp, 0D4h
  • .text:00414464 cmp ebp, esp
  • .text:00414466 call j___RTC_CheckEsp
  • .text:0041446B mov esp, ebp
  • .text:0041446D pop ebp
  • .text:0041446E retn
  • .text:0041446E _main_0 endp

结构体赋值

分析print函数调用,新的调用传参

  • .text:0041442A sub esp, 0Ch ; 这种函数传参也很有意思
  • .text:0041442D mov eax, esp ; 把esp给eax,通过eax来实现参数压入栈
  • .text:0041442F mov ecx, [ebp+var_10]
  • .text:00414432 mov [eax], ecx ; [eax]是对eax存储的地址引用,相当于 esp
  • .text:00414434 mov edx, [ebp+var_C]
  • .text:00414437 mov [eax+4], edx
  • .text:0041443A mov ecx, [ebp+var_8]
  • .text:0041443D mov [eax+8], ecx
  • .text:00414440 call sub_4113C0
  • .text:00414445 add esp, 0Ch

这种函数传参调用函数,没有通过esp,借助eax寄存器来寻址把参数入栈,实际上效果和原来一样,换汤不换药。

IDA中添加结构体

在IDA空白界面右击,选择 Add struct type 或者空白处摁下insert 如果想要创建标准结构体,就点击 add standard structure

输入名字

创建成功

在ends这一行,摁下d就可以创建结构体元素,在元素一行后面摁d可以修改大小

应用结构体

选到首个元素地址,摁下y,输入需要修改的结构体名称,然后重命名

IDA的变化

结构体的特征:给一段连续空间赋值,数组也有,但区别在于,两者寻址方式不一样,而且数组元素类型单一

传递参数的方式

方式一:

  • push 0x1;
  • push 0x2;
  • push 0x3;

方式二:

  • sub esp 0xC;
  • mov [esp+0x0],1;
  • mov [esp+0x4],2;
  • mov [esp+0x8],3;

方式三:

  • sub esp 0xC;
  • mov eax,esp;
  • mov [eax+0x0],1;
  • mov [eax+0x4],2;
  • mov [eax+0x8],3;
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门