继续更新个人的学习条记,
其它条记传送门
逆向基础条记一 进制篇
逆向基础条记二 数据宽度和逻辑运算
逆向基础条记三 通用寄存器和内存读写
逆向基础条记四 堆栈篇
逆向基础条记五 标志寄存器
逆向基础条记六 汇编跳转和比较指令
逆向基础条记七 堆栈图(重点)
逆向基础条记八 反汇编分析C语言
逆向基础条记九 C语言内联汇编和调用协定
逆向基础条记十 汇编寻找C程序入口
逆向基础条记十一 汇编C语言根本类型
逆向基础条记十二 汇编 全局和局部 变量
逆向基础条记十三 汇编C语言类型转换
逆向基础条记十四 汇编嵌套if else
逆向基础条记十五 汇编比较三种循环
逆向基础条记十六 汇编一维数组
逆向基础条记十七 汇编二维数组 位移 乘法
逆向基础条记十八 汇编 结构体和内存对齐
逆向基础条记十九 汇编switch比较if else
逆向基础条记二十 汇编 指针(一)
逆向基础条记二十一 汇编 指针(二)
逆向基础条记二十二 汇编 指针(三)
逆向基础条记二十三 汇编 指针(四)
指针作为参数
代码
#include "stdafx.h"void function(int num){ num=52;}void function2(int* num){ *num=52;}int main(int argc, char* argv[]){ int num=610; function(num); printf("%d\n",num); function2(&num); printf("%d\n",num); return 0;}运行结果
可以看到没有通过指针进行传参的数据在function内部修改后并没有影响到本来的数值
而通过指针进行传参的数据在function2内部修改后就影响了本来的数值
反汇编代码
函数外部
num初始化
20: int num=610;0040D978 mov dword ptr [ebp-4],262hfunction和输出
21: function(num);0040D97F mov eax,dword ptr [ebp-4]0040D982 push eax0040D983 call @ILT+15(function) (00401014)0040D988 add esp,422: printf("%d\n",num);0040D98B mov ecx,dword ptr [ebp-4]0040D98E push ecx0040D98F push offset string "%d\n" (0042201c)0040D994 call printf (00401130)0040D999 add esp,8function2和输出
23: function2(&num);0040D99C lea edx,[ebp-4]0040D99F push edx0040D9A0 call @ILT+20(function2) (00401019)0040D9A5 add esp,424: printf("%d\n",num);0040D9A8 mov eax,dword ptr [ebp-4]0040D9AB push eax0040D9AC push offset string "%d\n" (0042201c)0040D9B1 call printf (00401130)0040D9B6 add esp,8函数内部
function
8: void function(int num){0040D870 push ebp0040D871 mov ebp,esp0040D873 sub esp,40h0040D876 push ebx0040D877 push esi0040D878 push edi0040D879 lea edi,[ebp-40h]0040D87C mov ecx,10h0040D881 mov eax,0CCCCCCCCh0040D886 rep stos dword ptr [edi]9: num=52;0040D888 mov dword ptr [ebp+8],34h10: }0040D88F pop edi0040D890 pop esi0040D891 pop ebx0040D892 mov esp,ebp0040D894 pop ebp0040D895 retfunction2
12: void function2(int* num){0040D7E0 push ebp0040D7E1 mov ebp,esp0040D7E3 sub esp,40h0040D7E6 push ebx0040D7E7 push esi0040D7E8 push edi0040D7E9 lea edi,[ebp-40h]0040D7EC mov ecx,10h0040D7F1 mov eax,0CCCCCCCCh0040D7F6 rep stos dword ptr [edi]13: *num=52;0040D7F8 mov eax,dword ptr [ebp+8]0040D7FB mov dword ptr [eax],34h14: }0040D801 pop edi0040D802 pop esi0040D803 pop ebx0040D804 mov esp,ebp0040D806 pop ebp0040D807 ret反汇编分析
function分析
function外部
21: function(num);0040D97F mov eax,dword ptr [ebp-4]0040D982 push eax0040D983 call @ILT+15(function) (00401014)0040D988 add esp,4将[ebp-4]也就是num赋值给eax,然后将eax作为参数压入到堆栈中
用内存窗口观察此时ebp-4的情况:
此时的ebp-4对应地址为0012FF7C,也就是前面的num
function内部
截取出赋值的关键代码
9: num=52;0040D888 mov dword ptr [ebp+8],34h留意到此时赋值为[ebp+8](参数),用内存窗口观察其地址并比较和先前的ebp-4的地址
可以看到此时要赋值的地址为0012FF2C,和先前的num地址0012FF7C差别,但值是雷同的:0x262=610
于是就造成了就算修改了这里的地址中的值也不会影响本来的值
小总结
在函数内部得到的参数的值虽然和传入的参数的值一致,但实际的内存地址并不雷同,于是在函数内部修改值并不会影响到本来的值
function2分析
function2外部
23: function2(&num);0040D99C lea edx,[ebp-4]0040D99F push edx0040D9A0 call @ILT+20(function2) (00401019)0040D9A5 add esp,4将ebp-4的地址传给edx,然后将edx作为参数压入到堆栈中
观察此时ebp-4的情况:
此时ebp-4就是num的地址=0012FF7C
function2内部
截取出关键的赋值代码
13: *num=52;0040D7F8 mov eax,dword ptr [ebp+8]0040D7FB mov dword ptr [eax],34h起首看[ebp+8]:
会发现此时的ebp+8所存的内容就是num的地址:0012FF7C
这里是将[ebp+8](参数)赋值给eax,赋值后的eax是即是外面的num的
然后再将0x34赋值到参数所存储的内容里
小总结
使用指针作为参数可以实如今函数内部修改后外部的值也可以同步被修改
指针作为参数总结
通过比较指针传参和非指针传参得到了以下结论:
无论是指针传参照旧非指针传参,将参数传入函数内部后,只保证了参数的内容一致,但地址差别
之所以指针传参能够实现修改函数外部值的效果,是因为传入的参数的值就是外部值的地址,传入的是个地址,通过修改同个地址里的值而达到了影响外部值的效果
传入参数差异非指针传参参数是值修改值只修改了函数内部的值,不影响函数外部指针传参参数是址修改值是通过地址来修改的,因而能够影响函数外部使用指针作为参数十分常见,因为通过这种方式就可以不用返回值,直接将要返回的数据生存在指针里即可
常见的例子:
NTSTATUS ZwOpenProcess ( __out PHANDLE ProcessHandle, //进程句柄,PHANDLE 句柄指针 __in ACCESS_MASK DesiredAccess, //想要的权限 __in POBJECT_ATTRIBUTES ObjectAttributes, //指向ObjectAttributes的指针 __in_opt PCLIENT_ID ClientId //指向ClientId的指针 )这是一个内核函数,用来打开进程,具体使用细节这里不做重点
这里的ProcessHandle是一个指针,它作为参数就是用来存储打开进程后得到的进程句柄
很多内核函数都接纳了这种形式——指针作为参数来存储要返回的数据
指针作为返回值
先前在数组里跳过了将数组作为返回值来传递,因为当时还没有讲到指针,接下来看看指针作为返回值的情形
错误的返回值
代码
#include "stdafx.h"#include int* function(){ int arr[5]={1,2,3,4,5}; return arr;}int main(int argc, char* argv[]){ int*arr; arr=function(); int i; for(i=0;i |