_stdcall调用约定下,函数调用时用到的指令序列大致如下:
push 参数3
push 参数2
push 参数1
call 函数地址;a)向栈中压入当前指令在内存中的位置,即保存保存返回地址。
b)跳转到所调用函数的入口
push ebp 保存旧栈帧的底部
mov ebp,esp 设置新栈帧的底部(栈帧切换)
sub esp,xxx 设置新栈帧的顶部(抬高栈顶,为新栈帧开辟空间)
函数调用时系统栈的变化过程
2.2修改临近变量
#include <stdio.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[8];// add local buff
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//over flowed here!
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024];
while(1)
{
printf("please input password: ");
scanf("%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!\n\n");
}
else
{
printf("Congratulation! You have passed the verification!\n");
break;
}
}
}
动态调试分析:
进入该函数verify_password前:
此时的栈截图:
步入
进入strcmp前
进入strcpy前
步过strcpy之后
win32内存
内存数据与数值数据
内存中由低位到高位存储,但是作为数值应用时,按照高位到低位进行解释
输入8个字符且ASCII值比1234567就可过掉验证
2.3修改函数返回地址
#include <stdio.h>
#define PASSWORD "1234567"
int verify_password (char password)
{
int authenticated;
char buffer[8];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//over flowed here!
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024];
FILE fp;
if(!(fp=fopen("password.txt","rw+")))
{
exit(0);
}
fscanf(fp,"%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!\n");
}
else
{
printf("Congratulation! You have passed the verification!\n");
}
fclose(fp);
}
最后四字节是修改的返回地址,这个地址就是成功初地址
代码植入
弹个MessageBoxA
两个地址需要从本机上查出来修改