• 函数调用分析


    目录

    函数相关的汇编指令

    JMP指令

    call指令

    ret指令

    VS2019正向分析main函数

    总结调用函数堆栈变化规律

    x64dbg分析调用函数

    IDA分析调用函数


    函数相关的汇编指令

    JMP指令

    JMP 指令表示的是需要跳转到哪个内存地址,相当于是间接修改了 EIP

    call指令

    call 指令也是用来修改 EIP 寄存器的
    1. call 0x401000
    2. 相当于
    3. push 0x401000+5
    4. jmp 0x401000

    调用函数前地址

    执行后 进入函数执行代码段,call指令地址 00831f83+0x5 = 00831f88 压入堆栈

     

    ret指令

    相当于

    1. mov eip,[esp]; ESP地址内存的地址(call 函数后下一条指令地址)给EIP
    2. add esp,0x4;

    EIP存储的是一个地址,这个地址,这个地址的空间存储的是汇编指令

    VS2019正向分析main函数

    测试代码

    1. #include <stdio.h>
    2. int m = 999;
    3. int add(int a, int b)
    4. {
    5. int c = a + b;
    6. return c;
    7. }
    8. int main()
    9. {
    10. int x = 3;
    11. int y = 4;
    12. int z = add(x, y);
    13. printf("add()返回值是%d int m = %d", z, m );
    14. return 0;
    15. }

    调用堆栈

    invoke main函数调用了main函数,main函数有3个参数

    1. static int __cdecl invoke_main()
    2. {
    3. return main(__argc, __argv, _get_initial_narrow_environment());
    4. }

    main()函数汇编代码分析

    1. int main()
    2. {
    3. 00542560 55 push ebp
    4. 00542561 8B EC mov ebp,esp
    5. 00542563 81 EC E4 00 00 00 sub esp,0E4h
    6. 00542569 53 push ebx
    7. 0054256A 56 push esi
    8. 0054256B 57 push edi
    9. 0054256C 8D 7D DC lea edi,[ebp-24h]
    10. 0054256F B9 09 00 00 00 mov ecx,9
    11. 00542574 B8 CC CC CC CC mov eax,0CCCCCCCCh
    12. 00542579 F3 AB rep stos dword ptr es:[edi]
    13. 0054257B B9 03 C0 54 00 mov ecx,offset _5899AD65_test@cpp (054C003h)
    14. 00542580 E8 87 ED FF FF call @__CheckForDebuggerJustMyCode@4 (054130Ch)
    15. int x = 3;
    16. 00542585 C7 45 F8 03 00 00 00 mov dword ptr [x],3
    17. int y = 4;
    18. 0054258C C7 45 EC 04 00 00 00 mov dword ptr [y],4
    19. int z = add(x, y);
    20. 00542593 8B 45 EC mov eax,dword ptr [y]
    21. 00542596 50 push eax
    22. 00542597 8B 4D F8 mov ecx,dword ptr [x]
    23. 0054259A 51 push ecx
    24. 0054259B E8 1B EE FF FF call add (05413BBh)
    25. 005425A0 83 C4 08 add esp,8
    26. 005425A3 89 45 E0 mov dword ptr [z],eax
    27. printf("add()返回值是%d int m = %d", z, m);
    28. 005425A6 A1 28 A0 54 00 mov eax,dword ptr [m (054A028h)]
    29. 005425AB 50 push eax
    30. 005425AC 8B 4D E0 mov ecx,dword ptr [z]
    31. 005425AF 51 push ecx
    32. 005425B0 68 CC 7B 54 00 push offset string "add()\xb7\xb5\xbb\xd8\xd6\xb5\xca\xc7%d" (0547BCCh)
    33. 005425B5 E8 E8 ED FF FF call _printf (05413A2h)
    34. 005425BA 83 C4 0C add esp,0Ch
    35. return 0;
    36. 005425BD 33 C0 xor eax,eax
    37. }
    38. 005425BF 5F pop edi
    39. 005425C0 5E pop esi
    40. 005425C1 5B pop ebx
    41. 005425C2 81 C4 E4 00 00 00 add esp,0E4h
    42. 005425C8 3B EC cmp ebp,esp
    43. 005425CA E8 61 EC FF FF call __RTC_CheckEsp (0541230h)
    44. 005425CF 8B E5 mov esp,ebp
    45. 005425D1 5D pop ebp
    46. 005425D2 C3 ret

    开辟栈帧

    1. int main()
    2. {
    3. 00542560 55 push ebp
    4. 00542561 8B EC mov ebp,esp

    给函数的局部变量开辟空间,0E4h个空间

    00542563 81 EC E4 00 00 00    sub         esp,0E4h 

    保存寄存器值 

    1. 00542569 53 push ebx
    2. 0054256A 56 push esi
    3. 0054256B 57 push edi

    给24h(36个字节)初始化,每个字节为0xCC,范围是EBP(0x009bfdb0) - 0x009bfd8C

    具体细节:

    1. REP STOS 指令的作用是将一个指定的值写入字符串中的每个字节或字。
    2. EAC存储要初始化的值,0XCC ,是 int 3 截断告警(防止代码执行到此)
    3. ECX存储次数,9次,每次4个字节,一共36个字节
    4. lea取地址给EDI,目标
    5. rep stos根据DF寄存器决定赋值的方向,DF=0,低->高;高->低
    1. 0054256C 8D 7D DC lea edi,[ebp-24h]
    2. 0054256F B9 09 00 00 00 mov ecx,9
    3. 00542574 B8 CC CC CC CC mov eax,0CCCCCCCCh
    4. 00542579 F3 AB rep stos dword ptr es:[edi]

    初始化完成

    VS2019系统函数

    1. 0054257B B9 03 C0 54 00 mov ecx,offset _5899AD65_test@cpp (054C003h)
    2. 00542580 E8 87 ED FF FF call @__CheckForDebuggerJustMyCode@4 (054130Ch)

    局部变量赋值

    1. int x = 3;
    2. 00542585 C7 45 F8 03 00 00 00 mov dword ptr [x],3
    3. int y = 4;
    4. 0054258C C7 45 EC 04 00 00 00 mov dword ptr [y],4

    取地址查看

    转到对应内存空间

    maiin函数执行到最后一条语句,EAX是返回值,要清0

    1. return 0;
    2. 005425BD 33 C0 xor eax,eax

    恢复易失性寄存器

    1. 005425BF 5F pop edi
    2. 005425C0 5E pop esi
    3. 005425C1 5B pop ebx

    恢复函数局部变量空间,函数外平栈

    005425C2 81 C4 E4 00 00 00    add         esp,0E4h

    检查堆栈有无异常,VS2019函数,无需关注

    1. 005425C8 3B EC cmp ebp,esp
    2. 005425CA E8 61 EC FF FF call __RTC_CheckEsp (0541230h)

    恢复栈帧,具体细节如下:

    1. MOV ESP,EBP   
    2. pop ebp      恢复原先栈帧的栈底
    3. ret         恢复原先栈帧的栈顶
    1. 005425CF 8B E5 mov esp,ebp
    2. 005425D1 5D pop ebp
    3. 005425D2 C3 ret

    main函数调用已经分析完毕,中间还调用了add函数

    1. int z = add(x, y);
    2. 00542593 8B 45 EC mov eax,dword ptr [y]
    3. 00542596 50 push eax
    4. 00542597 8B 4D F8 mov ecx,dword ptr [x]
    5. 0054259A 51 push ecx
    6. 0054259B E8 1B EE FF FF call add (05413BBh)
    7. 005425A0 83 C4 08 add esp,8
    8. 005425A3 89 45 E0 mov dword ptr [z],eax

    具体细节:

    函数参数压入堆栈

    1. 00542593 8B 45 EC mov eax,dword ptr [y]
    2. 00542596 50 push eax
    3. 00542597 8B 4D F8 mov ecx,dword ptr [x]
    4. 0054259A 51 push ecx

    调用函数,并且下一条指令压入堆栈

    0054259B E8 1B EE FF FF       call        add (05413BBh)

    查看add函数汇编

    1. int add(int a, int b)
    2. {
    3. 开辟栈帧
    4. 00542EA0 55 push ebp
    5. 00542EA1 8B EC mov ebp,esp
    6. 开辟局部变量空间
    7. 00542EA3 81 EC CC 00 00 00 sub esp,0CCh
    8. 保存易失性寄存器
    9. 00542EA9 53 push ebx
    10. 00542EAA 56 push esi
    11. 00542EAB 57 push edi
    12. 初始化局部变量的堆栈
    13. 00542EAC 8D 7D F4 lea edi,[ebp-0Ch]
    14. 00542EAF B9 03 00 00 00 mov ecx,3
    15. 00542EB4 B8 CC CC CC CC mov eax,0CCCCCCCCh
    16. 00542EB9 F3 AB rep stos dword ptr es:[edi]
    17. VS2019的函数
    18. 00542EBB B9 03 C0 54 00 mov ecx,offset _5899AD65_test@cpp (054C003h)
    19. 00542EC0 E8 47 E4 FF FF call @__CheckForDebuggerJustMyCode@4 (054130Ch)
    20. 加法运算
    21. int c = a + b;
    22. 00542EC5 8B 45 08 mov eax,dword ptr [a]
    23. 00542EC8 03 45 0C add eax,dword ptr [b]
    24. 00542ECB 89 45 F8 mov dword ptr [c],eax
    25. c作为函数返回值,把值给eax寄存器
    26. return c;
    27. 00542ECE 8B 45 F8 mov eax,dword ptr [c]
    28. }
    29. 恢复寄存器
    30. 00542ED1 5F pop edi
    31. 00542ED2 5E pop esi
    32. 00542ED3 5B pop ebx
    33. 平栈局部变量
    34. 00542ED4 81 C4 CC 00 00 00 add esp,0CCh
    35. VS2019函数,检查堆栈是否有异常
    36. 00542EDA 3B EC cmp ebp,esp
    37. 00542EDC E8 4F E3 FF FF call __RTC_CheckEsp (0541230h)
    38. 恢复原栈帧的栈底
    39. 00542EE1 8B E5 mov esp,ebp
    40. 00542EE3 5D pop ebp
    41. 恢复原栈帧的栈顶,并且恢复程序执行流程
    42. 00542EE4 C3 ret
    43. 到此栈还未回复完全,还有函数参数

    平栈函数参数

    005425A0 83 C4 08             add         esp,8 

    把函数返回值给z

    005425A3 89 45 E0             mov         dword ptr [z],eax 

    总结调用函数堆栈变化规律

    1. 把函数参数压入栈
    2. call 函数   下一条指令地址压入堆栈(之后都是被调函数的引起的变化)
    3. 把原栈帧的栈帧基址(EBP)压入堆栈
    4. 开辟栈帧   
    5. 开辟局部变量空间
    6. 保存寄存器
    7. 给局部变量空间初始化
    8. 函数有返回值一半保存给eax
    9. 恢复寄存器
    10. 平栈 函数局部变量空间
    11. 恢复栈帧

    x64dbg分析调用函数

    定位到main函数

    add函数

    main函数

    IDA分析调用函数

    IDA其实和x64dbg一样

    1. .text:00412560 ; int __cdecl main(int argc, const char **argv, const char **envp)
    2. .text:00412560 main proc near ; CODE XREF: j_main↑j
    3. .text:00412560
    4. .text:00412560 var_24 = byte ptr -24h
    5. .text:00412560 var_20 = dword ptr -20h
    6. .text:00412560 var_14 = dword ptr -14h
    7. .text:00412560 var_8 = dword ptr -8
    8. .text:00412560 argc = dword ptr 8
    9. .text:00412560 argv = dword ptr 0Ch
    10. .text:00412560 envp = dword ptr 10h
    11. .text:00412560
    12. .text:00412560 push ebp
    13. .text:00412561 mov ebp, esp
    14. .text:00412563 sub esp, 0E4h
    15. .text:00412569 push ebx
    16. .text:0041256A push esi
    17. .text:0041256B push edi
    18. .text:0041256C lea edi, [ebp+var_24]
    19. .text:0041256F mov ecx, 9
    20. .text:00412574 mov eax, 0CCCCCCCCh
    21. .text:00412579 rep stosd
    22. .text:0041257B mov ecx, offset unk_41C003
    23. .text:00412580 call sub_41130C
    24. .text:00412585 mov [ebp+var_8], 3
    25. .text:0041258C mov [ebp+var_14], 4
    26. .text:00412593 mov eax, [ebp+var_14]
    27. .text:00412596 push eax
    28. .text:00412597 mov ecx, [ebp+var_8]
    29. .text:0041259A push ecx
    30. .text:0041259B call sub_4113BB
    31. .text:004125A0 add esp, 8
    32. .text:004125A3 mov [ebp+var_20], eax
    33. .text:004125A6 mov eax, dword_41A028
    34. .text:004125AB push eax
    35. .text:004125AC mov ecx, [ebp+var_20]
    36. .text:004125AF push ecx
    37. .text:004125B0 push offset unk_417BCC
    38. .text:004125B5 call sub_4113A2
    39. .text:004125BA add esp, 0Ch
    40. .text:004125BD xor eax, eax
    41. .text:004125BF pop edi
    42. .text:004125C0 pop esi
    43. .text:004125C1 pop ebx
    44. .text:004125C2 add esp, 0E4h
    45. .text:004125C8 cmp ebp, esp
    46. .text:004125CA call sub_411230
    47. .text:004125CF mov esp, ebp
    48. .text:004125D1 pop ebp
    49. .text:004125D2 retn
    50. .text:004125D2 main endp

  • 相关阅读:
    如何正确选择UPS负载箱?
    chrome108 版本跨域问题
    如何解决全局工业相机飞拍拖影问题
    图扑软件数字孪生民航飞联网,构建智慧民航新业态
    LabVIEW在 XY Graph中选择一组点
    Ansible任务控制loop循环、when和block条件判断介绍演示
    JAVA高级教程-Java Map(6)
    UE4_材质_湿度着色器及Desaturation算法_ben材质教程
    Android 使用FFmpeg3.3.9基于命令实现视频压缩
    20220701
  • 原文地址:https://blog.csdn.net/qq_61553520/article/details/132676793